Wine 运行 PyInstaller onefile 程序(如 labelImg)报错:`INTERNAL ERROR: cannot create temporary directory!` 排查
摘要: 在 Linux 上使用 Wine 运行 PyInstaller onefile 打包的 Windows 程序(如 labelImg.exe)时,可能遇到 INTERNAL ERROR: cannot create temporary directory! 报错。原因是 PyInstaller 的安全修复(CVE-2019-16784)使用了 Windows SID S-1-3-4 设置临时
Wine 运行 PyInstaller onefile 程序报错:INTERNAL ERROR: cannot create temporary directory! 的排查与修复
背景
在 Linux 上用 Wine 运行某些 Windows 程序(尤其是 PyInstaller 的 onefile 打包产物,例如 labelImg.exe)时,可能会直接退出并提示:
[PID] INTERNAL ERROR: cannot create temporary directory!
同时常见伴随信息包括:
... starting ... in experimental wow64 mode(运行 32 位程序时的 wow64 提示)- 程序目录或 Wine 前缀本身看起来没有明显权限问题
这篇记录一个可复用的定位思路,以及对“已发布 exe、无法重打包”的情况下的可行修复方法。
现象复现与关键线索
运行程序:
wine labelImg.exe
报错:
[PID] INTERNAL ERROR: cannot create temporary directory!
进一步检查 Wine 的临时目录(默认是 C:\users\<name>\Temp,映射到 ~/.wine/drive_c/users/<name>/Temp)后,发现大量 _MEIxxxx 目录(PyInstaller onefile 运行时解包目录)权限异常:
ls -ld ~/.wine/drive_c/users/*/Temp/_MEI* | head
典型异常权限类似:
d--------- 2 user user 4096 ... _MEI1234
这意味着目录虽然“存在”,但当前用户在 Linux 侧 没有任何读写执行权限,在 Wine 内部访问就会变成 Access denied,从而触发 PyInstaller 的 “cannot create temporary directory”。
根因:PyInstaller 的安全修复 + Wine 对特定 SID 的兼容问题
PyInstaller 曾做过一个 Windows 侧的安全修复(CVE-2019-16784),核心是:
- onefile 解包目录默认会被创建在
%TEMP%下(例如_MEI1234) - 为避免在某些场景(比如服务账户的
C:\Windows\Temp)发生本地提权,PyInstaller 的 bootloader 会给_MEIxxxx目录设置非常严格的 ACL - 早期实现里会用一个特殊的 SID:
S-1-3-4(在 Windows 上可代表“当前目录所有者”一类语义)
问题在于:Wine 对 S-1-3-4 的 ACL 处理不完整/不兼容,导致创建出来的 _MEIxxxx 目录在宿主 Linux 文件系统上落成 000 权限(d---------),于是程序自己也进不去,最终报:
INTERNAL ERROR: cannot create temporary directory!
如何快速验证
1) 在 exe 内搜索 S-1-3-4
很多 PyInstaller onefile 程序会把相关 ACL 描述串直接编进 exe(UTF-16LE 文本)。可以直接查:
strings -el labelImg.exe | rg "S-1-3-4"
若能搜到类似:
D:(A;;FA;;;S-1-3-4)
基本就坐实了:这是 PyInstaller bootloader 的 ACL 逻辑触发了 Wine 兼容问题。
2) 验证 _MEIxxxx 目录确实不可访问
在 Wine 的 cmd 里尝试进入目录(会 Access denied):
wine cmd /c "dir %TEMP% | findstr _MEI"
wine cmd /c "cd %TEMP%\\_MEI1234 && echo OK"
解决方案(无需重打包):二进制补丁替换 SID
如果你拿到的只有一个 labelImg.exe,无法从源码重新用新版 PyInstaller 打包,一个“务实可用”的办法是:
把 exe 里的
S-1-3-4替换为S-1-1-0(Everyone),让_MEIxxxx目录不再被 Wine 弄成000权限,从而能正常解包启动。
步骤
在 labelImg.exe 所在目录执行:
cp -n labelImg.exe labelImg.exe.bak
python - <<'PY'
from pathlib import Path
path = Path("labelImg.exe")
data = path.read_bytes()
old = "S-1-3-4".encode("utf-16le")
new = "S-1-1-0".encode("utf-16le") # Everyone
assert len(old) == len(new)
count = data.count(old)
assert count >= 1, "pattern not found"
path.write_bytes(data.replace(old, new))
print("patched occurrences:", count)
PY
然后再运行:
wine labelImg.exe
回滚
如果要恢复原版:
mv -f labelImg.exe.bak labelImg.exe
可选:清理残留的坏 _MEIxxxx 目录
旧的 _MEIxxxx 目录可能已经是 000 权限,会越积越多。可以在确保没有 Wine 程序运行后清理:
# 先尽量关闭 Wine 后台服务(如果 wineserver 本身已退出,这条可能返回非 0,可以忽略)
wineserver -k || true
find ~/.wine/drive_c/users/*/Temp -maxdepth 1 -type d -name '_MEI*' \
-exec chmod 700 {} + \
-exec rm -rf {} +
说明:
wineserver -k返回非 0 不一定是错误,常见原因是当前没有 wineserver 在跑。
更“正统”的长期方案(推荐)
上面的二进制补丁属于“救火”方式。更推荐的长期方案是:
-
重新打包
- 用较新的 PyInstaller 版本重新构建(新版本已避免使用 Wine 不支持的
S-1-3-4方案) - 或改用
onedir(不走 onefile 解包逻辑,直接避免_MEIxxxx)
- 用较新的 PyInstaller 版本重新构建(新版本已避免使用 Wine 不支持的
-
不建议:
sudo wine ...- Wine 官方 FAQ 明确不建议用 root 跑 Wine;不仅有安全风险,还容易把
~/.wine权限弄坏
- Wine 官方 FAQ 明确不建议用 root 跑 Wine;不仅有安全风险,还容易把
注意事项(安全/副作用)
- 该补丁把 onefile 临时目录权限从“只允许所有者”放宽为“Everyone 可访问”,会降低 Windows 侧的隔离强度。
- 但在 Wine 环境里,这通常是为了绕开兼容性问题的权衡;实际风险取决于你的使用场景(是否多人共享、是否运行不可信 exe 等)。
总结
当 Wine 运行 PyInstaller onefile 程序报 INTERNAL ERROR: cannot create temporary directory! 且出现 d--------- 的 _MEIxxxx 目录时,优先怀疑 PyInstaller bootloader 的 ACL(S-1-3-4)与 Wine 的兼容问题;对无法重打包的 exe,可用“等长替换 SID”的二进制补丁快速恢复可用性。
创作:framsit
编译:GPT 5.2
更多推荐



所有评论(0)