-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
175 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/target | ||
/Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "set_cmdline_from_stdin" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
base64 = "0.21.7" | ||
killmyargv = { path = "../.." } | ||
|
||
# A deliberately empty workspace section so that Cargo doesn't try to search | ||
# upwards, just in case the parent manifest is broken. See: | ||
# https://github.com/rust-lang/cargo/issues/10872#issuecomment-1186112506 | ||
[workspace] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use std::{ | ||
error::Error, | ||
io::{stdin, BufRead}, | ||
}; | ||
|
||
use base64::{ | ||
alphabet, | ||
engine::{general_purpose::GeneralPurpose, GeneralPurposeConfig}, | ||
Engine, | ||
}; | ||
use killmyargv::KillMyArgv; | ||
|
||
fn main() -> Result<(), Box<dyn Error>> { | ||
let stdin = stdin().lock(); | ||
let alphabet = alphabet::STANDARD; | ||
let config = GeneralPurposeConfig::default(); | ||
let engine = GeneralPurpose::new(&alphabet, config); | ||
|
||
let kill_my_argv = KillMyArgv::new()?; | ||
|
||
if let Some(output_argv_max_len) = std::env::args().nth(1) { | ||
if "true" == &output_argv_max_len { | ||
println!("{}", kill_my_argv.max_len()) | ||
} | ||
} | ||
|
||
for next_cmd_line in stdin.lines() { | ||
let cmd_line = next_cmd_line?; | ||
let cmd_line = engine.decode(&cmd_line)?; | ||
kill_my_argv.set(&cmd_line); | ||
|
||
println!("set done"); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,52 @@ | ||
use std::{error::Error, process}; | ||
|
||
use killmyargv::KillMyArgv; | ||
use sysinfo::{Pid, ProcessRefreshKind}; | ||
use utils::{get_set_cmdline_path, set_cmdline, set_cmdline_with_child}; | ||
|
||
#[test] | ||
fn test_set_cmdline() -> Result<(), Box<dyn Error>> { | ||
// KillMyArgv is unsafe to call in parallel. | ||
// When we add new tests, we must either set this variable, | ||
// or use a `Mutex` lock | ||
// | ||
// assert_eq!(env!("RUST_TEST_THREADS"), 1); | ||
let pid = Pid::from_u32(process::id()); | ||
let mut system = sysinfo::System::new(); | ||
let kill_my_argv = KillMyArgv::new()?; | ||
fn test_set_cmdline_once() -> Result<()> { | ||
set_cmdline(["Hello?"], [vec!["Hello?"]])?; | ||
set_cmdline(["Hi\0there!"], [vec!["Hi", "there!"]])?; | ||
Ok(()) | ||
} | ||
|
||
for case_str in [ | ||
"MAGIC USED HERE\0-p LOL", | ||
"Or\0This\0--help\0--secret=***********", | ||
] { | ||
kill_my_argv.set(case_str.as_bytes()); | ||
#[test] | ||
fn test_set_cmdline_multiple_times() -> Result<()> { | ||
// Note: On a sort of OS, when `**argv` is not continuous to `envp`, | ||
// cmdline terminates on it's first NUL byte. | ||
set_cmdline( | ||
["Hello?", "Hi\0there!"], | ||
[vec!["Hello?"], vec!["Hi", "there!"]], | ||
)?; | ||
Ok(()) | ||
} | ||
|
||
let args = case_str | ||
.split_terminator('\0') | ||
.map(|s| s.to_owned()) | ||
.collect::<Vec<String>>(); | ||
assert!(system.refresh_process_specifics( | ||
pid, | ||
ProcessRefreshKind::new().with_cmd(sysinfo::UpdateKind::Always) | ||
)); | ||
let set_cmdline_process = system.process(pid).expect("set-cmdline exits unexpectedly"); | ||
assert_eq!(set_cmdline_process.cmd(), &args); | ||
} | ||
#[test] | ||
fn test_set_cmdline_truncate_max_len() -> Result<()> { | ||
let set_cmdline_path = get_set_cmdline_path()?; | ||
let mut child = Command::new(set_cmdline_path) | ||
.arg("true") | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.spawn()?; | ||
let child_pid = child.id(); | ||
let child_stdin = child.stdin.take().unwrap(); | ||
let child_stdout = child.stdout.take().unwrap(); | ||
|
||
let mut reader = linereader::LineReader::new(child_stdout); | ||
let max_len = reader.next_line().unwrap()?; | ||
let max_len = String::from_utf8_lossy(max_len).trim().parse()?; | ||
let expected = "o".repeat(max_len); | ||
let input = "o".repeat(max_len * 1); | ||
set_cmdline_with_child( | ||
[input], | ||
[vec![expected]], | ||
child_stdin, | ||
reader.into_inner(), | ||
child_pid, | ||
)?; | ||
Ok(()) | ||
} | ||
|
||
mod utils; | ||
|
||
use std::error::Error; | ||
use std::process::{Command, Stdio}; | ||
type Result<T> = std::result::Result<T, Box<dyn Error>>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
use base64::alphabet::STANDARD; | ||
use base64::engine::GeneralPurpose; | ||
use base64::Engine; | ||
use sysinfo::{Pid, ProcessRefreshKind}; | ||
use test_binary::build_test_binary; | ||
|
||
pub fn get_set_cmdline_path() -> Result<OsString> { | ||
Ok(build_test_binary("set_cmdline_from_stdin", "testbin")?) | ||
} | ||
|
||
pub fn set_cmdline( | ||
inputs: impl IntoIterator<Item = impl AsRef<str>>, | ||
results: impl IntoIterator<Item = impl IntoIterator<Item = impl AsRef<str>>>, | ||
) -> Result<()> { | ||
let set_cmdline_path = get_set_cmdline_path()?; | ||
let mut set_cmdline = std::process::Command::new(set_cmdline_path) | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.spawn()?; | ||
let child_stdin = Option::take(&mut set_cmdline.stdin).unwrap(); | ||
let child_stdout = Option::take(&mut set_cmdline.stdout).unwrap(); | ||
let child_pid = set_cmdline.id(); | ||
|
||
set_cmdline_with_child(inputs, results, child_stdin, child_stdout, child_pid) | ||
} | ||
|
||
pub fn set_cmdline_with_child( | ||
inputs: impl IntoIterator<Item = impl AsRef<str>>, | ||
results: impl IntoIterator<Item = impl IntoIterator<Item = impl AsRef<str>>>, | ||
mut child_stdin: ChildStdin, | ||
child_stdout: ChildStdout, | ||
child_pid: u32, | ||
) -> Result<()> { | ||
let mut child_stdout = linereader::LineReader::new(child_stdout); | ||
let pid = Pid::from_u32(child_pid); | ||
let engine = GeneralPurpose::new(&STANDARD, Default::default()); | ||
let mut system = sysinfo::System::new(); | ||
|
||
for (case_str, results) in inputs.into_iter().zip(results) { | ||
let case_base64 = engine | ||
.encode(case_str.as_ref()) | ||
.bytes() | ||
.filter(|ch| ch != &b'\n') | ||
.collect::<Vec<_>>(); | ||
child_stdin.write(&case_base64)?; | ||
child_stdin.write(&[b'\n'])?; | ||
child_stdin.flush()?; | ||
|
||
if let Some(line) = child_stdout.next_line() { | ||
line?; | ||
} | ||
|
||
assert!(system.refresh_process_specifics( | ||
pid, | ||
ProcessRefreshKind::new().with_cmd(sysinfo::UpdateKind::Always) | ||
)); | ||
let set_cmdline_process = system.process(pid).expect("set-cmdline exits unexpectedly"); | ||
let actual_cmdline = set_cmdline_process.cmd(); | ||
let expected_cmdline = results | ||
.into_iter() | ||
.map(|s| s.as_ref().to_owned()) | ||
.collect::<Vec<String>>(); | ||
assert_eq!(actual_cmdline, &expected_cmdline); | ||
} | ||
Ok(()) | ||
} | ||
|
||
use std::{ | ||
error::Error, | ||
ffi::OsString, | ||
io::Write, | ||
process::{ChildStdin, ChildStdout, Stdio}, | ||
}; | ||
type Result<T> = std::result::Result<T, Box<dyn Error>>; |