跳转到内容

沙箱与权限

Linux(bubblewrap / Landlock)、macOS Seatbelt、Windows ACL runner 的差异,以及 read-only / workspace-write / danger-full-access 三档模式。

qialike 通过 harness 的 ctx.sandbox.confine() 运行受限 bash(Windows 上是 pwsh)。三个平台都开箱即用: Linux 优先用宿主的 bubblewrap,没有则落到 qialike 自带的 Landlock(需内核启用该 LSM,≥5.13);macOS 用系统自带的 Seatbelt;Windows 用 harness 的 ACL restricted-token runner。danger-full-access 不加隔离直接运行。

沙箱的边界是「与宿主共享内核和文件系统的子进程」。需要隔离整个环境时,应当使用容器、microVM 或远程执行器。


三档模式

在输入框按 Tab 循环切换,状态栏会显示当前档位:

模式状态栏标签效果
read-onlyRead Only拒绝写入,必需 sink(如 /dev/null)除外。
workspace-writeWorkspace Write允许写入工作区根目录及后端定义的临时区域。
danger-full-accessFull access绕过隔离;直接 spawn 原始 argv。

几点语义:

  • 默认是 workspace-write。会话恢复时,档位取自会话最后一条持久化的 sandbox/mode 事件——也就是你上次的选择,而不是一个新的默认值。
  • 档位与审批策略是解耦的。切到 danger-full-access 只抬高文件边界,不会顺手把审批策略变成「永不询问」。关闭审批始终是一次显式的人类动作(在审批弹窗里对某个工具选「Allow always」)。
  • 被拒绝的调用会带 [sandbox: file access denied under <mode> mode] 标记;模型可以用 sandbox_permissions(足以放行的最窄更宽模式)加 justification 重试一次完全相同的调用,由人类审批。升权必须严格宽于当前生效模式,且只作用于该次调用。

Linux:bubblewrap → Landlock 两级

受限 bash 优先经 bwrap(bubblewrap)运行,并要求内核开启非特权 user namespace。装了 bubblewrap 就是这一档,安全性最好:

Terminal window
# Debian / Ubuntu
sudo apt install bubblewrap
# Fedora / RHEL
sudo dnf install bubblewrap
# Arch
sudo pacman -S bubblewrap

没有 bubblewrap 不等于没有沙箱:qialike 自带 Landlock 档(apps/tui-bin/src/landlock-shim.ts 实现其 launcher),只要内核启用了 Landlock LSM(≥5.13)就会自动落到这一档,功能上仍受内核级约束。

两级都不可用时才会发生下面这些(这才是 SANDBOX_UNAVAILABLE 的触发条件):

  • 应用照常启动。
  • 非 shell 工具全部可用(纯 JS 的 fs-sandbox 栅栏仍在)。
  • 但 workspace-write / read-only 下每条 bash 都 fail-closed 报 SANDBOX_UNAVAILABLE,而不是不受限制地运行。
  • 只有 danger-full-access(无隔离)能跑。
  • 执行器不提供内核隔离时,再由逐次 shell 审批兜底——提示会说明该命令拥有你的完整用户权限。

这是刻意的**故障关闭(fail-closed)**设计:无法强制执行所请求的模式时,调用以 SANDBOX_UNAVAILABLE 失败,绝不静默无限制放行。错误文本会指明缺失的平台 runner。

如果内核禁用了非特权 user namespace,也可能出现同样结果:

Terminal window
# 检查
cat /proc/sys/kernel/unprivileged_userns_clone # Debian/Ubuntu 系
cat /proc/sys/user/max_user_namespaces

macOS:Seatbelt

macOS 使用系统自带的 Seatbelt(sandbox-exec)。workspace-write 的可写范围由 Seatbelt profile 与进程内 fs 栅栏共用同一份可写根目录推导,二者授予完全相同的根。

无需额外安装。若 sandbox-exec 不可用,处理方式与 Linux 相同:请求的模式无法强制执行时以 SANDBOX_UNAVAILABLE 失败。


Windows:ACL restricted-token runner

Windows 用 harness 的 ACL restricted-token runner 提供 OS 级隔离,与另两个平台一样开箱即用。单文件构建需要自带两样东西才能把它跑起来:它依赖的原生 koffi(由 apps/tui-bin/stub/koffi.js 顶替),以及 runner 进程本身——harness 用模块 specifier 定位它,而编译后的二进制答不了这个调用,于是 qialike 把 harness 自己的 runner 一并携带并充当其 launcher(见 apps/tui-bin/src/windows-acl-shim.ts)。

permission(presets)行在所有平台都已启用,Windows 不例外。

实际后果:

  • 纯 JS 的 fs-sandbox 栅栏 + workspace-write + ask 审批边界仍是文件效应的闸门。
  • ACL runner 提供内核级的进程隔离。
  • 仍然可以在 WSL2 里使用 qialike(获得 Linux 的 bubblewrap / Landlock 档),但这是可选项,不是必需。见 Windows 与 WSL。

设计边界

  • 强制执行完整度是逐调用报告的:full 表示后端管辖模式承诺的每个文件操作,partial 表示只管辖子集。需要绝对边界的消费方可以拒绝或向上暴露 partial。
  • 策略随调用传递,不固定在 provider 上:两个消费方可以同时按不同策略隔离;获批的升权重试只是一次用更宽策略发起的新调用。
  • 机密文件读不到:.env 系列、.git 内部路径与 harness 凭据文档一律拒绝读取(.env.example 例外)。这条在任何沙箱模式下都生效,danger-full-access 也不解除。它只拦读工具:shell 命令里点名这些文件仍读得到——这是如实记录的缺口,Gemini CLI 同样存在。
  • 仓库无权放宽你的沙箱:改(或关掉)sandbox / sandbox-policy / fs-sandbox / bash-sandbox / pwsh-sandbox / approval / permission / fs-observation-policy 的行只能写在你自己的 overlay 里;仓库级 overlay 里的这类行一律被拒绝。详见 配置。

下一步

  • Windows 与 WSL —— Windows 原生使用,或可选地改走 WSL2
  • 故障排除 —— SANDBOX_UNAVAILABLE 的处理
  • 命令 —— qialike --dump-config 查看组合后的分层