Loading

Codex 在 Windows 上输入 /permissions 卡住:一次命令启动链与目录权限排查


Codex 在 Windows 上输入 /permissions 卡住:一次命令启动链与目录权限排查

最近在 Windows 上使用 Codex 时遇到一个很奇怪的问题:进入部分新项目目录后,输入 /permissions 会长时间没有响应;有时连最简单的 PowerShell 命令也无法在沙箱中启动,并出现类似下面的错误:

windows sandbox: runner failed during SpawnChild:
SetTokenInformation(TokenDefaultDacl) failed: 1344

换成 Windows PowerShell 后现象并没有完全消失,使用 danger-full-access 启动时却可以正常运行。

一开始很容易怀疑是 Windows Sandbox 或 Codex 自身出了问题。最后才发现,这并不是单一故障:PATH 中的 Anaconda 目录权限过宽,增加了沙箱建立安全边界时的检查负担;而通过 Microsoft Store 安装的 PowerShell 7 又位于受 AppX 保护的 WindowsApps 目录,使受限沙箱用户在创建 PowerShell 子进程时进一步触发了权限错误。

两者表面上一个表现为 /permissions 卡住,一个表现为 PowerShell 启动失败,本质上都指向同一件事:沙箱需要保护的不只是项目目录,还包括从 PATH 解析命令、启动 shell 到加载工具的整条执行链。

现象与定位

排查时有几个关键现象:

  • 普通沙箱模式下 /permissions 容易卡住;
  • danger-full-access 下可以正常运行;
  • 调整 sandbox_private_desktop 没有解决问题;
  • 从 PATH 中暂时移除 Anaconda 后,/permissions 卡住的问题立即消失;
  • 但沙箱启动 PowerShell 7 时仍可能报 SpawnChildTokenDefaultDacl 或错误码 1344
  • pwsh.exeWindowsApps 中的 Store 包切换到 C:\Program Files\PowerShell\7 后,命令启动恢复正常。

这些现象说明问题不在 /permissions 或具体 PowerShell 命令本身,而在 Codex 建立 Windows 沙箱边界、随后以受限身份创建命令进程的过程中。

Codex 启动命令时会使用 PATH 查找可执行文件。如果 PATH 中某个工具目录允许 Everyone 或普通 Users 写入,那么其他本机进程就可能替换其中的程序。对沙箱来说,这意味着即使工作区权限受控,最终执行的命令仍可能被篡改。

检查 Anaconda 安装目录的 NTFS 权限后,确实发现它对普通用户开放了过高的写权限,同时还积累了不少已经无法解析的旧 ACL 条目。这不仅带来安全风险,也显著增加了沙箱扫描的复杂度。

继续检查 PowerShell 7 的来源时,发现 pwsh.exe 来自类似下面的目录:

C:\Program Files\WindowsApps\Microsoft.PowerShell_<版本>_x64__8wekyb3d8bbwe\pwsh.exe

这是 Microsoft Store 安装的 AppX/MSIX 包目录。普通桌面用户可以通过系统注册的应用入口正常启动它,但 Codex 的 Windows 沙箱使用专用低权限用户或受限令牌,并重新设置进程的默认 DACL。此时,WindowsApps 的包身份和目录访问模型可能使沙箱子进程在真正执行脚本前就失败,因此会看到 SpawnChildSetTokenInformation(TokenDefaultDacl) 一类错误。

可以用下面几条命令确认 PowerShell 实际来自哪里:

Get-Command pwsh -All | Select-Object Source, Path
where.exe pwsh
$PSHOME
Get-AppxPackage -Name Microsoft.PowerShell |
    Select-Object Name, Version, InstallLocation

这里需要区分“PowerShell 版本”和“PowerShell 安装形态”:版本号相同,并不代表沙箱中的启动行为相同。问题也不是简单因为程序没有安装在 C 盘,而是可执行文件所在目录的 ACL、AppX 包身份以及沙箱令牌能否完成读取和执行。

解决方案

1. 不再把整套 Anaconda 放进永久 PATH

首先从用户和系统 PATH 中移除 Anaconda 根目录以及 ScriptsLibrary\bin 等子目录。

这不会妨碍 Conda 的正常使用。更合适的方式是运行 Conda 的 PowerShell hook:终端启动时只注册 conda 命令,真正执行 conda activate 后再临时修改当前会话的 PATH。

PowerShell profile 可以使用类似配置:

$Env:PYTHONUTF8 = "1"
$Env:PYTHONIOENCODING = "utf-8"
(& "<ANACONDA_HOME>\Scripts\conda.exe" "shell.powershell" "hook") |
    Out-String | Invoke-Expression

同时建议关闭 base 环境自动激活:

conda config --set auto_activate_base false

这样,新终端启动时 Anaconda 不会长期占据 PATH;需要使用时再显式激活环境。

2. 收紧 Anaconda 安装目录权限

先查看当前权限:

icacls "<ANACONDA_HOME>"

理想的权限模型是:

主体 权限
当前安装用户 完全控制
SYSTEM 完全控制
Administrators 完全控制
普通Users 读取和执行
Everyone 不单独授权

修改时不要直接复制网上的递归 ACL 命令。应先导出权限备份,确认安装目录的准确路径,再调整根目录并让子项正常继承。尤其不要把操作范围误设为整个磁盘。

权限调整后,需要确认当前用户仍能更新 Conda、安装包和创建环境,而普通用户不能替换其中的可执行文件。

3. 将 PowerShell 7 安装到标准程序目录

如果 Get-Command pwsh$PSHOME 指向 C:\Program Files\WindowsApps,可以另外安装非 Store 版 PowerShell 7,让 pwsh.exe 位于普通的系统程序目录:

winget install --id Microsoft.PowerShell --exact --source winget

安装完成后关闭并重新打开终端与 Codex,再确认命令解析结果:

Get-Command pwsh -All | Select-Object Source, Path
where.exe pwsh
$PSHOME

期望优先命中:

C:\Program Files\PowerShell\7\pwsh.exe

如果 Store 版和标准安装版同时存在,应先确认新路径能够正常启动,再通过 Windows“设置 → 应用”移除 Store 版,或调整 PATH 使标准安装版排在前面。不要在尚未验证新版本时直接删除 WindowsApps 内的文件,也不要手工修改该目录的所有权和 ACL;这会破坏 Microsoft Store 的包管理和更新机制。

Windows PowerShell 5.1 位于 C:\Windows\System32\WindowsPowerShell\v1.0,可以作为对照测试,但它不能替代对 PowerShell 7 安装来源的修复。如果错误发生在沙箱创建受限子进程这一层,仅仅切换 profile 或提示符配置也不会解决问题。

4. 修复 Conda 的 PowerShell 初始化

如果执行 conda init powershell 后仍提示找不到 conda,应检查它实际修改的是哪个 profile:

$PROFILE
$PROFILE.CurrentUserAllHosts

旧版 Conda 在包含非 ASCII 字符的用户目录或“文档”路径上,可能把 profile 写到错误位置。此时仅重复执行 conda init 往往只会得到 no change

解决方法是先升级 Conda,再确认 PowerShell 5.1 和 PowerShell 7 各自实际使用的 profile,并把 hook 写入正确文件。不要为了省事重新把整套 Anaconda 加回永久 PATH。

5. 优先使用 Windows 的 elevated 沙箱

Codex 在 Windows 上支持两种原生沙箱实现:

[windows]
sandbox = "elevated"

elevated 使用专用低权限沙箱用户和更完整的文件系统、网络边界,是官方推荐模式。unelevated 主要依赖当前用户的受限令牌和 ACL,适合管理员初始化受阻时临时使用。

这里的“Windows 原生沙箱”并不是 Windows 可选功能中的 Windows Sandbox,因此不需要为了 Codex 专门启用 Hyper-V 或 Windows Sandbox。

danger-full-access 虽然能绕开卡住问题,但也会同时移除重要的文件系统保护,只适合诊断,不应作为长期配置。

修复后的验证

完成以上调整后,建议至少检查这些常用流程:

Get-Command pwsh -All | Select-Object Source, Path
$PSHOME
pwsh -NoProfile -Command '$PSVersionTable.PSVersion'
conda info
conda doctor -v
conda create -n sandbox-test python pip
conda activate sandbox-test
python --version
conda deactivate
conda env remove -n sandbox-test

还要完全关闭并重新打开 Codex 与终端,因为已经运行的进程可能继续继承修改前的 PATH。

还应让 Codex 在普通沙箱模式下执行一条最简单的命令,例如读取当前目录或运行 pwsh -NoProfile -Command 'Get-Location'。如果它在命令正文尚未执行前就报 SpawnChildTokenDefaultDacl1344,应继续检查 PowerShell 的解析路径、Windows 登录权限和沙箱日志,而不是只调整项目目录权限。

本次修复后,pwsh.exe 优先解析到 C:\Program Files\PowerShell\7\pwsh.exe,普通沙箱模式下的 /permissions 恢复正常。PowerShell 中的 Conda 激活与退出、新环境在线创建、软件包下载和 Python 网络访问也都能正常工作。

总结

这次问题表面上像 Codex 或 PowerShell 卡死,实质上是一个命令启动链上的安全边界问题:

Codex 的 Windows 沙箱不仅要限制工作区写入,还必须能够安全地解析并启动 PATH 中的 shell 与工具;目录权限过宽或可执行文件位于受特殊包权限保护的位置,都可能让这条链路失败。

最终有效的处理方式不是关闭沙箱,而是:

  1. 从永久 PATH 中移除整套 Anaconda;
  2. 使用 PowerShell hook 按需激活 Conda;
  3. 将 Anaconda 目录权限收紧到“安装用户可写、普通用户只读执行”;
  4. 确认 PowerShell 的实际解析路径,必要时把 Store 版切换为安装在 C:\Program Files\PowerShell\7 的标准版本;
  5. 修正 Conda profile 初始化位置;
  6. 在条件允许时使用官方推荐的 elevated Windows 沙箱。

如果以后再次遇到类似卡住或命令无法启动,应沿着“Codex 沙箱 → PowerShell 实际路径 → PATH 中的工具目录 → 各目录 ACL”逐层检查,通常比反复切换沙箱选项或修改 profile 更接近问题根源。

参考资料:


文章作者: 叁月柒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 叁月柒 !
评论