ostree_ext/
isolation.rs

1use std::process::Command;
2use std::sync::OnceLock;
3
4pub(crate) const DEFAULT_UNPRIVILEGED_USER: &str = "nobody";
5
6/// Checks if the current process is (apparently at least)
7/// running under systemd.  We use this in various places
8/// to e.g. log to the journal instead of printing to stdout.
9pub(crate) fn running_in_systemd() -> bool {
10    static RUNNING_IN_SYSTEMD: OnceLock<bool> = OnceLock::new();
11    *RUNNING_IN_SYSTEMD.get_or_init(|| {
12        // See https://www.freedesktop.org/software/systemd/man/systemd.exec.html#%24INVOCATION_ID
13        std::env::var_os("INVOCATION_ID")
14            .filter(|s| !s.is_empty())
15            .is_some()
16    })
17}
18
19/// Return a prepared subprocess configuration that will run as an unprivileged user if possible.
20///
21/// This currently only drops privileges when run under systemd with DynamicUser.
22pub(crate) fn unprivileged_subprocess(binary: &str, user: &str) -> Command {
23    // TODO: if we detect we're running in a container as uid 0, perhaps at least switch to the
24    // "bin" user if we can?
25    if !running_in_systemd() {
26        return Command::new(binary);
27    }
28    let mut cmd = Command::new("setpriv");
29    // Clear some strategic environment variables that may cause the containers/image stack
30    // to look in the wrong places for things.
31    cmd.env_remove("HOME");
32    cmd.env_remove("XDG_DATA_DIR");
33    cmd.env_remove("USER");
34    cmd.args([
35        "--no-new-privs",
36        "--init-groups",
37        "--reuid",
38        user,
39        "--bounding-set",
40        "-all",
41        "--pdeathsig",
42        "TERM",
43        "--",
44        binary,
45    ]);
46    cmd
47}