mirror of
https://github.com/openai/codex.git
synced 2026-05-02 04:11:39 +03:00
## Why `codex-utils-pty` and `codex-windows-sandbox` were the remaining crates in `codex-rs` that still overrode the workspace's Rust 2024 edition. Moving them forward in a separate PR keeps the baseline edition update isolated from the follow-on Bazel clippy workflow in #15955, while making linting and formatting behavior consistent with the rest of the workspace. This PR also needs Cargo and Bazel to agree on the edition for `codex-windows-sandbox`. Without the Bazel-side sync, the experimental Bazel app-server builds fail once they compile `windows-sandbox-rs`. ## What changed - switch `codex-rs/utils/pty` and `codex-rs/windows-sandbox-rs` to `edition = "2024"` - update `codex-utils-pty` callsites and tests to use the collapsed `if let` form that Clippy expects under the new edition - fix the Rust 2024 fallout in `windows-sandbox-rs`, including the reserved `gen` identifier, `unsafe extern` requirements, and new Clippy findings that surfaced under the edition bump - keep the edition bump separate from a larger unsafe cleanup by temporarily allowing `unsafe_op_in_unsafe_fn` in the Windows entrypoint modules that now report it under Rust 2024 - update `codex-rs/windows-sandbox-rs/BUILD.bazel` to `crate_edition = "2024"` so Bazel compiles the crate with the same edition as Cargo --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/15954). * #15976 * #15955 * __->__ #15954
197 lines
6.6 KiB
Rust
197 lines
6.6 KiB
Rust
use crate::logging;
|
|
use crate::token::get_current_token_for_restriction;
|
|
use crate::token::get_logon_sid_bytes;
|
|
use crate::winutil::format_last_error;
|
|
use crate::winutil::to_wide;
|
|
use anyhow::Result;
|
|
use rand::Rng;
|
|
use rand::SeedableRng;
|
|
use rand::rngs::SmallRng;
|
|
use std::path::Path;
|
|
use std::ffi::c_void;
|
|
use std::ptr;
|
|
use windows_sys::Win32::Foundation::CloseHandle;
|
|
use windows_sys::Win32::Foundation::GetLastError;
|
|
use windows_sys::Win32::Foundation::HLOCAL;
|
|
use windows_sys::Win32::Foundation::ERROR_SUCCESS;
|
|
use windows_sys::Win32::Foundation::LocalFree;
|
|
use windows_sys::Win32::Security::Authorization::EXPLICIT_ACCESS_W;
|
|
use windows_sys::Win32::Security::Authorization::GRANT_ACCESS;
|
|
use windows_sys::Win32::Security::Authorization::SE_WINDOW_OBJECT;
|
|
use windows_sys::Win32::Security::Authorization::SetEntriesInAclW;
|
|
use windows_sys::Win32::Security::Authorization::SetSecurityInfo;
|
|
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::System::StationsAndDesktops::CloseDesktop;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_CREATEMENU;
|
|
use windows_sys::Win32::System::StationsAndDesktops::CreateDesktopW;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_CREATEWINDOW;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_DELETE;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_ENUMERATE;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_HOOKCONTROL;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_JOURNALPLAYBACK;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_JOURNALRECORD;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_READOBJECTS;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_READ_CONTROL;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_SWITCHDESKTOP;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_WRITE_DAC;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_WRITE_OWNER;
|
|
use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_WRITEOBJECTS;
|
|
|
|
const DESKTOP_ALL_ACCESS: u32 = DESKTOP_READOBJECTS
|
|
| DESKTOP_CREATEWINDOW
|
|
| DESKTOP_CREATEMENU
|
|
| DESKTOP_HOOKCONTROL
|
|
| DESKTOP_JOURNALRECORD
|
|
| DESKTOP_JOURNALPLAYBACK
|
|
| DESKTOP_ENUMERATE
|
|
| DESKTOP_WRITEOBJECTS
|
|
| DESKTOP_SWITCHDESKTOP
|
|
| DESKTOP_DELETE
|
|
| DESKTOP_READ_CONTROL
|
|
| DESKTOP_WRITE_DAC
|
|
| DESKTOP_WRITE_OWNER;
|
|
|
|
pub struct LaunchDesktop {
|
|
_private_desktop: Option<PrivateDesktop>,
|
|
startup_name: Vec<u16>,
|
|
}
|
|
|
|
impl LaunchDesktop {
|
|
pub fn prepare(use_private_desktop: bool, logs_base_dir: Option<&Path>) -> Result<Self> {
|
|
if use_private_desktop {
|
|
let private_desktop = PrivateDesktop::create(logs_base_dir)?;
|
|
let startup_name = to_wide(format!("Winsta0\\{}", private_desktop.name));
|
|
Ok(Self {
|
|
_private_desktop: Some(private_desktop),
|
|
startup_name,
|
|
})
|
|
} else {
|
|
Ok(Self {
|
|
_private_desktop: None,
|
|
startup_name: to_wide("Winsta0\\Default"),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub fn startup_info_desktop(&self) -> *mut u16 {
|
|
self.startup_name.as_ptr() as *mut u16
|
|
}
|
|
}
|
|
|
|
struct PrivateDesktop {
|
|
handle: isize,
|
|
name: String,
|
|
}
|
|
|
|
impl PrivateDesktop {
|
|
fn create(logs_base_dir: Option<&Path>) -> Result<Self> {
|
|
let mut rng = SmallRng::from_entropy();
|
|
let name = format!("CodexSandboxDesktop-{:x}", rng.r#gen::<u128>());
|
|
let name_wide = to_wide(&name);
|
|
let handle = unsafe {
|
|
CreateDesktopW(
|
|
name_wide.as_ptr(),
|
|
ptr::null(),
|
|
ptr::null_mut(),
|
|
0,
|
|
DESKTOP_ALL_ACCESS,
|
|
ptr::null_mut(),
|
|
)
|
|
};
|
|
if handle == 0 {
|
|
let err = unsafe { GetLastError() } as i32;
|
|
logging::debug_log(
|
|
&format!(
|
|
"CreateDesktopW failed for {name}: {} ({})",
|
|
err,
|
|
format_last_error(err),
|
|
),
|
|
logs_base_dir,
|
|
);
|
|
return Err(anyhow::anyhow!("CreateDesktopW failed: {err}"));
|
|
}
|
|
|
|
unsafe {
|
|
if let Err(err) = grant_desktop_access(handle, logs_base_dir) {
|
|
let _ = CloseDesktop(handle);
|
|
return Err(err);
|
|
}
|
|
}
|
|
|
|
Ok(Self { handle, name })
|
|
}
|
|
}
|
|
|
|
unsafe fn grant_desktop_access(handle: isize, logs_base_dir: Option<&Path>) -> Result<()> {
|
|
let token = get_current_token_for_restriction()?;
|
|
let mut logon_sid = get_logon_sid_bytes(token)?;
|
|
CloseHandle(token);
|
|
|
|
let entries = [EXPLICIT_ACCESS_W {
|
|
grfAccessPermissions: DESKTOP_ALL_ACCESS,
|
|
grfAccessMode: GRANT_ACCESS,
|
|
grfInheritance: 0,
|
|
Trustee: TRUSTEE_W {
|
|
pMultipleTrustee: ptr::null_mut(),
|
|
MultipleTrusteeOperation: 0,
|
|
TrusteeForm: TRUSTEE_IS_SID,
|
|
TrusteeType: TRUSTEE_IS_UNKNOWN,
|
|
ptstrName: logon_sid.as_mut_ptr() as *mut c_void as *mut u16,
|
|
},
|
|
}];
|
|
|
|
let mut updated_dacl = ptr::null_mut();
|
|
let set_entries_code = SetEntriesInAclW(
|
|
entries.len() as u32,
|
|
entries.as_ptr(),
|
|
ptr::null_mut(),
|
|
&mut updated_dacl,
|
|
);
|
|
if set_entries_code != ERROR_SUCCESS {
|
|
logging::debug_log(
|
|
&format!("SetEntriesInAclW failed for private desktop: {set_entries_code}"),
|
|
logs_base_dir,
|
|
);
|
|
return Err(anyhow::anyhow!(
|
|
"SetEntriesInAclW failed for private desktop: {set_entries_code}"
|
|
));
|
|
}
|
|
|
|
let set_security_code = SetSecurityInfo(
|
|
handle,
|
|
SE_WINDOW_OBJECT,
|
|
DACL_SECURITY_INFORMATION,
|
|
ptr::null_mut(),
|
|
ptr::null_mut(),
|
|
updated_dacl,
|
|
ptr::null_mut(),
|
|
);
|
|
if !updated_dacl.is_null() {
|
|
LocalFree(updated_dacl as HLOCAL);
|
|
}
|
|
if set_security_code != ERROR_SUCCESS {
|
|
logging::debug_log(
|
|
&format!("SetSecurityInfo failed for private desktop: {set_security_code}"),
|
|
logs_base_dir,
|
|
);
|
|
return Err(anyhow::anyhow!(
|
|
"SetSecurityInfo failed for private desktop: {set_security_code}"
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
impl Drop for PrivateDesktop {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
if self.handle != 0 {
|
|
let _ = CloseDesktop(self.handle);
|
|
}
|
|
}
|
|
}
|
|
}
|