Skip to content

Commit da05463

Browse files
committed
fix(supervisor): harden tests for restricted CI container environments
Guard tests against CI-specific constraints: root without CAP_SETPCAP, UIDs with no /etc/passwd entry, and restricted /proc access. Signed-off-by: Seth Jennings <sjennings@nvidia.com> Signed-off-by: Seth Jennings <sjenning@redhat.com>
1 parent be05115 commit da05463

2 files changed

Lines changed: 48 additions & 7 deletions

File tree

crates/openshell-supervisor-process/src/bypass_monitor/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,18 @@ mod tests {
540540
}
541541
}
542542

543+
if std::fs::read_link(format!("/proc/{child_pid}/exe")).is_err()
544+
|| std::fs::read_dir(format!("/proc/{child_pid}/fd")).is_err()
545+
{
546+
#[allow(unsafe_code)]
547+
unsafe {
548+
libc::kill(child_pid, libc::SIGKILL);
549+
libc::waitpid(child_pid, std::ptr::null_mut(), 0);
550+
}
551+
eprintln!("skipping: cannot read /proc/{child_pid} (restricted /proc)");
552+
return;
553+
}
554+
543555
let deadline = Instant::now() + Duration::from_secs(2);
544556
loop {
545557
if let Ok(link) = std::fs::read_link(format!("/proc/{child_pid}/exe"))

crates/openshell-supervisor-process/src/process.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,17 @@ mod tests {
15991599
});
16001600

16011601
let result = drop_privileges(&policy);
1602+
#[cfg(target_os = "linux")]
1603+
{
1604+
if nix::unistd::geteuid().is_root() && !capability_bounding_set_clear_available() {
1605+
let msg = format!("{}", result.unwrap_err());
1606+
assert!(
1607+
msg.contains("Failed to clear child capability bounding set"),
1608+
"unexpected failure: {msg}"
1609+
);
1610+
return;
1611+
}
1612+
}
16021613
assert!(result.is_ok(), "drop_privileges failed: {result:?}");
16031614
}
16041615

@@ -1913,9 +1924,10 @@ mod tests {
19131924
return;
19141925
}
19151926

1916-
let current_user = User::from_uid(nix::unistd::geteuid())
1917-
.unwrap()
1918-
.expect("current user entry");
1927+
let Ok(Some(current_user)) = User::from_uid(nix::unistd::geteuid()) else {
1928+
eprintln!("skipping: current UID has no /etc/passwd entry");
1929+
return;
1930+
};
19191931
let restricted_group = Group::from_gid(Gid::from_raw(0))
19201932
.unwrap()
19211933
.expect("gid 0 group entry");
@@ -2266,10 +2278,10 @@ mod tests {
22662278
}
22672279

22682280
#[test]
2269-
fn drop_privileges_numeric_uid_without_passwd_entry_skips_lookup() {
2270-
// UID/GID 999999 has no /etc/passwd entry. drop_privileges must not fail
2271-
// with "Failed to resolve user record" — if it fails, EPERM is expected
2272-
// (non-root can't setuid to a different UID), not a lookup error.
2281+
fn numeric_uid_privilege_drop_child() {
2282+
if std::env::var_os("OPENSHELL_TEST_NUMERIC_UID_CHILD").is_none() {
2283+
return;
2284+
}
22732285
let policy = policy_with_process(ProcessPolicy {
22742286
run_as_user: Some("999999".into()),
22752287
run_as_group: Some("999999".into()),
@@ -2284,4 +2296,21 @@ mod tests {
22842296
}
22852297
}
22862298
}
2299+
2300+
#[test]
2301+
fn drop_privileges_numeric_uid_without_passwd_entry_skips_lookup() {
2302+
let mut cmd = std::process::Command::new(std::env::current_exe().expect("current exe"));
2303+
cmd.arg("numeric_uid_privilege_drop_child")
2304+
.arg("--nocapture")
2305+
.env("OPENSHELL_TEST_NUMERIC_UID_CHILD", "1")
2306+
.stdin(std::process::Stdio::null())
2307+
.stdout(std::process::Stdio::piped())
2308+
.stderr(std::process::Stdio::piped());
2309+
let output = cmd.output().expect("spawn child");
2310+
assert!(
2311+
output.status.success(),
2312+
"numeric UID privilege drop child failed: {}",
2313+
String::from_utf8_lossy(&output.stderr)
2314+
);
2315+
}
22872316
}

0 commit comments

Comments
 (0)