Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add env & tr fuzzers + small improvs #6167

Merged
merged 4 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/fuzzing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ jobs:
- { name: fuzz_wc, should_pass: false }
- { name: fuzz_cut, should_pass: false }
- { name: fuzz_split, should_pass: false }
- { name: fuzz_tr, should_pass: false }
- { name: fuzz_env, should_pass: false }
- { name: fuzz_parse_glob, should_pass: true }
- { name: fuzz_parse_size, should_pass: true }
- { name: fuzz_parse_time, should_pass: true }
Expand Down
14 changes: 14 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ uu_sort = { path = "../src/uu/sort/" }
uu_wc = { path = "../src/uu/wc/" }
uu_cut = { path = "../src/uu/cut/" }
uu_split = { path = "../src/uu/split/" }
uu_tr = { path = "../src/uu/tr/" }
uu_env = { path = "../src/uu/env/" }

# Prevent this from interfering with workspaces
[workspace]
Expand Down Expand Up @@ -107,3 +109,15 @@ name = "fuzz_parse_time"
path = "fuzz_targets/fuzz_parse_time.rs"
test = false
doc = false

[[bin]]
name = "fuzz_tr"
path = "fuzz_targets/fuzz_tr.rs"
test = false
doc = false

[[bin]]
name = "fuzz_env"
path = "fuzz_targets/fuzz_env.rs"
test = false
doc = false
1 change: 1 addition & 0 deletions fuzz/fuzz_targets/fuzz_echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn generate_echo() -> String {
// Randomly decide whether to include options
let include_n = rng.gen_bool(0.1); // 10% chance
let include_e = rng.gen_bool(0.1); // 10% chance
#[allow(non_snake_case)]
let include_E = rng.gen_bool(0.1); // 10% chance

if include_n {
Expand Down
97 changes: 97 additions & 0 deletions fuzz/fuzz_targets/fuzz_env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore chdir

#![no_main]
use libfuzzer_sys::fuzz_target;
use uu_env::uumain;

use std::ffi::OsString;

mod fuzz_common;
use crate::fuzz_common::{
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd, CommandResult,
};
use rand::Rng;

static CMD_PATH: &str = "env";

fn generate_env_args() -> Vec<String> {
let mut rng = rand::thread_rng();
let mut args = Vec::new();

let opts = ["-i", "-0", "-v", "-vv"];
for opt in &opts {
if rng.gen_bool(0.2) {
args.push(opt.to_string());
}
}

if rng.gen_bool(0.3) {
args.push(format!(
"-u={}",
generate_random_string(rng.gen_range(3..10))
));
}

if rng.gen_bool(0.2) {
args.push(format!("--chdir={}", "/tmp")); // Simplified example
}

/*
Options not implemented for now
if rng.gen_bool(0.15) {
let sig_opts = ["--block-signal"];//, /*"--default-signal",*/ "--ignore-signal"];
let chosen_sig_opt = sig_opts[rng.gen_range(0..sig_opts.len())];
args.push(chosen_sig_opt.to_string());
// Simplify by assuming SIGPIPE for demonstration
if !chosen_sig_opt.ends_with("list-signal-handling") {
args.push(String::from("SIGPIPE"));
}
}*/

// Adding a few random NAME=VALUE pairs
for _ in 0..rng.gen_range(0..3) {
args.push(format!(
"{}={}",
generate_random_string(5),
generate_random_string(5)
));
}

args
}

fuzz_target!(|_data: &[u8]| {
let env_args = generate_env_args();
let mut args = vec![OsString::from("env")];
args.extend(env_args.iter().map(OsString::from));
let input_lines = generate_random_string(10);

let rust_result = generate_and_run_uumain(&args, uumain, Some(&input_lines));

let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false, None) {
Ok(result) => result,
Err(error_result) => {
eprintln!("Failed to run GNU command:");
eprintln!("Stderr: {}", error_result.stderr);
eprintln!("Exit Code: {}", error_result.exit_code);
CommandResult {
stdout: String::new(),
stderr: error_result.stderr,
exit_code: error_result.exit_code,
}
}
};

compare_result(
"env",
&format!("{:?}", &args[1..]),
None,
&rust_result,
&gnu_result,
false,
);
});
3 changes: 2 additions & 1 deletion fuzz/fuzz_targets/fuzz_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ static CMD_PATH: &str = "expr";
fn generate_expr(max_depth: u32) -> String {
let mut rng = rand::thread_rng();
let ops = [
"+", "-", "*", "/", "%", "<", ">", "=", "&", "|", "!=", "<=", ">=", ":", "index", "length", "substr",
"+", "-", "*", "/", "%", "<", ">", "=", "&", "|", "!=", "<=", ">=", ":", "index", "length",
"substr",
];

let mut expr = String::new();
Expand Down
1 change: 1 addition & 0 deletions fuzz/fuzz_targets/fuzz_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::fuzz_common::{
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd,
};

#[allow(clippy::upper_case_acronyms)]
#[derive(PartialEq, Debug, Clone)]
enum ArgType {
STRING,
Expand Down
73 changes: 73 additions & 0 deletions fuzz/fuzz_targets/fuzz_tr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#![no_main]
use libfuzzer_sys::fuzz_target;
use std::ffi::OsString;
use uu_tr::uumain;

use rand::Rng;

mod fuzz_common;
use crate::fuzz_common::{
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd, CommandResult,
};
static CMD_PATH: &str = "tr";

fn generate_tr_args() -> Vec<String> {
let mut rng = rand::thread_rng();
let mut args = Vec::new();

// Translate, squeeze, and/or delete characters
let opts = ["-c", "-d", "-s", "-t"];
for opt in &opts {
if rng.gen_bool(0.25) {
args.push(opt.to_string());
}
}

// Generating STRING1 and optionally STRING2
let string1 = generate_random_string(rng.gen_range(1..=20));
args.push(string1);
if rng.gen_bool(0.7) {
// Higher chance to add STRING2 for translation
let string2 = generate_random_string(rng.gen_range(1..=20));
args.push(string2);
}

args
}

fuzz_target!(|_data: &[u8]| {
let tr_args = generate_tr_args();
let mut args = vec![OsString::from("tr")];
args.extend(tr_args.iter().map(OsString::from));

let input_chars = generate_random_string(100);

let rust_result = generate_and_run_uumain(&args, uumain, Some(&input_chars));
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false, Some(&input_chars)) {
Ok(result) => result,
Err(error_result) => {
eprintln!("Failed to run GNU command:");
eprintln!("Stderr: {}", error_result.stderr);
eprintln!("Exit Code: {}", error_result.exit_code);
CommandResult {
stdout: String::new(),
stderr: error_result.stderr,
exit_code: error_result.exit_code,
}
}
};

compare_result(
"tr",
&format!("{:?}", &args[1..]),
Some(&input_chars),
&rust_result,
&gnu_result,
false,
);
});
Loading