mirror of
https://github.com/openai/codex.git
synced 2026-05-18 18:22:39 +00:00
Skip Windows sandbox ACL grants on non-ACL volumes
This commit is contained in:
@@ -1,55 +1,60 @@
|
||||
use crate::winutil::to_wide;
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Result;
|
||||
use anyhow::anyhow;
|
||||
use std::ffi::c_void;
|
||||
use std::path::Path;
|
||||
use windows_sys::Win32::Foundation::CloseHandle;
|
||||
use windows_sys::Win32::Foundation::LocalFree;
|
||||
use windows_sys::Win32::Foundation::ERROR_SUCCESS;
|
||||
use windows_sys::Win32::Foundation::GetLastError;
|
||||
use windows_sys::Win32::Foundation::HLOCAL;
|
||||
use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
|
||||
use windows_sys::Win32::Foundation::LocalFree;
|
||||
use windows_sys::Win32::Security::ACCESS_ALLOWED_ACE;
|
||||
use windows_sys::Win32::Security::ACE_HEADER;
|
||||
use windows_sys::Win32::Security::ACL;
|
||||
use windows_sys::Win32::Security::ACL_SIZE_INFORMATION;
|
||||
use windows_sys::Win32::Security::AclSizeInformation;
|
||||
use windows_sys::Win32::Security::Authorization::EXPLICIT_ACCESS_W;
|
||||
use windows_sys::Win32::Security::Authorization::GetNamedSecurityInfoW;
|
||||
use windows_sys::Win32::Security::Authorization::GetSecurityInfo;
|
||||
use windows_sys::Win32::Security::Authorization::SetEntriesInAclW;
|
||||
use windows_sys::Win32::Security::Authorization::SetNamedSecurityInfoW;
|
||||
use windows_sys::Win32::Security::Authorization::SetSecurityInfo;
|
||||
use windows_sys::Win32::Security::Authorization::EXPLICIT_ACCESS_W;
|
||||
use windows_sys::Win32::Security::Authorization::TRUSTEE_IS_SID;
|
||||
use windows_sys::Win32::Security::Authorization::TRUSTEE_IS_UNKNOWN;
|
||||
use windows_sys::Win32::Security::Authorization::TRUSTEE_W;
|
||||
use windows_sys::Win32::Security::DACL_SECURITY_INFORMATION;
|
||||
use windows_sys::Win32::Security::EqualSid;
|
||||
use windows_sys::Win32::Security::GENERIC_MAPPING;
|
||||
use windows_sys::Win32::Security::GetAce;
|
||||
use windows_sys::Win32::Security::GetAclInformation;
|
||||
use windows_sys::Win32::Security::MapGenericMask;
|
||||
use windows_sys::Win32::Security::ACCESS_ALLOWED_ACE;
|
||||
use windows_sys::Win32::Security::ACE_HEADER;
|
||||
use windows_sys::Win32::Security::ACL;
|
||||
use windows_sys::Win32::Security::ACL_SIZE_INFORMATION;
|
||||
use windows_sys::Win32::Security::DACL_SECURITY_INFORMATION;
|
||||
use windows_sys::Win32::Security::GENERIC_MAPPING;
|
||||
use windows_sys::Win32::Storage::FileSystem::CreateFileW;
|
||||
use windows_sys::Win32::Storage::FileSystem::DELETE;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_ALL_ACCESS;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_APPEND_DATA;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_NORMAL;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_DELETE_CHILD;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_EXECUTE;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_READ;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_WRITE;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_PERSISTENT_ACLS;
|
||||
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::FILE_WRITE_ATTRIBUTES;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_WRITE_DATA;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_WRITE_EA;
|
||||
use windows_sys::Win32::Storage::FileSystem::GetVolumeInformationW;
|
||||
use windows_sys::Win32::Storage::FileSystem::GetVolumePathNameW;
|
||||
use windows_sys::Win32::Storage::FileSystem::OPEN_EXISTING;
|
||||
use windows_sys::Win32::Storage::FileSystem::READ_CONTROL;
|
||||
use windows_sys::Win32::Storage::FileSystem::DELETE;
|
||||
const SE_KERNEL_OBJECT: u32 = 6;
|
||||
const INHERIT_ONLY_ACE: u8 = 0x08;
|
||||
const GENERIC_WRITE_MASK: u32 = 0x4000_0000;
|
||||
const DENY_ACCESS: i32 = 3;
|
||||
const VOLUME_PATH_BUFFER_LEN: usize = 1024;
|
||||
|
||||
/// Fetch DACL via handle-based query; caller must LocalFree the returned SD.
|
||||
///
|
||||
@@ -92,6 +97,50 @@ pub unsafe fn fetch_dacl_handle(path: &Path) -> Result<(*mut ACL, *mut c_void)>
|
||||
Ok((p_dacl, p_sd))
|
||||
}
|
||||
|
||||
pub fn path_supports_persistent_acls(path: &Path) -> Result<bool> {
|
||||
let wpath = to_wide(path);
|
||||
let mut volume_path = vec![0u16; VOLUME_PATH_BUFFER_LEN];
|
||||
let ok = unsafe {
|
||||
GetVolumePathNameW(
|
||||
wpath.as_ptr(),
|
||||
volume_path.as_mut_ptr(),
|
||||
volume_path.len() as u32,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
let err = unsafe { GetLastError() };
|
||||
return Err(anyhow!(
|
||||
"GetVolumePathNameW failed for {}: {}",
|
||||
path.display(),
|
||||
err
|
||||
));
|
||||
}
|
||||
|
||||
let mut file_system_flags = 0u32;
|
||||
let ok = unsafe {
|
||||
GetVolumeInformationW(
|
||||
volume_path.as_ptr(),
|
||||
std::ptr::null_mut(),
|
||||
0,
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
&mut file_system_flags,
|
||||
std::ptr::null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
let err = unsafe { GetLastError() };
|
||||
return Err(anyhow!(
|
||||
"GetVolumeInformationW failed for {}: {}",
|
||||
path.display(),
|
||||
err
|
||||
));
|
||||
}
|
||||
|
||||
Ok((file_system_flags & FILE_PERSISTENT_ACLS) != 0)
|
||||
}
|
||||
|
||||
/// Fast mask-based check: does an ACE for provided SIDs grant the desired mask? Skips inherit-only.
|
||||
/// When `require_all_bits` is true, all bits in `desired_mask` must be present; otherwise any bit suffices.
|
||||
pub unsafe fn dacl_mask_allows(
|
||||
@@ -259,12 +308,8 @@ pub unsafe fn dacl_has_write_deny_for_sid(p_dacl: *mut ACL, psid: *mut c_void) -
|
||||
false
|
||||
}
|
||||
|
||||
const WRITE_ALLOW_MASK: u32 = FILE_GENERIC_READ
|
||||
| FILE_GENERIC_WRITE
|
||||
| FILE_GENERIC_EXECUTE
|
||||
| DELETE
|
||||
| FILE_DELETE_CHILD;
|
||||
|
||||
const WRITE_ALLOW_MASK: u32 =
|
||||
FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE | FILE_DELETE_CHILD;
|
||||
|
||||
unsafe fn ensure_allow_mask_aces_with_inheritance_impl(
|
||||
path: &Path,
|
||||
@@ -275,12 +320,7 @@ unsafe fn ensure_allow_mask_aces_with_inheritance_impl(
|
||||
let (p_dacl, p_sd) = fetch_dacl_handle(path)?;
|
||||
let mut entries: Vec<EXPLICIT_ACCESS_W> = Vec::new();
|
||||
for sid in sids {
|
||||
if dacl_mask_allows(
|
||||
p_dacl,
|
||||
&[*sid],
|
||||
allow_mask,
|
||||
/*require_all_bits*/ true,
|
||||
) {
|
||||
if dacl_mask_allows(p_dacl, &[*sid], allow_mask, /*require_all_bits*/ true) {
|
||||
continue;
|
||||
}
|
||||
entries.push(EXPLICIT_ACCESS_W {
|
||||
|
||||
@@ -91,6 +91,8 @@ pub use acl::fetch_dacl_handle;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use acl::path_mask_allows;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use acl::path_supports_persistent_acls;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use audit::apply_world_writable_scan_and_denies;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use cap::load_or_create_cap_sids;
|
||||
|
||||
@@ -24,6 +24,7 @@ use codex_windows_sandbox::is_command_cwd_root;
|
||||
use codex_windows_sandbox::load_or_create_cap_sids;
|
||||
use codex_windows_sandbox::log_note;
|
||||
use codex_windows_sandbox::path_mask_allows;
|
||||
use codex_windows_sandbox::path_supports_persistent_acls;
|
||||
use codex_windows_sandbox::sandbox_bin_dir;
|
||||
use codex_windows_sandbox::sandbox_dir;
|
||||
use codex_windows_sandbox::sandbox_secrets_dir;
|
||||
@@ -158,6 +159,35 @@ fn apply_read_acls(
|
||||
)?;
|
||||
continue;
|
||||
}
|
||||
match path_supports_persistent_acls(root) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
log_line(
|
||||
log,
|
||||
&format!(
|
||||
"{access_label} root {} is on a filesystem without persistent ACL support; skipping sandbox ACL grant",
|
||||
root.display()
|
||||
),
|
||||
)?;
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
refresh_errors.push(format!(
|
||||
"{access_label} ACL capability check failed on {}: {}",
|
||||
root.display(),
|
||||
err
|
||||
));
|
||||
log_line(
|
||||
log,
|
||||
&format!(
|
||||
"{access_label} ACL capability check failed on {}: {}; continuing",
|
||||
root.display(),
|
||||
err
|
||||
),
|
||||
)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let builtin_has = read_mask_allows_or_log(
|
||||
root,
|
||||
subjects.rx_psids,
|
||||
|
||||
Reference in New Issue
Block a user