From 91f6aa4e7b37ccc97359ec69f7d5d6dba0585b92 Mon Sep 17 00:00:00 2001 From: Sebastien Tardif Date: Wed, 24 Jun 2026 10:54:11 -0700 Subject: [PATCH] std: reject interior NULs in UEFI process::Command argument encoding create_args copied program and arg OsStrs into a wide LoadOptions buffer without rejecting embedded 0 units. UEFI treats these as C-style wide strings (see os_string_to_raw / OwnedDevicePath::from_text), so an interior NUL would truncate the command line. Return InvalidInput early. Signed-off-by: Sebastien Tardif --- library/std/src/sys/process/uefi.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index e0c4fa579275a..70499737d975e 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -152,7 +152,7 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec // UEFI adds the bin name by default if !command.args.is_empty() { - let args = uefi_command_internal::create_args(&command.prog, &command.args); + let args = uefi_command_internal::create_args(&command.prog, &command.args)?; cmd.set_args(args); } @@ -872,12 +872,30 @@ mod uefi_command_internal { } } - pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { + pub fn create_args(prog: &OsStr, args: &[OsString]) -> io::Result> { const QUOTE: u16 = 0x0022; const SPACE: u16 = 0x0020; const CARET: u16 = 0x005e; const NULL: u16 = 0; + // Interior wide NULs would truncate the UEFI LoadOptions / shell command + // line the same way WinAPI C strings do; reject early (see os_string_to_raw). + fn ensure_no_interior_nul(s: &OsStr) -> io::Result<()> { + if s.encode_wide().any(|c| c == NULL) { + Err(io::const_error!( + io::ErrorKind::InvalidInput, + "strings passed to UEFI cannot contain NULs", + )) + } else { + Ok(()) + } + } + + ensure_no_interior_nul(prog)?; + for arg in args { + ensure_no_interior_nul(arg)?; + } + // This is the lower bound on the final length under the assumption that // the arguments only contain ASCII characters. let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum()); @@ -902,7 +920,7 @@ mod uefi_command_internal { res.push(QUOTE); } - res.into_boxed_slice() + Ok(res.into_boxed_slice()) } }