** Description changed:
+ [ Impact ]
+
+ sudo-rs fails on systems where any group with sudo privileges on the system
has
+ a large amount of users. This leads to users on such systems being unable to
+ use the sudo command, which arguably serves as justification for backporting
+ the fix.
+
+ The root cause is that when sudo-rs tries to determine the gid of a named
+ group, a buffer is allocated for getgrnam_r / getgrgid/_r. If this buffer is
+ too small, sudo-rs fails and assumes the group does not exist.
+
+ The fix is to use flexible array sizes for the buffer and impose an artificial
+ upper limit, panicking if it is breached (this limit is *very* large).
+
+ [ Test Plan ]
+
+ Reproduce the bug:
+ ------------------
+
+ * Create a user called "ubuntu"
+
+ useradd -M ubuntu 2>/dev/null || true
+
+ * Verify that sudo-rs is the sudo provider:
+
+ sudo --version
+
+ # Output:
+ # sudo-rs 0.2.13-0ubuntu1
+ # ~~~~~~~
+
+ * Create a group with a large member list:
+
+ # Create the group
+ groupadd biggroup
+
+ # Generate ~200 dummy members so the /etc/group entry exceeds the
+ # 1024-byte buffer (NSS_BUFLEN_GROUP / _SC_GETGR_R_SIZE_MAX)
+ MEMBERS=""
+ for i in $(seq 1 200); do
+ MEMBERS="${MEMBERS},user${i}"
+ done
+ MEMBERS="${MEMBERS:1}" # strip leading comma
+
+ # Add ubuntu as a real member
+ gpasswd -a ubuntu biggroup
+
+ # Rewrite the group line to include all dummy members + ubuntu
+ GID=$(getent group biggroup | cut -d: -f3)
+ sed -i "s/^biggroup:x:${GID}:.*$/biggroup:x:${GID}:${MEMBERS},ubuntu/"
/etc/group
+
+ # Verify the line exceeds 1024 bytes
+ echo "Group line length: $(getent group biggroup | wc -c) bytes (buffer is
1024)"
+ '
+
+ * Isolate the sudoers rule to only %biggroup
+
+ # Remove ubuntu from the "sudo" group so %sudo rule does not match
+ gpasswd -d ubuntu sudo 2>/dev/null || true
+
+ # Disable the cloud-init NOPASSWD rule for ubuntu (if applicable)
+ mv /etc/sudoers.d/90-cloud-init-users
/etc/sudoers.d/90-cloud-init-users.disabled
+
+ # Add the sudoers rule for %biggroup
+ echo "%biggroup ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/biggroup
+ chmod 440 /etc/sudoers.d/biggroup
+
+ # Verify the rule is syntactically valid
+ visudo -cf /etc/sudoers.d/biggroup
+
+ * Verify the group entry exceeds the buffer and triggers ERANGE
+
+ B=$(getconf NSS_BUFLEN_GROUP); L=$(getent group biggroup | wc -c)
+ echo "Buffer: $B bytes | Group entry: $L bytes → $([ $L -gt $B ] && echo
ERANGE || echo OK)"
+
+ * Run sudo:
+
+ sudo id
+
+ # Output:
+ # sudo: I'm sorry ubuntu. I'm afraid I can't do that
+
+ Testing proposed (same system as reproduced):
+ ---------------------------------------------
+
+ * Install the proposed sudo-rs:
+
+ sudo apt install -t resolute-proposed rust-sudo-rs
+
+ * Verify that sudo now works:
+
+ sudo id
+
+ # Expected: uid=0(root) gid=0(root) groups=0(root)
+
+ Testing for regressions:
+ ------------------------
+
+ * Test many groups:
+
+ # 1. Create 100 groups
+ for i in $(seq 1 100); do groupadd manygrp$i; done
+
+ # 2. Create a user and add them to all 100 groups
+ useradd -m -G $(seq -f 'manygrp%g' -s, 1 100 | sed 's/\n//') testuser2
+
+ # 3. Verify group count
+ id testuser2 | grep -o 'gid=' | wc -l # should show many groups
+
+ # 4. Add a sudoers rule matching one of those groups
+ echo "%manygrp50 ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-manygrp
+ sudo visudo -cf /etc/sudoers.d/test-manygrp
+
+ # 5. Verify sudo works
+ su - testuser2 -c "sudo -n id"
+ # Expected: euid=0(root) - getgrouplist correctly enumerated 100+ groups
+
+ * Test long group member list:
+
+ # 1. Create a group
+ groupadd biggrp
+
+ # 2. Add 500 users to it (creates a very long /etc/group line)
+ for i in $(seq 1 500); do
+ useradd -M biguser$i 2>/dev/null || true
+ gpasswd -a biguser$i biggrp
+ done
+
+ # 3. Add a sudoers rule for this group
+ echo "%biggrp ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp
+ visudo -cf /etc/sudoers.d/test-biggrp
+
+ # 4. Create a user in biggrp and test
+ useradd -m -G biggrp testuser3
+ su - testuser3 -c "sudo -n id"
+ # Expected: euid=0(root) - getgrnam_r grew its buffer to handle the long
line
+
+ # 5. Also verify from the GID direction
+ GID=$(getent group biggrp | cut -d: -f3)
+ echo "#$GID ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp-gid
+ rm /etc/sudoers.d/test-biggrp
+ su - testuser3 -c "sudo -n id"
+ # Expected: euid=0(root) - getgrgid_r also grew its buffer
+
+
+ [ Where problems could occur ]
+
+ * The fix allows sudo-rs to allocate a transient buffer of up to i32::MAX
+ (2 GiB), whereas the previous version of the code only allowed a transient
+ size of 16 KiB. This can in the worst case introduce a DoS attack surface
+ where malformed/NSS group entries consistently return ERANGE (result too
+ large) and could cause OOM on memory constrained systems. The pre-condition
+ for this attack requires the ability to modify /etc/group, but can also be
+ achieved by a misbehaving NSS plugin.
+
+ * sudo-rs will now directly panic rather than return an error if the new upper
+ bound is exceeded. Although, this means that there are either more than
+ 65 536 groups on the system or over 1 TiB of group data, which would likely
+ trigger other problems before surfacing in sudo.
+
+ * Since the group data buffer is dynamically filled, sudo-rs will retry with
+ new sizes exponentially before giving up. This may introduce latency issues
+ on a slow NSS backend where the time to failure is longer than before.
+
+
+ [ Other Info ]
+
+ * This SRU is part of a larger merge proposal for 26.04.1
+
+ * The fix is also natively part of the 0.2.14-1 upload to Stonking, currently
+ in proposed-migration
+
+
+ [ Original Description ]
+
This is tracked in the upstream bug
https://github.com/trifectatechfoundation/sudo-rs/issues/1572
In 26.04 LTS, sudo-rs fails when you have any group in your system with
many users; the trigger is long lines in /etc/group or `getent group`
returning many users. When that happens:
- kiko@solitaire:~$ sudo vi /etc/sudoers
- sudo: I'm sorry kiko. I'm afraid I can't do that
+ kiko@solitaire:~$ sudo vi /etc/sudoers
+ sudo: I'm sorry kiko. I'm afraid I can't do that
whereas sudo.ws works fine.
One workaround is to use the group ID in sudoers (using the %#id
format); shortening groups and using sudo.ws are others.
This should qualify for an SRU.
** Summary changed:
- sudo-rs fails with "I'm sorry" message in systems with large groups
+ [SRU] sudo-rs fails with "I'm sorry" message in systems with large groups
** Description changed:
[ Impact ]
- sudo-rs fails on systems where any group with sudo privileges on the system
has
+ sudo-rs fails on systems where any group on the system has
a large amount of users. This leads to users on such systems being unable to
use the sudo command, which arguably serves as justification for backporting
the fix.
The root cause is that when sudo-rs tries to determine the gid of a named
group, a buffer is allocated for getgrnam_r / getgrgid/_r. If this buffer is
too small, sudo-rs fails and assumes the group does not exist.
The fix is to use flexible array sizes for the buffer and impose an artificial
upper limit, panicking if it is breached (this limit is *very* large).
[ Test Plan ]
Reproduce the bug:
------------------
* Create a user called "ubuntu"
useradd -M ubuntu 2>/dev/null || true
* Verify that sudo-rs is the sudo provider:
sudo --version
# Output:
# sudo-rs 0.2.13-0ubuntu1
# ~~~~~~~
* Create a group with a large member list:
# Create the group
groupadd biggroup
# Generate ~200 dummy members so the /etc/group entry exceeds the
# 1024-byte buffer (NSS_BUFLEN_GROUP / _SC_GETGR_R_SIZE_MAX)
MEMBERS=""
for i in $(seq 1 200); do
- MEMBERS="${MEMBERS},user${i}"
+ MEMBERS="${MEMBERS},user${i}"
done
MEMBERS="${MEMBERS:1}" # strip leading comma
# Add ubuntu as a real member
gpasswd -a ubuntu biggroup
# Rewrite the group line to include all dummy members + ubuntu
GID=$(getent group biggroup | cut -d: -f3)
sed -i "s/^biggroup:x:${GID}:.*$/biggroup:x:${GID}:${MEMBERS},ubuntu/"
/etc/group
# Verify the line exceeds 1024 bytes
echo "Group line length: $(getent group biggroup | wc -c) bytes (buffer is
1024)"
'
* Isolate the sudoers rule to only %biggroup
# Remove ubuntu from the "sudo" group so %sudo rule does not match
gpasswd -d ubuntu sudo 2>/dev/null || true
# Disable the cloud-init NOPASSWD rule for ubuntu (if applicable)
mv /etc/sudoers.d/90-cloud-init-users
/etc/sudoers.d/90-cloud-init-users.disabled
# Add the sudoers rule for %biggroup
echo "%biggroup ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/biggroup
chmod 440 /etc/sudoers.d/biggroup
# Verify the rule is syntactically valid
visudo -cf /etc/sudoers.d/biggroup
* Verify the group entry exceeds the buffer and triggers ERANGE
B=$(getconf NSS_BUFLEN_GROUP); L=$(getent group biggroup | wc -c)
echo "Buffer: $B bytes | Group entry: $L bytes → $([ $L -gt $B ] && echo
ERANGE || echo OK)"
* Run sudo:
sudo id
# Output:
# sudo: I'm sorry ubuntu. I'm afraid I can't do that
Testing proposed (same system as reproduced):
---------------------------------------------
* Install the proposed sudo-rs:
sudo apt install -t resolute-proposed rust-sudo-rs
* Verify that sudo now works:
sudo id
# Expected: uid=0(root) gid=0(root) groups=0(root)
Testing for regressions:
------------------------
* Test many groups:
- # 1. Create 100 groups
- for i in $(seq 1 100); do groupadd manygrp$i; done
+ # 1. Create 100 groups
+ for i in $(seq 1 100); do groupadd manygrp$i; done
- # 2. Create a user and add them to all 100 groups
- useradd -m -G $(seq -f 'manygrp%g' -s, 1 100 | sed 's/\n//') testuser2
+ # 2. Create a user and add them to all 100 groups
+ useradd -m -G $(seq -f 'manygrp%g' -s, 1 100 | sed 's/\n//') testuser2
- # 3. Verify group count
- id testuser2 | grep -o 'gid=' | wc -l # should show many groups
+ # 3. Verify group count
+ id testuser2 | grep -o 'gid=' | wc -l # should show many groups
- # 4. Add a sudoers rule matching one of those groups
- echo "%manygrp50 ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-manygrp
- sudo visudo -cf /etc/sudoers.d/test-manygrp
+ # 4. Add a sudoers rule matching one of those groups
+ echo "%manygrp50 ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-manygrp
+ sudo visudo -cf /etc/sudoers.d/test-manygrp
- # 5. Verify sudo works
- su - testuser2 -c "sudo -n id"
- # Expected: euid=0(root) - getgrouplist correctly enumerated 100+ groups
+ # 5. Verify sudo works
+ su - testuser2 -c "sudo -n id"
+ # Expected: euid=0(root) - getgrouplist correctly enumerated 100+ groups
* Test long group member list:
- # 1. Create a group
- groupadd biggrp
+ # 1. Create a group
+ groupadd biggrp
- # 2. Add 500 users to it (creates a very long /etc/group line)
- for i in $(seq 1 500); do
- useradd -M biguser$i 2>/dev/null || true
- gpasswd -a biguser$i biggrp
- done
+ # 2. Add 500 users to it (creates a very long /etc/group line)
+ for i in $(seq 1 500); do
+ useradd -M biguser$i 2>/dev/null || true
+ gpasswd -a biguser$i biggrp
+ done
- # 3. Add a sudoers rule for this group
- echo "%biggrp ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp
- visudo -cf /etc/sudoers.d/test-biggrp
+ # 3. Add a sudoers rule for this group
+ echo "%biggrp ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp
+ visudo -cf /etc/sudoers.d/test-biggrp
- # 4. Create a user in biggrp and test
- useradd -m -G biggrp testuser3
- su - testuser3 -c "sudo -n id"
- # Expected: euid=0(root) - getgrnam_r grew its buffer to handle the long
line
+ # 4. Create a user in biggrp and test
+ useradd -m -G biggrp testuser3
+ su - testuser3 -c "sudo -n id"
+ # Expected: euid=0(root) - getgrnam_r grew its buffer to handle the long
line
- # 5. Also verify from the GID direction
- GID=$(getent group biggrp | cut -d: -f3)
- echo "#$GID ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp-gid
- rm /etc/sudoers.d/test-biggrp
- su - testuser3 -c "sudo -n id"
- # Expected: euid=0(root) - getgrgid_r also grew its buffer
-
+ # 5. Also verify from the GID direction
+ GID=$(getent group biggrp | cut -d: -f3)
+ echo "#$GID ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp-gid
+ rm /etc/sudoers.d/test-biggrp
+ su - testuser3 -c "sudo -n id"
+ # Expected: euid=0(root) - getgrgid_r also grew its buffer
[ Where problems could occur ]
* The fix allows sudo-rs to allocate a transient buffer of up to i32::MAX
- (2 GiB), whereas the previous version of the code only allowed a transient
- size of 16 KiB. This can in the worst case introduce a DoS attack surface
- where malformed/NSS group entries consistently return ERANGE (result too
- large) and could cause OOM on memory constrained systems. The pre-condition
- for this attack requires the ability to modify /etc/group, but can also be
- achieved by a misbehaving NSS plugin.
+ (2 GiB), whereas the previous version of the code only allowed a transient
+ size of 16 KiB. This can in the worst case introduce a DoS attack surface
+ where malformed/NSS group entries consistently return ERANGE (result too
+ large) and could cause OOM on memory constrained systems. The pre-condition
+ for this attack requires the ability to modify /etc/group, but can also be
+ achieved by a misbehaving NSS plugin.
* sudo-rs will now directly panic rather than return an error if the new upper
- bound is exceeded. Although, this means that there are either more than
- 65 536 groups on the system or over 1 TiB of group data, which would likely
- trigger other problems before surfacing in sudo.
+ bound is exceeded. Although, this means that there are either more than
+ 65 536 groups on the system or over 1 TiB of group data, which would likely
+ trigger other problems before surfacing in sudo.
* Since the group data buffer is dynamically filled, sudo-rs will retry with
- new sizes exponentially before giving up. This may introduce latency issues
- on a slow NSS backend where the time to failure is longer than before.
-
+ new sizes exponentially before giving up. This may introduce latency issues
+ on a slow NSS backend where the time to failure is longer than before.
[ Other Info ]
* This SRU is part of a larger merge proposal for 26.04.1
* The fix is also natively part of the 0.2.14-1 upload to Stonking, currently
- in proposed-migration
-
+ in proposed-migration
[ Original Description ]
This is tracked in the upstream bug
https://github.com/trifectatechfoundation/sudo-rs/issues/1572
In 26.04 LTS, sudo-rs fails when you have any group in your system with
many users; the trigger is long lines in /etc/group or `getent group`
returning many users. When that happens:
kiko@solitaire:~$ sudo vi /etc/sudoers
sudo: I'm sorry kiko. I'm afraid I can't do that
whereas sudo.ws works fine.
One workaround is to use the group ID in sudoers (using the %#id
format); shortening groups and using sudo.ws are others.
This should qualify for an SRU.
** Description changed:
[ Impact ]
sudo-rs fails on systems where any group on the system has
a large amount of users. This leads to users on such systems being unable to
use the sudo command, which arguably serves as justification for backporting
the fix.
The root cause is that when sudo-rs tries to determine the gid of a named
group, a buffer is allocated for getgrnam_r / getgrgid/_r. If this buffer is
too small, sudo-rs fails and assumes the group does not exist.
The fix is to use flexible array sizes for the buffer and impose an artificial
upper limit, panicking if it is breached (this limit is *very* large).
[ Test Plan ]
Reproduce the bug:
------------------
* Create a user called "ubuntu"
useradd -M ubuntu 2>/dev/null || true
* Verify that sudo-rs is the sudo provider:
sudo --version
# Output:
# sudo-rs 0.2.13-0ubuntu1
# ~~~~~~~
* Create a group with a large member list:
# Create the group
groupadd biggroup
# Generate ~200 dummy members so the /etc/group entry exceeds the
# 1024-byte buffer (NSS_BUFLEN_GROUP / _SC_GETGR_R_SIZE_MAX)
MEMBERS=""
for i in $(seq 1 200); do
MEMBERS="${MEMBERS},user${i}"
done
MEMBERS="${MEMBERS:1}" # strip leading comma
# Add ubuntu as a real member
gpasswd -a ubuntu biggroup
# Rewrite the group line to include all dummy members + ubuntu
GID=$(getent group biggroup | cut -d: -f3)
sed -i "s/^biggroup:x:${GID}:.*$/biggroup:x:${GID}:${MEMBERS},ubuntu/"
/etc/group
# Verify the line exceeds 1024 bytes
echo "Group line length: $(getent group biggroup | wc -c) bytes (buffer is
1024)"
'
* Isolate the sudoers rule to only %biggroup
- # Remove ubuntu from the "sudo" group so %sudo rule does not match
+ # Remove ubuntu from the "sudo" group to make sure %sudo rule does not match
gpasswd -d ubuntu sudo 2>/dev/null || true
# Disable the cloud-init NOPASSWD rule for ubuntu (if applicable)
mv /etc/sudoers.d/90-cloud-init-users
/etc/sudoers.d/90-cloud-init-users.disabled
# Add the sudoers rule for %biggroup
echo "%biggroup ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/biggroup
chmod 440 /etc/sudoers.d/biggroup
# Verify the rule is syntactically valid
visudo -cf /etc/sudoers.d/biggroup
* Verify the group entry exceeds the buffer and triggers ERANGE
B=$(getconf NSS_BUFLEN_GROUP); L=$(getent group biggroup | wc -c)
echo "Buffer: $B bytes | Group entry: $L bytes → $([ $L -gt $B ] && echo
ERANGE || echo OK)"
* Run sudo:
sudo id
# Output:
# sudo: I'm sorry ubuntu. I'm afraid I can't do that
Testing proposed (same system as reproduced):
---------------------------------------------
* Install the proposed sudo-rs:
sudo apt install -t resolute-proposed rust-sudo-rs
* Verify that sudo now works:
sudo id
# Expected: uid=0(root) gid=0(root) groups=0(root)
Testing for regressions:
------------------------
* Test many groups:
# 1. Create 100 groups
for i in $(seq 1 100); do groupadd manygrp$i; done
# 2. Create a user and add them to all 100 groups
useradd -m -G $(seq -f 'manygrp%g' -s, 1 100 | sed 's/\n//') testuser2
# 3. Verify group count
id testuser2 | grep -o 'gid=' | wc -l # should show many groups
# 4. Add a sudoers rule matching one of those groups
echo "%manygrp50 ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-manygrp
sudo visudo -cf /etc/sudoers.d/test-manygrp
# 5. Verify sudo works
su - testuser2 -c "sudo -n id"
# Expected: euid=0(root) - getgrouplist correctly enumerated 100+ groups
* Test long group member list:
# 1. Create a group
groupadd biggrp
# 2. Add 500 users to it (creates a very long /etc/group line)
for i in $(seq 1 500); do
useradd -M biguser$i 2>/dev/null || true
gpasswd -a biguser$i biggrp
done
# 3. Add a sudoers rule for this group
echo "%biggrp ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp
visudo -cf /etc/sudoers.d/test-biggrp
# 4. Create a user in biggrp and test
useradd -m -G biggrp testuser3
su - testuser3 -c "sudo -n id"
# Expected: euid=0(root) - getgrnam_r grew its buffer to handle the long
line
# 5. Also verify from the GID direction
GID=$(getent group biggrp | cut -d: -f3)
echo "#$GID ALL=(ALL:ALL) ALL" > /etc/sudoers.d/test-biggrp-gid
rm /etc/sudoers.d/test-biggrp
su - testuser3 -c "sudo -n id"
# Expected: euid=0(root) - getgrgid_r also grew its buffer
[ Where problems could occur ]
* The fix allows sudo-rs to allocate a transient buffer of up to i32::MAX
(2 GiB), whereas the previous version of the code only allowed a transient
size of 16 KiB. This can in the worst case introduce a DoS attack surface
where malformed/NSS group entries consistently return ERANGE (result too
large) and could cause OOM on memory constrained systems. The pre-condition
for this attack requires the ability to modify /etc/group, but can also be
achieved by a misbehaving NSS plugin.
* sudo-rs will now directly panic rather than return an error if the new upper
bound is exceeded. Although, this means that there are either more than
65 536 groups on the system or over 1 TiB of group data, which would likely
trigger other problems before surfacing in sudo.
* Since the group data buffer is dynamically filled, sudo-rs will retry with
new sizes exponentially before giving up. This may introduce latency issues
on a slow NSS backend where the time to failure is longer than before.
[ Other Info ]
* This SRU is part of a larger merge proposal for 26.04.1
* The fix is also natively part of the 0.2.14-1 upload to Stonking, currently
in proposed-migration
[ Original Description ]
This is tracked in the upstream bug
https://github.com/trifectatechfoundation/sudo-rs/issues/1572
In 26.04 LTS, sudo-rs fails when you have any group in your system with
many users; the trigger is long lines in /etc/group or `getent group`
returning many users. When that happens:
kiko@solitaire:~$ sudo vi /etc/sudoers
sudo: I'm sorry kiko. I'm afraid I can't do that
whereas sudo.ws works fine.
One workaround is to use the group ID in sudoers (using the %#id
format); shortening groups and using sudo.ws are others.
This should qualify for an SRU.
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2158541
Title:
[SRU] sudo-rs fails with "I'm sorry" message in systems with large
groups
To manage notifications about this bug go to:
https://bugs.launchpad.net/sudo-rs/+bug/2158541/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs