diff --git a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs index dc43abd922..1d9340c6db 100644 --- a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs +++ b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs @@ -1035,6 +1035,10 @@ fn run_setup_full(payload: &Payload, log: &mut dyn Write, sbx_dir: &Path) -> Res Ok(()) } +#[cfg(test)] +#[path = "win_acl_tests.rs"] +mod acl_tests; + #[cfg(test)] mod tests { use super::Payload; diff --git a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/no_reparse_dir.rs b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/no_reparse_dir.rs index dd9c100b07..93d983f12f 100644 --- a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/no_reparse_dir.rs +++ b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/no_reparse_dir.rs @@ -21,6 +21,7 @@ use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_NORMAL; use windows_sys::Win32::Storage::FileSystem::FILE_SHARE_DELETE; use windows_sys::Win32::Storage::FileSystem::FILE_SHARE_READ; use windows_sys::Win32::Storage::FileSystem::FILE_SHARE_WRITE; +use windows_sys::Win32::Storage::FileSystem::READ_CONTROL; use windows_sys::Win32::Storage::FileSystem::WRITE_DAC; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK_0; @@ -115,9 +116,10 @@ pub(super) fn open_or_create_no_reparse(path: &Path) -> Result { }; let mut handle = 0; let status = unsafe { + // SetSecurityInfo can reject a WRITE_DAC-only directory handle. NtCreateFile( &mut handle, - WRITE_DAC, + READ_CONTROL | WRITE_DAC, &object_attributes, &mut io_status_block, ptr::null(), diff --git a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win_acl_tests.rs b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win_acl_tests.rs new file mode 100644 index 0000000000..e488e2a914 --- /dev/null +++ b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win_acl_tests.rs @@ -0,0 +1,29 @@ +use super::DELETE; +use super::FILE_GENERIC_EXECUTE; +use super::FILE_GENERIC_READ; +use super::FILE_GENERIC_WRITE; +use super::GRANT_ACCESS; +use super::SetupMode; +use super::lock_sandbox_dir; +use super::resolve_sid; + +#[test] +fn provision_only_locks_plain_directory_via_handle() { + let temp = tempfile::tempdir().expect("tempdir"); + let sandbox_bin = temp.path().join(".sandbox-bin"); + let real_user = std::env::var("USERNAME").unwrap_or_else(|_| "Administrators".to_string()); + let real_sid = resolve_sid(&real_user).expect("resolve real user SID"); + + lock_sandbox_dir( + &sandbox_bin, + &real_user, + &real_sid, + GRANT_ACCESS, + FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, + FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE, + SetupMode::ProvisionOnly, + ) + .expect("lock sandbox bin via no-reparse handle"); + + assert!(sandbox_bin.is_dir()); +}