From 1126e2f6f330352c6fc81087ff819b9f62a8ef46 Mon Sep 17 00:00:00 2001 From: pancake Date: Mon, 9 Mar 2026 23:43:36 +0100 Subject: [PATCH] sanitize debugger argv before building r2 doo command --- radius/src/r2_api.rs | 45 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/radius/src/r2_api.rs b/radius/src/r2_api.rs index f949f9e..acba1dc 100644 --- a/radius/src/r2_api.rs +++ b/radius/src/r2_api.rs @@ -213,7 +213,6 @@ pub struct SearchResult { pub data: String, } - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DisasmSearchResult { pub addr: u64, @@ -516,6 +515,30 @@ pub struct R2Api { } impl R2Api { + fn escape_debug_arg(arg: &str) -> String { + let mut escaped = String::from("\""); + for ch in arg.chars() { + match ch { + '\\' | '"' => { + escaped.push('\\'); + escaped.push(ch); + } + '\n' => escaped.push_str("\\n"), + '\r' => escaped.push_str("\\r"), + _ => escaped.push(ch), + } + } + escaped.push('"'); + escaped + } + + fn escape_debug_args(args: &[String]) -> String { + args.iter() + .map(|arg| Self::escape_debug_arg(arg)) + .collect::>() + .join(" ") + } + pub fn new>(filename: Option, opts: Option>) -> R2Api { let options = &opts.as_ref().map(|o| R2PipeSpawnOptions { exepath: "r2".to_owned(), @@ -899,7 +922,8 @@ impl R2Api { Mode::Frida => panic!("can't enter debug from frida mode, also why would you?"), _ => { self.mode = Mode::Debugger; - self.cmd(&format!("doo {};db {};dc", args.join(" "), addr)) + let escaped_args = Self::escape_debug_args(args); + self.cmd(&format!("doo {};db {};dc", escaped_args, addr)) } }) .unwrap_or_default(); @@ -1209,3 +1233,20 @@ impl R2Api { self.r2p.lock().unwrap().close(); } } + +#[cfg(test)] +mod tests { + use super::R2Api; + + #[test] + fn escape_debug_args_quotes_each_argument() { + let args = vec!["arg1".to_owned(), "arg 2".to_owned()]; + assert_eq!(R2Api::escape_debug_args(&args), "\"arg1\" \"arg 2\""); + } + + #[test] + fn escape_debug_args_escapes_quotes_backslashes_and_newlines() { + let args = vec!["a\"b\\c\nd\r".to_owned()]; + assert_eq!(R2Api::escape_debug_args(&args), "\"a\\\"b\\\\c\\nd\\r\""); + } +}