Repository navigation
Replies: 2 comments
|
用UE引擎工程也碰到了 |
0 replies
|
Low 完整性标签是吧, 可以去掉 用 pwsh 另外还有一个简单的办法, 重建目录. 就是把目录里边东西复制走, 新建目录复制回去 |
0 replies
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.
Windows 下 workspace-write 会永久改写工作区安全描述符(Low 完整性标签 + Everyone 删除拒绝),且无法回收
写在前面
我用 dsh 0.2.1-rc.2(Windows 桌面版)开发一个 .NET 项目。项目的运行时数据放在工作区之外(
D:\GrossingData),代码工作区是D:\code\dev-SmartGrossing。在一次会话之后,我发现工作区目录的安全描述符被改写了,而且这个改动在会话结束后依然存在,卸载也带不走,
icacls也删不掉。顺着源码查下去,确认这是 Windows 沙箱workspace-write的授权物化逻辑(grantWrite)写入的三条可继承项。我不是来报"程序崩了"的——运行时确实没有崩。我想讨论的是:这层常驻改动对用户目录来说代价是不是太大了,有没有可能做成零残留或可撤销。 下面把我能证明的部分都列出来,方便判断。
环境
D:\code\dev-SmartGrossing(git worktree)D:\GrossingData(工作区之外)现象
bin、obj、.git);GENERIC_ALL/FullControl打开(对所有者、Administrators、SYSTEM 都是);icacls清理会报ERROR_NONE_MAPPED(包的 README 里已经写明这一点);需要区分一件事:"程序写不了工作区外的数据"和"工作区 ACL 被改"是两个机制。 前者来自受限令牌(restricting SIDs + Low 完整性),后者是目录安全描述符。两者都来自同一个沙箱,所以体感上是同时出现的,但成因和解决办法不同。我一开始也把它们混为一谈了,后来逐项验证才分开。
最小复现
改动后会出现(解析结果,icacls 里等价显示为一条 DENY(DC)、一条按 SID 显示的未知账户、一条 Low 标签):
0x40FILE_DELETE_CHILDS-1-1-0Everyone0x110156S-1-4-297152335-144657661NO_WRITE_UPS-1-16-4096(Low)证据 1:这条 SID 就是 dsh 按工作区路径算出来的
按
packages/sandbox/sandbox-windows-acl/src/workspace-sid.ts的算法:和工作区里那条 ACE 的 SID 完全一致。可以排除是系统、杀软或其他软件留下的。
证据 2:写入时间点 = 会话第一次执行沙箱命令
D:\code\dev-SmartGrossing的 ctime 变为 2026-10-20 08:34:49,正好是本会话第一次工具调用被沙箱执行之前的一刻。作为对照,同一台机器上D:\GrossingData的 ctime 仍停在 10-19,没有被写过。也就是说,改动只落在"工作区根 + 每会话私有临时目录",和项目数据目录无关。
证据 3:对自己进程的影响(同机实测)
用携带工作区能力 SID 的令牌,对工作区根发起目录打开:
FILE_DELETE_CHILD单独请求都被拒绝,说明 Everyone 那条 deny 在第一次访问检查就生效;GENERIC_ALL包含0x40,所以工作区内任何目录的FullControl打开都会返回ERROR_ACCESS_DENIED。这一点和2026-09-19-windows-acl-mandatory-integrity-confinement.zh.md里写的"授权根内目录的 FullControl 打开被拒绝,这是无法避免的代价"是一致的,不是我这台机器的个例。影响
不可回收的残留。 包的文档明确写了工作区 ACE 和标签"按设计常驻,绝不撤销",手工
icacls清理会ERROR_NONE_MAPPED,只能靠重建目录回收。对于把工具装在公司机器、项目目录又要长期保留的人来说,这个成本不太容易接受。改变了用户自己进程的行为。 目录 FullControl 打开被拒;靠父目录
FILE_DELETE_CHILD的删除路径被移除(文件自身 DACL 没有 DELETE 时,用户自己的进程也删不掉)。安全面副作用。 Low 标签比 dsh 生命周期更长,同一用户下任何 Low 完整性进程都能写这个工作区。
完全不可见。 改动发生在后台,用户只能靠
icacls自己发现。对比只改子进程令牌的工具(Codex 一类),它不会在你目录上留下任何东西,所以用户很难把因果对上。调试时非常容易误判。 受限令牌下,任何试图写工作区外数据的程序都会以应用层错误失败,而这些错误都不指向沙箱。我遇到的例子是 ASP.NET + EF Core + SQLite,库在
D:\GrossingData\API\DB\app.db:同时 Serilog 的 File sink 静默失败(控制台有日志,文件一行都没有),因为 File sink 拿不到写权限时不报错。两条线索看起来都像数据库损坏或文件锁,实际原因是"数据在工作区之外,被沙箱拒绝"。这一条不是 bug,但可诊断性几乎为零。
源码定位(0.2.1-rc.2)
packages/sandbox/sandbox-windows-acl/src/acl.ts→grantWrite(),一次SetNamedSecurityInfoW完成三项编辑;packages/sandbox/sandbox-windows-acl/src/index.ts只对writableDirs和每会话私有临时目录调用grantWrite,没有恢复/撤销路径(revokeWrite只处理可回收的临时目录授权);packages/sandbox/sandbox-windows-acl/src/win32-abi.ts(GRANT_MASK = 0x110156、CONTAINER_INHERIT_ACE、WinLowLabelSid);.agents/notes/implemented/feature/2026-09-19-windows-acl-mandatory-integrity-confinement.zh.md。这是 0.2.x 才有的行为
2026-08-08-windows-acl-restricted-token-sandbox.zh.md描述的初版只加能力 SID 的允许 ACE,没有 Low 标签、没有 Everyone 删除拒绝。那一版对普通进程完全惰性,用户基本无感。2026-09-19为修复 issue #4581(cmd /c del能删工作区外的文件)追加了标签和拒绝项,笔记里明确写了:所以:同一个项目、同一台机器,0.1.x 用着没事,0.2.x 开始出现残留和目录权限变化。这和我自己的经历一致,也说明它是一次有意的行为变更,而不是偶发故障。
想讨论的几个问题
icacls已经回收不了(ERROR_NONE_MAPPED),用户没有任何自救路径。是否值得提供类似sandbox: denied及原因;文档里列出典型症状(SQLiteCANTOPEN、File sink 静默失败、构建产物删除失败、目录 FullControl 打开失败)。workspace-write的说明里加一句"运行时数据必须位于工作区内,否则被沙箱运行的程序会以应用层错误失败",并附上whoami /groups的判别方法(看是否出现 Low 完整性级别和S-1-4-…)。我目前的规避方式
附:另一个独立的 Windows 问题(可以另开讨论)
在这台机器上,
pwsh工具 100% 以0xC0000142失败,连Get-Location都跑不起来:同机 bash 工具、文件读写工具正常。README 把"以
CREATE_NO_WINDOW/CREATE_NEW_CONSOLE创建的子进程在 DLL 初始化期死亡"列为已知限制,但这里是每一次都失败,Windows 上的 PowerShell 能力实际不可用。不确定是否和本机控制台/会话环境有关,或者是否应该在 spawn 侧回退为继承控制台。最后
如果需要,我可以提供:工作区根的完整 ACE/SACL 解析、改动前后的
icacls输出、以及在一台干净目录上做最小复现的录屏。谢谢。
All reactions