[Windows] workspace-write 沙箱下 tempfile.TemporaryDirectory() 失败:chmod 重写 DACL 抹掉 capability ACE #7395
Replies: 1 comment
|
这条的机制判断成立 —— 而且你标为「未经直接验证」的那一步,我在同一套环境上测出来了(Windows 11 / Python 3.12.14,用 你未验证的那一步:成立,但触发条件是「恰好 0o700」同一父目录下逐个 mode,看新建目录的 DACL 结构:
对你表述的两点修正:
更关键:它不是「照抄父目录」,是换成一个固定集合我给父目录加一条可继承的 Everyone ACE,再看子目录: 父目录给了什么都会被丢掉。这正是问题所在 —— 看仓库里这段注释(
于是 这个 mode 恰好是那条假设的反例: 顺带解释你那两条无效规避:重定向 对修法方向的影响你的方向我同意,但理由要换一个:因为它是创建时写死 + 阻断继承,没有任何创建后的钩子能通用地补回来 —— 沙箱看不到那次 mkdir,也没有事件可靠地通知它 DACL 被替换了。所以能选的其实是:
取舍该由你们定,我不越界。 边界我没有在受限 token 下跑 —— 这个 shell 是不受限的,所以我测的是「DACL 被替换」这一步(也就是你标未验证的那一步),不是 capability ACE 丢失本身。环境:Windows 11、Python 3.12.14、 |
Uh oh!
There was an error while loading. Please reload this page.
Summary
(背景:我在一个 Python 测试套件里遇到这 37 个失败,定位过程中做的 mode 对照实验如下。)
在 Windows 的
workspace-write沙箱下(@deepseek-ai/dsh-sandbox-windows-acl后端),受限子进程无法使用 Python 标准库的tempfile.TemporaryDirectory()/tempfile.mkdtemp(),持续抛PermissionError: [WinError 5]。目录创建和写入本身都成功,失败发生在退出清理时扫描该目录。
触发点是
tempfile.mkdtemp()的mode=0o700:沙箱给受限进程新建对象补的 capability ACE,被chmod重写 DACL 时抹掉,导致包括创建者在内的所有 restricting SID 都被 write pass-2 检查拒绝。影响面:任何在
workspace-write下用标准库tempfile的 Python 代码。实测一个 266 用例的测试套件中 37 个受影响(约 14%)。属于静默失败——目录创建和写入都正常,只有清理阶段报错,容易被误判为被测代码的缺陷。Reproduction
在
workspace-write受限会话中运行:更小的隔离复现——同一受限进程内逐个 mode 测试:
Current behavior
0o700是唯一触发值:0o7770o7550o7500o7110o7000o500完整报错:
栈落在
tempfile.py→shutil.rmtree→os.scandir→_resetperms→os.chmod。即扫描阶段先被拒,清理的重试路径再次被拒。以下规避手段已实测全部无效:
TMP/TEMP/TMPDIR到工作区或会话私有临时目录;tempfile.mkdtemp(dir=<可写目录>)。说明问题不在路径,而在新建目录的 DACL。
补充观测:对失败目录执行
os.stat报 mode 为0o777(Windows 上 mode 位不反映真实 DACL),所以不能靠 mode 位判断。Expected behavior
受限进程对自己创建的目录执行
chmod后,应当仍可访问该目录;或至少该目录应保留 token default DACL 中的 capability ACE。Environment
0.1.6-alpha.1,commit0d1f50007fworkspace-write(沙箱模式workspace-write,审批ask)@deepseek-ai/dsh-sandbox-windows-acl机制推测(未经直接验证,供定位参考)
packages/sandbox/sandbox-windows-acl/src/index.ts第 284–296 行的注释说明:受限 token 的 default DACL 只含用户的环境 SID、不含任何 restricting SID;因此代码显式把某个 capability SID 的 full-access ACE 合并进 default DACL(setTokenDefaultDaclGrant),好让新建对象的 DACL 能通过 write pass-2 检查。在此之上,CPython 的
os.mkdir(path, mode)在 Windows 上当mode != 0o777时会额外执行一次chmod来设置权限位。这一次chmod重写了新建目录的 DACL,移除了上面那个 capability ACE,于是所有 restricting SID(含创建者自己)都被 pass-2 拒绝。这一推断能同时解释:只有
0o700失败(Python 单独为它走chmod路径)、重定向临时目录无效(问题在 DACL 不在路径)、以及stat报0o777。未验证部分:
os.mkdir的chmod行为是从 CPython 设计推断的(其 C 实现无法用inspect读源码),未在 DSH 内打断点确认。若上游采纳,建议先复核这一步。建议方向
在
setTokenDefaultDaclGrant之后,考虑对受限进程新建对象的 DACL 修改保持宽容;或至少让chmod不再整体替换 DACL。具体取舍取决于对 pass-2 收紧程度的期望。All reactions