diff --git a/src/uu/chroot/src/chroot.rs b/src/uu/chroot/src/chroot.rs index 04cb8c0c965..e6c4ee70192 100644 --- a/src/uu/chroot/src/chroot.rs +++ b/src/uu/chroot/src/chroot.rs @@ -14,7 +14,7 @@ use std::os::unix::prelude::OsStrExt; use std::os::unix::process::CommandExt; use std::path::{Path, PathBuf}; use std::process; -use uucore::entries::{Locate, Passwd, grp2gid, usr2uid}; +use uucore::entries::{Locate, Passwd, grp2gid, usr2gid, usr2uid}; use uucore::error::{UResult, UUsageError}; use uucore::fs::{MissingHandling, ResolveMode, canonicalize}; use uucore::libc::{self, chroot, setgid, setgroups, setuid}; @@ -401,7 +401,7 @@ fn set_context(options: &Options) -> UResult<()> { } Some(UserSpec::UserOnly(user)) => { let uid = name_to_uid(user)?; - let gid = uid as libc::gid_t; + let gid = usr2gid(user).map_err(|_| ChrootError::NoGroupSpecified(uid))?; let strategy = Strategy::FromUID(uid, false); set_supplemental_gids_with_strategy(strategy, options.groups.as_ref())?; set_gid(gid).map_err(|e| ChrootError::SetGidFailed(user.to_owned(), e))?; diff --git a/src/uucore/src/lib/features/entries.rs b/src/uucore/src/lib/features/entries.rs index 6a067e132b7..b6c969a04bc 100644 --- a/src/uucore/src/lib/features/entries.rs +++ b/src/uucore/src/lib/features/entries.rs @@ -356,6 +356,11 @@ pub fn usr2uid(name: &str) -> IOResult { Passwd::locate(name).map(|p| p.uid) } +#[inline] +pub fn usr2gid(name: &str) -> IOResult { + Passwd::locate(name).map(|p| p.gid) +} + #[inline] pub fn grp2gid(name: &str) -> IOResult { Group::locate(name).map(|p| p.gid) diff --git a/tests/by-util/test_chroot.rs b/tests/by-util/test_chroot.rs index adeaf32bf6c..7d7a1c3b227 100644 --- a/tests/by-util/test_chroot.rs +++ b/tests/by-util/test_chroot.rs @@ -327,3 +327,43 @@ fn test_chroot_extra_arg() { print!("Test skipped; requires root user"); } } + +#[test] +fn test_chroot_userspec_does_not_set_gid_with_uid() { + use uucore::entries::{usr2gid, usr2uid}; + + let ts = TestScenario::new(util_name!()); + if let Ok(uid) = usr2uid("sync") { + if let Ok(gid) = usr2gid("sync") { + if gid == uid { + println!("Test skipped; requires sync user to have uid != gid"); + return; + } + // Ubuntu has a sync user whose gid is 65534 per default + if let Ok(result) = run_ucmd_as_root(&ts, &["--userspec=sync", "/", "id", "-g"]) { + result.success().no_stderr().stdout_is(format!("{gid}\n")); + } else { + println!("Test skipped; requires root user"); + } + } else { + println!("Test skipped; requires 'sync' user"); + } + } else { + println!("Test skipped; requires 'sync' user"); + } +} + +#[test] +fn test_chroot_userspec_unknown_uid() { + let ts = TestScenario::new(util_name!()); + if let Ok(result) = + run_ucmd_as_root(&ts, &["--userspec=99999", "--groups=root", "/", "id", "-g"]) + { + result + .failure() + .code_is(125) + .stderr_is("chroot: no group specified for unknown uid: 99999\n"); + } else { + println!("Test skipped; requires root user"); + } +}