Replies: 2 comments
|
补充一个同根因、而且比正文的 当前: 前台 using d = deadline(spec.signal, spec.timeoutMs, 'BASH_TIMEOUT')
const handle = this.ctx.subprocess.spawn(
this.spawnSpec(spec, spec.stdoutMaxBytes, d.signal, argv),
)而 const onAbort = (): void => { terminate() }
spec.signal?.addEventListener('abort', onAbort, { once: true })Windows 下 spawnSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore' })所以不需要 jobs: 同样,用户/上游取消导致 这进一步说明修复应位于共享的 Windows tree-termination boundary:把 |
|
补充一个Linux 上相同 Host-helper authority boundary 的变体。这不是 当前产品启动器会读取调用目录的 项目自己的配置边界文档明确规定,项目 同时: 中的 Host native runner 使用: execFile(command, args, {
encoding: 'utf8',
signal,
windowsHide: true,
})没有提供独立 Linux 而 GNOME/GNOME3(以及部分 MATE/XFCE 路径)的 GIO 会从 我在当前提交上做了无害动态验证。测试项目只有: GIO_EXTRA_MODULES=./modules
测试按真实产品调用顺序: 当前源码测试输出: 另外直接对系统 GIO 做了控制实验:设置相同 这条路径和正文 Windows 区别是这里不依赖 Windows executable search,也不是运行中 Agent 写 修复上,我觉得应该同时考虑两层:
项目现有设计文档自己已经指出“逐变量枚举是一场输的游戏”,所以第二层尤其有价值:否则新增一个 Host helper/runtime 后,还需要重新猜一遍它有哪些 module/plugin loader 环境变量。 |
Uh oh!
There was an error while loading. Please reload this page.
先说结论:Windows 下,当前后台任务终止路径会由 Harness 宿主进程直接执行裸命令名
taskkill。Node/libuv 在 Windows 对这种裸 executable 的查找会先检查进程当前工作目录,再检查PATH。而默认配置里,进程当前工作目录同时也是初始 session 的 workspace。因此,一个只拥有
workspace-write的模型如果在 workspace 中放入taskkill.exe,随后启动并终止一个 background PowerShell job,宿主侧清理逻辑可能优先执行 workspace 中的taskkill.exe,而不是系统的System32\\taskkill.exe。关键点是:这个
taskkill.exe不是由受限 PowerShell token 启动的。它是dsh-subprocess-local的宿主 Node 进程为了清理 job 而调用spawnSync()启动,所以一旦搜索顺序被 workspace 文件劫持,代码会以 Harness 宿主用户的正常权限运行,绕过当前workspace-writerestricted-token 边界。可能影响包括:
workspace-write直接进入 Harness 宿主用户权限下的代码执行;下面的分析基于当前
master:我当前的测试环境不是 Windows,所以没有把下面的 Windows 端到端 marker PoC 冒充成已经动态跑过的结果;但涉及的 DSH 调用链和 Node/libuv Windows executable search 规则都是当前源码中的确定行为。
1. Windows 默认 composition 暴露 background PowerShell + jobs
基础 composition 在 Windows 下启用:
对应位置:
默认 sandbox mode 是:
tool-pwsh默认开启run_in_background:因此模型正常就可以:
这不是额外插件或非默认 trusted extension 才有的能力。
2. 默认 session cwd 也是 Host 的
process.cwd()Host API proxy 的默认 cwd 来自:
创建 session 时,如果没有显式 workspace/cwd override:
因此默认启动场景下:
也就是说,
workspace-write允许模型修改的初始 workspace 正好也是后续裸 executable 查找会检查的 Host current directory。3. Windows
workspace-write明确允许模型在 workspace 内创建文件Windows shipped sandbox 使用 restricted token + workspace SID 来约束写入。
项目自己的 Windows sandbox 文档明确描述:
同时
workspace-write下 PowerShell 保持 FullLanguage(没有额外 host-wide WDAC/AppLocker 时),所以模型有正常的 workspace 内代码/文件生成能力。攻击者不需要先获得任何 workspace 外写权限。
4. background job 的
job_kill最终进入 subprocess tree terminationtool-pwsh的 background producer:jobs-local的kill():所以模型调用:
会进入:
5. Windows terminate 路径由宿主直接执行裸
taskkill当前:
包含:
并且 Windows tree signaling 直接调用它:
这里没有:
这样的绝对系统路径,也没有为这个宿主 helper 设置一个可信 cwd。
这个
spawnSync()发生在 Harness 宿主 Node 进程中,不是在前面启动的 restricted-token child 内。所以它不受当前 pwsh 的 workspace-write token 限制。
6. Node/libuv 在 Windows 会先从 current directory 查裸 executable
当前 Node 24 使用 libuv 的 Windows process implementation 来解析裸命令名。
libuv 当前
src/win/process.c的search_path()明确实现了 Windows executable 查找,并在PATH之前检查 current directory;对于没有扩展名的命令,还会尝试.com和.exe。参考源码:
因此:
在 Windows 上并不等同于:
而更接近:
这正好与默认 model-writable workspace / process cwd 重合。
7. 完整利用链
把上面的当前实现串起来:
这里发生了明确的 authority transition:
8. 为什么这不是 Windows sandbox 已声明的 partial-enforcement 限制
Windows ACL backend 的文档已经明确列出一些结构性 partial boundaries,例如:
这个问题不依赖这些条件。
攻击者只在 sandbox 明确允许的 workspace 内创建文件。
真正的问题发生在 sandbox 之外的宿主清理路径:Host 使用 model-writable current directory 去解析一个需要被当作 trusted OS helper 的裸 executable name。
因此它不是 restricted-token backend 报告
partial所覆盖的“某些文件对象仍然可写”,而是一个独立的 untrusted executable search path / confused-deputy 问题。9. 建议的无害 Windows 回归验证
可以在独立测试 workspace + 独立 outside marker directory 中验证,不需要修改真实系统文件。
测试结构建议:
其中
taskkill.exe只做:验证顺序:
如果 marker 出现,就同时证明:
这能把 authority transition 明确区分出来。
10. 修复建议
这里不应该依赖 PATH/search-path 去定位系统 tree-kill helper。
Windows 下应把 helper 固定到可信系统路径,例如基于
%SystemRoot%/ Windows system directory API 构造:然后使用该绝对路径执行。
更稳妥的方案是完全避免外部
taskkill.exe,直接通过受控 Win32 API / Job Object 实现 tree termination;这样既消除 executable lookup,也减少外部 helper 行为和环境依赖。建议增加 regression test,至少固定:
并测试 Windows cleanup 路径实际调用的是绝对可信系统 helper(如果仍保留 taskkill 实现)。
总结
当前 Windows 默认能力和调用链为:
因此,model-writable workspace 可以进入一个本应只解析可信系统 binary 的宿主 executable-search boundary。
建议将 Windows tree termination helper 改为绝对可信路径,或者直接使用 Win32-native tree ownership/termination primitive,避免任何 current-directory / PATH executable resolution。
All reactions