mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Summary This is the runtime/foundation half of the Windows sandbox unified-exec work. - add Windows sandbox `unified_exec` session support in `windows-sandbox-rs` for both: - the legacy restricted-token backend - the elevated runner backend - extend the PTY/process runtime so driver-backed sessions can support: - stdin streaming - stdout/stderr separation - exit propagation - PTY resize hooks - add Windows sandbox runtime coverage in `codex-windows-sandbox` / `codex-utils-pty` This PR does **not** enable Windows sandbox `UnifiedExec` for product callers yet because hooking this up to app-server comes in the next PR. Windows sandbox advertising is intentionally kept aligned with `main`, so sandboxed Windows callers still fall back to `ShellCommand`. This PR isolates the runtime/session layer so it can be reviewed independently from product-surface enablement. --------- Co-authored-by: jif-oai <jif@openai.com> Co-authored-by: Codex <noreply@openai.com>
101 lines
3.2 KiB
Rust
101 lines
3.2 KiB
Rust
use std::io;
|
|
use windows_sys::Win32::Foundation::GetLastError;
|
|
use windows_sys::Win32::Foundation::HANDLE;
|
|
use windows_sys::Win32::System::Threading::DeleteProcThreadAttributeList;
|
|
use windows_sys::Win32::System::Threading::InitializeProcThreadAttributeList;
|
|
use windows_sys::Win32::System::Threading::LPPROC_THREAD_ATTRIBUTE_LIST;
|
|
use windows_sys::Win32::System::Threading::UpdateProcThreadAttribute;
|
|
|
|
const PROC_THREAD_ATTRIBUTE_HANDLE_LIST: usize = 0x0002_0002;
|
|
const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 0x0002_0016;
|
|
|
|
pub struct ProcThreadAttributeList {
|
|
buffer: Vec<u8>,
|
|
handle_list: Option<Vec<HANDLE>>,
|
|
}
|
|
|
|
impl ProcThreadAttributeList {
|
|
pub fn new(attr_count: u32) -> io::Result<Self> {
|
|
let mut size: usize = 0;
|
|
unsafe {
|
|
InitializeProcThreadAttributeList(std::ptr::null_mut(), attr_count, 0, &mut size);
|
|
}
|
|
if size == 0 {
|
|
return Err(io::Error::from_raw_os_error(unsafe {
|
|
GetLastError() as i32
|
|
}));
|
|
}
|
|
let mut buffer = vec![0u8; size];
|
|
let list = buffer.as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST;
|
|
let ok = unsafe { InitializeProcThreadAttributeList(list, attr_count, 0, &mut size) };
|
|
if ok == 0 {
|
|
return Err(io::Error::from_raw_os_error(unsafe {
|
|
GetLastError() as i32
|
|
}));
|
|
}
|
|
Ok(Self {
|
|
buffer,
|
|
handle_list: None,
|
|
})
|
|
}
|
|
|
|
pub fn as_mut_ptr(&mut self) -> LPPROC_THREAD_ATTRIBUTE_LIST {
|
|
self.buffer.as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST
|
|
}
|
|
|
|
pub fn set_pseudoconsole(&mut self, hpc: isize) -> io::Result<()> {
|
|
let list = self.as_mut_ptr();
|
|
let mut hpc_value = hpc;
|
|
let ok = unsafe {
|
|
UpdateProcThreadAttribute(
|
|
list,
|
|
0,
|
|
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
|
(&mut hpc_value as *mut isize).cast(),
|
|
std::mem::size_of::<isize>(),
|
|
std::ptr::null_mut(),
|
|
std::ptr::null_mut(),
|
|
)
|
|
};
|
|
if ok == 0 {
|
|
return Err(io::Error::from_raw_os_error(unsafe {
|
|
GetLastError() as i32
|
|
}));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn set_handle_list(&mut self, handles: Vec<HANDLE>) -> io::Result<()> {
|
|
self.handle_list = Some(handles);
|
|
let list = self.as_mut_ptr();
|
|
let Some(handle_list) = self.handle_list.as_mut() else {
|
|
return Err(io::Error::other("handle list missing after initialization"));
|
|
};
|
|
let ok = unsafe {
|
|
UpdateProcThreadAttribute(
|
|
list,
|
|
0,
|
|
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
|
handle_list.as_mut_ptr().cast(),
|
|
std::mem::size_of_val(handle_list.as_slice()),
|
|
std::ptr::null_mut(),
|
|
std::ptr::null_mut(),
|
|
)
|
|
};
|
|
if ok == 0 {
|
|
return Err(io::Error::from_raw_os_error(unsafe {
|
|
GetLastError() as i32
|
|
}));
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Drop for ProcThreadAttributeList {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
DeleteProcThreadAttributeList(self.as_mut_ptr());
|
|
}
|
|
}
|
|
}
|