Keep env values off the bwrap command line
This commit is contained in:
+24
-29
@@ -1,25 +1,27 @@
|
||||
pub fn keepenv_args(keys: &[String], parent_env: &[(String, String)]) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
for key in keys {
|
||||
if let Some(value) = parent_env.iter().find_map(|(k, v)| (k == key).then_some(v)) {
|
||||
args.push("--setenv".to_string());
|
||||
args.push(key.clone());
|
||||
args.push(value.clone());
|
||||
}
|
||||
}
|
||||
args
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub type SandboxEnv = BTreeMap<String, String>;
|
||||
|
||||
pub fn find_parent_value(parent_env: &[(String, String)], key: &str) -> Option<String> {
|
||||
parent_env
|
||||
.iter()
|
||||
.find_map(|(k, v)| (k == key).then(|| v.clone()))
|
||||
}
|
||||
|
||||
pub fn whitelist_env_args(parent_env: &[(String, String)]) -> Vec<String> {
|
||||
let mut args = vec!["--clearenv".to_string()];
|
||||
for (key, value) in parent_env {
|
||||
if whitelist_keeps(key) {
|
||||
args.push("--setenv".to_string());
|
||||
args.push(key.clone());
|
||||
args.push(value.clone());
|
||||
}
|
||||
}
|
||||
args
|
||||
pub fn copy_parent_env(parent_env: &[(String, String)]) -> SandboxEnv {
|
||||
select_vars(parent_env, |_| true)
|
||||
}
|
||||
|
||||
fn select_vars(parent_env: &[(String, String)], permits: impl Fn(&str) -> bool) -> SandboxEnv {
|
||||
parent_env
|
||||
.iter()
|
||||
.filter(|(key, _)| permits(key))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn apply_whitelist(parent_env: &[(String, String)]) -> SandboxEnv {
|
||||
select_vars(parent_env, whitelist_keeps)
|
||||
}
|
||||
|
||||
fn whitelist_keeps(key: &str) -> bool {
|
||||
@@ -96,15 +98,8 @@ const WHITELIST_KEEP_PREFIXES: &[&str] = &[
|
||||
"OTEL_",
|
||||
];
|
||||
|
||||
pub fn blacklist_env_args(parent_env: &[(String, String)]) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
for (key, _) in parent_env {
|
||||
if blacklist_drops(key) {
|
||||
args.push("--unsetenv".to_string());
|
||||
args.push(key.clone());
|
||||
}
|
||||
}
|
||||
args
|
||||
pub fn apply_blacklist(parent_env: &[(String, String)]) -> SandboxEnv {
|
||||
select_vars(parent_env, |key| !blacklist_drops(key))
|
||||
}
|
||||
|
||||
fn blacklist_drops(key: &str) -> bool {
|
||||
|
||||
+32
-21
@@ -71,8 +71,7 @@ fn build_command(config: &SandboxConfig) -> Result<(Bwrap, BwrapCommandLine), Sa
|
||||
add_rw_bind(&mut cmd, spec)?;
|
||||
}
|
||||
|
||||
add_env_policy(&mut cmd, config);
|
||||
add_user_env_overrides(&mut cmd, config);
|
||||
set_sandbox_env(&mut cmd, config);
|
||||
|
||||
cmd.args(["--remount-ro", "/"]);
|
||||
cmd.arg("--die-with-parent");
|
||||
@@ -97,36 +96,48 @@ fn build_command(config: &SandboxConfig) -> Result<(Bwrap, BwrapCommandLine), Sa
|
||||
Ok((bwrap, command_line))
|
||||
}
|
||||
|
||||
fn add_env_policy(cmd: &mut Command, config: &SandboxConfig) {
|
||||
if !config.env_filter {
|
||||
return;
|
||||
}
|
||||
/// bwrap passes its own environment on to the child. `--setenv` would instead
|
||||
/// publish every value in the world-readable `/proc/<pid>/cmdline`.
|
||||
fn set_sandbox_env(cmd: &mut Command, config: &SandboxConfig) {
|
||||
let parent_env: Vec<(String, String)> = std::env::vars().collect();
|
||||
let args = match config.mode {
|
||||
SandboxMode::Blacklist => env::blacklist_env_args(&parent_env),
|
||||
SandboxMode::Whitelist => env::whitelist_env_args(&parent_env),
|
||||
};
|
||||
cmd.args(args);
|
||||
|
||||
let mut sandbox_env = apply_env_filter(&parent_env, config);
|
||||
apply_user_env_overrides(&mut sandbox_env, &parent_env, config);
|
||||
|
||||
cmd.env_clear();
|
||||
cmd.envs(sandbox_env);
|
||||
}
|
||||
|
||||
fn add_user_env_overrides(cmd: &mut Command, config: &SandboxConfig) {
|
||||
let mut keep_keys: Vec<String> = Vec::new();
|
||||
fn apply_env_filter(parent_env: &[(String, String)], config: &SandboxConfig) -> env::SandboxEnv {
|
||||
if !config.env_filter {
|
||||
return env::copy_parent_env(parent_env);
|
||||
}
|
||||
match config.mode {
|
||||
SandboxMode::Blacklist => env::apply_blacklist(parent_env),
|
||||
SandboxMode::Whitelist => env::apply_whitelist(parent_env),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_user_env_overrides(
|
||||
sandbox_env: &mut env::SandboxEnv,
|
||||
parent_env: &[(String, String)],
|
||||
config: &SandboxConfig,
|
||||
) {
|
||||
for entry in &config.env {
|
||||
match entry {
|
||||
EnvEntry::Set(key, value) => {
|
||||
cmd.arg("--setenv").arg(key).arg(value);
|
||||
sandbox_env.insert(key.clone(), value.clone());
|
||||
}
|
||||
EnvEntry::Keep(key) => {
|
||||
if let Some(value) = env::find_parent_value(parent_env, key) {
|
||||
sandbox_env.insert(key.clone(), value);
|
||||
}
|
||||
}
|
||||
EnvEntry::Keep(key) => keep_keys.push(key.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
if !keep_keys.is_empty() {
|
||||
let parent_env: Vec<(String, String)> = std::env::vars().collect();
|
||||
cmd.args(env::keepenv_args(&keep_keys, &parent_env));
|
||||
}
|
||||
|
||||
for key in &config.unsetenv {
|
||||
cmd.arg("--unsetenv").arg(key);
|
||||
sandbox_env.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user