Skip to content

Commit 5e63dcc

Browse files
authored
Merge pull request #65 from bleggett/bleggett/add-no-new-privs
Add PR_SET_NO_NEW_PRIVS flag
2 parents a4ff564 + 49cb1ca commit 5e63dcc

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ pub struct ExecutableSpec {
7070
/// An optional set of process-specific resource limits.
7171
/// If this set is not provided, setrlimit(2) will not be called.
7272
pub process_limits: Option<ProcessResourceLimits>,
73+
74+
/// If `true`, sets `PR_SET_NO_NEW_PRIVS` before
75+
/// spawning the target executable.
76+
pub no_new_privs: bool,
7377
}
7478

7579
#[derive(Default, Debug, Serialize, Deserialize)]

src/runner.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ impl AttachRequestBuilder {
7979
self
8080
}
8181

82+
pub fn set_no_new_privs(mut self, no_new_privs: bool) -> AttachRequestBuilder {
83+
self.config.exec.no_new_privs = no_new_privs;
84+
self
85+
}
86+
8287
pub fn push_environment(mut self, key: &str, value: &str) -> AttachRequestBuilder {
8388
if self.config.exec.environment.is_none() {
8489
self.config.exec.environment = BTreeMap::new().into();
@@ -182,6 +187,11 @@ impl CreateRequestBuilder {
182187
self
183188
}
184189

190+
pub fn set_no_new_privs(mut self, no_new_privs: bool) -> CreateRequestBuilder {
191+
self.config.exec.no_new_privs = no_new_privs;
192+
self
193+
}
194+
185195
pub fn set_hostname(mut self, hostname: &str) -> CreateRequestBuilder {
186196
self.config.hostname = hostname.to_string().into();
187197
self

src/wrap.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use libc;
2-
31
use std::env;
42
use std::ffi::CString;
53
use std::fs;
@@ -22,7 +20,8 @@ use crate::signal;
2220
use crate::unshare::{setns, unshare};
2321
use anyhow::{Result, anyhow, bail};
2422
use libc::{
25-
PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, PR_CAP_AMBIENT_RAISE, PR_CAPBSET_DROP, c_int, prctl,
23+
self, PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, PR_CAP_AMBIENT_RAISE, PR_CAPBSET_DROP,
24+
PR_SET_NO_NEW_PRIVS, c_int, prctl,
2625
};
2726

2827
use log::{debug, error, warn};
@@ -569,6 +568,10 @@ impl ExecutableSpec {
569568
env::set_current_dir(wd.clone())?;
570569
}
571570

571+
if self.no_new_privs {
572+
self.set_no_new_privs()?;
573+
}
574+
572575
unsafe {
573576
if libc::execvpe(
574577
program_cstring.as_ptr(),
@@ -611,6 +614,21 @@ impl ExecutableSpec {
611614

612615
Ok(())
613616
}
617+
618+
// Note that `PR_SET_NO_NEW_PRIVS` is *not* a foolproof privilege escalation
619+
// setting - it just "locks" the privilege set. If the process is granted
620+
// CAP_ADMIN or similar elsewhere, it is trivial to escalate privs in spite of this flag.
621+
fn set_no_new_privs(&self) -> Result<()> {
622+
let error = unsafe { prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) };
623+
if error != 0 {
624+
bail!(
625+
"failed to set no_new_privs flag: {}",
626+
Error::last_os_error()
627+
);
628+
}
629+
630+
Ok(())
631+
}
614632
}
615633

616634
impl AttachRequest {

0 commit comments

Comments
 (0)