Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ pub struct ExecutableSpec {
/// An optional set of process-specific resource limits.
/// If this set is not provided, setrlimit(2) will not be called.
pub process_limits: Option<ProcessResourceLimits>,

/// If `true`, sets `PR_SET_NO_NEW_PRIVS` before
/// spawning the target executable.
pub no_new_privs: bool,
}

#[derive(Default, Debug, Serialize, Deserialize)]
Expand Down
10 changes: 10 additions & 0 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ impl AttachRequestBuilder {
self
}

pub fn set_no_new_privs(mut self, no_new_privs: bool) -> AttachRequestBuilder {
self.config.exec.no_new_privs = no_new_privs;
self
}

pub fn push_environment(mut self, key: &str, value: &str) -> AttachRequestBuilder {
if self.config.exec.environment.is_none() {
self.config.exec.environment = BTreeMap::new().into();
Expand Down Expand Up @@ -182,6 +187,11 @@ impl CreateRequestBuilder {
self
}

pub fn set_no_new_privs(mut self, no_new_privs: bool) -> CreateRequestBuilder {
self.config.exec.no_new_privs = no_new_privs;
self
}

pub fn set_hostname(mut self, hostname: &str) -> CreateRequestBuilder {
self.config.hostname = hostname.to_string().into();
self
Expand Down
24 changes: 21 additions & 3 deletions src/wrap.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use libc;

use std::env;
use std::ffi::CString;
use std::fs;
Expand All @@ -22,7 +20,8 @@ use crate::signal;
use crate::unshare::{setns, unshare};
use anyhow::{Result, anyhow, bail};
use libc::{
PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, PR_CAP_AMBIENT_RAISE, PR_CAPBSET_DROP, c_int, prctl,
self, PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, PR_CAP_AMBIENT_RAISE, PR_CAPBSET_DROP,
PR_SET_NO_NEW_PRIVS, c_int, prctl,
};

use log::{debug, error, warn};
Expand Down Expand Up @@ -569,6 +568,10 @@ impl ExecutableSpec {
env::set_current_dir(wd.clone())?;
}

if self.no_new_privs {
self.set_no_new_privs()?;
}

unsafe {
if libc::execvpe(
program_cstring.as_ptr(),
Expand Down Expand Up @@ -611,6 +614,21 @@ impl ExecutableSpec {

Ok(())
}

// Note that `PR_SET_NO_NEW_PRIVS` is *not* a foolproof privilege escalation
// setting - it just "locks" the privilege set. If the process is granted
// CAP_ADMIN or similar elsewhere, it is trivial to escalate privs in spite of this flag.
fn set_no_new_privs(&self) -> Result<()> {
let error = unsafe { prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) };
if error != 0 {
bail!(
"failed to set no_new_privs flag: {}",
Error::last_os_error()
);
}

Ok(())
}
}

impl AttachRequest {
Expand Down
Loading