# [Windows] 非系统盘工作区在 sandbox provisioning 阶段 fail-closed(Win32 5),且唯一官方修复手段与「避免 Low 完整性标签副作用」不可兼得 #8275
Replies: 1 comment
|
Two of your six pain points are answered by a mechanism rather than a policy decision, and one of your expectations comes out differently once that mechanism is on the table. The rest are yours to argue upstream — I am not upstream. 1. The either-or is real, but the label is not one of two independent layersYour framing is right as a description of the shipped API, and your附录 A is right that Read off the shipped source (
That is why your附录 B's community patch had to skip 2. 痛点 5 has an answer that does not need a shellYou are right that the skill cannot solve its own no-shell problem: a script needs npm install @argszero/cordis-plugin-sandbox-grant-advisor- insert:
- id: sandbox-grant-advisor
name: '@argszero/cordis-plugin-sandbox-grant-advisor'It observes the public 3. What it now says about your痛点 3This is what 0.9.1 added, and it is your report's shape rather than your report's proposal:
It is phrased as a mechanism rather than a refusal on purpose: a reader told only "no" reaches for the workaround without knowing what else it has to change, which is the failure mode your附录 B documents from the outside. 4. What I am not taking a position on
Verified for the release named above: 86 tests green, 32 defect-injection arms (31 caught, one measured equivalent, none silent), all five peer lines re-probed; |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
TL;DR
在非系统盘上使用 DSH(工作区如
E:\MyWorkspace),只要该目录的 ACL 是 Windows 盘的默认继承形态,grantWrite就会抛Win32 5并 fail-closed —— 所有pwsh/bash/run_code类工具全部不可用,且每条命令都以同一个错误失败,没有任何可用性降级路径。0.2.0 引入的
diagnose-windows-sandbox-acl技能确实能修好它(补WRITE_OWNER),但修好的同时会把 Low 完整性标签写回工作区,导致两个长期副作用回归。也就是说:"沙箱能用" 和 "没有 Low 标签副作用" 目前只能二选一。环境
E:\MyWorkspace(非系统盘,NTFS)0.1.7-rc.2(Web / TUI)与 Desktop0.2.0-rc.2均可复现@deepseek-ai/dsh-sandbox-windows-acl0.1.7-rc.2 / 0.2.0-rc.2(两者grantWrite逻辑一致,见附录 A)%USERPROFILE%\.dsh(与工作区分属不同盘)工作区 ACL(
icacls关键行,脱敏):复现
E:/D:/F:)创建一个目录作为工作区,不做任何 ACL 调整(即保持盘根继承的Authenticated Users:(M))。pwsh工具调用,例如Get-Location。痛点(本 issue 的重点)
痛点 1:最常见的用户目录形态,恰好是最容易触发失败的形态
grantWrite的注释自己写明了前置条件(lib/types-*.js,0.1.7 与 0.2.0 措辞一致):问题在于:
Authenticated Users:(M)(Modify),不含WRITE_OWNER;READ_CONTROL+WRITE_DAC,也不含WRITE_OWNER;也就是说这不是边缘 case,而是默认路径上的坑。而且系统盘(
C:\)下用户目录常常带(F),所以问题会呈现为"换个盘就炸",进一步增加迷惑性。痛点 2:失败发生在 provisioning 阶段,表现为"整个工具面消失"
grantWrite失败是 fail-closed by construction(注释原话:"throws on ANY Win32 failure — never spawns unrestricted")。设计上可以理解,但用户体验是:whoami都不行;Win32 5+grantWrite(<path>)推断出"缺WRITE_OWNER",更不知道有一个诊断技能可用。错误信息里没有任何指向解法的线索。痛点 3:唯一官方修复手段,与「避免 Low 标签副作用」互斥 —— 这是本 issue 的核心
0.2.0 的
diagnose-windows-sandbox-acl技能对本文场景的裁决是PRECONDITION,动作是给当前用户补FullControlallow ACE。补完之后grantWrite成功,一切正常。但
grantWrite成功时,那一次SetNamedSecurityInfoW是三处编辑一起落地的(源码注释):于是:
这两种状态互为前提,中间没有落脚点。 用户想要的是"沙箱能用,但工作区保持 Medium",而当前架构下这个组合不存在。
而且由于
grantWrite的幂等 skip 判据是 exact ACE + exact deny + exact Low label 三者齐备,用户也无法用icacls /setintegritylevel Medium手工把标签改回 Medium 来"骗过" skip —— 标签一旦与 Low 不符,apply 分支就会重新执行,再次写回 Low。痛点 4:Low 标签的副作用被明确划到 scope 之外,但用户每天都在撞
官方 README 承认了 Low 标签会外溢:
技能文档则直接把后果排除在修复范围外:
但实际观察到的两个副作用都是用户可见、持久、且会传播到 DSH 之外的:
4a. 工作区内双击
.bat/.exe时出现「无法验证发布者」警告。 用户在自己刚创建的脚本上双击,得到的是安全警告 —— 这直接破坏"工作区就是我的目录"的直觉。4b.(更严重)把工作区里的文件复制出去,文件会被写上
Zone.IdentifierADS(ZoneId=3,即 MOTW)。 这条最要命:也就是说:DSH 在"只是跑了个命令"之后,悄悄改变了用户文件的元数据,并让这个改变传播到 DSH 之外的环境。 这是我们认为最需要优先解决的一点。
补充说明:这一条是在移除
FullControl让 grant 失败之后才消失的 —— 反过来说,官方修复手段必然让它回来。痛点 5:修沙箱的工具,需要沙箱能用才能跑(鸡生蛋)
diagnose-windows-sandbox-acl是一份 PowerShell 脚本(assets/diagnose-windows-sandbox-acl/scripts/*.ps1,约 45 KB / 798 行),必须用pwsh执行。但故障场景恰恰是
pwsh工具完全不可用(痛点 2)。技能文档也确认沙箱内无法运行:结论是一个没有出口的循环:
建议:把该技能的调用路径做成"沙箱不可用时也能一键触发"的形态(例如由 host 端直接执行并走 approval,而不是依赖
pwsh工具)。痛点 6:诊断脚本住在临时目录,DSH 一重启就消失
registerAclDiagnosisSkill()的实现是解压到mkdtempSync(join(tmpdir(), "dsh-acl-skill-")),并且 "disposal removes the directory"。后果:技能文档只提醒了不要把
-Out放进去,没有提示"想留下工具请自行复制"。已经做得好的部分(希望保留)
不是全盘否定,以下几点确实到位:
diagnose-windows-sandbox-acl技能,第一次给了官方诊断入口,而不是让用户自己grep源码;ROLLBACK命令和(脚本级)-Restore模式,工程上比"手敲icacls"稳得多;-AllowRoot把改动范围锁死在授权目录内,并拒绝 reparse point 和受管应用目录;READ-ONLY的约束、FILE_DELETE_CHILD只继承到目录、hard link 与 AppContainer ACL 的边界等)。期望
按优先级:
提供"降级 provisioning"模式(最高优先级):当
SetNamedSecurityInfoW因缺少WRITE_OWNER而失败时,允许退化为 DACL-only(应用 capability-SID allow ACE +Everyonedeny,跳过 SACL 的 Low 标签编辑),并明确告知这是一次降级。理由:write-restricted token 的 restricting-SID 交集检查是主要的强制机制,Low 标签是纵深防御的第二层;牺牲第二层换取可用性,比 fail-closed 更符合实际。这也是社区补丁被迫采用的方案(附录 B)。把
grantWrite的三处编辑拆开,让 Low 标签可独立开关。当前"一次调用三件事"的设计使得用户无法只取 DACL 部分,这是痛点 3 的根因。区分处置 4a / 4b:至少不该因"创建文件的方式"而给文件写 MOTW。如果 4b 的成因确实是标签策略导致的 ADS 写入,请把它纳入修复范围,而不是排除在 scope 外。
启动期预检 + 可操作的错误信息:在 provisioning 必然失败时,启动日志/UI 直接给出"缺
WRITE_OWNER,可运行diagnose-windows-sandbox-acl"的提示,而不是让每条命令都重复Win32 5。非系统盘工作区应单独给出提示(这正是最容易踩的形态)。让诊断技能在沙箱不可用时也能被触发:走 host 端 + approval,不依赖
pwsh工具链(痛点 5)。技能资源放到持久位置,或提供一行命令让用户自行持久化(痛点 6)。
附录 A:
grantWrite在 0.1.7-rc.2 与 0.2.0-rc.2 之间未变对比两份打包产物(
lib/types-*.js):hasExactGrant(oldAcl, sidPtr) && hasExactDeny(oldAcl, worldSidPtr) && hasExactLabel(labelAcl, lowLabelSidPtr);mergeAndApply(api, path, Buffer.concat([buildExplicitAccess(worldSidPtr, 3, 64, 2), buildExplicitAccess(sidPtr, 1, GRANT_MASK)]), oldAcl, { kind: "apply", acl: label }, descriptor, "grantWrite");setNamedSecurityInfoW为 7 参数(str16, int, uint32, PVOID ×4),getNamedSecurityInfoW为 8 参数;ACL_DIAGNOSIS_SKILL/registerAclDiagnosisSkill以及assets/目录。结论:0.2.0 修的是"诊断与修复的可用性",不是"这个前置条件本身"。 因此本 issue 描述的故障在 0.2.0-rc.2 上原样复现。
附录 B:社区已被迫用 koffi hook 绕过
社区侧存在
dsh-acl-sandbox-patch这类插件,做法是在SetNamedSecurityInfoW收到Win32 5时剥离LABEL | SACL标志重试,即只应用 DACL 部分,并在进程内标记"降级"状态,同时跳过子进程的SetTokenInformation(TokenIntegrityLevel)。它的存在本身就是对痛点 3 的佐证:用户想要的是"沙箱能授权"而不是"沙箱能打标签",而当前 API 只提供后者。同时它也说明痛点 1/2 的修复需求足够普遍,以至于有人愿意维护一个第三方 hook。
(此处不主张官方采用任何具体第三方实现,仅作为需求强度的证据。)
All reactions