Start the Windows sandbox service during registered Core setup (#51256)

## Why

A stopped provisioning service is treated as unavailable by the connection path, preventing registered Core setup from provisioning the sandbox.

## What changed

Start a stopped Windows sandbox service before provisioning during explicit registered Core setup. Request service-start permission through the Windows Service Control Manager and tolerate the service already running if another caller starts it concurrently. Preserve existing unavailable-service handling when the service is missing or marked for deletion.

GitOrigin-RevId: fab87c10dfabd4324f631077262f7e0dccc170f6
This commit is contained in:
zm-oai
2026-10-06 03:43:22 +00:00
committed by copyberry
parent 7ac954ea24
commit 580b18cb74
3 changed files with 54 additions and 20 deletions
@@ -216,6 +216,9 @@ impl WindowsSandboxRequestProcessor {
&service_setup_request.command_cwd,
)?;
}
if codex_windows_sandbox::registered_core_requested() {
codex_windows_sandbox::start_windows_sandbox_service_for_setup()?;
}
// The shared setup path below handles helper fallback and
// refreshes workspace ACLs after provisioning.
codex_windows_sandbox::provision_windows_sandbox_via_service(
+2
View File
@@ -372,6 +372,8 @@ pub use provisioning_client::refresh_registered_core_via_service;
#[cfg(target_os = "windows")]
pub use provisioning_client::register_desktop_installation;
#[cfg(target_os = "windows")]
pub use provisioning_client::start_windows_sandbox_service_for_setup;
#[cfg(target_os = "windows")]
pub use provisioning_protocol::FramedProvisioningMessage;
#[cfg(target_os = "windows")]
pub use provisioning_protocol::PROVISIONING_PROTOCOL_VERSION;
@@ -26,6 +26,7 @@ use windows_sys::Win32::Foundation::ERROR_NO_DATA;
use windows_sys::Win32::Foundation::ERROR_PIPE_BUSY;
use windows_sys::Win32::Foundation::ERROR_PIPE_NOT_CONNECTED;
use windows_sys::Win32::Foundation::ERROR_SEM_TIMEOUT;
use windows_sys::Win32::Foundation::ERROR_SERVICE_ALREADY_RUNNING;
use windows_sys::Win32::Foundation::ERROR_SERVICE_DOES_NOT_EXIST;
use windows_sys::Win32::Foundation::ERROR_SERVICE_MARKED_FOR_DELETE;
use windows_sys::Win32::Foundation::HANDLE;
@@ -189,6 +190,37 @@ fn service_unavailable() -> anyhow::Result<WindowsSandboxProvisioningOutcome> {
Ok(WindowsSandboxProvisioningOutcome::Unavailable)
}
/// Starts a stopped service only for explicit setup. The normal connection path
/// waits for startup and authenticates the pipe server; SCM authorizes the start.
pub fn start_windows_sandbox_service_for_setup() -> anyhow::Result<()> {
query_service_status()
.and_then(|status| {
if status.dwCurrentState == Services::SERVICE_STOPPED {
let service = open_service(Services::SERVICE_START)
.context("request permission to start sandbox service for setup")?;
if unsafe { Services::StartServiceW(service.0, 0, ptr::null()) } == 0 {
let error = io::Error::last_os_error();
if error.raw_os_error() != Some(ERROR_SERVICE_ALREADY_RUNNING as i32) {
return Err(error).context("start sandbox service for setup");
}
}
}
Ok(())
})
.or_else(|error| {
if error.downcast_ref::<io::Error>().is_some_and(|error| {
matches!(error.raw_os_error(), Some(code)
if code == ERROR_SERVICE_DOES_NOT_EXIST as i32
|| code == ERROR_SERVICE_MARKED_FOR_DELETE as i32)
}) {
// The connection path preserves registered Core's no-fallback error.
Ok(())
} else {
Err(error)
}
})
}
/// Records desktop uninstall ownership without creating or enabling a sandbox.
pub fn register_desktop_installation(codex_home: &Path) -> anyhow::Result<()> {
let request = crate::FramedProvisioningMessage {
@@ -385,26 +417,7 @@ fn verify_server(pipe: HANDLE) -> anyhow::Result<u32> {
}
fn query_service_status() -> anyhow::Result<Services::SERVICE_STATUS_PROCESS> {
let manager =
unsafe { Services::OpenSCManagerW(ptr::null(), ptr::null(), Services::SC_MANAGER_CONNECT) };
if manager.is_null() {
return Err(io::Error::last_os_error()).context("open service control manager");
}
let manager = ServiceHandle(manager);
let service_name = crate::to_wide(crate::windows_sandbox_service_name()?);
let service = unsafe {
Services::OpenServiceW(
manager.0,
service_name.as_ptr(),
Services::SERVICE_QUERY_STATUS,
)
};
if service.is_null() {
return Err(io::Error::last_os_error()).context("open sandbox provisioning service");
}
let service = ServiceHandle(service);
let service = open_service(Services::SERVICE_QUERY_STATUS)?;
let mut status: Services::SERVICE_STATUS_PROCESS = unsafe { std::mem::zeroed() };
let mut bytes_needed = 0;
if unsafe {
@@ -425,6 +438,22 @@ fn query_service_status() -> anyhow::Result<Services::SERVICE_STATUS_PROCESS> {
Ok(status)
}
fn open_service(access: u32) -> anyhow::Result<ServiceHandle> {
let manager =
unsafe { Services::OpenSCManagerW(ptr::null(), ptr::null(), Services::SC_MANAGER_CONNECT) };
if manager.is_null() {
return Err(io::Error::last_os_error()).context("open service control manager");
}
let manager = ServiceHandle(manager);
let service_name = crate::to_wide(crate::windows_sandbox_service_name()?);
let service = unsafe { Services::OpenServiceW(manager.0, service_name.as_ptr(), access) };
if service.is_null() {
return Err(io::Error::last_os_error()).context("open sandbox provisioning service");
}
Ok(ServiceHandle(service))
}
struct ServiceHandle(SC_HANDLE);
impl Drop for ServiceHandle {