Repository navigation
[Bug][Windows][FAT/exFAT] 两项静默失效:ACL 沙箱在不存储 DACL 的卷上"授权成功但零效果"(与出厂 README 的 "fails loudly" 相反);版本令牌在 2 秒时间戳卷上漏检外部改动 #10216
Replies: 1 comment
|
发现 1 我核到了一处README 自相矛盾,这比我原本预期的更支持你的判断;发现 2 的机制组成也对得上。 发现 1:README 一边说 "fails loudly",一边说 "not implemented"
所以 README 自己就同时写着"会响亮地失败"和"没实现"。你的实测(授权成功、零效果)正是在裁决这两句里哪一句是真的 —— 而且从代码看,答案倾向于
这一点值得作为报告的主证据:不是"实现有 bug",是"承诺与实现不一致,且实现里缺少做出该承诺所需要的探测"。修法也随之明确:grant 之前查一次卷是否 另外要注意你实测时工作区根到底是不是 发现 2:版本令牌的组成确实会在 exFAT 上退化
三者叠加后,五元组里真正有效的只剩 两点建议
|
Uh oh!
There was an error while loading. Please reload this page.
环境
dsh release 0.2.1-rc.2,nodeVersion 24.21.0),更新通道 nightlydeepseek-ai/deepseek-harnessmaster@687f282e8625c6b8d11ff58211a90524be2e4317(2026-10-17T07:22:43Z)E:= exFAT,DriveType Fixed,Get-Volume报HealthStatus Warning/OperationalStatus Full Repair NeededC:= NTFSfsutil fsinfo volumeinfo E:不含Supports Hard Links、Preserves & Enforces ACL's、Supports Reparse Points、Supports USN Journal;fsutil 8dot3name query E:→Error -2147024895: Incorrect function发现 1:ACL 沙箱在不存储安全描述符的卷上授权成功、效果为零(安全相关)
1.1 实测(跑的是出厂 runner 与出厂
grant.ts/acl.ts,不是推断)grantWrite/AclWriteGrant.add,即SetEntriesInAclW+SetNamedSecurityInfoW)icacls读回No permissions are set. All users have full control.(与授予前逐字一致)Everyone:(CI)(DENY)(DC)、S-1-4-<hash>:(OI)(CI)(W,D,DC)、Mandatory Label\Low:(OI)(CI)(NW)均在read-only模式下被约束的子进程workspace-write模式下被约束的子进程Access is denied.,exit 1)dsh-fs-sandbox的路径围栏一句话:令牌层(Low IL / WRITE_RESTRICTED)仍然生效,文件系统 ACL 层在 FAT 类卷上等于 0,于是"工作区内可写 / 工作区外不可写"这条边界对这些卷完全不存在;而没有任何一层会报错,UI 与模型侧看到的是一个"已经启用沙箱"的会话。
1.2 为什么它不会被发现(源码对照)
defaultProbeWindowsAcl永不调用(98 行明确写了)。因此SANDBOX_UNAVAILABLE只在 runner 起不来时触发;"runner 起来了但内核不持久化 DACL"与"真正受约束的 NTFS 工作区"在代码里不可区分。enforcement恒为静态表里的"partial"(188 行)——它既不区分卷类型,也不区分"部分生效"与"完全没生效"。packages/sandbox/sandbox-windows-acl/src/grant.ts:92-96,107:幂等判断读的是 apply 之前的 DACL("an already-standing exact ACE …"),acl.ts:131,154的GetNamedSecurityInfoW也只在 read-merge 阶段;acl.ts:262检查的是SetNamedSecurityInfoW的返回码。我在acl.ts/grant.ts(master)里找不到 apply 之后回读期望 ACE 的校验——若它存在于其它模块,请指出。FAT 类卷正是"返回ERROR_SUCCESS但不持久化"的情形。1.3 与出厂文档相反
packages/sandbox/sandbox-windows-acl/README.md:190:前半句(警告未实现)与实测一致;但 "a FAT volume as a grant root fails loudly" 不成立:实测它 fails silently,且返回一个看起来完全正常的成功。README:204 也只把 FAT 列为"未决方向",没有把它当作会让约束完全失效的安全前提。
1.4 建议(按代价从小到大)
SetNamedSecurityInfoW成功后,对同一句柄再GetNamedSecurityInfoW一次,比对期望的 capability-SID allow + world deny + Low label 三条 ACE 是否真的存在;不一致即视为该根未被授予。read-only/workspace-write对命令行进程没有文件系统级约束(现在partial这个词把"完全失效"和"边缘未覆盖"混在一起)。GetVolumeInformationW的FileSystemName做一次卷类型判定,把结论写进sandboxMode的可见信息里;顺带修正 README 190 行的表述。发现 2:版本令牌在 2 秒时间戳卷上退化 →
FS_STALE_VERSION漏检 → 静默覆盖外部改动在
E:(exFAT) 上的实测:mtimeNs精度LastWriteTime恒为13:58:38.000;utimes写入.005落到:02ctimeNs1240428288000000000(对 12 个不同文件都一样)→ 该分量不贡献任何信息ino结果(同尺寸外部改写,同一 2 秒刻度内):
于是:agent 读文件 → 用户 / IDE / 另一个脚本在同一 2 秒刻度内做等长度改写 → agent 写回 → 不报
FS_STALE_VERSION,外部改动被静默覆盖(丢更新)。跨过一个刻度才正常。注意fsio.ts:633-638的createIfAbsent只在观察之后做 guarded 检查,因此这个窗口对write(整文件替换)完全适用;edit因需匹配old_string会偶然挡住一部分,但同尺寸且文本仍匹配的情况同样会静默通过。与已报问题的区别:#5432/#JNNarrator(macOS:ctime 进入判据导致过多误报)、JohnMikron(NTFS 纳秒抖动导致误报)都是 false positive 方向;本条是 false negative,后果是丢用户改动,且它发生在"agent 与外部编辑器同时工作"这一非常常见的场景。
建议:观察时一并记录内容摘要(
writeText已经会读before基线,成本几乎为零),stale 判据用sha256 + size + mtime而不是纯 stat;或在探测到"卷无亚秒时间戳 / ctime 恒定"时自动降级为哈希比较。另外ino会被回收这一点,也影响任何把ino当持久身份的地方(containment 回退、spill 去重、持久化 generation 见证)。复现材料(可全部提供)
dsh-fs-local/lib/index.js在 44.0.0 与 44.7.0 完全相同(41 311 B,63fbb41d2c33e07111884b798be507e68c2752acab8249c821c20ade436e894f)。icacls对照、受限子进程增删测试、fsutil fsinfo volumeinfo对照、版本令牌逐字节对照。如果官方希望我把任一项做成可提交的补丁或更细的实验(例如按 ABI 枚举
SetNamedSecurityInfoW在 exFAT 上的实际返回与持久化结果),我可以直接补。All reactions