[BUG] Workspace-write 沙箱缺陷:受限进程可通过工作区内的目录 Junction 删除工作区外文件 #7517
Replies: 4 comments
|
Thank you for the report. The asymmetry you measured — create/append refused, delete allowed — is not a side detail: it is the fingerprint of the one route the design already knows about, and it points at one specific line in the grant. Read at 1. Your guess is right in shape, with one correction: the authority is the capability SID, not the ambient one
The workspace grant gives the capability SID
The same grant also writes a world deny for that same right ( So 2. This is the same shape as the three delete-confinement commits — and it is the case they assume away
Read that over the directory whose right supplies the authority: a junction created inside the workspace is such a directory, and it is inside the root, carrying both the Low label and the capability ACE. An alias does not have to defeat either edit — it only has to be the object those edits landed on. The same note's decision list ( The series each closed one route of the same shape: 3. One precondition, two experiments I could not runC0 — check the target's label first. E1 — attribute the authority (this decides which fix applies). Remove the outside ambient route while leaving the workspace-side route untouched: mkdir C:\dsh-out
icacls C:\dsh-out /deny "$env:USERNAME:(DC)"Then recreate the junction, and delete a file in E2 — is it delete-only? The grant propagates eagerly through the tree ( mkdir C:\ws2
mklink /J C:\ws2\j C:\outside2
icacls C:\outside2 # before: expect no capability SID, no Low label
# provision a workspace-write session whose workspace is C:\ws2
icacls C:\outside2 # after: capability SID? Low label?If the outside tree gains the ACE and the label, the boundary is not delete-only there but a write escape for that subtree, which is the more urgent half. I could not decide from the source whether the inheritance walk follows a mount point. 4. Where a fix can go (maintainers' call, not mine)
5. Interim and residue
Cross-reference: #7298 is the same family, and PerryLink's reply there reduces it to one question — was the deleted link's parent inside the granted tree? Your case is outside by construction, so it needs none of the three facts that question was waiting on. |
|
Correction, and it is the most useful part: I read HEAD ( At your tag the grant was one entry, with no deny and no label: ( On that build your asymmetry needs no further explanation, because HEAD's README names the route in so many words:
Write outside → needs the restricting-SID pass-2 co-sign, which no outside directory carries → refused. Delete outside → authorized by your ambient rights on the object's own parent, which nothing in that build intersected and nothing denied → succeeds. Note what that means for the junction: the ambient route is path-independent, so it needs no junction to be reachable — and no junction can change its outcome either. Read that way, the junction is how you demonstrated the escape, not what produced it. So my earlier §1 ("the authority is the capability SID, not the ambient one") should be read as a claim about HEAD, not about your build: it assumed the deny and the label already stood. Which parent the kernel actually evaluates What this leaves open, in order of what I would spend effort on:
My earlier C0/E1 still apply; on HEAD they now sit behind the version question. If you can say which volume the target was on and whether the junction existed before or during the session, items 2 and 3 become decidable without any DSH internals. |
|
A plugin for this shape is now published, so the thread is not left without a mountable answer.
It mounts on the public The second line is the part that is genuinely absent upstream, and it is not a string prefix test: the walk stops where the path first enters a writable root and re-appends the remaining components untouched. That is what makes Reads are deliberately not judged — no enforcement dialect restricts reads, and What it does not do, stated plainly, because this thread is about a deletion through a junction performed by a shell command:
On this thread's own mechanism: the report is against 37 tests run against a real Cordis context, a real One note for anyone mounting it, because it is the kind of thing that only shows up after the release: this package's own |
|
按讨论中的 C0、E1、E2,在 Windows 上对 环境
各测试在做什么
最初六次测试
两版 E2 的区外目录,开通后的 测试中未使用 FAT 卷。 补充记录用与 此后按三套安装各跑 baseline、E1、E2,并更换目录后再跑全部6+3个测试。三轮用的都是新建子目录:
这三轮里,两套 |
Uh oh!
There was an error while loading. Please reload this page.
在 Windows 上,DeepSeek Harness(@deepseek-ai/dsh 0.1.5-rc.2)的 @deepseek-ai/dsh-sandbox-windows-acl 在 sandbox: workspace-write 模式下:
受限进程可在工作区内自行创建指向区外任意目录的 directory junction,再经该 junction 删除区外已有文件。
案例
在 〈工作区根〉 内创建 junction probe-j,指向工作区外的 〈区外目录〉。
删除路径:〈工作区根〉\probe-j\某文件(该路径解析到 〈区外目录〉\某文件)。
删除成功;随后区外该文件不存在。
同一 junction 下:新建文件、向已有文件追加写入 → 均被拒绝。
该案例曾误用真实资源文件作靶,造成一次实际损坏。
推测原理
workspace-write 会对工作区授予 capability SID 的 Modify 级权限(实现中含 DELETE、FILE_DELETE_CHILD 等)。在工作区内创建 junction 属于对可写目录的写入,故被允许。
Windows 删除文件通常需:对文件有 DELETE,或对父目录有 FILE_DELETE_CHILD。经 〈工作区〉\某junction\某文件 访问时:
创建 / 覆写:更可能按最终目标文件做 ACL 校验 → 区外无写权限 → 拒绝。
删除:更可能(或至少在效果上)用到了工作区侧 junction 目录上已继承的 FILE_DELETE_CHILD,从而删掉目标命名空间中的文件 → 放行。
因此表现为「能删不能写」:写入边界整体有效,删除路径与创建路径的鉴权不一致,形成仅限删除的逃逸。
All reactions