Documentation
¶
Overview ¶
Linux 后端编排:施加序与探测子进程(真源 §2.1/§1.3)。
capability SID 派生(windows 后端的平台无关部分,真源 §4):按可写根 路径确定性派生 S-1-4-x-y(dsh workspace-sid.ts 蓝本,subauthority 30-bit)。 确定性 = 跨会话/跨进程重启稳定——工作区根的 standing ACE 只需授予一次 (codex cap.rs 的随机 SID 方案要持久化状态文件,丢档即孤儿 ACE)。SID 字符串本身不是秘密:权力完全由命名它的 ACE 定义,且只在本进程铸造的 restricted token 里携带。
DockerProvider Docker 一次性容器后端(dockerWrap 正规化迁移——既有 EINO_RUN_DOCKER env 魔法开关与「绕过 policy」优先级告警退役,策略翻译 进容器参数)。形态定位 = 真源 §5.3 的过渡形态:一次性容器(--rm 每命令 一弹);终局 = §0.2/§5.3 的每会话长驻容器(Manus 形态——懒启动/会话终 销毁、只挂工作区、凭证在围栏外),届时本 Provider 的 Wrap 改实现为 docker exec、容器生命周期归 Provider 内部,接口形状不变。
策略翻译(只收紧不放宽):
Mode readonly → --read-only + 工作区 :ro 挂载
Mode workspace-write → --read-only(容器根只读)+ 工作区 :rw
Mode danger-full → 容器根可写(隔离仍在——容器即边界)+ 工作区 :rw
Network=false → --network none;true = 默认 bridge
WritableRoots → 同路径 :rw 追加挂载(缓存类目录逃生门,与 OS 档同义)
ProtectedReadOnly → 同路径 :ro 子挂载(嵌套 bind 遮蔽——docker 按路径
深度解析覆盖顺序,Landlock 做不到的回盖此处可治)
Env → -e 逐条注入;容器面天然最小环境(不继承宿主 env,
EnvMode 对本后端无操作面)
Limit.NProc → --pids-limit(FileSizeMB 无 docker 等价面,不翻译)
已知缝隙(真源 §5.3 缝隙②,随终局长驻形态治):docker run attached 形态 下杀 docker CLI 进程不终止容器——run_command 后台任务的 task_stop 只杀 CLI,容器残留至自身退出(--rm 缓解一次性,长任务仍有窗口)。
降级语义(审查 A-3 明示):daemon 不可达 → nil argv,调用方按姿态降级 (当前接线 = auto:命令裸跑于宿主进程环境,容器隔离失效——启动告警已 如实声明;fail-closed 拒跑属 require 姿态接线,真源 §10.4)。
re-exec 哨兵协议(真源 §2.1):run_command 侧以 [<exe>, "__einox-sandbox", "--", "sh", "-c", <cmd>] re-exec 产品自身,产品 main() 顶部挂 RunHelper 拦截哨兵子命令——helper 路径内施加策略(LockOSThread → NO_NEW_PRIVS → seccomp → Landlock → rlimit)后 syscall.Exec 真实命令。策略 JSON 经 env 传递(不污染 ps 输出);exe 路径 init 期 os.Executable() 固化(审查 C2: os.Args[0] 相对形态在子进程 cwd 下解析落空)。依赖产品 main 挂钩是本机制 唯一侵入点(一行)——未挂钩时探测报 unusable 而非静默裸跑(审查 C1)。
Landlock 文件系统围栏——dsh native/landlock-run main.c(C11)的 Go 直译 (第一参照)。UAPI 经 x/sys/unix(syscall 号/访问位常量 = 内核稳定契约, 不依赖内核头),属性结构自携最小形并显式传内核 size——x/sys 结构含 ABI4/6 字段(24 字节),旧内核自身 struct 只有 8 字节时 size 超限直接 E2BIG。规则只能授不能收(allow-list 联合语义):可写根内只读回盖 (ProtectedReadOnly,如 .git)做不到——探测面如实报 partial + 未覆盖项 (真源 §2.2)。
进程组治理(沙箱形态进程组杀的前提——修 stopTask 只杀单进程瑕疵的 沙箱路径部分,真源 §2.1)。
rlimit 资源限额(helper 内 exec 前 setrlimit,真源 §2.4):NPROC 默认 512 ——内核按有效 uid 计数且含线程,容器形态下服务进程 Go 运行时线程与同 uid 任务共享同一预算,256 会被「服务高线程 + go build -p 并行 fork」打穿 且报 EAGAIN 不命中拒绝签名;FSIZE 默认 1GB 防写满挂载卷;CORE=0。跳过 RLIMIT_AS——Go 工具链运行时/链接器 GB 级虚拟地址预留会被误杀,内存硬 限额归 cgroup/容器层。
Package sandbox 提供 run_command 执行面的 OS 级沙箱机制(Phase S): 策略模型(三档/网络开关/可写根/限额,平台无关)+ re-exec 哨兵协议 (Landlock/seccomp/rlimit 必须 fork 后 exec 前在子进程内施加,Go self re-exec 惯例,codex helper 同构)+ 后端探测三态如实上报(dsh 式)。 机制归基座、选择归业务:应用装配层决定用不用/用哪档/参数(PM 默认关 opt-in),基座承载实现与安全不变量。设计 = 2026-08-26 沙箱设计定案 (含同日独立审查修订)。
Seatbelt profile 纯构造(darwin 后端的平台无关部分,真源 §3):组装 顺序对齐 codex seatbelt.rs——base(deny default 起手)→ file-read 段 → file-write 段 → 网络段 → 保护子路径 require-not 排除 → 锚点 deny。路径 全部经 -D KEY=VALUE 参数注入、profile 内 (param "KEY") 引用——路径不拼进 policy 字符串(转义/注入面,codex 同款纪律)。本文件零 fs 调用(纯字符串 构造,任意平台可单测);路径规范化(嵌套 symlink 拒绝/顶层别名解析)在 seatbelt_darwin.go 运行时侧。
seccomp BPF 断网围栏(手写经典 BPF,x/sys/unix 原语)。deny 清单逐条照抄 codex linux-sandbox/landlock.rs L179-216:recvfrom 故意放行(socketpair+ 子进程管理的工具兼容性,codex 注释原话照搬);connect 无条件 deny 连 AF_UNIX 也断——防 docker.sock 类逃逸的故意设计(codex 同款,真源 §2.3 D3 披露:docker CLI / psql -h /sock 类本地 socket 客户端同断)。 default allow + 命中返回 EPERM;audit arch 不符(32 位兼容模式号表错位) KILL_PROCESS fail-closed。号表仅 x86_64/aarch64(x/sys per-arch 常量), 其余架构由 backend_stub 运行时桩报 unusable(审查 B2)。
Linux 分支 Wrap 装配:re-exec 哨兵形(真源 §2.1)。arch 桩平台同样编入 本文件(不可达——unsupported-arch 探测 unusable 已在 Wrap 短路)。
Index ¶
- Constants
- func ArgvEnv(pol *Policy, workspace, cmdLine string) (argv []string, env []string)
- func AttachToken(*exec.Cmd, *Policy, string) error
- func DenialHint(output string) string
- func KillGroup(p *os.Process)
- func RunHelper(args []string)
- func SetGroupLeader(cmd *exec.Cmd)
- func WorkspaceWriteSID(root string) string
- func Wrap(pol *Policy, workspace, cmdLine string) (argv []string, env []string)
- type Backend
- type DockerProvider
- type Enforcement
- type EnvMode
- type Limit
- type Mode
- type Policy
- type Provider
- type Status
Constants ¶
const ( DefaultNProc = 512 DefaultFileSizeMB = 1024 )
默认限额。
Variables ¶
This section is empty.
Functions ¶
func AttachToken ¶
AttachToken unix 平台 no-op(windows 专用侧挂:restricted token 进 SysProcAttr;unix 侧进程属性经 SetGroupLeader 完成)。
func DenialHint ¶
DenialHint 命中沙箱拒绝签名时返回提示行(空 = 未命中)。仅沙箱生效的 执行路径调用(裸跑降级路径命令输出与沙箱无关,不标注)。
func KillGroup ¶
KillGroup 进程组杀(负 pid SIGKILL 整组终结——后台任务/超时通道同款)。 未组化(同调用方进程组,负 pid 无组可寻 ESRCH)或已死则回退单进程杀。
func RunHelper ¶
func RunHelper(args []string)
RunHelper 产品 main() 顶部挂接:命中哨兵子命令进入 helper 路径永不返回, 未命中原样返回(正常产品流程)。
func WorkspaceWriteSID ¶
WorkspaceWriteSID 可写根 → 确定性 capability SID(S-1-4-x-y)。
Types ¶
type DockerProvider ¶ added in v0.2.0
type DockerProvider struct {
Image string
// contains filtered or unexported fields
}
DockerProvider Docker 一次性容器后端(Image 空 = alpine:3.20,与既有 dockerWrap 缺省一致)。零值可用;探测进程级缓存一次。
func (*DockerProvider) Probe ¶ added in v0.2.0
func (d *DockerProvider) Probe() Status
Probe docker CLI/daemon 可达性探测(进程级一次缓存;daemon 不可达 = unusable——Wrap 返回 nil argv,调用方按姿态降级:当前接线 = auto 裸跑 + 本告警;fail-closed 拒跑属 require 姿态,接线随首个消费者,真源 §10.4)。
func (*DockerProvider) Wrap ¶ added in v0.2.0
func (d *DockerProvider) Wrap(pol *Policy, workspace, cmdLine string) ([]string, []string)
Wrap 一次性容器执行参数(daemon 不可达 → nil argv,调用方按姿态降级—— 与 OSProvider 同款 auto 裸跑语义,容器隔离失效面如实告警)。env 返回 nil(CLI 进程继承宿主环境——DOCKER_HOST/凭证面服务于 daemon 通信,容器 内环境不继承宿主、只收 -e 显式注入)。
type Enforcement ¶
type Enforcement string
Enforcement 执行力三态(真源 §1.2,dsh 式如实上报)。
const ( EnforcementFull Enforcement = "full" // 目标策略全量生效 EnforcementPartial Enforcement = "partial" // 生效但有未覆盖项(旧 ABI 少位等) EnforcementUnusable Enforcement = "unusable" // 后端不可用(未挂钩/内核不支持/平台未实现) )
type EnvMode ¶ added in v0.2.0
type EnvMode string
EnvMode 围栏内环境继承档(凭据外泄面治理:inherit 是 denylist——记住要剥 谁,对未知凭据名结构性失效;minimal 是 allowlist——业务所需环境一律经 Policy.Env 显式注入,缓存重定向既有惯例不变)。
type Limit ¶
type Limit struct {
NProc int // RLIMIT_NPROC;0 = 默认 512(内核按有效 uid 计数含线程,256 会被服务高线程+go build -p 打穿)
FileSizeMB int // RLIMIT_FSIZE;0 = 默认 1024;单文件写上限,大产物场景调大
}
Limit 资源限额(0 = 默认;helper 内 exec 前 setrlimit,真源 §2.4)。
type Policy ¶
type Policy struct {
Mode Mode // 三档
Network bool // 默认 false 断网;LLM 调用在服务进程内不受影响
WritableRoots []string // workspace-write 档追加可写根(HOME 缓存类目录逃生门)
Env []string // 附加环境变量 "K=V"(缓存重定向载体,注入点 = cmd.Env)
EnvMode EnvMode // 环境继承档(缺省 inherit 零行为变化;minimal = 白名单)
ExcludeTmpdir bool // true = $TMPDIR 不计入可写根(默认 false = 计入,审查 A1)
ExcludeSlashTmp bool // true = /tmp 不计入可写根(默认 false = 计入)
ProtectedReadOnly []string // 可写区内希望只读的子路径(Landlock 做不到——探测报 partial)
Limit Limit
}
Policy 沙箱策略(对齐 codex legacy SandboxPolicy 形状 + 缓存重定向载体, 审查 A2 修订)。静态一次装配(真源 §7.5——PM 会话工作区固定,per-call 留演进)。
type Provider ¶ added in v0.2.0
type Provider interface {
// Wrap 一次命令的沙箱化执行参数(argv[0] 为可执行名,PATH 解析归调用方)。
Wrap(pol *Policy, workspace, cmdLine string) (argv, env []string)
// Probe 后端可用性(缓存策略归实现自担;OSProvider 维持进程级一次)。
Probe() Status
}
Provider 沙箱后端面:把 Policy 翻译成一次命令的执行参数(默认 OSProvider = 平台内建,构建标签分流;应用注入容器/gVisor 等自定义后端—— engine.Options.SandboxProvider / runcommand.Config.SandboxProvider)。 名称不叫 Backend:该名已被姿态类型占用(上方 off/auto/require,真源 §1.3)。
义务:①Probe 如实上报三态(Enforcement 语义,dsh 哲学),策略映射不全时 报 partial + Uncovered;②只许收紧不许放宽——宽于 Policy 的翻译即后端实现 违约(readonly 档不得给出可写挂载);③不修改 pol(并发共享的静态单份)。
nil argv = 本次不可沙箱(调用方按姿态降级:auto 裸跑已告警;require 拒跑 接线留待首个 fail-closed 消费者,真源 §10.4)。容器类后端形态兼容:一次性 容器 Wrap 即 docker run;真源 §0.2/§5.3 的每会话长驻终局 = Wrap 实现 docker exec、容器生命周期归 Provider 内部,接口形状不变。
var OSProvider Provider = osProvider{}
OSProvider 平台内建后端(默认 Provider:Linux Landlock+seccomp+rlimit / darwin Seatbelt / windows restricted token,构建标签分流——wrapOSBackend 平台实现)。ProtectedReadOnly 告警在 Linux 分支发——Landlock 做不到可写区 内回盖(审查 B-2),darwin/windows 后端可真回盖(require-not 排除 / deny ACE),不发该告警。