Document Windows argument splitting
This commit is contained in:
parent
f66a096607
commit
ceedae178e
@ -199,8 +199,60 @@ pub trait CommandExt: Sealed {
|
||||
|
||||
/// Append literal text to the command line without any quoting or escaping.
|
||||
///
|
||||
/// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow
|
||||
/// `CommandLineToArgvW` escaping rules.
|
||||
/// This is useful for passing arguments to applications which doesn't follow
|
||||
/// the standard C run-time escaping rules, such as `cmd.exe /c`.
|
||||
///
|
||||
/// # Bat files
|
||||
///
|
||||
/// Note the `cmd /c` command line has slightly different escaping rules then bat files
|
||||
/// themselves. If possible, it may be better to write complex arguments to a temporary
|
||||
/// .bat file, with appropriate escaping, and simply run that using:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::process::Command;
|
||||
/// # let temp_bat_file = "";
|
||||
/// # #[allow(unused)]
|
||||
/// let output = Command::new("cmd").args(["/c", &format!("\"{temp_bat_file}\"")]).output();
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Run a bat script using both trusted and untrusted arguments.
|
||||
///
|
||||
/// ```no_run
|
||||
/// #[cfg(windows)]
|
||||
/// // `my_script_path` is a path to known bat file.
|
||||
/// // `user_name` is an untrusted name given by the user.
|
||||
/// fn run_script(
|
||||
/// my_script_path: &str,
|
||||
/// user_name: &str,
|
||||
/// ) -> Result<std::process::Output, std::io::Error> {
|
||||
/// use std::io::{Error, ErrorKind};
|
||||
/// use std::os::windows::process::CommandExt;
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// // Create the command line, making sure to quote the script path.
|
||||
/// // This assumes the fixed arguments have been tested to work with the script we're using.
|
||||
/// let mut cmd_args = format!(r#""{my_script_path}" "--features=[a,b,c]""#);
|
||||
///
|
||||
/// // Make sure the user name is safe. In particular we need to be
|
||||
/// // cautious of ascii symbols that cmd may interpret specially.
|
||||
/// // Here we only allow alphanumeric characters.
|
||||
/// if !user_name.chars().all(|c| c.is_alphanumeric()) {
|
||||
/// return Err(Error::new(ErrorKind::InvalidInput, "invalid user name"));
|
||||
/// }
|
||||
/// // now we've checked the user name, let's add that too.
|
||||
/// cmd_args.push(' ');
|
||||
/// cmd_args.push_str(&format!("--user {user_name}"));
|
||||
///
|
||||
/// // call cmd.exe and return the output
|
||||
/// Command::new("cmd.exe")
|
||||
/// .arg("/c")
|
||||
/// // surround the entire command in an extra pair of quotes, as required by cmd.exe.
|
||||
/// .raw_arg(&format!("\"{cmd_args}\""))
|
||||
/// .output()
|
||||
/// }
|
||||
/// ````
|
||||
#[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
|
||||
fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
|
||||
|
||||
|
@ -88,6 +88,47 @@
|
||||
//! assert_eq!(b"test", output.stdout.as_slice());
|
||||
//! ```
|
||||
//!
|
||||
//! # Windows argument splitting
|
||||
//!
|
||||
//! On Unix systems arguments are passed to a new process as an array of strings
|
||||
//! but on Windows arguments are passed as a single commandline string and it's
|
||||
//! up to the child process to parse it into an array. Therefore the parent and
|
||||
//! child processes must agree on how the commandline string is encoded.
|
||||
//!
|
||||
//! Most programs use the standard C run-time `argv`, which in practice results
|
||||
//! in consistent argument handling. However some programs have their own way of
|
||||
//! parsing the commandline string. In these cases using [`arg`] or [`args`] may
|
||||
//! result in the child process seeing a different array of arguments then the
|
||||
//! parent process intended.
|
||||
//!
|
||||
//! Two ways of mitigating this are:
|
||||
//!
|
||||
//! * Validate untrusted input so that only a safe subset is allowed.
|
||||
//! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping
|
||||
//! rules used by [`arg`] so should be used with due caution.
|
||||
//!
|
||||
//! `cmd.exe` and `.bat` use non-standard argument parsing and are especially
|
||||
//! vulnerable to malicious input as they may be used to run arbitrary shell
|
||||
//! commands. Untrusted arguments should be restricted as much as possible.
|
||||
//! For examples on handling this see [`raw_arg`].
|
||||
//!
|
||||
//! ### Bat file special handling
|
||||
//!
|
||||
//! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to
|
||||
//! spawn new processes. An undocumented feature of this function is that,
|
||||
//! when given a `.bat` file as the application to run, it will automatically
|
||||
//! convert that into running `cmd.exe /c` with the bat file as the next argument.
|
||||
//!
|
||||
//! For historical reasons Rust currently preserves this behaviour when using
|
||||
//! [`Command::new`], and escapes the arguments according to `cmd.exe` rules.
|
||||
//! Due to the complexity of `cmd.exe` argument handling, it might not be
|
||||
//! possible to safely escape some special chars, and using them will result
|
||||
//! in an error being returned at process spawn. The set of unescapeable
|
||||
//! special chars might change between releases.
|
||||
//!
|
||||
//! Also note that running `.bat` scripts in this way may be removed in the
|
||||
//! future and so should not be relied upon.
|
||||
//!
|
||||
//! [`spawn`]: Command::spawn
|
||||
//! [`output`]: Command::output
|
||||
//!
|
||||
@ -97,6 +138,12 @@
|
||||
//!
|
||||
//! [`Write`]: io::Write
|
||||
//! [`Read`]: io::Read
|
||||
//!
|
||||
//! [`arg`]: Command::arg
|
||||
//! [`args`]: Command::args
|
||||
//! [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg
|
||||
//!
|
||||
//! [`CreateProcessW`]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
|
||||
|
||||
#![stable(feature = "process", since = "1.0.0")]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
@ -611,6 +658,22 @@ impl Command {
|
||||
/// escaped characters, word splitting, glob patterns, variable substitution, etc.
|
||||
/// have no effect.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// On Windows use caution with untrusted inputs. Most applications use the
|
||||
/// standard convention for decoding arguments passed to them. These are safe to use with `arg`.
|
||||
/// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
|
||||
/// and are therefore vulnerable to malicious input.
|
||||
/// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
|
||||
///
|
||||
/// See [Windows argument splitting][windows-args] for more details
|
||||
/// or [`raw_arg`] for manually implementing non-standard argument encoding.
|
||||
///
|
||||
/// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg
|
||||
/// [windows-args]: crate::process#windows-argument-splitting
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
@ -641,6 +704,22 @@ impl Command {
|
||||
/// escaped characters, word splitting, glob patterns, variable substitution, etc.
|
||||
/// have no effect.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// On Windows use caution with untrusted inputs. Most applications use the
|
||||
/// standard convention for decoding arguments passed to them. These are safe to use with `args`.
|
||||
/// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
|
||||
/// and are therefore vulnerable to malicious input.
|
||||
/// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
|
||||
///
|
||||
/// See [Windows argument splitting][windows-args] for more details
|
||||
/// or [`raw_arg`] for manually implementing non-standard argument encoding.
|
||||
///
|
||||
/// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg
|
||||
/// [windows-args]: crate::process#windows-argument-splitting
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
Loading…
x
Reference in New Issue
Block a user