mirror of
https://github.com/openai/codex.git
synced 2026-10-26 18:38:47 +00:00
## Why The Windows sandbox service had provisioning policy and client authentication in place, but its IPC listener was still disabled. ## What changed - Serve framed provisioning requests over a local named pipe, authenticate packaged clients, validate requests and machine policy, and report provisioning outcomes through bounded responses and Windows event logging. - Return `unavailable` for configuration parse failures so clients can fall back to the elevated setup helper. - Keep validated directory handles alive in the setup helper so path protections survive an unexpected service exit. - Make connection recovery and shutdown wakeups tolerate clients that disconnect before the listener accepts them. ## Testing Added Windows tests for response framing, configuration-error classification, pipe security and reconnect behavior, shutdown wakeups, and retained helper handles. GitOrigin-RevId: 68e9d546dcada88ff162ea4f98c0f4d748706b34
76 lines
2.6 KiB
Rust
76 lines
2.6 KiB
Rust
//! Starts provisioning helpers only after their retained directory handles are installed.
|
|
//! The child owns its duplicates until exit, independently of the service lifetime.
|
|
|
|
use std::io;
|
|
use std::os::windows::io::AsRawHandle;
|
|
use std::os::windows::io::BorrowedHandle;
|
|
use std::os::windows::process::CommandExt;
|
|
use std::process::Child;
|
|
use std::process::Command;
|
|
use std::process::Stdio;
|
|
use windows_sys::Win32::Foundation::DUPLICATE_SAME_ACCESS;
|
|
use windows_sys::Win32::Foundation::DuplicateHandle;
|
|
use windows_sys::Win32::Foundation::HANDLE;
|
|
use windows_sys::Win32::Foundation::NTSTATUS;
|
|
use windows_sys::Win32::Foundation::RtlNtStatusToDosError;
|
|
use windows_sys::Win32::System::Threading::CREATE_NO_WINDOW;
|
|
use windows_sys::Win32::System::Threading::CREATE_SUSPENDED;
|
|
use windows_sys::Win32::System::Threading::GetCurrentProcess;
|
|
|
|
#[link(name = "ntdll")]
|
|
unsafe extern "system" {
|
|
fn NtResumeProcess(process_handle: HANDLE) -> NTSTATUS;
|
|
}
|
|
|
|
pub(super) fn spawn_with_retained_handles(
|
|
command: &mut Command,
|
|
retained_handles: &[BorrowedHandle<'_>],
|
|
) -> io::Result<Child> {
|
|
let mut child = command
|
|
.creation_flags(CREATE_NO_WINDOW | CREATE_SUSPENDED)
|
|
.stdin(Stdio::null())
|
|
.stdout(Stdio::null())
|
|
.stderr(Stdio::null())
|
|
.spawn()?;
|
|
let initialized = (|| {
|
|
for handle in retained_handles {
|
|
let mut child_handle = 0;
|
|
if unsafe {
|
|
DuplicateHandle(
|
|
GetCurrentProcess(),
|
|
handle.as_raw_handle() as HANDLE,
|
|
child.as_raw_handle() as HANDLE,
|
|
&mut child_handle,
|
|
/*dwdesiredaccess*/ 0,
|
|
/*binherithandle*/ 0,
|
|
DUPLICATE_SAME_ACCESS,
|
|
)
|
|
} == 0
|
|
{
|
|
return Err(io::Error::last_os_error());
|
|
}
|
|
// This value belongs to the child's handle table. Do not close it here
|
|
// or make it inheritable by unrelated processes or helper descendants.
|
|
}
|
|
let status = unsafe { NtResumeProcess(child.as_raw_handle() as HANDLE) };
|
|
if status < 0 {
|
|
return Err(io::Error::from_raw_os_error(
|
|
unsafe { RtlNtStatusToDosError(status) } as i32,
|
|
));
|
|
}
|
|
Ok(())
|
|
})();
|
|
if let Err(error) = initialized {
|
|
// A partially initialized helper must never run after its parent drops
|
|
// the directory protections. Reap it, including any installed duplicates.
|
|
child.kill()?;
|
|
child.wait()?;
|
|
return Err(error);
|
|
}
|
|
Ok(child)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "setup_launch_tests.rs"]
|
|
mod tests;
|