host_env: Reject interior NULs for CreateProcessW (#8555)

This commit is contained in:
Joshua Megnauth authored and GitHub committed 2026-08-19 13:13:03 +09:00
1 parent a0eec84cb0
commit aaa4e65364
1 file changed
+23 -37
+23 -37
View File
@@ -188,7 +188,7 @@ pub fn create_file_w(
/// `startup_info` must point to a valid `STARTUPINFOW` (or extended).
unsafe fn create_process_w_raw(
app_name: Option<&widestring::WideCStr>,
command_line: Option<&mut [u16]>,
command_line: Option<&mut widestring::WideCStr>,
inherit_handles: i32,
creation_flags: u32,
env: Option<&[u16]>,
@@ -214,37 +214,6 @@ unsafe fn create_process_w_raw(
Ok(unsafe { procinfo.assume_init() })
}
/// Win32 `CreateProcessW` requires `lpCommandLine` to be NUL-terminated.
/// The buffer is passed `&mut [u16]` because `CreateProcessW` may modify it
/// in place.
#[inline]
fn validate_command_line_terminated(buf: &[u16]) -> io::Result<()> {
if buf.last() == Some(&0) {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"command_line buffer passed to create_process must be NUL-terminated",
))
}
}
/// Win32 `CreateProcessW` with `CREATE_UNICODE_ENVIRONMENT` requires
/// `lpEnvironment` to be a sequence of `KEY=value\0` strings followed by a
/// final terminating `\0` — i.e. the block ends with two consecutive zero
/// `u16`s.
#[inline]
fn validate_environment_block_terminated(buf: &[u16]) -> io::Result<()> {
if buf.len() >= 2 && buf[buf.len() - 2..] == [0, 0] {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"env block passed to create_process must end with a double NUL terminator",
))
}
}
#[allow(
clippy::too_many_arguments,
reason = "This is the semantic host wrapper for Win32 CreateProcess parameters."
@@ -259,11 +228,28 @@ pub fn create_process(
startup_info: StartupInfoData,
handle_list: Option<Vec<usize>>,
) -> io::Result<ProcessInfo> {
if let Some(cmd) = command_line.as_deref() {
validate_command_line_terminated(cmd)?;
}
if let Some(env_block) = env {
validate_environment_block_terminated(env_block)?;
// Win32 `CreateProcessW` requires `lpCommandLine` to be NUL-terminated.
// The buffer is passed `&mut [u16]` because `CreateProcessW` may modify it in place.
let command_line = command_line
.map(widestring::WideCStr::from_slice_mut)
.transpose()
.map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"command_line buffer passed to create_process must be NUL-terminated",
)
})?;
// Win32 `CreateProcessW` with `CREATE_UNICODE_ENVIRONMENT` requires
// `lpEnvironment` to be a sequence of `KEY=value\0` strings followed by a
// final terminating `\0` — i.e. the block ends with two consecutive zero
// `u16`s.
if let Some(env_block) = env
&& !env_block.ends_with(&[0, 0])
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"env block passed to create_process must end with a double NUL terminator",
));
}
let mut si: windows_sys::Win32::System::Threading::STARTUPINFOEXW =