Skip to content

Commit 3d4c0e0

Browse files
authored
cmdline to take the first 4 arguments (#340)
* cmdline to take the first 4 arguments * fix in common code path
1 parent c259110 commit 3d4c0e0

3 files changed

Lines changed: 76 additions & 2 deletions

File tree

.github/actions/spelling/expect.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ oneshot
207207
opencode
208208
opensource
209209
parseable
210+
peekable
210211
PERCPU
211212
pgpkey
212213
pgrep

proxy_agent/src/proxy.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub struct User {
7777

7878
const UNDEFINED: &str = "undefined";
7979
const EMPTY: &str = "empty";
80+
const MAX_CMD_ARGS: usize = 4;
8081

8182
async fn get_user(
8283
logon_id: u64,
@@ -112,10 +113,12 @@ fn get_process_info(process_id: u32) -> (PathBuf, String) {
112113
let cmdline_path = format!("/proc/{}/cmdline", process_id);
113114
let process_cmd_line = match std::fs::read(&cmdline_path) {
114115
Ok(bytes) => {
115-
// cmdline is null-separated, convert to space-separated string
116+
// cmdline is null-separated; take only the first few arguments
117+
// to avoid capturing credentials in later args
116118
bytes
117119
.split(|&b| b == 0)
118120
.filter(|s| !s.is_empty())
121+
.take(MAX_CMD_ARGS)
119122
.map(|s| String::from_utf8_lossy(s).into_owned())
120123
.collect::<Vec<String>>()
121124
.join(" ")

proxy_agent/src/proxy/windows.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,46 @@ pub fn get_process_cmd(handler: isize) -> Result<String> {
292292
std::slice::from_raw_parts(cmd_buffer.Buffer, (cmd_buffer.Length / 2) as usize)
293293
});
294294

295-
Ok(cmd)
295+
// Only keep the first few arguments to avoid capturing credentials
296+
// that may appear in later command-line arguments
297+
Ok(truncate_cmd_args(&cmd, super::MAX_CMD_ARGS))
298+
}
299+
300+
/// Truncate a command line string to at most `max_args` arguments,
301+
/// respecting double-quoted strings that may contain whitespace.
302+
fn truncate_cmd_args(cmd: &str, max_args: usize) -> String {
303+
let mut args = Vec::new();
304+
let mut chars = cmd.chars().peekable();
305+
306+
while args.len() < max_args {
307+
// Skip whitespace between arguments
308+
while chars.peek().is_some_and(|c| c.is_whitespace()) {
309+
chars.next();
310+
}
311+
if chars.peek().is_none() {
312+
break;
313+
}
314+
315+
let mut arg = String::new();
316+
if chars.peek() == Some(&'"') {
317+
// Quoted argument — consume until closing quote
318+
arg.push(chars.next().unwrap()); // opening "
319+
for c in chars.by_ref() {
320+
arg.push(c);
321+
if c == '"' {
322+
break;
323+
}
324+
}
325+
} else {
326+
// Unquoted argument — consume until whitespace
327+
while chars.peek().is_some_and(|c| !c.is_whitespace()) {
328+
arg.push(chars.next().unwrap());
329+
}
330+
}
331+
args.push(arg);
332+
}
333+
334+
args.join(" ")
296335
}
297336

298337
#[allow(dead_code)]
@@ -379,4 +418,35 @@ mod tests {
379418
);
380419
assert!(!cmd.is_empty(), "process cmd should not be empty");
381420
}
421+
422+
#[test]
423+
fn truncate_cmd_args_tests() {
424+
// no arguments
425+
let result = super::truncate_cmd_args("", 4);
426+
assert_eq!(result, "", "empty input should return empty string");
427+
428+
// fewer than max args
429+
let result = super::truncate_cmd_args("app.exe arg1", 4);
430+
assert_eq!(
431+
result, "app.exe arg1",
432+
"should return all args when fewer than max"
433+
);
434+
435+
// exactly max args
436+
let result = super::truncate_cmd_args("app.exe arg1 arg2 arg3 --secret=password", 4);
437+
assert_eq!(
438+
result, "app.exe arg1 arg2 arg3",
439+
"should truncate to first 4 args"
440+
);
441+
442+
// more than max args and quoted arg with spaces
443+
let result = super::truncate_cmd_args(
444+
r#""C:\Program Files\app.exe" arg1 "arg with spaces" arg3 --secret=password"#,
445+
4,
446+
);
447+
assert_eq!(
448+
result, r#""C:\Program Files\app.exe" arg1 "arg with spaces" arg3"#,
449+
"should treat quoted strings with whitespace as single args"
450+
);
451+
}
382452
}

0 commit comments

Comments
 (0)