From 77871bfa56db92fe160c9f70bc78f7497cfaf430 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Sat, 12 Sep 2026 00:12:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=8A=E5=8F=AF=E8=83=BD=E5=BC=B9=20UAC=20?= =?UTF-8?q?=E7=9A=84=20ACL=20=E6=8F=90=E6=9D=83=E4=BF=AE=E5=A4=8D=E7=A7=BB?= =?UTF-8?q?=E5=87=BA=20append=20=E9=94=81=E7=9A=84=E6=8C=81=E9=94=81?= =?UTF-8?q?=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - project/agent_db.rs:Windows 取锁成功路径不再在"已持有零共享句柄"时做带提权的 ACL 修复;持锁期间只做不提权的严格校验,校验不过就先释放句柄、再提权修复,并返回"这轮没取到锁"由外层重试循环按修复后的 DACL 重新打开 - project/agent_db.rs:新增 release_project_append_os_lock_then_repair_acl,参数按值接收锁句柄且函数体第一件事是 drop,使"边持锁边等 UAC"在签名层面无法被表达 - 原因:提权修复走 powershell Start-Process -Verb RunAs -Wait 同步等用户点 UAC,在持锁期间等它等于把用户犹豫的时间记进别人的持锁窗口;只有 Windows 存在这条路径 - 判据(结构级):提权修复只在此一处被调用,且调用点必须交出句柄所有权;测试环境不弹真 UAC(config.rs 测试分支本地收紧),故不写假 UAC 用例 - 真机判据:DACL 有缺陷的机器上,持锁方进入修复期间不再持锁,等待方从"超时"变为可成功 - 不变项:首次创建锁文件的本地 harden 仍留在持锁期间(本进程新建对象不因继承 DACL 自动提权) --- .../src-tauri/src/project/agent_db.rs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/project/agent_db.rs b/apps/ai-game-creator-shell/src-tauri/src/project/agent_db.rs index bb3039585..0bce5df4a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/project/agent_db.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/project/agent_db.rs @@ -3714,6 +3714,22 @@ fn try_open_project_append_os_lock(path: &Path, error_label: &str) -> Result Result<(), String> { + drop(held_lock); + crate::secure_windows_game_creator_path_for_current_user_with_auto_elevation(path, false, true) + .map_err(|repair_error| format!("{strict_error};自动提权修复未完成:{repair_error}")) +} + #[cfg(windows)] fn try_open_project_append_os_lock(path: &Path, error_label: &str) -> Result, String> { use std::os::windows::fs::OpenOptionsExt; @@ -3733,15 +3749,24 @@ fn try_open_project_append_os_lock(path: &Path, error_label: &str) -> Result { crate::runner::validate_windows_regular_file_handle(&file, error_label)?; if !existed { + // 自建对象的本地收紧不会触发 UAC(既有口径:本进程新建的 Windows 私有对象 + // 不因继承 DACL 自动提权),所以它留在持锁期间;**提权修复**不留在这里。 if let Err(error) = harden_new_game_creator_private_path(path, false, error_label) { drop(file); let _ = fs::remove_file(path); return Err(error); } } - crate::secure_windows_game_creator_path_for_current_user_with_auto_elevation( - path, false, true, - )?; + // 严格校验留在持锁期间(对象就是刚打开的这个句柄),**修复移到锁外**:提权修复会 + // `powershell.exe -Command "Start-Process -Verb RunAs -Wait …"` 同步等用户点 UAC + // (config.rs 的 attempt_elevated_windows_acl_repair),在这里等它等于把"用户犹豫 + // 的时间"记进别人的持锁窗口——1s 预算必然打满,而且只有 Windows 有这条路径。 + if let Err(error) = + crate::secure_windows_game_creator_path_for_current_user(path, false, true) + { + release_project_append_os_lock_then_repair_acl(file, path, &error)?; + return Ok(None); + } crate::runner::validate_windows_regular_file_handle(&file, error_label)?; Ok(Some(file)) }