构建 Linux 命名空间隔离命令 — 源码 sandbox.rs:211-262 真正的隔离是靠 Linux 的 unshare 命令实现的。 unshare 创建新的 namespace(命名空间),让进程运行在 一个"假的"隔离环境中,类似轻量级容器。 各 flag 的含义: --user 创建新的用户命名空间(进程觉得自己是 root,但实际没有特权) --map-root-user 将容器内的 root 映射到宿主机当前用户 --mount 创建新的挂载命名空间(看不到宿主的挂载点)
(
command: str,
cwd: Path,
status: SandboxStatus
)
| 294 | |
| 295 | |
| 296 | def build_linux_sandbox_command( |
| 297 | command: str, |
| 298 | cwd: Path, |
| 299 | status: SandboxStatus |
| 300 | ) -> Optional[LinuxSandboxCommand]: |
| 301 | """构建 Linux 命名空间隔离命令 — 源码 sandbox.rs:211-262 |
| 302 | |
| 303 | 真正的隔离是靠 Linux 的 unshare 命令实现的。 |
| 304 | unshare 创建新的 namespace(命名空间),让进程运行在 |
| 305 | 一个"假的"隔离环境中,类似轻量级容器。 |
| 306 | |
| 307 | 各 flag 的含义: |
| 308 | --user 创建新的用户命名空间(进程觉得自己是 root,但实际没有特权) |
| 309 | --map-root-user 将容器内的 root 映射到宿主机当前用户 |
| 310 | --mount 创建新的挂载命名空间(看不到宿主的挂载点) |
| 311 | --ipc 创建新的 IPC 命名空间(隔离共享内存、信号量) |
| 312 | --pid 创建新的 PID 命名空间(看不到宿主的进程) |
| 313 | --uts 创建新的 UTS 命名空间(可以有不同的主机名) |
| 314 | --fork fork 后在新 namespace 中执行 |
| 315 | --net 创建新的网络命名空间(完全隔离网络,可选) |
| 316 | """ |
| 317 | # 不是 Linux、没启用、或者命名空间和网络都没激活 → 不用沙箱 |
| 318 | if sys.platform != "linux": |
| 319 | return None # macOS 用 seatbelt (sandbox-exec),这里不覆盖 |
| 320 | if not status.enabled: |
| 321 | return None |
| 322 | if not status.namespace_active and not status.network_active: |
| 323 | return None |
| 324 | |
| 325 | args = [ |
| 326 | "--user", # 用户命名空间 |
| 327 | "--map-root-user", # root 映射 |
| 328 | "--mount", # 挂载命名空间 |
| 329 | "--ipc", # IPC 命名空间 |
| 330 | "--pid", # PID 命名空间 |
| 331 | "--uts", # UTS 命名空间 |
| 332 | "--fork", # fork 执行 |
| 333 | ] |
| 334 | if status.network_active: |
| 335 | args.append("--net") # 网络命名空间(完全断网) |
| 336 | |
| 337 | args.extend(["sh", "-lc", command]) |
| 338 | |
| 339 | # 环境变量——重定向 HOME 和 TMPDIR 到沙箱目录 |
| 340 | sandbox_home = str(cwd / ".sandbox-home") |
| 341 | sandbox_tmp = str(cwd / ".sandbox-tmp") |
| 342 | |
| 343 | env = { |
| 344 | "HOME": sandbox_home, |
| 345 | "TMPDIR": sandbox_tmp, |
| 346 | "CLAWD_SANDBOX_FILESYSTEM_MODE": status.filesystem_mode.value, |
| 347 | "CLAWD_SANDBOX_ALLOWED_MOUNTS": ":".join(status.allowed_mounts), |
| 348 | } |
| 349 | # 保留 PATH |
| 350 | if "PATH" in os.environ: |
| 351 | env["PATH"] = os.environ["PATH"] |
| 352 | |
| 353 | return LinuxSandboxCommand( |
no test coverage detected