Repository navigation
fix(私有文件): icacls 授权对象改用当前用户 SID,避免同名机器上把自己锁死 - #742
Open
colorgarden wants to merge 1 commit into
Open
colorgarden wants to merge 1 commit into
colorgarden wants to merge 1 commit into
Conversation
`restrictPermissions()` 用裸 `process.env.USERNAME` 调 `icacls /inheritance:r /grant:r`。 计算机名与登录名只差大小写时(Windows 允许、个人机常见),icacls 在账户数据库与计算机 账户之间解析该名字,计算机账户胜出,写入的 ACE 指向 `S-1-5-21-<machine>`——没有任何 用户令牌携带它;而同一调用里的 `/inheritance:r` 已先删掉继承 ACE。文件只剩一条谁都 匹配不上的 ACE,随后的 `renameSync` 必然 EPERM,文件连同内容一起变成不可读、不可写、 不可删。 该函数服务于全部「临时文件 + rename」的私有落盘路径,所以这台机器上登录令牌、 settings.json、catalog.json、upgrade-state.json 全部只留在内存里,升级也卡在状态 落盘(Ebony-Vinyl#738)。 改为 `whoami /user /fo csv /nh` 取当前令牌 SID,以 `*S-1-...` 形式交给 icacls (`*` 明确表示 SID,不做名字解析);whoami 缺失或失败时回退到 `USERDOMAIN\USERNAME` 全限定名,仍比裸名严格。结果按进程记忆化——令牌 SID 在进程 生命周期内不变,而这些存储定时 flush。 保留 PR Ebony-Vinyl#637 的原始动机:whoami 的账户名输出走 OEM 代码页会毁掉非 ASCII 机器名; SID 是纯 ASCII 且不含可本地化文本,该顾虑不适用。 回归套件的断言口径由「acl 含 (F) 且不含 (I)」加强为「DACL 的 SDDL 必须出现当前令牌 SID」——旧的 (F) 断言在坏 ACE 上同样成立,捕不到本缺陷;并新增一条端到端用例,在 USERNAME 与 COMPUTERNAME 相同的前提下走完写 tmp → restrictPermissions → rename 覆盖 → 回读。 Fixes Ebony-Vinyl#738
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #738。
根因
restrictPermissions()用裸process.env.USERNAME调icacls /inheritance:r /grant:r:计算机名与登录名只差大小写时(Windows 允许、个人机常见),
icacls在账户数据库与计算机账户之间解析这个裸名字,计算机账户胜出。写入的 ACE 因此指向S-1-5-21-<machine>——没有任何用户令牌携带它;而同一次调用里的/inheritance:r已先删掉继承 ACE。文件只剩一条谁都匹配不上的 ACE,紧接着的renameSync必然EPERM,文件连同已写入的内容一起变成不可读、不可写、不可删。函数被 10 个模块的 14 处私有落盘点复用,所以这台机器上登录令牌、
settings.json、catalog.json、stats.json、upgrade-state.json全部只留在内存里;升级流程也停在这一步。改动
src/open-external.js新增currentUserGrantee(),restrictPermissions()改用它取授权对象:whoami /user /fo csv /nh取当前令牌 SID,以*S-1-...形式交给icacls——*明确表示这是 SID,不要做名字解析。whoami缺失或失败时回退到USERDOMAIN\USERNAME全限定名;仍比裸名严格,因为它点名了账户域,不再把二选一留给 icacls。保留 PR #637 的原始动机:
whoami的账户名输出走 OEM 代码页,非 ASCII 机器名会被 UTF-8 解码毁掉。SID 是纯 ASCII、不含可本地化文本,这条顾虑对 SID 不适用——这也正是选 SID 而不是改回「解析账户名」的原因。restrictPermissions()的语义、icacls 失败即抛错放弃写入的行为、POSIX 分支、以及全部 14 处调用点均未改动。回归套件
scripts/private-file-permissions-test.mjs:(F)且不含(I)——坏 ACE 同样满足这两条,捕不到本缺陷。现在额外用icacls /save取 SDDL(恒以 SID 记录),断言 DACL 必须点名当前令牌的 SID。USERNAME/USERDOMAIN与COMPUTERNAME相同的前提下,走完「写 tmp →restrictPermissions→ rename 覆盖正式文件 → 回读」整条私有落盘路径,即 GitHub 登录「授权已完成」但令牌永远无法落盘:机器名与用户名相同时 restrictPermissions() 用裸用户名调 icacls 把文件锁死(附最小复现与可应用补丁,v2.8.0) #738 的最小复现。discard()用icacls /reset /T兜底清理:失败用例本身会留下不可删的 fixture 目录,不清会污染后续运行。已执行检查
本机:Windows 10.0.26300.9818 / Node v24.15.0,
COMPUTERNAME=COLOR、USERNAME=color、USERDOMAIN=COLOR(触发条件成立)。node scripts/private-file-permissions-test.mjs→5 private-file check(s) failed,首个失败the DACL does not name S-1-5-21-...-1001: COLOR\:(F),renameSync复现EPERM。5/5 private-file checks passed。private-file5/5、open-external、updater、subscriptions38/38。node --check、git diff --check:通过。node scripts/test-all.mjs --mode contributor:103/108。失败 5 项已用git stash在干净 baseline 上逐项对标,与本改动无关:legacy-upgrade:本机浅克隆缺f14d261对象,CI 用fetch-depth: 0不触发;magpie-engine:4 项 reviewer 回归,baseline 同样失败;magpie-policy、standalone-management:registry.npmjs.org在本机不可达 + 残留EPERM临时目录,baseline 同样失败;forward:并发抖动,单跑 2/2 通过。验证记录:
docs/verification/2026-11-02-issue-738-icacls-grantee.md。未验证范围
whoami的环境实测。restrictPermissions()只处理新写入的临时文件。历史残留仍需icacls <path> /reset手工恢复(已验证可恢复且内容不丢)——如果认为需要在启动时做一次孤儿 tmp 自愈,那是另一个改动,本 PR 不做。test:release(签名清单对齐属正式发布流程,本分支不触碰)。