Repository navigation
工作区目录缺少 WRITE_OWNER 时,grantWrite 报 Win32 5 且错误信息未指明原因 #8886
lincolnwang1
started this conversation in
General
Replies: 0 comments
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 上用 DSH 时遇到工作区无法打开的问题,排查后定位到
grantWrite的授权前置条件不满足。错误信息只给出了 Win32 5,没有指出真正缺的是什么,
花了较多时间才定位,想反馈一下,并提两个改进建议。
环境
0.2.0-rc.2(npm 安装)BUILTIN\Administrators成员,但 DSH 非提权运行,因此该组在访问令牌中是 deny-only 状态
C:\02_project\99_temp,直接位于盘根下的自建目录现象
打开工作区时直接失败,报:
SetNamedSecurityInfoW failed (Win32 5): grantWrite(C:\02_project\99_temp)
整个会话无法启动,需要手动改目录权限后才能继续。
根因
grantWrite通过一次SetNamedSecurityInfoW调用完成三件事:FILE_DELETE_CHILD拒绝项传入的信息类别是
20(=DACL_SECURITY_INFORMATION0x4 |LABEL_SECURITY_INFORMATION0x10)。其中第 3 项写的是 SACL,而写 SACL需要 WRITE_OWNER。
问题在于 Windows 给目录所有者的隐式权限只有
READ_CONTROL和WRITE_DAC,并不包含
WRITE_OWNER。而盘根下发的继承权限项里,唯一包含WRITE_OWNER 的是BUILTIN\Administrators的完全控制——非提权时它不生效。最终有效权限是 writeDac=true / writeOwner=false,调用被拒绝。
值得注意的是,这个前置条件在
dsh-sandbox-windows-acl自己的文档里已经写明了:
也就是说这是一个已知的、文档化的前置条件,但运行时只抛出了裸的
Win32 错误码。
触发条件
同时满足以下三条即会复现:
对照:用户目录(如
C:\Users\<name>)有一条显式的user: Full control,所以 profile 目录下的工作区不会触发。
验证数据
writeDac=true/writeOwner=falseuser: Full control后:两者均为 true,授权成功C:\02_project下 36 个目录,只有 3 个带显式完全控制,其中 2 个是之前遇到同样问题后手工修过的——说明复发条件很容易被满足## 已采取的处置
在
C:\02_project这一处加了user: Full control并设为向下继承,36 个现有子目录和以后新建的子目录全部覆盖,问题不再复发。
(或临时方案:以管理员身份启动 DSH。可用但不推荐,等于整个 agent 都提权。)
两个改进建议
1. 让 grantWrite 的错误信息带上诊断(成本低)
在
SetNamedSecurityInfoW返回 ACCESS_DENIED 时,把已知的前置条件一起带进错误上下文,例如:
2. 在 grantWrite 之前加一次前置检查(能根治复发)
授权前检查目标目录是否具备 WRITE_OWNER,不具备就直接报上面那条可执行的
提示,而不是先失败再让用户去猜 Win32 5 的含义。
考虑到触发条件是确定性的(新建目录 + 非提权),这个检查能省掉一整轮排查。
一个可复用的检测方法
判断某个目录是否满足 DSH 授权的前置条件:
如果这个检测逻辑值得沉淀进
dsh-sandbox-windows-acl,让故障能自诊断,那我这边很愿意把它整理成 PR——虽然目前看 CONTRIBUTING 说明暂不接受外部 PR,
那就先放在这里供团队取用。
All reactions