From b125159535945843c2be7dfaf128c1ab1ed9d1b5 Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Sun, 12 Sep 2021 13:12:28 +0200 Subject: [PATCH] getgroups: Handle race conditions properly --- src/uucore/src/lib/features/entries.rs | 35 ++++++++++++++++---------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/uucore/src/lib/features/entries.rs b/src/uucore/src/lib/features/entries.rs index 14908b796..61ed7f1e5 100644 --- a/src/uucore/src/lib/features/entries.rs +++ b/src/uucore/src/lib/features/entries.rs @@ -72,19 +72,28 @@ extern "C" { /// > to be used in a further call to getgroups(). #[cfg(not(target_os = "redox"))] pub fn get_groups() -> IOResult> { - let ngroups = unsafe { getgroups(0, ptr::null_mut()) }; - if ngroups == -1 { - return Err(IOError::last_os_error()); - } - let mut groups = vec![0; ngroups.try_into().unwrap()]; - let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) }; - if ngroups == -1 { - Err(IOError::last_os_error()) - } else { - let ngroups = ngroups.try_into().unwrap(); - assert!(ngroups <= groups.len()); - groups.truncate(ngroups); - Ok(groups) + loop { + let ngroups = match unsafe { getgroups(0, ptr::null_mut()) } { + -1 => return Err(IOError::last_os_error()), + // Not just optimization; 0 would mess up the next call + 0 => return Ok(Vec::new()), + n => n, + }; + + let mut groups = vec![0; ngroups.try_into().unwrap()]; + let res = unsafe { getgroups(ngroups, groups.as_mut_ptr()) }; + if res == -1 { + let err = IOError::last_os_error(); + if err.raw_os_error() == Some(libc::EINVAL) { + // Number of groups changed, retry + continue; + } else { + return Err(err); + } + } else { + groups.truncate(ngroups.try_into().unwrap()); + return Ok(groups); + } } }