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}