77 lines
3.1 KiB
Rust
77 lines
3.1 KiB
Rust
use std::process::ExitCode;
|
|
|
|
use rustix::thread::{
|
|
CapabilitySet, capabilities, capability_is_in_ambient_set, configure_capability_in_ambient_set,
|
|
set_capabilities,
|
|
};
|
|
|
|
#[allow(clippy::disallowed_methods, clippy::disallowed_types)]
|
|
fn main() -> ExitCode {
|
|
if std::env::var_os("LAZARET_CAPABILITY_DROP_ISOLATED").is_none() {
|
|
let before = lazaret_linux::capability::inspect(CapabilitySet::NET_ADMIN)
|
|
.expect("inspect unprivileged capability state");
|
|
if lazaret_linux::capability::irreversibly_drop(CapabilitySet::NET_ADMIN).is_err()
|
|
|| lazaret_linux::capability::inspect(CapabilitySet::NET_ADMIN).ok() != Some(before)
|
|
{
|
|
return ExitCode::FAILURE;
|
|
}
|
|
return match std::process::Command::new("unshare")
|
|
.args(["--user", "--map-root-user"])
|
|
.arg(std::env::current_exe().expect("test executable path"))
|
|
.env("LAZARET_CAPABILITY_DROP_ISOLATED", "1")
|
|
.output()
|
|
{
|
|
Ok(output) if output.status.success() => ExitCode::SUCCESS,
|
|
Ok(output)
|
|
if String::from_utf8_lossy(&output.stderr).contains("Operation not permitted") =>
|
|
{
|
|
eprintln!("SKIP isolated capability-positive branch: user namespaces unavailable");
|
|
ExitCode::SUCCESS
|
|
}
|
|
Ok(output) => {
|
|
eprintln!(
|
|
"isolated capability-positive branch failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
ExitCode::FAILURE
|
|
}
|
|
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
|
|
eprintln!("SKIP isolated capability-positive branch: unshare is unavailable");
|
|
ExitCode::SUCCESS
|
|
}
|
|
Err(error) => {
|
|
eprintln!("failed to run isolated capability-positive branch: {error}");
|
|
ExitCode::FAILURE
|
|
}
|
|
};
|
|
}
|
|
|
|
let capability = CapabilitySet::NET_ADMIN;
|
|
let retained = CapabilitySet::CHOWN;
|
|
let mut sets = capabilities(None).expect("inspect isolated capability sets");
|
|
sets.inheritable.insert(retained);
|
|
set_capabilities(None, sets).expect("prepare unrelated ambient capability");
|
|
configure_capability_in_ambient_set(retained, true)
|
|
.expect("raise unrelated ambient capability");
|
|
if lazaret_linux::capability::irreversibly_drop(capability).is_err() {
|
|
return ExitCode::FAILURE;
|
|
}
|
|
if lazaret_linux::capability::require_regain_refused(capability).is_err() {
|
|
return ExitCode::FAILURE;
|
|
}
|
|
let Ok(observed) = lazaret_linux::capability::inspect(capability) else {
|
|
return ExitCode::FAILURE;
|
|
};
|
|
if observed.sets.effective.intersects(capability)
|
|
|| observed.sets.permitted.intersects(capability)
|
|
|| observed.sets.inheritable.intersects(capability)
|
|
|| observed.ambient
|
|
|| observed.bounding
|
|
|| !capability_is_in_ambient_set(retained).unwrap_or(false)
|
|
|| configure_capability_in_ambient_set(capability, true).is_ok()
|
|
{
|
|
ExitCode::FAILURE
|
|
} else {
|
|
ExitCode::SUCCESS
|
|
}
|
|
}
|