Rework handling of /run and ${RUNUSER} in blacklist mode

This commit is contained in:
2026-03-25 22:48:39 +01:00
parent 0bd91ffad2
commit 82f84247f1
5 changed files with 115 additions and 3 deletions

View File

@@ -43,7 +43,7 @@ pub fn resolve_path_context() -> Result<PathContext, SandboxError> {
let run_user = std::env::var("XDG_RUNTIME_DIR")
.ok()
.or_else(resolve_run_user_from_proc)
.unwrap_or_default();
.ok_or(SandboxError::RunUserNotFound)?;
Ok(PathContext { home, run_user })
}

View File

@@ -3,6 +3,7 @@ use std::path::PathBuf;
#[derive(Debug)]
pub enum SandboxError {
HomeNotSet,
RunUserNotFound,
BwrapNotFound,
CommandNotFound(PathBuf),
CommandNotExecutable(PathBuf),
@@ -21,6 +22,10 @@ impl std::fmt::Display for SandboxError {
f,
"$HOME is not set; cannot determine which paths to protect"
),
Self::RunUserNotFound => write!(
f,
"cannot determine XDG_RUNTIME_DIR; tried $XDG_RUNTIME_DIR and /proc/self/status"
),
Self::BwrapNotFound => write!(
f,
"bwrap not found; install bubblewrap (e.g. `apt install bubblewrap` or `pacman -S bubblewrap`)"

View File

@@ -1,5 +1,5 @@
mod agents;
mod blacklist;
pub mod blacklist;
mod errors;
mod preflight;
mod sandbox;

View File

@@ -62,7 +62,6 @@ fn add_blacklist_mode(cmd: &mut Command) -> Result<(), SandboxError> {
cmd.args(["--proc", "/proc"]);
cmd.args(["--bind", "/tmp", "/tmp"]);
cmd.args(["--bind", "/var/tmp", "/var/tmp"]);
cmd.args(["--bind", "/run", "/run"]);
let overlays = blacklist::resolve_overlays(&ctx)?;
for dir in &overlays.tmpfs_dirs {
@@ -72,6 +71,26 @@ fn add_blacklist_mode(cmd: &mut Command) -> Result<(), SandboxError> {
cmd.arg("--ro-bind").arg("/dev/null").arg(file);
}
cmd.args(["--tmpfs", "/run"]);
ro_bind_under_tmpfs(
cmd,
"/run",
&[
"/run/dbus/system_bus_socket",
"/run/systemd/resolve",
"/run/systemd/journal",
"/run/log/journal",
"/run/udev",
"/run/NetworkManager/resolv.conf",
"/run/media",
],
);
ensure_parent_dirs(cmd, "/run", &ctx.run_user);
cmd.arg("--tmpfs").arg(&ctx.run_user);
let run_user_bus = format!("{}/bus", ctx.run_user);
ro_bind_under_tmpfs(cmd, &ctx.run_user, &[&run_user_bus]);
Ok(())
}
@@ -127,6 +146,37 @@ fn add_whitelist_mode(cmd: &mut Command) -> Result<(), SandboxError> {
Ok(())
}
fn ensure_parent_dirs(cmd: &mut Command, base: &str, path: &str) {
let base = Path::new(base);
let ancestors: Vec<_> = Path::new(path)
.ancestors()
.skip(1)
.take_while(|a| *a != base)
.collect();
for dir in ancestors.into_iter().rev() {
cmd.arg("--dir").arg(dir);
}
}
fn ro_bind_under_tmpfs(cmd: &mut Command, base: &str, paths: &[&str]) {
let base = Path::new(base);
let mut dirs_created = std::collections::HashSet::new();
for path in paths {
let ancestors: Vec<_> = Path::new(path)
.ancestors()
.skip(1) // skip the path itself
.take_while(|a| *a != base)
.filter(|a| dirs_created.insert(a.to_path_buf()))
.collect();
for dir in ancestors.into_iter().rev() {
cmd.arg("--dir").arg(dir);
}
cmd.args(["--ro-bind-try", path, path]);
}
}
fn add_rw_bind(cmd: &mut Command, path: &Path) -> Result<(), SandboxError> {
if !path.exists() {
return Err(SandboxError::RwPathMissing(path.to_path_buf()));