[BUG REPORT] Windows 沙箱无法在用户自建目录上 provision 工作区 ACE → 该目录下所有 shell 命令失败 #7538
Replies: 1 comment
|
Your anchors are all correct, and both things you flagged as unverified are answerable from the tree. One of them changes the fix discussion: the repository documents the label's prerequisite as Your anchors check out, and the failing edit is pinned by where you did not fail
The documented prerequisite is
|
Uh oh!
There was an error while loading. Please reload this page.
Windows 沙箱无法在用户自建目录上 provision 工作区 ACE → 该目录下所有 shell 命令失败
0.1.7-alpha.1(HEADc36a83ff6b,tagdsh-v0.1.7-alpha.1)packages/sandbox/sandbox-windows-aclpwsh调用)1. 最小复现
D:\proj;mkdir即可,无需任何特殊操作)。node --version)。期望:命令正常执行(沙箱为该工作区物化 capability ACE 后放行)。
实际:每次调用都以同一错误失败:
Win32 5 = ERROR_ACCESS_DENIED。重试没有意义——错误逐字相同。2. 实际观测(一次真实 run)
某阶段(子代理)的 13 次工具调用里,
tool/result有 7 条isError: true,全部是同一句:模型的行为是可预期的:它反复重试同一条命令(第 1/2/5/6/7/9/10 步都是
pwsh),确认无望后开始长篇推理,最终被输出上限截断:pwsh)即:一个环境故障在一个阶段里烧掉 52.6k 输出,而且最终停下来的原因是「撞上模型输出上限」,不是「环境不可用」——排查时极易被误导(我们最初就按
max-tokens排查了很久)。3. 为什么是路径相关的:ACE 对照
同一台机器上,
Get-Acl读到的沙箱 capability ACE(S-1-4-*派生 SID)分布如下:D:\proj)Documents、Desktop、~/.dsh%TEMP%及其中子目录S-1-5-21-*组账户)OI CI)对照结论:只有"以前被 provision 过(或从其继承)"的树能用。用户随手新建的目录没有这条 ACE,而沙箱这次又没能把它加上。
补充实验:ACE 本身是可加的
在一个一次性目录上以当前用户身份执行等价的授权操作,成功:
注意:该 SID 无法翻译成账户名(
Translate()抛 "Some or all identity references could not be translated."),但作为 ACE 合法可用——所以它应当是 DSH 派生的沙箱身份,而不是本机账户。
4. 代码线索
packages/sandbox/sandbox-windows-acl/src/acl.ts:262src/index.ts:270-277、src/grant.ts:107(grantWrite(api, path, sidPtr, lowLabelSid, worldSid))。README.zh.md:90 / 108 / 177):workspaceWriteSid),因此工作区根目录的安全描述符改动每台机器每个工作区只物化一次」;grantWrite读取当前 DACL,当完全相同的 ACE 已存在时跳过重新传播」;5. 根因(已实测定位:第三项编辑是 SACL 写入,普通用户令牌无权)
grantWrite在同一次SetNamedSecurityInfoW调用里做三项编辑(见同包README.zh.md:90):① 给工作区 capability SID 加写 ACE;② 给 world SID 拒绝
FILE_DELETE_CHILD;③ 把该目录标记为 Low 完整性。第 ③ 项写的是 SACL,而写 SACL 需要
SeSecurityPrivilege——普通(非提升)用户令牌没有这个权限。源码佐证(
packages/sandbox/sandbox-windows-acl/src/acl.ts)::387-388跳过条件 =hasExactGrant && hasExactDeny && hasExactLabel(三者都"精确已在"才跳过整次应用);:398-409三项编辑 =buildLowLabelAcl(Low +OI|CI+ no-write-up)/buildExplicitAccess(world, DENY_ACCESS, FILE_DELETE_CHILD, CONTAINER_INHERIT_ACE)(仅 CI)/buildExplicitAccess(capability, GRANT_ACCESS, 0x110156);:257提交时labelEdit.kind === 'keep' ? DACL_SECURITY_INFORMATION : DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION—— 标签若已精确在,则完全不传 SACL 位。这就是"历史 provision 过的树不需要特权、而全新目录必然需要"的确切分界:
前者走"纯 DACL 写入"(owner 就能做),后者必须写 SACL(需要
SeSecurityPrivilege)。在本机以普通用户令牌逐项实测(一次性目录;用该包的
workspaceWriteSid()算法算出 SID):0x110156,OI|CI)FILE_DELETE_CHILDAccess is denied.(exit 5)且
whoami /priv中没有SeSecurityPrivilege。三项编辑在同一次调用里 → ③ 失败即整次返回ERROR_ACCESS_DENIED—— 与观测到的Win32 5完全一致。这同时解释了"为什么只有历史 provision 过的树能用":
grantWrite在精确 ACE + 精确拒绝 + 精确标签都已存在时会跳过该调用(幂等快路径,见
tests/acl-failure-paths.spec.ts:575),所以那些目录不再需要写 SACL。它们应当是在某个提升权限的进程里被物化过一次的。
仍未验证:provision 具体在宿主进程还是沙箱 runner 里执行(与结论无关——非提升场景下两者都没有
SeSecurityPrivilege)。6. 影响面(为什么值得修)
mkdir的目录上 100% 失败(即本报告的复现场景)。是否为所有新建目录,取决于该目录(或祖先)是否已是 Low 完整性——
若已是 Low,第 ③ 项编辑无需发生,provision 就不需要特权即可成功(这解释了
%TEMP%下与历史项目树里为什么能留下沙箱 ACE)。标签分布我们没有测:读取 SACL 本身就需要
SeSecurityPrivilege,非提升进程读不到(实测四种路径全部返回 "does not possess the 'SeSecurityPrivilege' privilege"),
所以"哪些常见位置会中"仍待宿主侧确认。
会先被看到。agent 的典型反应是重试 → 推理 → 烧钱。
7. 建议(交给宿主侧决策)
acl.ts:257已经具备"标签已在就不传 SACL 位"的能力,只需再进一步——标签写不了(无
SeSecurityPrivilege)时退化为纯 DACL 写入并如实告警,而不是让整次
SetNamedSecurityInfoW回滚成"该工作区永远不可用"。或者在初始化阶段用能写 SACL 的令牌完成首次物化(之后精确跳过,成本一次)。
「该目录无法用于沙箱执行:<路径>(Access denied)」并给出补救(换目录 / 手工授权 / 关闭沙箱),
而不是让它以一条工具错误的形式在 run 深处爆炸。
(本次涉及的插件侧问题——把一个环境故障误报成
max-tokens、以及护栏没拦住同一工具连续相同失败——已由插件侧自行修复:判据用结构化
isError、连续 5 次相同错误即中止并点名「环境不可用」。宿主侧这条 ACE provision 失败本身仍待修。)
附:原始证据
工具错误原文(逐字,路径已替换)
ACL(SDDL 形状,SID 已截断)
环境
node v22.22.3、dsh 0.1.7-alpha.1、Windows、工作区在非系统盘(NTFS Fixed)。teams.json(首个需要 shell 的阶段即失败,无产物)。SID 派生交叉验证(确认 capability SID 确由工作区路径派生:拿已带 ACE 的目录反算,与磁盘上的 ACE 逐字相符)
三项编辑逐项实测(普通用户令牌,一次性目录)
关键交叉验证:同一段代码在提权令牌下成功(证明不是代码缺陷,而是令牌权限)
以管理员 PowerShell 运行该包自带的 agentless runner(它会自行 grant 工作区,且工作区 ACE 是
standing、
dispose()不撤销):之后
icacls <workspace>(提权才看得到 Mandatory Label 行)恰好是设计中的终态:普通用户令牌手工只补前两项(ACE + deny)不够:标签写不进去 → 精确跳过条件(
acl.ts:387-388)不成立→ 下次仍要写 SACL → 依然
ACCESS_DENIED(实测:手工补 ACE 后 resume 仍以同一错误早停)。旁证:修好之后插件侧的行为(同一工作区、同一故障)
max-tokens(误报,真因被掩)env-unavailable+ 点名环境与原文错误All reactions