Skip to content
Draft
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
12 changes: 11 additions & 1 deletion crates/lens-sandbox-core/src/privilege.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const KEEP_CAP_MASK: u64 = (1u64 << 0) // CAP_CHOWN
| (1u64 << 6) // CAP_SETGID
| (1u64 << 7); // CAP_SETUID

/// The root group, kept as the dropped workload's sole supplementary group.
#[cfg(target_os = "linux")]
pub(crate) const ROOT_GID: u32 = 0;

/// Reduce the child's capability set to `KEEP_CAP_MASK` and pin
/// `NO_NEW_PRIVS` so the upcoming `execve` cannot re-acquire dropped
/// caps via file caps or a setuid bit. Designed for `Command::pre_exec`
Expand Down Expand Up @@ -285,8 +289,14 @@ impl SandboxCredentials {
let gid = self.gid;
unsafe {
cmd.pre_exec(move || {
// Drop the supervisor's supplementary groups but keep the root
// group (gid 0): images built for the "run as an arbitrary
// non-root uid" model (bitnami, OpenShift) own their writable
// dirs `root:0` with group-write and expect the process to be a
// member of the root group rather than a specific uid.
#[cfg(target_os = "linux")]
nix::unistd::setgroups(&[]).map_err(|e| std::io::Error::other(e.to_string()))?;
nix::unistd::setgroups(&[nix::unistd::Gid::from_raw(ROOT_GID)])
.map_err(|e| std::io::Error::other(e.to_string()))?;
nix::unistd::setgid(gid).map_err(|e| std::io::Error::other(e.to_string()))?;
nix::unistd::setuid(uid).map_err(|e| std::io::Error::other(e.to_string()))?;
// setuid(non-root) already zeroed effective/permitted/inheritable
Expand Down
4 changes: 3 additions & 1 deletion crates/lens-sandbox-core/src/pty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ pub fn spawn_pty(
// agent (e.g. Claude Code with TERM=xterm-256color) can't keep
// CAP_NET_ADMIN or skip NO_NEW_PRIVS / pdeathsig.
if let Some((uid, gid)) = creds_info {
// Keep the root group (gid 0) — see privilege::apply: images built
// for the "arbitrary non-root uid in the root group" model expect it.
#[cfg(target_os = "linux")]
nix::unistd::setgroups(&[])
nix::unistd::setgroups(&[nix::unistd::Gid::from_raw(crate::privilege::ROOT_GID)])
.map_err(|e| std::io::Error::other(format!("setgroups: {e}")))?;
nix::unistd::setgid(gid)
.map_err(|e| std::io::Error::other(format!("setgid: {e}")))?;
Expand Down
Loading