Skip to content

Commit 31dec96

Browse files
authored
Merge pull request #63 from bleggett/bleggett/fix-gidset
Must change GID *before* changing UID, to avoid permission errors
2 parents a33e2e1 + 044eb76 commit 31dec96

2 files changed

Lines changed: 41 additions & 25 deletions

File tree

src/caps.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ impl AsRef<str> for CapabilityBit {
219219

220220
pub const PR_SET_SECUREBITS: i32 = 28;
221221
pub const SECBIT_KEEP_CAPS: i32 = 16;
222+
pub const SECBIT_NO_SETUID_FIXUP: i32 = 4;
222223
pub const SECBIT_KEEP_CAPS_LOCKED: i32 = 32;
223224

224225
/* from <unistd.h> */
@@ -418,10 +419,10 @@ pub fn set_caps(caps: CapResult) -> anyhow::Result<()> {
418419
}
419420

420421
pub fn set_keep_caps() -> anyhow::Result<()> {
421-
let ret = unsafe { libc::prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS) };
422+
let ret = unsafe { libc::prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP) };
422423
if ret < 0 {
423424
Err(anyhow!(
424-
"failed to set SECBIT_KEEP_CAPS: {}",
425+
"failed to set SECBIT_NO_SETUID_FIXUP: {}",
425426
io::Error::last_os_error()
426427
))
427428
} else {

src/wrap.rs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::path::PathBuf;
1111
use std::process;
1212
use std::ptr;
1313

14-
use crate::caps::{CapabilityBit, get_caps, set_caps};
14+
use crate::caps::{CapabilityBit, get_caps, set_caps, set_keep_caps};
1515
use crate::cgroup::CGroup;
1616
use crate::config::{
1717
AttachRequest, Capabilities, CreateDirMutation, CreateRequest, ExecutableSpec, IdMapping,
@@ -508,8 +508,6 @@ impl Wrappable for CreateRequest {
508508
unshare(&vec![Namespace::User])?;
509509
}
510510

511-
apply_capabilities(self.capabilities.as_ref())?;
512-
513511
debug!("signalling supervisor to do configuration");
514512
pef.write_all(&2_u64.to_ne_bytes())?;
515513
pef.flush()?;
@@ -520,6 +518,17 @@ impl Wrappable for CreateRequest {
520518
let mut buf = [0u8; 8];
521519
cef.read_exact(&mut buf)?;
522520

521+
// We need to toggle SECBIT before we change UID/GID,
522+
// or else changing UID/GID may cause us to lose the capabilities
523+
// we need to explicitly drop capabilities later on.
524+
set_keep_caps()?;
525+
// Set these *first*, before we exec. Otherwise
526+
// we may not be able to switch after dropping caps.
527+
apply_gid_uid(self.exec.gid, self.exec.uid)?;
528+
// Now, we can synchronize effective/inherited/permitted caps
529+
// as a final step.
530+
apply_capabilities(self.capabilities.as_ref())?;
531+
523532
debug!("ready to launch workload");
524533
self.exec.execute()
525534
}
@@ -556,26 +565,6 @@ impl ExecutableSpec {
556565
let mut env_charptrs: Vec<_> = env_cstrings.iter().map(|arg| arg.as_ptr()).collect();
557566
env_charptrs.push(ptr::null());
558567

559-
if let Some(target_uid) = self.uid {
560-
unsafe {
561-
// Check this to avoid a spurious log if we don't need to change,
562-
// because we are already running as the target UID.
563-
if libc::getuid() != target_uid && libc::setuid(target_uid as libc::uid_t) < 0 {
564-
warn!("unable to set target UID: {:?}", Error::last_os_error());
565-
}
566-
}
567-
}
568-
569-
if let Some(target_gid) = self.gid {
570-
unsafe {
571-
// Check this to avoid a spurious log if we don't need to change,
572-
// because we are already running as the target GID.
573-
if libc::getgid() != target_gid && libc::setgid(target_gid as libc::gid_t) < 0 {
574-
warn!("unable to set target GID: {:?}", Error::last_os_error());
575-
}
576-
}
577-
}
578-
579568
if let Some(wd) = &self.working_directory {
580569
env::set_current_dir(wd.clone())?;
581570
}
@@ -718,6 +707,32 @@ impl Mutatable for CreateDirMutation {
718707
}
719708
}
720709

710+
fn apply_gid_uid(gid: Option<u32>, uid: Option<u32>) -> Result<()> {
711+
// NOTE - order is important here - must change GID *before* changing UID, to avoid
712+
// locking oneself out of the GID change with an "operation not permitted" error
713+
if let Some(target_gid) = gid {
714+
unsafe {
715+
// Check this to avoid a spurious log if we don't need to change,
716+
// because we are already running as the target GID.
717+
if libc::getgid() != target_gid && libc::setgid(target_gid as libc::gid_t) < 0 {
718+
warn!("unable to set target GID: {:?}", Error::last_os_error());
719+
}
720+
}
721+
}
722+
723+
if let Some(target_uid) = uid {
724+
unsafe {
725+
// Check this to avoid a spurious log if we don't need to change,
726+
// because we are already running as the target UID.
727+
if libc::getuid() != target_uid && libc::setuid(target_uid as libc::uid_t) < 0 {
728+
warn!("unable to set target UID: {:?}", Error::last_os_error());
729+
}
730+
}
731+
}
732+
733+
Ok(())
734+
}
735+
721736
fn apply_capabilities(capabilities: Option<&Capabilities>) -> Result<()> {
722737
let Some(caps) = capabilities else {
723738
return Ok(());

0 commit comments

Comments
 (0)