Repository navigation
[Bug Report] Windows ACL 沙箱:工作区被打上「可继承的 Low 完整性标签」→ 目录内所有 .lnk 变白图标;非预期目录亦会被静默改写 ACL #8665
caliburzero
started this conversation in
General
Replies: 1 comment 1 reply
|
补充一条「真实桌面工作区」的批量止血与边界(DSH Desktop 2.0.17 / core 0.2.0-rc.2,Windows 11)。 环境差异:我这里工作区在系统盘 C:\Users\Litho_7\Desktop,目录属主是用户本人(不是 批量止血(一条命令覆盖工作区根下全部快捷方式;目录保持 Low 不动,受限进程靠它才能写入): 实测(SHGetFileInfo iIcon,0 = 泛型白图标): 正文没覆盖的三点:
|
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
[Bug Report] Windows ACL 沙箱:工作区被打上「可继承的 Low 完整性标签」→ 目录内所有
.lnk变白图标;非预期目录亦会被静默改写 ACL一、环境
@deepseek-ai/dsh)@deepseek-ai/dsh-sandbox-windows-acl0.2.0-rc.2workspace-write(Windows ACL 受限令牌 runner)BUILTIN\Administrators,带 FULL二、摘要
AclWriteGrant.grantWrite在一次SetNamedSecurityInfoW调用里对工作区根写入三样东西(这一点
dsh-acl-sandbox-patch的 README 也独立描述过):S-1-4-x-y,由工作区路径 sha256 派生)的 Allow ACE;FILE_DELETE_CHILDDeny ACE;问题出在第 3 项——它是可继承的(
(OI)(CI)(NW)),并且按设计"急切全树传播",于是工作区里每一个既有文件也都被标成 Low。
而 Windows 外壳对带 Low 完整性标签的
.lnk/.pif会拒绝解析快捷方式图标:SHGetFileInfo(..., SHGFI_ICON | SHGFI_SYSICONINDEX)返回iIcon = 0(泛型"未知文件"图标);.lnk图标"逐字节相同,连快捷方式里显式写死的IconLocation也被忽略;.lnk/.pif受影响:.txt/.url/.exe/ 文件夹即使标 Low 也一切正常。反向验证:把该
.lnk的标签改回Medium,图标立即恢复(iIcon0 → 50)。用户可见症状:工作区里所有快捷方式永远显示白图标(双击仍可正常打开)。
更隐蔽的部分:一旦工作区根被解析成非预期目录(本机是
%USERPROFILE%\Desktop),那个目录及其整个子树会被静默、且按设计永不撤销地改写 ACL —— 见第 5 节。
三、复现
复现 A:不涉及 DSH 的最小机制复现(约 10 行,管理员 PowerShell)
正文里这 10 行就够(附件脚本是它的严谨版)。观察时有个前提:别在同一进程里反复量同一个路径——
有两个坑会给出假阴性(见 4.2)。
完整可运行脚本见附件
low-integrity-lnk-icon-repro.ps1:三个变体放在各自的目录里、每个只量一次。本机(Windows 11 26H2 / build 26300.9457 / PowerShell 5.1)实测输出:
复现 B:DSH 侧(工作区里的快捷方式必然白图标)
workspace-write模式下启动 DSH(工作区根被grantWrite授权过);.lnk(新建或从别处复制进来都行);icacls <那个.lnk>→Mandatory Label\Low Mandatory Level:(I)(NW)(继承自工作区根);工作区根自身:
Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)——(OI)(CI)就是传染源。复现 C:工作区根被解析成非预期目录(本机的实际事故)
dsh web)放成%USERPROFILE%\Desktop\dsh-start.bat,双击运行;Windows 会把 **bat 所在目录(桌面)**设为进程 cwd;
workspaceRoot→dsh-sandbox-policy的this.workspaceRoot = resolveWorkspaceRoot(config.workspaceRoot ?? process.cwd())取到桌面;
这一条有硬证据(不是推测):桌面上实测到的 capability ACE 是
S-1-4-1039366120-933337351,而(派生化简自包内
workspaceWriteSid:sha256(canonicalPath)前 8 字节按% (2**30-1) + 1生成两个 subauthority。工作区路径的 SID 用同一公式复算亦精确匹配。)四、证据
4.1 因果矩阵(9 组对照,全部实测)
.lnk的 iIcon.txt,对照)结论:决定因素是
.lnk文件自身的完整性标签;world Deny 与 capability ACE 与图标无关。第 6 行说明"目录带 Low 但文件不带"不会出问题 —— 这正是下面 4.2 那次误判的成因。
4.2 两个会给出假阴性的坑
我们最初也是这样把它排除掉的,原始记录:
两点:
icacls /setintegritylevel Low写入的是不可继承标签 —— 只标目录、不标文件;icacls /setintegritylevel '(OI)(CI)(NW)'不被接受(报"参数错误"),所以照 DSH 的做法写出可继承标签必须走
SetNamedSecurityInfoW+LABEL_SECURITY_INFORMATION。因此"给目录打 Low 标签后图标没变"不能证明该标签无罪。
坑 2:
SHGetFileInfo在进程内按路径缓存图标。先量过一个路径(拿到 50)、再改它的标签、然后在同一进程里重量同一路径 —— 仍然返回 50;
换一个新进程量就是 0。本机实测(Windows 11 26H2 / build 26300.9457):
所以因果验证必须做到"每个变体一个独立路径(或独立进程),且每个路径只量一次"。
坑 1 是我们最初把它误判为无罪的原因,坑 2 是我们写第一版复现脚本时踩到的原因
(同一路径量三遍,结果 "not reproduced")。
4.3 量测方法
SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SYSICONINDEX),把 HICON 画进 32×32 位图后统计"非透明且非近白"像素占比:
shell32.dll,137图标 + 快捷方式箭头.lnk(= 白图标)沙箱内与被降权的进程里量测结果一致;另外用 SYSTEM 身份、经计划任务在沙箱之外量测,
结论相同(排除"只是在受限令牌里看起来白"的可能)。
五、影响面与触发条件
5.1 触发条件(同时成立才会中)
dsh-sandbox-windows-acl);本机 0.2.0-rc.2 仍存在workspace-write(read-only不授予可写根,danger-full-access不起沙箱,都走不到grantWrite)workspaceRoot(工作区根回退到process.cwd()).lnk/.pif(否则无症状)注意条件 6 的反转:写 Low 标签需要
WRITE_OWNER。非系统盘上由继承Modify建出的目录拿不到它,于是
SetNamedSecurityInfoW直接Win32 5失败、fail-closed(见上游 #7771 / #7720 / #7804 与第三方补丁
dsh-acl-sandbox-patch)。也就是说:"能成功打上标签"恰恰是出现白图标的前提;打不上的那批环境报的是
grantWrite失败,反而躲过了 ACL 被改。5.2 不止"桌面",而且看不见的那种更严重
任何被解析为工作区根的目录都会被打上同一套三条改动,并急切传播到全部子孙。
下载夹、项目夹、游戏夹同理。
FILE_DELETE_CHILDDeny、一条可继承 Low 标签,且按 README 的表述"standing …the reuse cache, never revoked"——永久驻留,
icacls也清理不掉(ERROR_NONE_MAPPED 1332)。对用户而言这是"一句话没问就把一个目录的权限改成了沙箱可写根",
而且这个目录可能根本不该被交给沙箱(本机就是用户的桌面)。
六、建议
process.cwd()。 至少在解析出的根位于%USERPROFILE%根、Desktop、Downloads、Documents根等敏感位置时,拒绝授权并给出一条明确错误(现在这种情形是完全静默的)。
.lnk/.pif降为 Low(或对这类文件改用别的授权方式)。Windows 外壳把对象的完整性当作"这个快捷方式是否可信"的输入,因此这条标签会直接把图标打回泛型;
而这三个文件类型恰好是外壳要解释的类型。若出于写权限必须标,建议至少跳过这两类扩展名并
在文档里说明取舍。
.lnk失去图标"写进sandbox-windows-aclREADME 的已知代价。目前 README 只在"常驻改动"里提到 ACE/拒绝项/标签,没有提继承语义与这个可观测后果。顺带把 4.2 那个
icacls假阴性也写进排查指引。让用户有机会发现"工作区根取错了"。
grantWrite无法写标签时 fail-closed,与"标签继承语义"是同一处代码的两面,建议一并设计(例如标签写失败时是否也跳过降 Low)。
七、相关
packages/sandbox/sandbox-windows-acl/README.zh.md("…并在同一次SetNamedSecurityInfoW调用中把该目录标记为 Low")grantWrite失败:#7771 / #7720 / #7804,及第三方补丁 https://github.com/masknull/dsh-acl-sandbox-patch0xC0000142的成因讨论):#758可能的关联:#758 的评论把桌面端
0xC0000142归因于"工作区派生的 SID 进入 restricting 列表",而设计注记说
logon SID + Everyone是保命项、缺了才会0xC0000142。两种说法我们未能统一,也未在本机复现验证;但两者都与"工作区根 / 沙箱令牌"这一处有关,附此供参考。
八、附:完整复现脚本
§三 的 10 行版已足够说明问题;下面是带 idx 量测、前后对照表与自动清理的完整版。
点开:low-integrity-lnk-icon-repro.ps1(完整脚本,约 200 行)
脚本头部注释写清了 4.2 那两个假阴性陷阱,以及为什么必须那样设计。
本机(Windows 11 26H2 / build 26300.9457 / PowerShell 5.1)实测:reproduced。
All reactions