From bc7736bc9965d2df2e406f0e4fe9f4fe0d8c29f7 Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Sat, 16 Sep 2023 22:32:53 +0200 Subject: [PATCH] Add 2 fuzzers for nu-path, nu-parser (#10376) # Description This PR adds a fuzzer for the nu-path and the nu-parser crate. Now you can go to `crates/nu-path/fuzz`/`crates/nu-parser/fuzz` and run `cargo fuzz` to find crashes. https://github.com/nushell/nushell/issues/10365 and #9417 was found by this --------- Co-authored-by: sholderbach --- crates/nu-parser/Cargo.toml | 1 + crates/nu-parser/fuzz/.gitignore | 8 +++++ crates/nu-parser/fuzz/Cargo.toml | 29 +++++++++++++++++++ crates/nu-parser/fuzz/README.md | 9 ++++++ crates/nu-parser/fuzz/fuzz_targets/parse.rs | 13 +++++++++ crates/nu-parser/fuzz/gather_seeds.nu | 6 ++++ crates/nu-parser/fuzz/rust-toolchain.toml | 2 ++ crates/nu-path/Cargo.toml | 1 + crates/nu-path/fuzz/.gitignore | 7 +++++ crates/nu-path/fuzz/Cargo.toml | 27 +++++++++++++++++ crates/nu-path/fuzz/README.md | 8 +++++ .../nu-path/fuzz/fuzz_targets/path_fuzzer.rs | 25 ++++++++++++++++ crates/nu-path/fuzz/rust-toolchain.toml | 2 ++ 13 files changed, 138 insertions(+) create mode 100644 crates/nu-parser/fuzz/.gitignore create mode 100644 crates/nu-parser/fuzz/Cargo.toml create mode 100644 crates/nu-parser/fuzz/README.md create mode 100644 crates/nu-parser/fuzz/fuzz_targets/parse.rs create mode 100755 crates/nu-parser/fuzz/gather_seeds.nu create mode 100644 crates/nu-parser/fuzz/rust-toolchain.toml create mode 100644 crates/nu-path/fuzz/.gitignore create mode 100644 crates/nu-path/fuzz/Cargo.toml create mode 100644 crates/nu-path/fuzz/README.md create mode 100644 crates/nu-path/fuzz/fuzz_targets/path_fuzzer.rs create mode 100644 crates/nu-path/fuzz/rust-toolchain.toml diff --git a/crates/nu-parser/Cargo.toml b/crates/nu-parser/Cargo.toml index f4224f3bdc..4df0286a63 100644 --- a/crates/nu-parser/Cargo.toml +++ b/crates/nu-parser/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" license = "MIT" name = "nu-parser" version = "0.84.1" +exclude = ["/fuzz"] [lib] bench = false diff --git a/crates/nu-parser/fuzz/.gitignore b/crates/nu-parser/fuzz/.gitignore new file mode 100644 index 0000000000..b641f8c561 --- /dev/null +++ b/crates/nu-parser/fuzz/.gitignore @@ -0,0 +1,8 @@ +target +corpus +artifacts +coverage +Cargo.lock +out +seeds + diff --git a/crates/nu-parser/fuzz/Cargo.toml b/crates/nu-parser/fuzz/Cargo.toml new file mode 100644 index 0000000000..db97e0f654 --- /dev/null +++ b/crates/nu-parser/fuzz/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "nu-parser-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +nu-protocol = { path = "../../nu-protocol" } + + +[dependencies.nu-parser] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "parse" +path = "fuzz_targets/parse.rs" +test = false +doc = false diff --git a/crates/nu-parser/fuzz/README.md b/crates/nu-parser/fuzz/README.md new file mode 100644 index 0000000000..131fb50237 --- /dev/null +++ b/crates/nu-parser/fuzz/README.md @@ -0,0 +1,9 @@ +# Fuzzer for `nu-parser` + +- For detailed info, please look at [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) + +# Quick start guide +- Install cargo-fuzz by `cargo install cargo-fuzz` +- Run `gather_seeds.nu` for preparing the initial seeds corpus +- Make output directory `mkdir out` +- Run the fuzzer with `cargo fuzz run parse out seeds` diff --git a/crates/nu-parser/fuzz/fuzz_targets/parse.rs b/crates/nu-parser/fuzz/fuzz_targets/parse.rs new file mode 100644 index 0000000000..e62de43b12 --- /dev/null +++ b/crates/nu-parser/fuzz/fuzz_targets/parse.rs @@ -0,0 +1,13 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; + +use nu_parser::*; +use nu_protocol::engine::{EngineState, StateWorkingSet}; + +fuzz_target!(|data: &[u8]| { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + + let _block = parse(&mut working_set, None, &data, true); +}); diff --git a/crates/nu-parser/fuzz/gather_seeds.nu b/crates/nu-parser/fuzz/gather_seeds.nu new file mode 100755 index 0000000000..1315ce0337 --- /dev/null +++ b/crates/nu-parser/fuzz/gather_seeds.nu @@ -0,0 +1,6 @@ +# Check if 'seeds' directory exists. If not, create one. +let seeds_exists = "./seeds" | path exists +if $seeds_exists == false { mkdir seeds } + +# Gather all "*.nu" files from '../..' and copy them into 'seeds' +ls ../../**/*.nu | get name | each {|f| cp $f ./seeds/} diff --git a/crates/nu-parser/fuzz/rust-toolchain.toml b/crates/nu-parser/fuzz/rust-toolchain.toml new file mode 100644 index 0000000000..5d56faf9ae --- /dev/null +++ b/crates/nu-parser/fuzz/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/crates/nu-path/Cargo.toml b/crates/nu-path/Cargo.toml index b1fba82318..de44e3db1c 100644 --- a/crates/nu-path/Cargo.toml +++ b/crates/nu-path/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" license = "MIT" name = "nu-path" version = "0.84.1" +exclude = ["/fuzz"] [lib] bench = false diff --git a/crates/nu-path/fuzz/.gitignore b/crates/nu-path/fuzz/.gitignore new file mode 100644 index 0000000000..7d4eb03448 --- /dev/null +++ b/crates/nu-path/fuzz/.gitignore @@ -0,0 +1,7 @@ +target +corpus +artifacts +coverage +Cargo.lock +out + diff --git a/crates/nu-path/fuzz/Cargo.toml b/crates/nu-path/fuzz/Cargo.toml new file mode 100644 index 0000000000..08121602d7 --- /dev/null +++ b/crates/nu-path/fuzz/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "nu-path-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.nu-path] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "path" +path = "fuzz_targets/path_fuzzer.rs" +test = false +doc = false diff --git a/crates/nu-path/fuzz/README.md b/crates/nu-path/fuzz/README.md new file mode 100644 index 0000000000..ab16045b3e --- /dev/null +++ b/crates/nu-path/fuzz/README.md @@ -0,0 +1,8 @@ +# Fuzzer for `nu-path` + +- For detailed info, please look at [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) + +# Quick start guide +- Install cargo-fuzz by `cargo install cargo-fuzz` +- Make output directory `mkdir out` +- Run the fuzzer with `cargo fuzz run parse out` diff --git a/crates/nu-path/fuzz/fuzz_targets/path_fuzzer.rs b/crates/nu-path/fuzz/fuzz_targets/path_fuzzer.rs new file mode 100644 index 0000000000..d3ccb7cdc7 --- /dev/null +++ b/crates/nu-path/fuzz/fuzz_targets/path_fuzzer.rs @@ -0,0 +1,25 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use nu_path::{expand_path_with, expand_tilde, expand_to_real_path, trim_trailing_slash}; + +fuzz_target!(|data: &[u8]| { + if let Ok(s) = std::str::from_utf8(data) { + let path = std::path::Path::new(s); + + // Fuzzing expand_to_real_path function + let _ = expand_to_real_path(path); + + // Fuzzing trim_trailing_slash function + let _ = trim_trailing_slash(s); + + // Fuzzing expand_tilde function + let _ = expand_tilde(path); + + // Fuzzing expand_path_with function + // Here, we're assuming a second path for the "relative to" aspect. + // For simplicity, we're just using the current directory. + let current_dir = std::path::Path::new("."); + let _ = expand_path_with(path, ¤t_dir); + } +}); diff --git a/crates/nu-path/fuzz/rust-toolchain.toml b/crates/nu-path/fuzz/rust-toolchain.toml new file mode 100644 index 0000000000..5d56faf9ae --- /dev/null +++ b/crates/nu-path/fuzz/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly"