From ba9d70a5b6da696d9552a98ecc2f14fca1d00f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 7 Oct 2026 14:02:21 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=B6=E6=B3=A5=E5=84=BF=E4=BA=A7=E7=89=A9?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=94=B9=E7=94=A8=20no-follow=20=E6=89=93?= =?UTF-8?q?=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - read_package_bytes 用 OpenOptions + O_NOFOLLOW / FILE_FLAG_OPEN_REPARSE_POINT,关掉 symlink_metadata 检查后到打开之间被换成符号链接的 TOCTOU 窗口 --- .../src/export/draft/taonier/build.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/draft/taonier/build.rs b/apps/ai-game-creator-shell/src-tauri/src/export/draft/taonier/build.rs index c20b25dc6..078132dce 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/draft/taonier/build.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/draft/taonier/build.rs @@ -262,7 +262,23 @@ pub(crate) fn read_artifact_package(root: &Path) -> Result Result<(Vec, String), String> { - let mut file = std::fs::File::open(path) + // 不跟随符号链接打开:`read_artifact_package` 先做了 symlink_metadata 检查,这里用 + // no-follow 打开关掉「检查后、打开前被换成同长度链接」的 TOCTOU 窗口。 + let mut options = std::fs::OpenOptions::new(); + options.read(true); + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + options.custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW); + } + #[cfg(windows)] + { + use std::os::windows::fs::OpenOptionsExt; + const FILE_FLAG_OPEN_REPARSE_POINT: u32 = 0x0020_0000; + options.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT); + } + let mut file = options + .open(path) .map_err(|error| format!("打开陶泥儿产物失败:{}:{error}", path.display()))?; let mut hasher = Sha256::new(); let mut bytes = Vec::with_capacity(expected_bytes as usize);