mirror of
https://github.com/instructkr/claw-code.git
synced 2026-09-01 00:00:13 +08:00
fix(sandbox): fall back to --map-auto when root-user mapping is restricted
Plain `unshare --user --map-root-user` fails on kernels and containers that block unprivileged writes to /proc/self/uid_map (e.g. GitHub Actions, restricted AppArmor profiles). On those systems util-linux delegates to the setuid newuidmap/newgidmap helpers when --map-auto is also present. Add the combined form as a fallback candidate and build the launcher args from the probed mapping, so systems without newuidmap/newgidmap or a /etc/subuid range keep using the plain form.
This commit is contained in:
@@ -220,15 +220,18 @@ pub fn build_linux_sandbox_command(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut args = vec![
|
let mut args: Vec<String> = working_unshare_mapping()
|
||||||
"--user".to_string(),
|
.unwrap_or(UNSHARE_MAPPING_CANDIDATES[0])
|
||||||
"--map-root-user".to_string(),
|
.iter()
|
||||||
|
.map(|arg| arg.to_string())
|
||||||
|
.collect();
|
||||||
|
args.extend([
|
||||||
"--mount".to_string(),
|
"--mount".to_string(),
|
||||||
"--ipc".to_string(),
|
"--ipc".to_string(),
|
||||||
"--pid".to_string(),
|
"--pid".to_string(),
|
||||||
"--uts".to_string(),
|
"--uts".to_string(),
|
||||||
"--fork".to_string(),
|
"--fork".to_string(),
|
||||||
];
|
]);
|
||||||
if status.network_active {
|
if status.network_active {
|
||||||
args.push("--net".to_string());
|
args.push("--net".to_string());
|
||||||
}
|
}
|
||||||
@@ -283,7 +286,16 @@ fn command_exists(command: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Candidate `unshare` user-namespace mapping options, in preference order.
|
/// Candidate `unshare` user-namespace mapping options, in preference order.
|
||||||
const UNSHARE_MAPPING_CANDIDATES: &[&[&str]] = &[&["--user", "--map-root-user"]];
|
///
|
||||||
|
/// Most systems accept `--map-root-user` alone. On kernels or containers that
|
||||||
|
/// block unprivileged writes to `/proc/self/uid_map` (e.g. GitHub Actions,
|
||||||
|
/// restricted AppArmor profiles), util-linux instead delegates to the setuid
|
||||||
|
/// `newuidmap`/`newgidmap` helpers when `--map-auto` is also present; that
|
||||||
|
/// requires the current user to have a range in `/etc/subuid`/`/etc/subgid`.
|
||||||
|
const UNSHARE_MAPPING_CANDIDATES: &[&[&str]] = &[
|
||||||
|
&["--user", "--map-root-user"],
|
||||||
|
&["--user", "--map-root-user", "--map-auto"],
|
||||||
|
];
|
||||||
|
|
||||||
/// Probe a candidate `unshare` mapping invocation with a trivial program.
|
/// Probe a candidate `unshare` mapping invocation with a trivial program.
|
||||||
fn unshare_probe(args: &[&str]) -> bool {
|
fn unshare_probe(args: &[&str]) -> bool {
|
||||||
@@ -383,6 +395,21 @@ mod tests {
|
|||||||
assert_eq!(request.allowed_mounts, vec!["tmp"]);
|
assert_eq!(request.allowed_mounts, vec!["tmp"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mapping_candidates_prefer_plain_root_mapping() {
|
||||||
|
assert!(!super::UNSHARE_MAPPING_CANDIDATES.is_empty());
|
||||||
|
for candidate in super::UNSHARE_MAPPING_CANDIDATES {
|
||||||
|
assert!(candidate.contains(&"--user"));
|
||||||
|
assert!(candidate.contains(&"--map-root-user"));
|
||||||
|
}
|
||||||
|
// The plain form must be tried first; `--map-auto` is only a fallback
|
||||||
|
// for kernels/containers that block unprivileged uid_map writes.
|
||||||
|
assert_eq!(
|
||||||
|
super::UNSHARE_MAPPING_CANDIDATES[0],
|
||||||
|
&["--user", "--map-root-user"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_linux_launcher_with_network_flag_when_requested() {
|
fn builds_linux_launcher_with_network_flag_when_requested() {
|
||||||
let config = SandboxConfig::default();
|
let config = SandboxConfig::default();
|
||||||
|
|||||||
Reference in New Issue
Block a user