From 04f130ac08115c013c1603cbdedf0f0fc68599dc Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 18 Jul 2024 23:43:24 +0200 Subject: [PATCH] fuzzing: add a new fuzzer for cksum --- fuzz/Cargo.lock | 289 ++++++++++++++++++++++++++++--- fuzz/Cargo.toml | 7 + fuzz/fuzz_targets/fuzz_cksum.rs | 164 ++++++++++++++++++ fuzz/fuzz_targets/fuzz_common.rs | 6 +- 4 files changed, 439 insertions(+), 27 deletions(-) create mode 100644 fuzz/fuzz_targets/fuzz_cksum.rs diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 4f7c56089..a95718bd4 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -81,6 +81,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.3.0" @@ -121,6 +133,39 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "1.9.1" @@ -146,13 +191,13 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "cc" -version = "1.0.98" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -245,12 +290,27 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cpufeatures" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -282,6 +342,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ctrlc" version = "3.4.4" @@ -292,6 +362,42 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-encoding-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +dependencies = [ + "data-encoding", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dlv-list" version = "0.5.2" @@ -335,6 +441,16 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -358,6 +474,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -414,6 +536,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + [[package]] name = "libc" version = "0.2.161" @@ -449,6 +580,16 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.2" @@ -743,21 +884,79 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.65", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "similar" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +[[package]] +name = "sm3" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb9a3b702d0a7e33bc4d85a14456633d2b165c2ad839c5fd9a8417c1ab15860" +dependencies = [ + "digest", +] + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.65" @@ -809,7 +1008,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.65", ] [[package]] @@ -827,6 +1026,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -845,9 +1050,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uu_cksum" +version = "0.0.28" +dependencies = [ + "clap", + "hex", + "regex", + "uucore", +] + [[package]] name = "uu_cut" -version = "0.0.27" +version = "0.0.28" dependencies = [ "bstr", "clap", @@ -857,7 +1072,7 @@ dependencies = [ [[package]] name = "uu_date" -version = "0.0.27" +version = "0.0.28" dependencies = [ "chrono", "clap", @@ -869,7 +1084,7 @@ dependencies = [ [[package]] name = "uu_echo" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "uucore", @@ -877,7 +1092,7 @@ dependencies = [ [[package]] name = "uu_env" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "nix 0.29.0", @@ -887,7 +1102,7 @@ dependencies = [ [[package]] name = "uu_expr" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "num-bigint", @@ -898,7 +1113,7 @@ dependencies = [ [[package]] name = "uu_printf" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "uucore", @@ -906,7 +1121,7 @@ dependencies = [ [[package]] name = "uu_seq" -version = "0.0.27" +version = "0.0.28" dependencies = [ "bigdecimal", "clap", @@ -917,7 +1132,7 @@ dependencies = [ [[package]] name = "uu_sort" -version = "0.0.27" +version = "0.0.28" dependencies = [ "binary-heap-plus", "clap", @@ -937,7 +1152,7 @@ dependencies = [ [[package]] name = "uu_split" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "memchr", @@ -946,7 +1161,7 @@ dependencies = [ [[package]] name = "uu_test" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "libc", @@ -955,7 +1170,7 @@ dependencies = [ [[package]] name = "uu_tr" -version = "0.0.27" +version = "0.0.28" dependencies = [ "clap", "nom", @@ -964,7 +1179,7 @@ dependencies = [ [[package]] name = "uu_wc" -version = "0.0.27" +version = "0.0.28" dependencies = [ "bytecount", "clap", @@ -977,21 +1192,36 @@ dependencies = [ [[package]] name = "uucore" -version = "0.0.27" +version = "0.0.28" dependencies = [ + "blake2b_simd", + "blake3", "clap", + "data-encoding", + "data-encoding-macro", + "digest", "dunce", "glob", + "hex", "itertools", "libc", + "md-5", + "memchr", "nix 0.29.0", "number_prefix", "once_cell", "os_display", + "regex", + "sha1", + "sha2", + "sha3", + "sm3", + "thiserror", "uucore_procs", "wild", "winapi-util", "windows-sys 0.59.0", + "z85", ] [[package]] @@ -1003,6 +1233,7 @@ dependencies = [ "rand", "similar", "tempfile", + "uu_cksum", "uu_cut", "uu_date", "uu_echo", @@ -1020,7 +1251,7 @@ dependencies = [ [[package]] name = "uucore_procs" -version = "0.0.27" +version = "0.0.28" dependencies = [ "proc-macro2", "quote", @@ -1029,7 +1260,13 @@ dependencies = [ [[package]] name = "uuhelp_parser" -version = "0.0.27" +version = "0.0.28" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -1058,7 +1295,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.65", "wasm-bindgen-shared", ] @@ -1080,7 +1317,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.65", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1265,3 +1502,9 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "z85" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a599daf1b507819c1121f0bf87fa37eb19daac6aff3aefefd4e6e2e0f2020fc" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 3bc5a3433..cc2df2d42 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -27,6 +27,7 @@ uu_cut = { path = "../src/uu/cut/" } uu_split = { path = "../src/uu/split/" } uu_tr = { path = "../src/uu/tr/" } uu_env = { path = "../src/uu/env/" } +uu_cksum = { path = "../src/uu/cksum/" } # Prevent this from interfering with workspaces [workspace] @@ -127,3 +128,9 @@ name = "fuzz_env" path = "fuzz_targets/fuzz_env.rs" test = false doc = false + +[[bin]] +name = "fuzz_cksum" +path = "fuzz_targets/fuzz_cksum.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/fuzz_cksum.rs b/fuzz/fuzz_targets/fuzz_cksum.rs new file mode 100644 index 000000000..411b21aab --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_cksum.rs @@ -0,0 +1,164 @@ +// 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 std::ffi::OsString; +use uu_cksum::uumain; +mod fuzz_common; +use crate::fuzz_common::{ + compare_result, generate_and_run_uumain, generate_random_file, generate_random_string, + run_gnu_cmd, CommandResult, +}; +use rand::Rng; +use std::env::temp_dir; +use std::fs::{self, File}; +use std::io::Write; +use std::process::Command; + +static CMD_PATH: &str = "cksum"; + +fn generate_cksum_args() -> Vec { + let mut rng = rand::thread_rng(); + let mut args = Vec::new(); + + let digests = [ + "sysv", "bsd", "crc", "md5", "sha1", "sha224", "sha256", "sha384", "sha512", "blake2b", + "sm3", + ]; + let digest_opts = [ + "--base64", + "--raw", + "--tag", + "--untagged", + "--text", + "--binary", + ]; + + if rng.gen_bool(0.3) { + args.push("-a".to_string()); + args.push(digests[rng.gen_range(0..digests.len())].to_string()); + } + + if rng.gen_bool(0.2) { + args.push(digest_opts[rng.gen_range(0..digest_opts.len())].to_string()); + } + + if rng.gen_bool(0.15) { + args.push("-l".to_string()); + args.push(rng.gen_range(8..513).to_string()); + } + + if rng.gen_bool(0.05) { + for _ in 0..rng.gen_range(0..3) { + args.push(format!("file_{}", generate_random_string(5))); + } + } else { + args.push("-c".to_string()); + } + + if rng.gen_bool(0.25) { + if let Ok(file_path) = generate_random_file() { + args.push(file_path); + } + } + + if args.is_empty() || !args.iter().any(|arg| arg.starts_with("file_")) { + args.push("-a".to_string()); + args.push(digests[rng.gen_range(0..digests.len())].to_string()); + + if let Ok(file_path) = generate_random_file() { + args.push(file_path); + } + } + + args +} + +fn generate_checksum_file( + algo: &str, + file_path: &str, + digest_opts: &[&str], +) -> Result { + let checksum_file_path = temp_dir().join("checksum_file"); + let mut cmd = Command::new(CMD_PATH); + cmd.arg("-a").arg(algo); + + for opt in digest_opts { + cmd.arg(opt); + } + + cmd.arg(file_path); + let output = cmd.output()?; + + let mut checksum_file = File::create(&checksum_file_path)?; + checksum_file.write_all(&output.stdout)?; + + Ok(checksum_file_path.to_str().unwrap().to_string()) +} + +fn select_random_digest_opts<'a>( + rng: &mut rand::rngs::ThreadRng, + digest_opts: &'a [&'a str], +) -> Vec<&'a str> { + digest_opts + .iter() + .filter(|_| rng.gen_bool(0.5)) + .copied() + .collect() +} + +fuzz_target!(|_data: &[u8]| { + let cksum_args = generate_cksum_args(); + let mut args = vec![OsString::from("cksum")]; + args.extend(cksum_args.iter().map(OsString::from)); + + if let Ok(file_path) = generate_random_file() { + let algo = cksum_args + .iter() + .position(|arg| arg == "-a") + .map_or("md5", |index| &cksum_args[index + 1]); + + let all_digest_opts = ["--base64", "--raw", "--tag", "--untagged"]; + let mut rng = rand::thread_rng(); + let selected_digest_opts = select_random_digest_opts(&mut rng, &all_digest_opts); + + if let Ok(checksum_file_path) = + generate_checksum_file(algo, &file_path, &selected_digest_opts) + { + if let Ok(content) = fs::read_to_string(&checksum_file_path) { + println!("File content: {checksum_file_path}={content}"); + } else { + eprintln!("Error reading the checksum file."); + } + println!("args: {:?}", args); + let rust_result = generate_and_run_uumain(&args, uumain, None); + + 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( + "cksum", + &format!("{:?}", &args[1..]), + None, + &rust_result, + &gnu_result, + false, + ); + } + } +}); diff --git a/fuzz/fuzz_targets/fuzz_common.rs b/fuzz/fuzz_targets/fuzz_common.rs index ba6c0a402..f9d974cf7 100644 --- a/fuzz/fuzz_targets/fuzz_common.rs +++ b/fuzz/fuzz_targets/fuzz_common.rs @@ -5,7 +5,6 @@ use libc::STDIN_FILENO; use libc::{close, dup, dup2, pipe, STDERR_FILENO, STDOUT_FILENO}; -use rand::distributions::Uniform; use rand::prelude::SliceRandom; use rand::Rng; use similar::TextDiff; @@ -398,9 +397,8 @@ pub fn generate_random_string(max_length: usize) -> String { pub fn generate_random_file() -> Result { let mut rng = rand::thread_rng(); - let file_name: String = (0..10) - .map(|_| rng.sample(Uniform::new_inclusive(b'a', b'z')) as char) + .map(|_| rng.gen_range(b'a'..=b'z') as char) .collect(); let mut file_path = temp_dir(); file_path.push(file_name); @@ -409,7 +407,7 @@ pub fn generate_random_file() -> Result { let content_length = rng.gen_range(10..1000); let content: String = (0..content_length) - .map(|_| (rng.gen_range(b' '..b'~' + 1) as char)) + .map(|_| (rng.gen_range(b' '..=b'~') as char)) .collect(); file.write_all(content.as_bytes())?;