chroot: fix gid being set by uid with --userspec #10307 (#10465)

* chroot: fix gid being set by uid with --userspec

* chroot: check using sync user that has uid != gid

* chroot: correct Error response on failure case

* chroot: fix test

* chroot: test failure output

---------

Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
This commit is contained in:
cerdelen
2026-02-12 02:54:14 -08:00
committed by GitHub
co-authored by Sylvestre Ledru
parent 808865e4ac
commit 04e258f171
3 changed files with 47 additions and 2 deletions
+2 -2
View File
@@ -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))?;
+5
View File
@@ -356,6 +356,11 @@ pub fn usr2uid(name: &str) -> IOResult<uid_t> {
Passwd::locate(name).map(|p| p.uid)
}
#[inline]
pub fn usr2gid(name: &str) -> IOResult<gid_t> {
Passwd::locate(name).map(|p| p.gid)
}
#[inline]
pub fn grp2gid(name: &str) -> IOResult<gid_t> {
Group::locate(name).map(|p| p.gid)
+40
View File
@@ -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");
}
}