diff --git a/src/config.rs b/src/config.rs index c53b41a..0241d80 100644 --- a/src/config.rs +++ b/src/config.rs @@ -68,6 +68,10 @@ pub struct ExecutableSpec { /// These GIDs are relative to the user namespace that is optionally set up. pub gid: Option, + /// Optional supplemental GIDs to assume, in addition to any primary GID. + /// These GIDs are relative to the user namespace that is optionally set up. + pub supplemental_gids: Option>, + /// An optional set of process-specific resource limits. /// If this set is not provided, setrlimit(2) will not be called. pub process_limits: Option, diff --git a/src/runner.rs b/src/runner.rs index 862e8a5..6bf06be 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -201,6 +201,11 @@ impl CreateRequestBuilder { self } + pub fn set_supplemental_gids(mut self, gids: Vec) -> CreateRequestBuilder { + self.config.exec.supplemental_gids = gids.into(); + self + } + pub fn set_no_new_privs(mut self, no_new_privs: bool) -> CreateRequestBuilder { self.config.exec.no_new_privs = no_new_privs; self diff --git a/src/wrap.rs b/src/wrap.rs index 4dadefa..fbe8b84 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -645,7 +645,11 @@ impl Wrappable for CreateRequest { set_keep_caps()?; // Set these *first*, before we exec. Otherwise // we may not be able to switch after dropping caps. - apply_gid_uid(self.exec.gid, self.exec.uid)?; + apply_gid_uid( + self.exec.gid, + self.exec.uid, + self.exec.supplemental_gids.as_ref(), + )?; // Now, we can synchronize effective/inherited/permitted caps // as a final step. apply_capabilities(self.capabilities.as_ref())?; @@ -840,7 +844,11 @@ impl Wrappable for AttachRequest { debug!("all namespaces joined -- forking child"); fork_and_wait()?; - apply_gid_uid(self.exec.gid, self.exec.uid)?; + apply_gid_uid( + self.exec.gid, + self.exec.uid, + self.exec.supplemental_gids.as_ref(), + )?; self.exec.execute() } @@ -856,7 +864,11 @@ impl Mutatable for CreateDirMutation { } } -fn apply_gid_uid(gid: Option, uid: Option) -> Result<()> { +fn apply_gid_uid( + gid: Option, + uid: Option, + supplemental_gids: Option<&Vec>, +) -> Result<()> { // NOTE - order is important here - must change GID *before* changing UID, to avoid // locking oneself out of the GID change with an "operation not permitted" error if let Some(target_gid) = gid { @@ -869,6 +881,22 @@ fn apply_gid_uid(gid: Option, uid: Option) -> Result<()> { } } + // Set supplemental gids, if any. As with changing the primary gid, this must happen before the UID shift. + if let Some(target_supplemental_gids) = supplemental_gids { + unsafe { + let gids_libc: Vec = target_supplemental_gids + .iter() + .map(|g| *g as libc::gid_t) + .collect(); + if libc::setgroups(gids_libc.len(), gids_libc.as_ptr()) < 0 { + warn!( + "unable to set supplemental GIDs: {:?}", + Error::last_os_error() + ); + } + } + } + if let Some(target_uid) = uid { unsafe { // Check this to avoid a spurious log if we don't need to change,