From fb8e07ea72da49d31e7b2b07b4f855879a9c4dc0 Mon Sep 17 00:00:00 2001 From: David Wiesen Date: Thu, 18 Jun 2026 10:28:04 -0700 Subject: [PATCH] windows-sandbox: retry 1312 launches on default desktop --- codex-rs/windows-sandbox-rs/src/conpty/mod.rs | 81 ++++++---- codex-rs/windows-sandbox-rs/src/process.rs | 145 +++++++++++------- 2 files changed, 142 insertions(+), 84 deletions(-) diff --git a/codex-rs/windows-sandbox-rs/src/conpty/mod.rs b/codex-rs/windows-sandbox-rs/src/conpty/mod.rs index cd839952b5..3ed5e75762 100644 --- a/codex-rs/windows-sandbox-rs/src/conpty/mod.rs +++ b/codex-rs/windows-sandbox-rs/src/conpty/mod.rs @@ -7,6 +7,7 @@ //! Windows sandbox flows that need a PTY. use crate::desktop::LaunchDesktop; +use crate::logging; use crate::proc_thread_attr::ProcThreadAttributeList; use crate::winutil::format_last_error; use crate::winutil::quote_windows_arg; @@ -19,6 +20,7 @@ use std::ffi::c_void; use std::os::windows::io::IntoRawHandle; use std::path::Path; use windows_sys::Win32::Foundation::CloseHandle; +use windows_sys::Win32::Foundation::ERROR_NO_SUCH_LOGON_SESSION; use windows_sys::Win32::Foundation::GetLastError; use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; @@ -111,40 +113,66 @@ pub fn spawn_conpty_process_as_user( si.StartupInfo.hStdInput = INVALID_HANDLE_VALUE; si.StartupInfo.hStdOutput = INVALID_HANDLE_VALUE; si.StartupInfo.hStdError = INVALID_HANDLE_VALUE; - let desktop = LaunchDesktop::prepare(use_private_desktop, logs_base_dir)?; - si.StartupInfo.lpDesktop = desktop.startup_info_desktop(); - let raw = RawConPty::new(/*cols*/ 80, /*rows*/ 24)?; let (pseudoconsole, input_write, output_read) = raw.into_handles(); let hpc = pseudoconsole.raw_handle() as HANDLE; - let conpty = ConptyInstance { - pseudoconsole: Some(pseudoconsole), - input_write: input_write.into_raw_handle() as HANDLE, - output_read: output_read.into_raw_handle() as HANDLE, - _desktop: Some(desktop), - }; + let input_write = input_write.into_raw_handle() as HANDLE; + let output_read = output_read.into_raw_handle() as HANDLE; let mut attrs = ProcThreadAttributeList::new(/*attr_count*/ 1)?; attrs.set_pseudoconsole(hpc)?; si.lpAttributeList = attrs.as_mut_ptr(); - let mut pi: PROCESS_INFORMATION = unsafe { std::mem::zeroed() }; - let ok = unsafe { - CreateProcessAsUserW( - h_token, - std::ptr::null(), - cmdline.as_mut_ptr(), - std::ptr::null_mut(), - std::ptr::null_mut(), - 0, - EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, - env_block.as_ptr() as *mut c_void, - to_wide(cwd).as_ptr(), - &si.StartupInfo, - &mut pi, - ) - }; - if ok == 0 { + let mut attempt_private_desktop = use_private_desktop; + loop { + let desktop = LaunchDesktop::prepare(attempt_private_desktop, logs_base_dir)?; + si.StartupInfo.lpDesktop = desktop.startup_info_desktop(); + + let mut pi: PROCESS_INFORMATION = unsafe { std::mem::zeroed() }; + let ok = unsafe { + CreateProcessAsUserW( + h_token, + std::ptr::null(), + cmdline.as_mut_ptr(), + std::ptr::null_mut(), + std::ptr::null_mut(), + 0, + EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, + env_block.as_ptr() as *mut c_void, + to_wide(cwd).as_ptr(), + &si.StartupInfo, + &mut pi, + ) + }; + if ok != 0 { + let conpty = ConptyInstance { + pseudoconsole: Some(pseudoconsole), + input_write, + output_read, + _desktop: Some(desktop), + }; + return Ok((pi, conpty)); + } + let err = unsafe { GetLastError() } as i32; + logging::debug_log( + &format!( + "CreateProcessAsUserW failed: {} ({}) | cwd={} | cmd={} | env_u16_len={}", + err, + format_last_error(err), + cwd.display(), + cmdline_str, + env_block.len() + ), + logs_base_dir, + ); + if attempt_private_desktop && err == ERROR_NO_SUCH_LOGON_SESSION as i32 { + logging::debug_log( + "CreateProcessAsUserW returned ERROR_NO_SUCH_LOGON_SESSION on a private desktop; retrying PTY launch on Winsta0\\Default", + logs_base_dir, + ); + attempt_private_desktop = false; + continue; + } return Err(anyhow::anyhow!( "CreateProcessAsUserW failed: {} ({}) | cwd={} | cmd={} | env_u16_len={}", err, @@ -154,5 +182,4 @@ pub fn spawn_conpty_process_as_user( env_block.len() )); } - Ok((pi, conpty)) } diff --git a/codex-rs/windows-sandbox-rs/src/process.rs b/codex-rs/windows-sandbox-rs/src/process.rs index 0899d34c2f..fb3d8ebd2f 100644 --- a/codex-rs/windows-sandbox-rs/src/process.rs +++ b/codex-rs/windows-sandbox-rs/src/process.rs @@ -11,6 +11,7 @@ use std::ffi::c_void; use std::path::Path; use std::ptr; use windows_sys::Win32::Foundation::CloseHandle; +use windows_sys::Win32::Foundation::ERROR_NO_SUCH_LOGON_SESSION; use windows_sys::Win32::Foundation::GetLastError; use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Foundation::HANDLE_FLAG_INHERIT; @@ -36,6 +37,10 @@ pub struct CreatedProcess { _desktop: LaunchDesktop, } +fn should_retry_on_default_desktop(err: i32, use_private_desktop: bool) -> bool { + use_private_desktop && err == ERROR_NO_SUCH_LOGON_SESSION as i32 +} + pub fn make_env_block(env: &HashMap) -> Vec { let mut items: Vec<(String, String)> = env.iter().map(|(k, v)| (k.clone(), v.clone())).collect(); @@ -87,22 +92,11 @@ pub unsafe fn create_process_as_user( let cmdline_str = argv_to_command_line(argv); let mut cmdline: Vec = to_wide(&cmdline_str); let env_block = make_env_block(env_map); - let desktop = LaunchDesktop::prepare(use_private_desktop, logs_base_dir)?; let mut pi: PROCESS_INFORMATION = std::mem::zeroed(); let cwd_wide = to_wide(cwd); let env_block_len = env_block.len(); match stdio { Some((stdin_h, stdout_h, stderr_h)) => { - let mut si: STARTUPINFOEXW = std::mem::zeroed(); - si.StartupInfo.cb = std::mem::size_of::() as u32; - // Some processes (e.g., PowerShell) can fail with STATUS_DLL_INIT_FAILED - // if lpDesktop is not set when launching with a restricted token. - // Point explicitly at the interactive desktop or a private desktop. - si.StartupInfo.lpDesktop = desktop.startup_info_desktop(); - si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; - si.StartupInfo.hStdInput = stdin_h; - si.StartupInfo.hStdOutput = stdout_h; - si.StartupInfo.hStdError = stderr_h; let mut inherited_handles = vec![stdin_h, stdout_h]; if !inherited_handles.contains(&stderr_h) { inherited_handles.push(stderr_h); @@ -115,25 +109,46 @@ pub unsafe fn create_process_as_user( )); } } - let mut attrs = ProcThreadAttributeList::new(/*attr_count*/ 1)?; - attrs.set_handle_list(inherited_handles)?; - si.lpAttributeList = attrs.as_mut_ptr(); let creation_flags = CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT; - let ok = CreateProcessAsUserW( - h_token, - std::ptr::null(), - cmdline.as_mut_ptr(), - std::ptr::null_mut(), - std::ptr::null_mut(), - 1, - creation_flags, - env_block.as_ptr() as *mut c_void, - cwd_wide.as_ptr(), - &si.StartupInfo, - &mut pi, - ); - if ok == 0 { + let mut attempt_private_desktop = use_private_desktop; + loop { + let desktop = LaunchDesktop::prepare(attempt_private_desktop, logs_base_dir)?; + let mut si: STARTUPINFOEXW = std::mem::zeroed(); + si.StartupInfo.cb = std::mem::size_of::() as u32; + // Some processes (e.g., PowerShell) can fail with STATUS_DLL_INIT_FAILED + // if lpDesktop is not set when launching with a restricted token. + // Point explicitly at the interactive desktop or a private desktop. + si.StartupInfo.lpDesktop = desktop.startup_info_desktop(); + si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + si.StartupInfo.hStdInput = stdin_h; + si.StartupInfo.hStdOutput = stdout_h; + si.StartupInfo.hStdError = stderr_h; + let mut attrs = ProcThreadAttributeList::new(/*attr_count*/ 1)?; + attrs.set_handle_list(inherited_handles.clone())?; + si.lpAttributeList = attrs.as_mut_ptr(); + + let ok = CreateProcessAsUserW( + h_token, + std::ptr::null(), + cmdline.as_mut_ptr(), + std::ptr::null_mut(), + std::ptr::null_mut(), + 1, + creation_flags, + env_block.as_ptr() as *mut c_void, + cwd_wide.as_ptr(), + &si.StartupInfo, + &mut pi, + ); + if ok != 0 { + return Ok(CreatedProcess { + process_info: pi, + startup_info: si.StartupInfo, + _desktop: desktop, + }); + } + let err = GetLastError() as i32; let msg = format!( "CreateProcessAsUserW failed: {} ({}) | cwd={} | cmd={} | env_u16_len={} | si_flags={} | creation_flags={}", @@ -146,35 +161,48 @@ pub unsafe fn create_process_as_user( creation_flags, ); logging::debug_log(&msg, logs_base_dir); + if should_retry_on_default_desktop(err, attempt_private_desktop) { + logging::debug_log( + "CreateProcessAsUserW returned ERROR_NO_SUCH_LOGON_SESSION on a private desktop; retrying on Winsta0\\Default", + logs_base_dir, + ); + attempt_private_desktop = false; + continue; + } return Err(anyhow!("CreateProcessAsUserW failed: {err}")); } - Ok(CreatedProcess { - process_info: pi, - startup_info: si.StartupInfo, - _desktop: desktop, - }) } None => { - let mut si: STARTUPINFOW = std::mem::zeroed(); - si.cb = std::mem::size_of::() as u32; - si.lpDesktop = desktop.startup_info_desktop(); - ensure_inheritable_stdio(&mut si)?; - let creation_flags = CREATE_UNICODE_ENVIRONMENT; - let ok = CreateProcessAsUserW( - h_token, - std::ptr::null(), - cmdline.as_mut_ptr(), - std::ptr::null_mut(), - std::ptr::null_mut(), - 1, - creation_flags, - env_block.as_ptr() as *mut c_void, - cwd_wide.as_ptr(), - &si, - &mut pi, - ); - if ok == 0 { + let mut attempt_private_desktop = use_private_desktop; + loop { + let desktop = LaunchDesktop::prepare(attempt_private_desktop, logs_base_dir)?; + let mut si: STARTUPINFOW = std::mem::zeroed(); + si.cb = std::mem::size_of::() as u32; + si.lpDesktop = desktop.startup_info_desktop(); + ensure_inheritable_stdio(&mut si)?; + + let ok = CreateProcessAsUserW( + h_token, + std::ptr::null(), + cmdline.as_mut_ptr(), + std::ptr::null_mut(), + std::ptr::null_mut(), + 1, + creation_flags, + env_block.as_ptr() as *mut c_void, + cwd_wide.as_ptr(), + &si, + &mut pi, + ); + if ok != 0 { + return Ok(CreatedProcess { + process_info: pi, + startup_info: si, + _desktop: desktop, + }); + } + let err = GetLastError() as i32; let msg = format!( "CreateProcessAsUserW failed: {} ({}) | cwd={} | cmd={} | env_u16_len={} | si_flags={} | creation_flags={}", @@ -187,13 +215,16 @@ pub unsafe fn create_process_as_user( creation_flags, ); logging::debug_log(&msg, logs_base_dir); + if should_retry_on_default_desktop(err, attempt_private_desktop) { + logging::debug_log( + "CreateProcessAsUserW returned ERROR_NO_SUCH_LOGON_SESSION on a private desktop; retrying on Winsta0\\Default", + logs_base_dir, + ); + attempt_private_desktop = false; + continue; + } return Err(anyhow!("CreateProcessAsUserW failed: {err}")); } - Ok(CreatedProcess { - process_info: pi, - startup_info: si, - _desktop: desktop, - }) } } }