From 4fb835ee64031b4df2cf5922b5b24a3edec2cde3 Mon Sep 17 00:00:00 2001 From: Nguyen Duc Toan Date: Wed, 4 Oct 2023 00:05:07 +0700 Subject: [PATCH] prevent arbitrary code execution when expanding path --- shared/src/fns.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/shared/src/fns.rs b/shared/src/fns.rs index d1b5dbc8..3ebcf268 100644 --- a/shared/src/fns.rs +++ b/shared/src/fns.rs @@ -10,11 +10,19 @@ pub fn expand_path(p: impl AsRef) -> PathBuf { // expand the environment variable by calling the "echo" command, in linux case, this also expands the '~' path #[cfg(target_os = "windows")] let expanded_path = match std::process::Command::new("cmd").args(&["/C", "echo"]).arg(p).output() { - Ok(output) if output.status.success() => Some(String::from_utf8_lossy(&output.stdout).trim_end().to_string()), + Ok(output) if output.status.success() => Some(String::from_utf8_lossy(&output.stdout) + .trim_end() + .trim_matches('"') + .replace("\\\"", "\"") + .to_string() + ), _ => None, }; #[cfg(not(target_os = "windows"))] - let expanded_path = match std::process::Command::new("sh").arg("-c").arg(format!("echo {}", p.display())).output() { + let expanded_path = match std::process::Command::new("sh") + .arg("-c") + .arg(format!("echo \"{}\"", p.to_string_lossy().replace("\"", "\\\""))) + .output() { Ok(output) if output.status.success() => Some(String::from_utf8_lossy(&output.stdout).trim_end().to_string()), _ => None, }; @@ -160,9 +168,11 @@ pub fn optional_bool(s: &str) -> Option { #[cfg(test)] mod tests { - use std::{borrow::Cow, path::Path}; + use std::{borrow::Cow, path::Path, env}; - use super::path_relative_to; + use crate::expand_path; + +use super::path_relative_to; #[cfg(unix)] #[test] @@ -191,4 +201,19 @@ mod tests { assert("C:\\a", "C:\\a\\b\\c", "..\\..\\"); assert("C:\\a\\a\\b", "C:\\a\\b\\b", "..\\..\\a\\b"); } + + #[test] + fn test_expand_path() { + let path_s = r#"a"b"#; + assert_eq!(expand_path(path_s), env::current_dir().unwrap().join(std::path::Path::new(path_s))); + + let path_s = r#"a'b"#; + assert_eq!(expand_path(path_s), env::current_dir().unwrap().join(std::path::Path::new(path_s))); + + let path_s = r#"a; x b"#; + assert_eq!(expand_path(path_s), env::current_dir().unwrap().join(std::path::Path::new(path_s))); + + let path_s = r#"a && x b"#; + assert_eq!(expand_path(path_s), env::current_dir().unwrap().join(std::path::Path::new(path_s))); + } }