From b4e15fe9f3764a783bb5911460c020b5facb4706 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sat, 6 Nov 2021 02:21:53 +0100 Subject: [PATCH] Bridge grammartec from Nautilus to libafl (#342) * nautilus dep * nautilus generation * fix mutator * start new mutator for nautilus * other mutators * baby * ci * NautilusFeedback * fix unparse * ci * ci * ci * ci * nigghtly clippy * ci * fix * ci * ci * update construct automatata * fix * ci * clippy * clippy * nightly clippy * more clippy * minor clippy Co-authored-by: Dominik Maier --- .github/workflows/build_and_test.yml | 10 +- Cargo.toml | 1 + README.md | 7 + fuzzers/baby_fuzzer_gramatron/src/main.rs | 16 +- fuzzers/baby_fuzzer_nautilus/.gitignore | 1 + fuzzers/baby_fuzzer_nautilus/Cargo.toml | 22 + fuzzers/baby_fuzzer_nautilus/README.md | 8 + fuzzers/baby_fuzzer_nautilus/grammar.json | 1184 +++++++++++++++++ fuzzers/baby_fuzzer_nautilus/rust-toolchain | 1 + fuzzers/baby_fuzzer_nautilus/src/main.rs | 163 +++ libafl/Cargo.toml | 73 +- libafl/src/bolts/launcher.rs | 2 +- libafl/src/bolts/llmp.rs | 77 +- libafl/src/bolts/os/unix_shmem_server.rs | 2 +- libafl/src/bolts/os/unix_signals.rs | 13 +- libafl/src/bolts/serdeany.rs | 4 +- libafl/src/bolts/shmem.rs | 14 +- libafl/src/events/llmp.rs | 13 +- libafl/src/events/simple.rs | 1 + libafl/src/feedbacks/map.rs | 5 +- libafl/src/feedbacks/mod.rs | 5 + libafl/src/feedbacks/nautilus.rs | 89 ++ libafl/src/generators/mod.rs | 5 + libafl/src/generators/nautilus.rs | 75 ++ libafl/src/inputs/mod.rs | 5 + libafl/src/inputs/nautilus.rs | 80 ++ libafl/src/mutators/gramatron.rs | 2 +- libafl/src/mutators/mod.rs | 5 + libafl/src/mutators/nautilus.rs | 192 +++ libafl_concolic/symcc_libafl/src/lib.rs | 8 +- libafl_frida/src/alloc.rs | 13 +- libafl_frida/src/asan_errors.rs | 3 +- libafl_frida/src/lib.rs | 22 +- libafl_qemu/src/executor.rs | 2 + libafl_sugar/src/inmemory.rs | 8 +- libafl_sugar/src/qemu.rs | 8 +- libafl_targets/src/libfuzzer.rs | 2 +- libafl_targets/src/sancov_pcguard.rs | 5 +- scripts/clippy.sh | 2 +- utils/README.md | 3 + {scripts => utils}/gramatron/README.md | 0 .../gramatron/construct_automata.py | 0 .../gramatron/construct_automata/Cargo.toml | 2 +- .../construct_automata/src/clap-config.yaml | 0 .../gramatron/construct_automata/src/main.rs | 48 +- {scripts => utils}/gramatron/gnf_converter.py | 0 .../gramatron/grammars/js_grammar.json | 0 .../gramatron/grammars/php_grammar.json | 0 .../gramatron/grammars/ruby_grammar.json | 0 49 files changed, 2046 insertions(+), 155 deletions(-) create mode 100644 fuzzers/baby_fuzzer_nautilus/.gitignore create mode 100644 fuzzers/baby_fuzzer_nautilus/Cargo.toml create mode 100644 fuzzers/baby_fuzzer_nautilus/README.md create mode 100644 fuzzers/baby_fuzzer_nautilus/grammar.json create mode 100644 fuzzers/baby_fuzzer_nautilus/rust-toolchain create mode 100644 fuzzers/baby_fuzzer_nautilus/src/main.rs create mode 100644 libafl/src/feedbacks/nautilus.rs create mode 100644 libafl/src/generators/nautilus.rs create mode 100644 libafl/src/inputs/nautilus.rs create mode 100644 libafl/src/mutators/nautilus.rs rename {scripts => utils}/gramatron/README.md (100%) rename {scripts => utils}/gramatron/construct_automata.py (100%) rename {scripts => utils}/gramatron/construct_automata/Cargo.toml (95%) rename {scripts => utils}/gramatron/construct_automata/src/clap-config.yaml (100%) rename {scripts => utils}/gramatron/construct_automata/src/main.rs (90%) rename {scripts => utils}/gramatron/gnf_converter.py (100%) rename {scripts => utils}/gramatron/grammars/js_grammar.json (100%) rename {scripts => utils}/gramatron/grammars/php_grammar.json (100%) rename {scripts => utils}/gramatron/grammars/ruby_grammar.json (100%) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 36acd69f83..b204f1af10 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -19,7 +19,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: nightly - uses: Swatinem/rust-cache@v1 - name: install mdbook run: cargo install mdbook @@ -52,6 +52,8 @@ jobs: run: command -v llvm-config && clang -v - name: Install cargo-hack run: curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-x86_64-unknown-linux-gnu.tar.gz | tar xzf - -C ~/.cargo/bin + - name: Add nightly rustfmt and clippy + run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade - uses: actions/checkout@v2 - name: Run a normal build run: cargo build --verbose @@ -61,7 +63,7 @@ jobs: # cargo-hack's --feature-powerset would be nice here but libafl has a too many knobs - name: Check each feature # Skipping python as it has to be built with the `maturin` tool - run: cargo hack check --feature-powerset --depth=2 --exclude-features=python,sancov_pcguard_edges,sancov_pcguard_edges_ptr --no-dev-deps + run: cargo hack check --feature-powerset --depth=2 --exclude-features=agpl,nautilus,python,sancov_pcguard_edges,sancov_pcguard_edges_ptr --no-dev-deps # pcguard edges and pcguard hitcounts are not compatible and we need to build them seperately - name: Check pcguard edges run: cargo check --features=sancov_pcguard_edges,sancov_pcguard_edges_ptr @@ -74,7 +76,7 @@ jobs: - name: Build Docs run: cargo doc - name: Test Docs - run: cargo test --all-features --doc + run: cargo +nightly test --doc --all-features - name: Run clippy run: ./scripts/clippy.sh ubuntu-concolic: @@ -153,6 +155,8 @@ jobs: profile: minimal toolchain: stable - uses: Swatinem/rust-cache@v1 + - name: Add nightly rustfmt and clippy + run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade - name: Install deps run: brew install z3 - uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index 02b87de87d..8d4f8b181e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "libafl_concolic/test/dump_constraints", "libafl_concolic/test/runtime_test", "utils/deexit", + "utils/gramatron/construct_automata", ] default-members = [ "libafl", diff --git a/README.md b/README.md index e3590ad05d..23b528871c 100644 --- a/README.md +++ b/README.md @@ -104,3 +104,10 @@ for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/fuzzers/baby_fuzzer_gramatron/src/main.rs b/fuzzers/baby_fuzzer_gramatron/src/main.rs index 577c89006f..b48b6e8da0 100644 --- a/fuzzers/baby_fuzzer_gramatron/src/main.rs +++ b/fuzzers/baby_fuzzer_gramatron/src/main.rs @@ -113,21 +113,31 @@ pub fn main() { /* use libafl::generators::Generator; use std::collections::HashSet; + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + let mut set = HashSet::new(); let st = libafl::bolts::current_milliseconds(); let mut b = vec![]; let mut c = 0; - for _ in 0..100000000 { + for _ in 0..100000 { let i = generator.generate(&mut state).unwrap(); i.unparse(&mut b); - set.insert(b.clone()); + set.insert(calculate_hash(&b)); c += b.len(); } println!("{} / {}", c, libafl::bolts::current_milliseconds() - st); - println!("{} / 100000000", set.len()); + println!("{} / 100000", set.len()); return; */ + // Generate 8 initial inputs state .generate_initial_inputs_forced(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8) diff --git a/fuzzers/baby_fuzzer_nautilus/.gitignore b/fuzzers/baby_fuzzer_nautilus/.gitignore new file mode 100644 index 0000000000..a977a2ca5b --- /dev/null +++ b/fuzzers/baby_fuzzer_nautilus/.gitignore @@ -0,0 +1 @@ +libpng-* \ No newline at end of file diff --git a/fuzzers/baby_fuzzer_nautilus/Cargo.toml b/fuzzers/baby_fuzzer_nautilus/Cargo.toml new file mode 100644 index 0000000000..72b87f68e4 --- /dev/null +++ b/fuzzers/baby_fuzzer_nautilus/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "baby_fuzzer" +version = "0.6.0" +authors = ["Andrea Fioraldi ", "Dominik Maier "] +edition = "2018" + +[features] +default = ["std"] +std = [] + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +lto = true +codegen-units = 1 +opt-level = 3 +debug = true + +[dependencies] +libafl = { path = "../../libafl/", features = ["default", "nautilus"] } diff --git a/fuzzers/baby_fuzzer_nautilus/README.md b/fuzzers/baby_fuzzer_nautilus/README.md new file mode 100644 index 0000000000..42fd9a5011 --- /dev/null +++ b/fuzzers/baby_fuzzer_nautilus/README.md @@ -0,0 +1,8 @@ +# Baby fuzzer + +This is a minimalistic example about how to create a libafl based fuzzer. + +It runs on a single core until a crash occurs and then exits. + +The tested program is a simple Rust function without any instrumentation. +For real fuzzing, you will want to add some sort to add coverage or other feedback. \ No newline at end of file diff --git a/fuzzers/baby_fuzzer_nautilus/grammar.json b/fuzzers/baby_fuzzer_nautilus/grammar.json new file mode 100644 index 0000000000..f6fff6782b --- /dev/null +++ b/fuzzers/baby_fuzzer_nautilus/grammar.json @@ -0,0 +1,1184 @@ +[ + ["RUBY","a=0\nb=\"asdfasdfasdf adaf asdf asdfa sdf asdfasdfasdfa sdf\"\nc=\\{1=>1, 2=>\"foo\", \"foo\"=>nil, nil=> nil\\}\nd=[1,nil,\" sdfg\"]\nsrand(1337)\n{PROGRAM}"], + ["PROGRAM","{STATEMENT}{NEWLINE}{PROGRAM}"], + ["PROGRAM",""], + + ["STATEMENT", "def {VAR}.{IDENTIFIER}({ARGS}){NEWLINE}{PROGRAM} end"], + ["STATEMENT","{VAR} = {VAR}.{IDENTIFIER}({ARGS})\\{|{ARGS}| {PROGRAM} \\}"], + ["STATEMENT","{VAR} = {IDENTIFIER}.{IDENTIFIER}({ARGS})\\{|{ARGS}| {PROGRAM} \\}"], + ["STATEMENT","{VAR} = {VAL}"], + ["STATEMENT","return {VAR}"], + ["STATEMENT","raise {VAR}"], + ["STATEMENT","yield {VAR}"], + ["STATEMENT","continue {VAR}"], + ["STATEMENT","break {VAR}"], + ["STATEMENT","next {VAR}"], + + ["VAR","a"], + ["VAR","b"], + ["VAR","c"], + ["VAR","d"], + + ["ARGS",""], + ["ARGS","{VAR}"], + ["ARGS","{VAR},{ARGS}"], + + ["VAL","\"foo\""], + ["VAL","\"foobadsfdsfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasfd\""], + ["VAL","1"], + ["VAL","0"], + ["VAL","0.0"], + ["VAL","nil"], + ["VAL","true"], + ["VAL","false"], + ["VAL","/foo/"], + ["VAL","({VAL}..{VAL})"], + ["VAL","[]"], + ["VAL","[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,nil]"], + ["VAL","{}"], + + ["NEWLINE","\n"], + + ["IDENTIFIER","abcdef0123456789ABCDEF"], + ["IDENTIFIER","abcdefghijklmnopqrstuvwxyz"], + ["IDENTIFIER","abort"], + ["IDENTIFIER","abs"], + ["IDENTIFIER","accept"], + ["IDENTIFIER","acos"], + ["IDENTIFIER","acosh"], + ["IDENTIFIER","address"], + ["IDENTIFIER","alias"], + ["IDENTIFIER","alias_method"], + ["IDENTIFIER","allocation"], + ["IDENTIFIER","all_symbols"], + ["IDENTIFIER","ancestors"], + ["IDENTIFIER","and"], + ["IDENTIFIER","anum"], + ["IDENTIFIER","append"], + ["IDENTIFIER","append_features"], + ["IDENTIFIER","Apr"], + ["IDENTIFIER","aref_args"], + ["IDENTIFIER","arg"], + ["IDENTIFIER","arg0"], + ["IDENTIFIER","arg1"], + ["IDENTIFIER","arg2"], + ["IDENTIFIER","arg_rhs"], + ["IDENTIFIER","args"], + ["IDENTIFIER","argument"], + ["IDENTIFIER","ArgumentError"], + ["IDENTIFIER","arguments"], + ["IDENTIFIER","argv"], + ["IDENTIFIER","ARGV"], + ["IDENTIFIER","arity"], + ["IDENTIFIER","array"], + ["IDENTIFIER","Array"], + ["IDENTIFIER","ary"], + ["IDENTIFIER","__ary_cmp"], + ["IDENTIFIER","ary_concat"], + ["IDENTIFIER","__ary_eq"], + ["IDENTIFIER","ary_F"], + ["IDENTIFIER","__ary_index"], + ["IDENTIFIER","ary_replace"], + ["IDENTIFIER","ary_T"], + ["IDENTIFIER","asctime"], + ["IDENTIFIER","asin"], + ["IDENTIFIER","asinh"], + ["IDENTIFIER","__assert_fail"], + ["IDENTIFIER","assignment"], + ["IDENTIFIER","assoc"], + ["IDENTIFIER","assoc_list"], + ["IDENTIFIER","assocs"], + ["IDENTIFIER","assumed"], + ["IDENTIFIER","at"], + ["IDENTIFIER","atan"], + ["IDENTIFIER","atan2"], + ["IDENTIFIER","atanh"], + ["IDENTIFIER","__attached__"], + ["IDENTIFIER","attr"], + ["IDENTIFIER","attr_accessor"], + ["IDENTIFIER","attr_reader"], + ["IDENTIFIER","attrsym"], + ["IDENTIFIER","attr_writer"], + ["IDENTIFIER","available"], + ["IDENTIFIER","backref"], + ["IDENTIFIER","backtrace"], + ["IDENTIFIER","Backtrace"], + ["IDENTIFIER","BasicObject"], + ["IDENTIFIER","basic_symbol"], + ["IDENTIFIER","beg"], + ["IDENTIFIER","begin"], + ["IDENTIFIER","BEGIN"], + ["IDENTIFIER","big"], + ["IDENTIFIER","BIT"], + ["IDENTIFIER","blkarg_mark"], + ["IDENTIFIER","block"], + ["IDENTIFIER","block_arg"], + ["IDENTIFIER","block_call"], + ["IDENTIFIER","block_command"], + ["IDENTIFIER","block_param"], + ["IDENTIFIER","block_param_def"], + ["IDENTIFIER","BMATZ0000IREP"], + ["IDENTIFIER","body"], + ["IDENTIFIER","bodystmt"], + ["IDENTIFIER","boundary"], + ["IDENTIFIER","brace_block"], + ["IDENTIFIER","break"], + ["IDENTIFIER","bsearch"], + ["IDENTIFIER","bsearch_index"], + ["IDENTIFIER","buf"], + ["IDENTIFIER","bvar"], + ["IDENTIFIER","bv_decls"], + ["IDENTIFIER","byte"], + ["IDENTIFIER","bytes"], + ["IDENTIFIER","bytesize"], + ["IDENTIFIER","byteslice"], + ["IDENTIFIER","call"], + ["IDENTIFIER","call_args"], + ["IDENTIFIER","caller"], + ["IDENTIFIER","call_op"], + ["IDENTIFIER","call_op2"], + ["IDENTIFIER","capitalize"], + ["IDENTIFIER","case"], + ["IDENTIFIER","case_body"], + ["IDENTIFIER","casecmp"], + ["IDENTIFIER","__case_eqq"], + ["IDENTIFIER","cases"], + ["IDENTIFIER","cbrt"], + ["IDENTIFIER","cdr"], + ["IDENTIFIER","ceil"], + ["IDENTIFIER","change_gen_gc_mode"], + ["IDENTIFIER","character"], + ["IDENTIFIER","chars"], + ["IDENTIFIER","chomp"], + ["IDENTIFIER","chop"], + ["IDENTIFIER","chr"], + ["IDENTIFIER","clamp"], + ["IDENTIFIER","Class"], + ["IDENTIFIER","class_eval"], + ["IDENTIFIER","__classname__"], + ["IDENTIFIER","class_variable_get"], + ["IDENTIFIER","class_variables"], + ["IDENTIFIER","class_variable_set"], + ["IDENTIFIER","clause"], + ["IDENTIFIER","clear_all_old"], + ["IDENTIFIER","clone"], + ["IDENTIFIER","closure"], + ["IDENTIFIER","cLVAR"], + ["IDENTIFIER","cmd_brace_block"], + ["IDENTIFIER","cmp"], + ["IDENTIFIER","cname"], + ["IDENTIFIER","codegen"], + ["IDENTIFIER","codepoints"], + ["IDENTIFIER","collect"], + ["IDENTIFIER","collect_concat"], + ["IDENTIFIER","color"], + ["IDENTIFIER","column_count"], + ["IDENTIFIER","column_index"], + ["IDENTIFIER","combination"], + ["IDENTIFIER","comma"], + ["IDENTIFIER","command"], + ["IDENTIFIER","command_args"], + ["IDENTIFIER","command_asgn"], + ["IDENTIFIER","command_call"], + ["IDENTIFIER","command_rhs"], + ["IDENTIFIER","compact"], + ["IDENTIFIER","Comparable"], + ["IDENTIFIER","compile"], + ["IDENTIFIER","compstmt"], + ["IDENTIFIER","concat"], + ["IDENTIFIER","constant"], + ["IDENTIFIER","CONSTANT"], + ["IDENTIFIER","constants"], + ["IDENTIFIER","const_get"], + ["IDENTIFIER","const_missing"], + ["IDENTIFIER","const_set"], + ["IDENTIFIER","cont"], + ["IDENTIFIER","context"], + ["IDENTIFIER","copyright"], + ["IDENTIFIER","corrupted"], + ["IDENTIFIER","cos"], + ["IDENTIFIER","cosh"], + ["IDENTIFIER","count"], + ["IDENTIFIER","count_objects"], + ["IDENTIFIER","cpath"], + ["IDENTIFIER","ctime"], + ["IDENTIFIER","__ctype_b_loc"], + ["IDENTIFIER","curr"], + ["IDENTIFIER","current"], + ["IDENTIFIER","curry"], + ["IDENTIFIER","cycle"], + ["IDENTIFIER","Data"], + ["IDENTIFIER","day"], + ["IDENTIFIER","debug_info"], + ["IDENTIFIER","Dec"], + ["IDENTIFIER","deep"], + ["IDENTIFIER","def"], + ["IDENTIFIER","default"], + ["IDENTIFIER","DEFAULT"], + ["IDENTIFIER","default_proc"], + ["IDENTIFIER","defined"], + ["IDENTIFIER","define_method"], + ["IDENTIFIER","define_singleton_method"], + ["IDENTIFIER","__delete"], + ["IDENTIFIER","delete"], + ["IDENTIFIER","delete_at"], + ["IDENTIFIER","delete_if"], + ["IDENTIFIER","delete_prefix"], + ["IDENTIFIER","delete_suffix"], + ["IDENTIFIER","Deleting"], + ["IDENTIFIER","depth"], + ["IDENTIFIER","detect"], + ["IDENTIFIER","detected"], + ["IDENTIFIER","developers"], + ["IDENTIFIER","differs"], + ["IDENTIFIER","digit"], + ["IDENTIFIER","digits"], + ["IDENTIFIER","disable"], + ["IDENTIFIER","disabled"], + ["IDENTIFIER","discarding"], + ["IDENTIFIER","div"], + ["IDENTIFIER","divmod"], + ["IDENTIFIER","do"], + ["IDENTIFIER","do_block"], + ["IDENTIFIER","DomainError"], + ["IDENTIFIER","dot"], + ["IDENTIFIER","dot_or_colon"], + ["IDENTIFIER","downcase"], + ["IDENTIFIER","downto"], + ["IDENTIFIER","drop"], + ["IDENTIFIER","dropped"], + ["IDENTIFIER","dropping"], + ["IDENTIFIER","drop_while"], + ["IDENTIFIER","dump"], + ["IDENTIFIER","dup"], + ["IDENTIFIER","each"], + ["IDENTIFIER","each_byte"], + ["IDENTIFIER","each_char"], + ["IDENTIFIER","each_codepoint"], + ["IDENTIFIER","each_cons"], + ["IDENTIFIER","each_index"], + ["IDENTIFIER","each_key"], + ["IDENTIFIER","each_line"], + ["IDENTIFIER","each_object"], + ["IDENTIFIER","each_pair"], + ["IDENTIFIER","each_slice"], + ["IDENTIFIER","each_value"], + ["IDENTIFIER","each_with_index"], + ["IDENTIFIER","each_with_object"], + ["IDENTIFIER","ecall"], + ["IDENTIFIER","elem"], + ["IDENTIFIER","else"], + ["IDENTIFIER","elsif"], + ["IDENTIFIER","en"], + ["IDENTIFIER","enable"], + ["IDENTIFIER","__ENCODING__"], + ["IDENTIFIER","end"], + ["IDENTIFIER","__END__"], + ["IDENTIFIER","END"], + ["IDENTIFIER","ensure"], + ["IDENTIFIER","entries"], + ["IDENTIFIER","Enumerable"], + ["IDENTIFIER","enumerator"], + ["IDENTIFIER","Enumerator"], + ["IDENTIFIER","enumerator_block_call"], + ["IDENTIFIER","enum_for"], + ["IDENTIFIER","enums"], + ["IDENTIFIER","env"], + ["IDENTIFIER","erf"], + ["IDENTIFIER","erfc"], + ["IDENTIFIER","__errno_location"], + ["IDENTIFIER","error"], + ["IDENTIFIER","escape"], + ["IDENTIFIER","ETIR"], + ["IDENTIFIER","ETIR0004Ci"], + ["IDENTIFIER","exception"], + ["IDENTIFIER","Exception"], + ["IDENTIFIER","exc_list"], + ["IDENTIFIER","exc_var"], + ["IDENTIFIER","exhausted"], + ["IDENTIFIER","exp"], + ["IDENTIFIER","expected"], + ["IDENTIFIER","expr"], + ["IDENTIFIER","expression"], + ["IDENTIFIER","expr_value"], + ["IDENTIFIER","extend"], + ["IDENTIFIER","extended"], + ["IDENTIFIER","extend_object"], + ["IDENTIFIER","fail"], + ["IDENTIFIER","failed"], + ["IDENTIFIER","failure"], + ["IDENTIFIER","false"], + ["IDENTIFIER","FalseClass"], + ["IDENTIFIER","f_arg"], + ["IDENTIFIER","f_arg_item"], + ["IDENTIFIER","f_arglist"], + ["IDENTIFIER","f_args"], + ["IDENTIFIER","f_bad_arg"], + ["IDENTIFIER","f_block_arg"], + ["IDENTIFIER","f_block_opt"], + ["IDENTIFIER","f_block_optarg"], + ["IDENTIFIER","fclose"], + ["IDENTIFIER","Feb"], + ["IDENTIFIER","feed"], + ["IDENTIFIER","feedvalue"], + ["IDENTIFIER","feof"], + ["IDENTIFIER","fetch"], + ["IDENTIFIER","fetch_values"], + ["IDENTIFIER","fflush"], + ["IDENTIFIER","fgetc"], + ["IDENTIFIER","fib"], + ["IDENTIFIER","fiber"], + ["IDENTIFIER","Fiber"], + ["IDENTIFIER","fiber_check"], + ["IDENTIFIER","FiberError"], + ["IDENTIFIER","field"], + ["IDENTIFIER","file"], + ["IDENTIFIER","File"], + ["IDENTIFIER","__FILE__"], + ["IDENTIFIER","filename"], + ["IDENTIFIER","filenames_len"], + ["IDENTIFIER","fill"], + ["IDENTIFIER","final_marking_phase"], + ["IDENTIFIER","find"], + ["IDENTIFIER","find_all"], + ["IDENTIFIER","find_index"], + ["IDENTIFIER","first"], + ["IDENTIFIER","fish"], + ["IDENTIFIER","Fixnum"], + ["IDENTIFIER","flag"], + ["IDENTIFIER","f_larglist"], + ["IDENTIFIER","flat_map"], + ["IDENTIFIER","flatten"], + ["IDENTIFIER","Float"], + ["IDENTIFIER","FloatDomainError"], + ["IDENTIFIER","floor"], + ["IDENTIFIER","f_marg"], + ["IDENTIFIER","f_marg_list"], + ["IDENTIFIER","f_margs"], + ["IDENTIFIER","fmod"], + ["IDENTIFIER","fn"], + ["IDENTIFIER","Fn"], + ["IDENTIFIER","fname"], + ["IDENTIFIER","f_norm_arg"], + ["IDENTIFIER","fopen"], + ["IDENTIFIER","f_opt"], + ["IDENTIFIER","f_optarg"], + ["IDENTIFIER","f_opt_asgn"], + ["IDENTIFIER","for"], + ["IDENTIFIER","force"], + ["IDENTIFIER","format"], + ["IDENTIFIER","for_var"], + ["IDENTIFIER","found"], + ["IDENTIFIER","fprintf"], + ["IDENTIFIER","fputc"], + ["IDENTIFIER","fread"], + ["IDENTIFIER","free"], + ["IDENTIFIER","FREE"], + ["IDENTIFIER","freeze"], + ["IDENTIFIER","f_rest_arg"], + ["IDENTIFIER","frexp"], + ["IDENTIFIER","Fri"], + ["IDENTIFIER","FrozenError"], + ["IDENTIFIER","FsC"], + ["IDENTIFIER","fsym"], + ["IDENTIFIER","fwrite"], + ["IDENTIFIER","games"], + ["IDENTIFIER","GB"], + ["IDENTIFIER","GC"], + ["IDENTIFIER","gc_mark_children"], + ["IDENTIFIER","_gc_root_"], + ["IDENTIFIER","generational_mode"], + ["IDENTIFIER","Generator"], + ["IDENTIFIER","getbyte"], + ["IDENTIFIER","get_file"], + ["IDENTIFIER","getgm"], + ["IDENTIFIER","getlocal"], + ["IDENTIFIER","gettimeofday"], + ["IDENTIFIER","getutc"], + ["IDENTIFIER","given"], + ["IDENTIFIER","given_args"], + ["IDENTIFIER","global_variables"], + ["IDENTIFIER","__gmon_start__"], + ["IDENTIFIER","gmtime"], + ["IDENTIFIER","gmtime_r"], + ["IDENTIFIER","gn"], + ["IDENTIFIER","gnu"], + ["IDENTIFIER","GNU"], + ["IDENTIFIER","go"], + ["IDENTIFIER","grep"], + ["IDENTIFIER","group_by"], + ["IDENTIFIER","gsub"], + ["IDENTIFIER","h0"], + ["IDENTIFIER","h2"], + ["IDENTIFIER","H3"], + ["IDENTIFIER","h4"], + ["IDENTIFIER","h5"], + ["IDENTIFIER","H5"], + ["IDENTIFIER","h6"], + ["IDENTIFIER","H6"], + ["IDENTIFIER","h7"], + ["IDENTIFIER","h8"], + ["IDENTIFIER","hA"], + ["IDENTIFIER","hash"], + ["IDENTIFIER","Hash"], + ["IDENTIFIER","head"], + ["IDENTIFIER","heredoc"], + ["IDENTIFIER","heredoc_bodies"], + ["IDENTIFIER","heredoc_body"], + ["IDENTIFIER","heredoc_string_interp"], + ["IDENTIFIER","heredoc_string_rep"], + ["IDENTIFIER","heredoc_treat_nextline"], + ["IDENTIFIER","hex"], + ["IDENTIFIER","high"], + ["IDENTIFIER","hour"], + ["IDENTIFIER","hypot"], + ["IDENTIFIER","i2"], + ["IDENTIFIER","iClass"], + ["IDENTIFIER","__id__"], + ["IDENTIFIER","id2name"], + ["IDENTIFIER","identifier"], + ["IDENTIFIER","idx"], + ["IDENTIFIER","idx2"], + ["IDENTIFIER","if"], + ["IDENTIFIER","ifnone"], + ["IDENTIFIER","if_tail"], + ["IDENTIFIER","implemented"], + ["IDENTIFIER","in"], + ["IDENTIFIER","include"], + ["IDENTIFIER","included"], + ["IDENTIFIER","included_modules"], + ["IDENTIFIER","incremental_gc"], + ["IDENTIFIER","index"], + ["IDENTIFIER","IndexError"], + ["IDENTIFIER","inf"], + ["IDENTIFIER","Inf"], + ["IDENTIFIER","INF"], + ["IDENTIFIER","Infinity"], + ["IDENTIFIER","INFINITY"], + ["IDENTIFIER","inherited"], + ["IDENTIFIER","initialize"], + ["IDENTIFIER","initialize_copy"], + ["IDENTIFIER","inject"], + ["IDENTIFIER","in_lower_half"], + ["IDENTIFIER","input"], + ["IDENTIFIER","insert"], + ["IDENTIFIER","_inspect"], + ["IDENTIFIER","inspect"], + ["IDENTIFIER","instance_eval"], + ["IDENTIFIER","instance_exec"], + ["IDENTIFIER","instance_methods"], + ["IDENTIFIER","instance_variable_get"], + ["IDENTIFIER","instance_variables"], + ["IDENTIFIER","instance_variable_set"], + ["IDENTIFIER","int"], + ["IDENTIFIER","integer"], + ["IDENTIFIER","Integer"], + ["IDENTIFIER","Integral"], + ["IDENTIFIER","intern"], + ["IDENTIFIER","interval_ratio"], + ["IDENTIFIER","invert"], + ["IDENTIFIER","io"], + ["IDENTIFIER","Io"], + ["IDENTIFIER","_IO_putc"], + ["IDENTIFIER","ip"], + ["IDENTIFIER","Ip"], + ["IDENTIFIER","irep"], + ["IDENTIFIER","IREP"], + ["IDENTIFIER","isz"], + ["IDENTIFIER","iterate"], + ["IDENTIFIER","_ITM_deregisterTMCloneTable"], + ["IDENTIFIER","_ITM_registerTMCloneTable"], + ["IDENTIFIER","itself"], + ["IDENTIFIER","Jan"], + ["IDENTIFIER","join"], + ["IDENTIFIER","_Jv_RegisterClasses"], + ["IDENTIFIER","keep_if"], + ["IDENTIFIER","Kernel"], + ["IDENTIFIER","key"], + ["IDENTIFIER","KeyError"], + ["IDENTIFIER","keys"], + ["IDENTIFIER","keyword_alias"], + ["IDENTIFIER","keyword_and"], + ["IDENTIFIER","keyword_begin"], + ["IDENTIFIER","keyword_BEGIN"], + ["IDENTIFIER","keyword_break"], + ["IDENTIFIER","keyword_case"], + ["IDENTIFIER","keyword_class"], + ["IDENTIFIER","keyword_def"], + ["IDENTIFIER","keyword_do"], + ["IDENTIFIER","keyword_do_block"], + ["IDENTIFIER","keyword_do_cond"], + ["IDENTIFIER","keyword_do_LAMBDA"], + ["IDENTIFIER","keyword_else"], + ["IDENTIFIER","keyword_elsif"], + ["IDENTIFIER","keyword__ENCODING__"], + ["IDENTIFIER","keyword_end"], + ["IDENTIFIER","keyword_END"], + ["IDENTIFIER","keyword_ensure"], + ["IDENTIFIER","keyword_false"], + ["IDENTIFIER","keyword__FILE__"], + ["IDENTIFIER","keyword_for"], + ["IDENTIFIER","keyword_if"], + ["IDENTIFIER","keyword_in"], + ["IDENTIFIER","keyword__LINE__"], + ["IDENTIFIER","keyword_module"], + ["IDENTIFIER","keyword_next"], + ["IDENTIFIER","keyword_nil"], + ["IDENTIFIER","keyword_not"], + ["IDENTIFIER","keyword_or"], + ["IDENTIFIER","keyword_redo"], + ["IDENTIFIER","keyword_rescue"], + ["IDENTIFIER","keyword_retry"], + ["IDENTIFIER","keyword_return"], + ["IDENTIFIER","keyword_self"], + ["IDENTIFIER","keyword_super"], + ["IDENTIFIER","keyword_then"], + ["IDENTIFIER","keyword_true"], + ["IDENTIFIER","keyword_undef"], + ["IDENTIFIER","keyword_unless"], + ["IDENTIFIER","keyword_until"], + ["IDENTIFIER","keyword_when"], + ["IDENTIFIER","keyword_while"], + ["IDENTIFIER","keyword_yield"], + ["IDENTIFIER","kh_del_ht"], + ["IDENTIFIER","kh_del_iv"], + ["IDENTIFIER","kh_del_mt"], + ["IDENTIFIER","kh_del_n2s"], + ["IDENTIFIER","kh_del_st"], + ["IDENTIFIER","KLVAR"], + ["IDENTIFIER","lambda"], + ["IDENTIFIER","lambda_body"], + ["IDENTIFIER","last"], + ["IDENTIFIER","lazy"], + ["IDENTIFIER","Lazy"], + ["IDENTIFIER","LC"], + ["IDENTIFIER","ld"], + ["IDENTIFIER","LD"], + ["IDENTIFIER","ldexp"], + ["IDENTIFIER","left"], + ["IDENTIFIER","len"], + ["IDENTIFIER","length"], + ["IDENTIFIER","level"], + ["IDENTIFIER","lfD"], + ["IDENTIFIER","lhs"], + ["IDENTIFIER","__libc_start_main"], + ["IDENTIFIER","LII"], + ["IDENTIFIER","lIJ"], + ["IDENTIFIER","lim"], + ["IDENTIFIER","line"], + ["IDENTIFIER","__LINE__"], + ["IDENTIFIER","LINE"], + ["IDENTIFIER","lines"], + ["IDENTIFIER","literal"], + ["IDENTIFIER","literals"], + ["IDENTIFIER","live_after_mark"], + ["IDENTIFIER","ljust"], + ["IDENTIFIER","ln"], + ["IDENTIFIER","Ln"], + ["IDENTIFIER","lo"], + ["IDENTIFIER","local"], + ["IDENTIFIER","LOCAL"], + ["IDENTIFIER","LocalJumpError"], + ["IDENTIFIER","localtime"], + ["IDENTIFIER","localtime_r"], + ["IDENTIFIER","local_variables"], + ["IDENTIFIER","log"], + ["IDENTIFIER","log10"], + ["IDENTIFIER","log2"], + ["IDENTIFIER","long"], + ["IDENTIFIER","longjmp"], + ["IDENTIFIER","lookahead"], + ["IDENTIFIER","loop"], + ["IDENTIFIER","low"], + ["IDENTIFIER","lround"], + ["IDENTIFIER","LS"], + ["IDENTIFIER","lstrip"], + ["IDENTIFIER","LVAR"], + ["IDENTIFIER","machine"], + ["IDENTIFIER","main"], + ["IDENTIFIER","make_curry"], + ["IDENTIFIER","map"], + ["IDENTIFIER","match"], + ["IDENTIFIER","matched"], + ["IDENTIFIER","Math"], + ["IDENTIFIER","max"], + ["IDENTIFIER","max_by"], + ["IDENTIFIER","max_cmp"], + ["IDENTIFIER","May"], + ["IDENTIFIER","mday"], + ["IDENTIFIER","member"], + ["IDENTIFIER","__members__"], + ["IDENTIFIER","members"], + ["IDENTIFIER","memchr"], + ["IDENTIFIER","memcmp"], + ["IDENTIFIER","memcpy"], + ["IDENTIFIER","memmove"], + ["IDENTIFIER","memory"], + ["IDENTIFIER","memset"], + ["IDENTIFIER","merge"], + ["IDENTIFIER","mesg"], + ["IDENTIFIER","message"], + ["IDENTIFIER","meth"], + ["IDENTIFIER","__method__"], + ["IDENTIFIER","method"], + ["IDENTIFIER","method_call"], + ["IDENTIFIER","method_missing"], + ["IDENTIFIER","method_removed"], + ["IDENTIFIER","methods"], + ["IDENTIFIER","mid"], + ["IDENTIFIER","min"], + ["IDENTIFIER","min_by"], + ["IDENTIFIER","min_cmp"], + ["IDENTIFIER","minmax"], + ["IDENTIFIER","minmax_by"], + ["IDENTIFIER","mktime"], + ["IDENTIFIER","mlhs_basic"], + ["IDENTIFIER","mlhs_inner"], + ["IDENTIFIER","mlhs_item"], + ["IDENTIFIER","mlhs_list"], + ["IDENTIFIER","mlhs_node"], + ["IDENTIFIER","mlhs_post"], + ["IDENTIFIER","mode"], + ["IDENTIFIER","modified"], + ["IDENTIFIER","modifier_if"], + ["IDENTIFIER","modifier_rescue"], + ["IDENTIFIER","modifier_unless"], + ["IDENTIFIER","modifier_until"], + ["IDENTIFIER","modifier_while"], + ["IDENTIFIER","module"], + ["IDENTIFIER","Module"], + ["IDENTIFIER","module_eval"], + ["IDENTIFIER","module_function"], + ["IDENTIFIER","modules"], + ["IDENTIFIER","mon"], + ["IDENTIFIER","Mon"], + ["IDENTIFIER","month"], + ["IDENTIFIER","mrb_ary_delete_at"], + ["IDENTIFIER","mrb_ary_new_from_values"], + ["IDENTIFIER","mrb_ary_plus"], + ["IDENTIFIER","mrb_ary_pop"], + ["IDENTIFIER","mrb_ary_push"], + ["IDENTIFIER","mrb_ary_push_m"], + ["IDENTIFIER","mrb_ary_resize"], + ["IDENTIFIER","mrb_ary_reverse"], + ["IDENTIFIER","mrb_ary_set"], + ["IDENTIFIER","mrb_ary_shift"], + ["IDENTIFIER","mrb_ary_splice"], + ["IDENTIFIER","mrb_ary_times"], + ["IDENTIFIER","mrb_ary_unshift"], + ["IDENTIFIER","mrb_ary_unshift_m"], + ["IDENTIFIER","mrb_assoc_new"], + ["IDENTIFIER","mrb_data_init"], + ["IDENTIFIER","mrb_debug_get_line"], + ["IDENTIFIER","mrb_debug_info_alloc"], + ["IDENTIFIER","mrb_debug_info_append_file"], + ["IDENTIFIER","mrb_debug_info_free"], + ["IDENTIFIER","mrb_field_write_barrier"], + ["IDENTIFIER","mrb_gc_mark"], + ["IDENTIFIER","MRB_GC_STATE_ROOT"], + ["IDENTIFIER","MRB_GC_STATE_SWEEP"], + ["IDENTIFIER","mrb_gc_unregister"], + ["IDENTIFIER","mrb_i_mt_state"], + ["IDENTIFIER","mrb_incremental_gc"], + ["IDENTIFIER","mrb_malloc"], + ["IDENTIFIER","mrb_mod_s_nesting"], + ["IDENTIFIER","mrb_obj_value"], + ["IDENTIFIER","mrb_random_init"], + ["IDENTIFIER","mrb_random_srand"], + ["IDENTIFIER","mrb_realloc"], + ["IDENTIFIER","mrb_str_format"], + ["IDENTIFIER","MRB_TT_DATA"], + ["IDENTIFIER","MRB_TT_FIBER"], + ["IDENTIFIER","MRB_TT_FREE"], + ["IDENTIFIER","mrb_vm_const_get"], + ["IDENTIFIER","mrb_vm_exec"], + ["IDENTIFIER","mrb_write_barrier"], + ["IDENTIFIER","mrhs"], + ["IDENTIFIER","mruby"], + ["IDENTIFIER","MRUBY_COPYRIGHT"], + ["IDENTIFIER","MRUBY_DESCRIPTION"], + ["IDENTIFIER","MRUBY_RELEASE_DATE"], + ["IDENTIFIER","MRUBY_RELEASE_NO"], + ["IDENTIFIER","MRUBY_VERSION"], + ["IDENTIFIER","name"], + ["IDENTIFIER","named"], + ["IDENTIFIER","NameError"], + ["IDENTIFIER","names"], + ["IDENTIFIER","nan"], + ["IDENTIFIER","NaN"], + ["IDENTIFIER","NAN"], + ["IDENTIFIER","nesting"], + ["IDENTIFIER","new"], + ["IDENTIFIER","new_args"], + ["IDENTIFIER","new_key"], + ["IDENTIFIER","new_msym"], + ["IDENTIFIER","next"], + ["IDENTIFIER","next_values"], + ["IDENTIFIER","nil"], + ["IDENTIFIER","NilClass"], + ["IDENTIFIER","nl"], + ["IDENTIFIER","nlocals"], + ["IDENTIFIER","nLVAR"], + ["IDENTIFIER","nMATZ0000IREP"], + ["IDENTIFIER","NODE_DREGX"], + ["IDENTIFIER","NODE_DSTR"], + ["IDENTIFIER","NODE_DXSTR"], + ["IDENTIFIER","NODE_FALSE"], + ["IDENTIFIER","NODE_NEGATE"], + ["IDENTIFIER","NODE_NIL"], + ["IDENTIFIER","NODE_REDO"], + ["IDENTIFIER","NODE_RETRY"], + ["IDENTIFIER","NODE_SELF"], + ["IDENTIFIER","NODE_TRUE"], + ["IDENTIFIER","NODE_UNDEF"], + ["IDENTIFIER","NODE_ZSUPER"], + ["IDENTIFIER","NoMemoryError"], + ["IDENTIFIER","NoMethodError"], + ["IDENTIFIER","none"], + ["IDENTIFIER","NONE"], + ["IDENTIFIER","norm"], + ["IDENTIFIER","not"], + ["IDENTIFIER","NotImplementedError"], + ["IDENTIFIER","Nov"], + ["IDENTIFIER","now"], + ["IDENTIFIER","Np"], + ["IDENTIFIER","nregs"], + ["IDENTIFIER","num"], + ["IDENTIFIER","number"], + ["IDENTIFIER","numbered"], + ["IDENTIFIER","numeric"], + ["IDENTIFIER","Numeric"], + ["IDENTIFIER","obj"], + ["IDENTIFIER","object"], + ["IDENTIFIER","Object"], + ["IDENTIFIER","object_id"], + ["IDENTIFIER","ObjectSpace"], + ["IDENTIFIER","oct"], + ["IDENTIFIER","Oct"], + ["IDENTIFIER","offset"], + ["IDENTIFIER","on"], + ["IDENTIFIER","On"], + ["IDENTIFIER","only"], + ["IDENTIFIER","Oo"], + ["IDENTIFIER","op"], + ["IDENTIFIER","Op"], + ["IDENTIFIER","operation"], + ["IDENTIFIER","operation2"], + ["IDENTIFIER","operation3"], + ["IDENTIFIER","OP_NOP"], + ["IDENTIFIER","OP_STOP"], + ["IDENTIFIER","opt_block_arg"], + ["IDENTIFIER","opt_block_param"], + ["IDENTIFIER","opt_bv_decl"], + ["IDENTIFIER","opt_call_args"], + ["IDENTIFIER","opt_else"], + ["IDENTIFIER","opt_ensure"], + ["IDENTIFIER","opt_f_block_arg"], + ["IDENTIFIER","opt_nl"], + ["IDENTIFIER","opt_paren_args"], + ["IDENTIFIER","opt_rescue"], + ["IDENTIFIER","opt_terms"], + ["IDENTIFIER","or"], + ["IDENTIFIER","ord"], + ["IDENTIFIER","orig"], + ["IDENTIFIER","other"], + ["IDENTIFIER","__outer__"], + ["IDENTIFIER","P9o"], + ["IDENTIFIER","padding"], + ["IDENTIFIER","pad_repetitions"], + ["IDENTIFIER","padstr"], + ["IDENTIFIER","parameters"], + ["IDENTIFIER","paren_args"], + ["IDENTIFIER","partition"], + ["IDENTIFIER","pattern"], + ["IDENTIFIER","PC"], + ["IDENTIFIER","peek"], + ["IDENTIFIER","peek_values"], + ["IDENTIFIER","permutation"], + ["IDENTIFIER","plen"], + ["IDENTIFIER","point"], + ["IDENTIFIER","pop"], + ["IDENTIFIER","popping"], + ["IDENTIFIER","pos"], + ["IDENTIFIER","posnum"], + ["IDENTIFIER","post"], + ["IDENTIFIER","pow"], + ["IDENTIFIER","pp"], + ["IDENTIFIER","pproc"], + ["IDENTIFIER","pre"], + ["IDENTIFIER","precision"], + ["IDENTIFIER","prefix"], + ["IDENTIFIER","prepend"], + ["IDENTIFIER","prepended"], + ["IDENTIFIER","prepend_features"], + ["IDENTIFIER","primary"], + ["IDENTIFIER","primary_value"], + ["IDENTIFIER","print"], + ["IDENTIFIER","printf"], + ["IDENTIFIER","__printstr__"], + ["IDENTIFIER","private"], + ["IDENTIFIER","private_methods"], + ["IDENTIFIER","prl"], + ["IDENTIFIER","proc"], + ["IDENTIFIER","Proc"], + ["IDENTIFIER","program"], + ["IDENTIFIER","protected"], + ["IDENTIFIER","protected_methods"], + ["IDENTIFIER","ps"], + ["IDENTIFIER","public"], + ["IDENTIFIER","public_methods"], + ["IDENTIFIER","push"], + ["IDENTIFIER","putchar"], + ["IDENTIFIER","puts"], + ["IDENTIFIER","quo"], + ["IDENTIFIER","raise"], + ["IDENTIFIER","rand"], + ["IDENTIFIER","Random"], + ["IDENTIFIER","range"], + ["IDENTIFIER","Range"], + ["IDENTIFIER","RangeError"], + ["IDENTIFIER","rassoc"], + ["IDENTIFIER","rb"], + ["IDENTIFIER","RB"], + ["IDENTIFIER","rbracket"], + ["IDENTIFIER","RC"], + ["IDENTIFIER","read_debug_record"], + ["IDENTIFIER","readint_mrb_int"], + ["IDENTIFIER","read_irep_record_1"], + ["IDENTIFIER","read_lv_record"], + ["IDENTIFIER","read_section_debug"], + ["IDENTIFIER","read_section_lv"], + ["IDENTIFIER","realloc"], + ["IDENTIFIER","redo"], + ["IDENTIFIER","reduce"], + ["IDENTIFIER","reg"], + ["IDENTIFIER","regexp"], + ["IDENTIFIER","Regexp"], + ["IDENTIFIER","RegexpError"], + ["IDENTIFIER","rehash"], + ["IDENTIFIER","reject"], + ["IDENTIFIER","remove_class_variable"], + ["IDENTIFIER","remove_const"], + ["IDENTIFIER","remove_instance_variable"], + ["IDENTIFIER","remove_method"], + ["IDENTIFIER","replace"], + ["IDENTIFIER","req"], + ["IDENTIFIER","required"], + ["IDENTIFIER","res"], + ["IDENTIFIER","rescue"], + ["IDENTIFIER","resize_capa"], + ["IDENTIFIER","rest"], + ["IDENTIFIER","restarg_mark"], + ["IDENTIFIER","result"], + ["IDENTIFIER","resume"], + ["IDENTIFIER","reswords"], + ["IDENTIFIER","ret"], + ["IDENTIFIER","retry"], + ["IDENTIFIER","return"], + ["IDENTIFIER","reverse"], + ["IDENTIFIER","reverse_each"], + ["IDENTIFIER","rewind"], + ["IDENTIFIER","right"], + ["IDENTIFIER","rindex"], + ["IDENTIFIER","rjust"], + ["IDENTIFIER","rotate"], + ["IDENTIFIER","round"], + ["IDENTIFIER","row"], + ["IDENTIFIER","rparen"], + ["IDENTIFIER","rpartition"], + ["IDENTIFIER","rs_len"], + ["IDENTIFIER","rstrip"], + ["IDENTIFIER","RUBY_ENGINE"], + ["IDENTIFIER","RUBY_ENGINE_VERSION"], + ["IDENTIFIER","RUBY_VERSION"], + ["IDENTIFIER","RuntimeError"], + ["IDENTIFIER","sample"], + ["IDENTIFIER","Sat"], + ["IDENTIFIER","satisfied"], + ["IDENTIFIER","scan"], + ["IDENTIFIER","SClass"], + ["IDENTIFIER","scope"], + ["IDENTIFIER","scope_new"], + ["IDENTIFIER","script"], + ["IDENTIFIER","ScriptError"], + ["IDENTIFIER","sec"], + ["IDENTIFIER","select"], + ["IDENTIFIER","self"], + ["IDENTIFIER","self_arity"], + ["IDENTIFIER","__send__"], + ["IDENTIFIER","send"], + ["IDENTIFIER","sep"], + ["IDENTIFIER","Sep"], + ["IDENTIFIER","sequence"], + ["IDENTIFIER","set"], + ["IDENTIFIER","set_backtrace"], + ["IDENTIFIER","setbyte"], + ["IDENTIFIER","_setjmp"], + ["IDENTIFIER","shift"], + ["IDENTIFIER","shuffle"], + ["IDENTIFIER","sin"], + ["IDENTIFIER","singleton"], + ["IDENTIFIER","singleton_class"], + ["IDENTIFIER","singleton_methods"], + ["IDENTIFIER","sinh"], + ["IDENTIFIER","size"], + ["IDENTIFIER","sl"], + ["IDENTIFIER","slice"], + ["IDENTIFIER","snprintf"], + ["IDENTIFIER","so"], + ["IDENTIFIER","So"], + ["IDENTIFIER","sort"], + ["IDENTIFIER","sort_by"], + ["IDENTIFIER","__sort_sub__"], + ["IDENTIFIER","source_location"], + ["IDENTIFIER","Sp"], + ["IDENTIFIER","spaces"], + ["IDENTIFIER","specifier"], + ["IDENTIFIER","splice"], + ["IDENTIFIER","split"], + ["IDENTIFIER","sprintf"], + ["IDENTIFIER","sqrt"], + ["IDENTIFIER","srand"], + ["IDENTIFIER","__stack_chk_fail"], + ["IDENTIFIER","StandardError"], + ["IDENTIFIER","start"], + ["IDENTIFIER","state"], + ["IDENTIFIER","stderr"], + ["IDENTIFIER","stdin"], + ["IDENTIFIER","stdout"], + ["IDENTIFIER","step"], + ["IDENTIFIER","step_ratio"], + ["IDENTIFIER","stmt"], + ["IDENTIFIER","stmts"], + ["IDENTIFIER","stop_exc"], + ["IDENTIFIER","StopIteration"], + ["IDENTIFIER","store"], + ["IDENTIFIER","str"], + ["IDENTIFIER","str2"], + ["IDENTIFIER","strchr"], + ["IDENTIFIER","strcmp"], + ["IDENTIFIER","str_each"], + ["IDENTIFIER","string"], + ["IDENTIFIER","String"], + ["IDENTIFIER","string_interp"], + ["IDENTIFIER","string_rep"], + ["IDENTIFIER","strip"], + ["IDENTIFIER","strlen"], + ["IDENTIFIER","str_make_shared"], + ["IDENTIFIER","strncmp"], + ["IDENTIFIER","strncpy"], + ["IDENTIFIER","strtoul"], + ["IDENTIFIER","struct"], + ["IDENTIFIER","Struct"], + ["IDENTIFIER","sub"], + ["IDENTIFIER","__sub_replace"], + ["IDENTIFIER","succ"], + ["IDENTIFIER","Sun"], + ["IDENTIFIER","super"], + ["IDENTIFIER","superclass"], + ["IDENTIFIER","supported"], + ["IDENTIFIER","__svalue"], + ["IDENTIFIER","SVD"], + ["IDENTIFIER","swapcase"], + ["IDENTIFIER","sym"], + ["IDENTIFIER","symbol"], + ["IDENTIFIER","Symbol"], + ["IDENTIFIER","symbols"], + ["IDENTIFIER","sym_inspect"], + ["IDENTIFIER","syntax"], + ["IDENTIFIER","SyntaxError"], + ["IDENTIFIER","_sys_fail"], + ["IDENTIFIER","SystemCallError"], + ["IDENTIFIER","SystemStackError"], + ["IDENTIFIER","TA"], + ["IDENTIFIER","tail"], + ["IDENTIFIER","take"], + ["IDENTIFIER","taken"], + ["IDENTIFIER","take_while"], + ["IDENTIFIER","tAMPER"], + ["IDENTIFIER","tan"], + ["IDENTIFIER","tANDDOT"], + ["IDENTIFIER","tANDOP"], + ["IDENTIFIER","tanh"], + ["IDENTIFIER","tap"], + ["IDENTIFIER","tAREF"], + ["IDENTIFIER","T_ARRAY"], + ["IDENTIFIER","tASET"], + ["IDENTIFIER","tASSOC"], + ["IDENTIFIER","TB"], + ["IDENTIFIER","tBACK_REF"], + ["IDENTIFIER","TbG"], + ["IDENTIFIER","T_CLASS"], + ["IDENTIFIER","tCMP"], + ["IDENTIFIER","tCOLON2"], + ["IDENTIFIER","tCOLON3"], + ["IDENTIFIER","tCONSTANT"], + ["IDENTIFIER","T_CPTR"], + ["IDENTIFIER","tCVAR"], + ["IDENTIFIER","T_DATA"], + ["IDENTIFIER","tDOT2"], + ["IDENTIFIER","tDOT3"], + ["IDENTIFIER","TeD"], + ["IDENTIFIER","T_ENV"], + ["IDENTIFIER","tEQ"], + ["IDENTIFIER","tEQQ"], + ["IDENTIFIER","term"], + ["IDENTIFIER","terms"], + ["IDENTIFIER","T_EXCEPTION"], + ["IDENTIFIER","T_FALSE"], + ["IDENTIFIER","T_FIBER"], + ["IDENTIFIER","tFID"], + ["IDENTIFIER","T_FILE"], + ["IDENTIFIER","T_FIXNUM"], + ["IDENTIFIER","tFLOAT"], + ["IDENTIFIER","T_FLOAT"], + ["IDENTIFIER","T_FREE"], + ["IDENTIFIER","tGEQ"], + ["IDENTIFIER","tGVAR"], + ["IDENTIFIER","T_HASH"], + ["IDENTIFIER","tHD_LITERAL_DELIM"], + ["IDENTIFIER","tHD_STRING_MID"], + ["IDENTIFIER","tHD_STRING_PART"], + ["IDENTIFIER","then"], + ["IDENTIFIER","tHEREDOC_BEG"], + ["IDENTIFIER","tHEREDOC_END"], + ["IDENTIFIER","this"], + ["IDENTIFIER","T_ICLASS"], + ["IDENTIFIER","tIDENTIFIER"], + ["IDENTIFIER","time"], + ["IDENTIFIER","Time"], + ["IDENTIFIER","times"], + ["IDENTIFIER","tINTEGER"], + ["IDENTIFIER","tIVAR"], + ["IDENTIFIER","tLABEL"], + ["IDENTIFIER","tLABEL_END"], + ["IDENTIFIER","tLAMBDA"], + ["IDENTIFIER","tLAMBEG"], + ["IDENTIFIER","tLAST_TOKEN"], + ["IDENTIFIER","tLBRACE"], + ["IDENTIFIER","tLBRACE_ARG"], + ["IDENTIFIER","tLBRACK"], + ["IDENTIFIER","tLEQ"], + ["IDENTIFIER","tLITERAL_DELIM"], + ["IDENTIFIER","tLOWEST"], + ["IDENTIFIER","tLPAREN"], + ["IDENTIFIER","tLPAREN_ARG"], + ["IDENTIFIER","tLSHFT"], + ["IDENTIFIER","tMATCH"], + ["IDENTIFIER","T_MODULE"], + ["IDENTIFIER","tmp"], + ["IDENTIFIER","tNEQ"], + ["IDENTIFIER","tNMATCH"], + ["IDENTIFIER","tNTH_REF"], + ["IDENTIFIER","to_ary"], + ["IDENTIFIER","T_OBJECT"], + ["IDENTIFIER","to_enum"], + ["IDENTIFIER","to_h"], + ["IDENTIFIER","to_hash"], + ["IDENTIFIER","to_i"], + ["IDENTIFIER","to_int"], + ["IDENTIFIER","TOJ"], + ["IDENTIFIER","TOLERANCE"], + ["IDENTIFIER","tolower"], + ["IDENTIFIER","tOP_ASGN"], + ["IDENTIFIER","top_compstmt"], + ["IDENTIFIER","to_proc"], + ["IDENTIFIER","top_stmt"], + ["IDENTIFIER","top_stmts"], + ["IDENTIFIER","tOROP"], + ["IDENTIFIER","to_s"], + ["IDENTIFIER","to_str"], + ["IDENTIFIER","to_sym"], + ["IDENTIFIER","TOTAL"], + ["IDENTIFIER","toupper"], + ["IDENTIFIER","tPOW"], + ["IDENTIFIER","T_PROC"], + ["IDENTIFIER","trailer"], + ["IDENTIFIER","T_RANGE"], + ["IDENTIFIER","transfer"], + ["IDENTIFIER","transform_keys"], + ["IDENTIFIER","transform_values"], + ["IDENTIFIER","transpose"], + ["IDENTIFIER","tREGEXP"], + ["IDENTIFIER","tREGEXP_BEG"], + ["IDENTIFIER","tREGEXP_END"], + ["IDENTIFIER","tRPAREN"], + ["IDENTIFIER","tRSHFT"], + ["IDENTIFIER","true"], + ["IDENTIFIER","TrueClass"], + ["IDENTIFIER","truncate"], + ["IDENTIFIER","try_convert"], + ["IDENTIFIER","T_SCLASS"], + ["IDENTIFIER","tSTAR"], + ["IDENTIFIER","tSTRING"], + ["IDENTIFIER","T_STRING"], + ["IDENTIFIER","tSTRING_BEG"], + ["IDENTIFIER","tSTRING_DVAR"], + ["IDENTIFIER","tSTRING_MID"], + ["IDENTIFIER","tSTRING_PART"], + ["IDENTIFIER","tSYMBEG"], + ["IDENTIFIER","T_SYMBOL"], + ["IDENTIFIER","tSYMBOLS_BEG"], + ["IDENTIFIER","tt"], + ["IDENTIFIER","T_TRUE"], + ["IDENTIFIER","Tue"], + ["IDENTIFIER","tUMINUS"], + ["IDENTIFIER","tUMINUS_NUM"], + ["IDENTIFIER","T_UNDEF"], + ["IDENTIFIER","tUPLUS"], + ["IDENTIFIER","twice"], + ["IDENTIFIER","tWORDS_BEG"], + ["IDENTIFIER","tXSTRING"], + ["IDENTIFIER","tXSTRING_BEG"], + ["IDENTIFIER","type"], + ["IDENTIFIER","TypeError"], + ["IDENTIFIER","umrb_obj_value"], + ["IDENTIFIER","undef"], + ["IDENTIFIER","undefined"], + ["IDENTIFIER","undef_list"], + ["IDENTIFIER","undef_method"], + ["IDENTIFIER","uniq"], + ["IDENTIFIER","unless"], + ["IDENTIFIER","unshift"], + ["IDENTIFIER","until"], + ["IDENTIFIER","upcase"], + ["IDENTIFIER","__update"], + ["IDENTIFIER","update"], + ["IDENTIFIER","upto"], + ["IDENTIFIER","usec"], + ["IDENTIFIER","useless"], + ["IDENTIFIER","utc"], + ["IDENTIFIER","v0000"], + ["IDENTIFIER","val"], + ["IDENTIFIER","validated"], + ["IDENTIFIER","vals"], + ["IDENTIFIER","value"], + ["IDENTIFIER","values"], + ["IDENTIFIER","values_at"], + ["IDENTIFIER","variable"], + ["IDENTIFIER","var_lhs"], + ["IDENTIFIER","var_ref"], + ["IDENTIFIER","verbose"], + ["IDENTIFIER","version"], + ["IDENTIFIER","vm"], + ["IDENTIFIER","Vm"], + ["IDENTIFIER","warn"], + ["IDENTIFIER","wday"], + ["IDENTIFIER","Wed"], + ["IDENTIFIER","when"], + ["IDENTIFIER","while"], + ["IDENTIFIER","width"], + ["IDENTIFIER","with_index"], + ["IDENTIFIER","with_object"], + ["IDENTIFIER","words"], + ["IDENTIFIER","x86_64"], + ["IDENTIFIER","xstring"], + ["IDENTIFIER","yday"], + ["IDENTIFIER","year"], + ["IDENTIFIER","yield"], + ["IDENTIFIER","yielder"], + ["IDENTIFIER","Yielder"], + ["IDENTIFIER","yield_self"], + ["IDENTIFIER","zip"], + ["IDENTIFIER","zone"] + ] diff --git a/fuzzers/baby_fuzzer_nautilus/rust-toolchain b/fuzzers/baby_fuzzer_nautilus/rust-toolchain new file mode 100644 index 0000000000..bf867e0ae5 --- /dev/null +++ b/fuzzers/baby_fuzzer_nautilus/rust-toolchain @@ -0,0 +1 @@ +nightly diff --git a/fuzzers/baby_fuzzer_nautilus/src/main.rs b/fuzzers/baby_fuzzer_nautilus/src/main.rs new file mode 100644 index 0000000000..bfdb1ef031 --- /dev/null +++ b/fuzzers/baby_fuzzer_nautilus/src/main.rs @@ -0,0 +1,163 @@ +use std::path::PathBuf; + +#[cfg(windows)] +use std::ptr::write_volatile; + +use libafl::{ + bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, + corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler}, + events::SimpleEventManager, + executors::{inprocess::InProcessExecutor, ExitKind}, + feedback_or, + feedbacks::{ + CrashFeedback, MapFeedbackState, MaxMapFeedback, NautilusChunksMetadata, NautilusFeedback, + }, + fuzzer::{Fuzzer, StdFuzzer}, + generators::{NautilusContext, NautilusGenerator}, + inputs::NautilusInput, + mutators::{ + NautilusRandomMutator, NautilusRecursionMutator, NautilusSpliceMutator, StdScheduledMutator, + }, + observers::StdMapObserver, + stages::mutational::StdMutationalStage, + state::{HasMetadata, StdState}, + stats::SimpleStats, +}; + +/// Coverage map with explicit assignments due to the lack of instrumentation +static mut SIGNALS: [u8; 16] = [0; 16]; +/* +/// Assign a signal to the signals map +fn signals_set(idx: usize) { + unsafe { SIGNALS[idx] = 1 }; +} +*/ + +#[allow(clippy::similar_names)] +pub fn main() { + let context = NautilusContext::from_file(15, "grammar.json"); + let mut bytes = vec![]; + + // The closure that we want to fuzz + let mut harness = |input: &NautilusInput| { + input.unparse(&context, &mut bytes); + unsafe { + println!(">>> {}", std::str::from_utf8_unchecked(&bytes)); + } + ExitKind::Ok + }; + + // Create an observation channel using the signals map + let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); + + // The state of the edges feedback. + let feedback_state = MapFeedbackState::with_observer(&observer); + + // Feedback to rate the interestingness of an input + let feedback = feedback_or!( + MaxMapFeedback::new(&feedback_state, &observer), + NautilusFeedback::new(&context) + ); + + // A feedback to choose if an input is a solution or not + let objective = CrashFeedback::new(); + + // create a State from scratch + let mut state = StdState::new( + // RNG + StdRand::with_seed(current_nanos()), + // Corpus that will be evolved, we keep it in memory for performance + InMemoryCorpus::new(), + // Corpus in which we store solutions (crashes in this example), + // on disk so the user can get them after stopping the fuzzer + OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), + // States of the feedbacks. + // They are the data related to the feedbacks that you want to persist in the State. + tuple_list!(feedback_state), + ); + + if state.metadata().get::().is_none() { + state.add_metadata(NautilusChunksMetadata::new("/tmp/".into())); + } + + // The Stats trait define how the fuzzer stats are reported to the user + let stats = SimpleStats::new(|s| println!("{}", s)); + + // The event manager handle the various events generated during the fuzzing loop + // such as the notification of the addition of a new item to the corpus + let mut mgr = SimpleEventManager::new(stats); + + // A queue policy to get testcasess from the corpus + let scheduler = QueueCorpusScheduler::new(); + + // A fuzzer with feedbacks and a corpus scheduler + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); + + // Create the executor for an in-process function with just one observer + let mut executor = InProcessExecutor::new( + &mut harness, + tuple_list!(observer), + &mut fuzzer, + &mut state, + &mut mgr, + ) + .expect("Failed to create the Executor"); + + let mut generator = NautilusGenerator::new(&context); + + // Use this code to profile the generator performance + /* + use libafl::generators::Generator; + use std::collections::hash_map::DefaultHasher; + use std::collections::HashSet; + use std::hash::{Hash, Hasher}; + + fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + let mut set = HashSet::new(); + let st = libafl::bolts::current_milliseconds(); + let mut b = vec![]; + let mut c = 0; + for _ in 0..100000 { + let i = generator.generate(&mut state).unwrap(); + i.unparse(&context, &mut b); + set.insert(calculate_hash(&b)); + c += b.len(); + } + println!("{} / {}", c, libafl::bolts::current_milliseconds() - st); + println!("{} / 100000", set.len()); + + return; + */ + + // Generate 8 initial inputs + state + .generate_initial_inputs_forced(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8) + .expect("Failed to generate the initial corpus"); + + // Setup a mutational stage with a basic bytes mutator + let mutator = StdScheduledMutator::with_max_iterations( + tuple_list!( + NautilusRandomMutator::new(&context), + NautilusRandomMutator::new(&context), + NautilusRandomMutator::new(&context), + NautilusRandomMutator::new(&context), + NautilusRandomMutator::new(&context), + NautilusRandomMutator::new(&context), + NautilusRecursionMutator::new(&context), + NautilusSpliceMutator::new(&context), + NautilusSpliceMutator::new(&context), + NautilusSpliceMutator::new(&context), + ), + 2, + ); + let mut stages = tuple_list!(StdMutationalStage::new(mutator)); + + fuzzer + .fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr) + .expect("Error in the fuzzing loop"); +} diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 8e0ee5b75f..2edffd251d 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -11,6 +11,26 @@ keywords = ["fuzzing", "testing", "security"] edition = "2021" build = "build.rs" +[features] +default = ["std", "anymap_debug", "derive", "llmp_compression", "rand_trait", "fork"] +std = ["serde_json", "serde_json/std", "hostname", "core_affinity", "nix", "serde/std", "bincode", "wait-timeout", "regex", "build_id", "uuid"] # print, env, launcher ... support +anymap_debug = ["serde_json"] # uses serde_json to Debug the anymap trait. Disable for smaller footprint. +derive = ["libafl_derive"] # provide derive(SerdeAny) macro. +fork = [] # uses the fork() syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on Windows, no_std). +rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng` +introspection = [] # Include performance statistics of the fuzzing pipeline +concolic_mutation = ["z3"] # include a simple concolic mutator based on z3 +# features hiding dependencies licensed under GPL +gpl = [] +# features hiding dependencies licensed under AGPL +agpl = ["gpl", "nautilus"] +nautilus = ["grammartec", "std", "serde_json/std"] +# LLMP features +llmp_bind_public = [] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. +llmp_compression = ["miniz_oxide"] # llmp compression using GZip +llmp_debug = ["backtrace"] # Enables debug output for LLMP +llmp_small_maps = [] # reduces initial map size for llmp + [build-dependencies] rustc_version = "0.4" @@ -23,38 +43,6 @@ serde_json = "1.0.60" num_cpus = "1.0" # cpu count, for llmp example serial_test = "0.5" -[[bench]] -name = "rand_speeds" -harness = false - -[[bench]] -name = "hash_speeds" -harness = false - -#[profile.release] -#lto = true -#opt-level = 3 -#debug = true - -[features] -default = ["std", "anymap_debug", "derive", "llmp_compression", "rand_trait", "fork"] -std = ["serde_json", "hostname", "core_affinity", "nix", "serde/std", "bincode", "wait-timeout", "regex", "build_id", "uuid"] # print, env, launcher ... support -anymap_debug = ["serde_json"] # uses serde_json to Debug the anymap trait. Disable for smaller footprint. -derive = ["libafl_derive"] # provide derive(SerdeAny) macro. -fork = [] # uses the fork() syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on Windows, no_std). -rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng` -llmp_bind_public = [] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. -llmp_compression = ["miniz_oxide"] # llmp compression using GZip -llmp_debug = ["backtrace"] # Enables debug output for LLMP -llmp_small_maps = [] # reduces initial map size for llmp -introspection = [] # Include performance statistics of the fuzzing pipeline -concolic_mutation = ["z3"] # include a simple concolic mutator based on z3 - -[[example]] -name = "llmp_test" -path = "./examples/llmp_test/main.rs" -required-features = ["std"] - [dependencies] tuple_list = { version = "0.1.3" } hashbrown = { version = "0.11", features = ["serde", "ahash-compile-time-rng"], default-features=false } # A faster hashmap, nostd compatible @@ -87,6 +75,9 @@ wait-timeout = { version = "0.2", optional = true } # used by CommandExecutor to z3 = { version = "0.11", features = ["static-link-z3"], optional = true } # for concolic mutation +# AGPL +grammartec = { git = "https://github.com/andreafioraldi/nautilus", optional = true } + [target.'cfg(target_os = "android")'.dependencies] backtrace = { version = "0.3", optional = true, default-features = false, features = ["std", "libbacktrace"] } # for llmp_debug @@ -105,3 +96,21 @@ uuid = { version = "0.8", features = ["v4"] } [target.'cfg(windows)'.build-dependencies] windows = "0.18.0" + +[[bench]] +name = "rand_speeds" +harness = false + +[[bench]] +name = "hash_speeds" +harness = false + +#[profile.release] +#lto = true +#opt-level = 3 +#debug = true + +[[example]] +name = "llmp_test" +path = "./examples/llmp_test/main.rs" +required-features = ["std"] diff --git a/libafl/src/bolts/launcher.rs b/libafl/src/bolts/launcher.rs index 91c1f9694b..03c419c492 100644 --- a/libafl/src/bolts/launcher.rs +++ b/libafl/src/bolts/launcher.rs @@ -81,7 +81,7 @@ where /// Then, clients launched by this [`Launcher`] can connect to the original `broker`. #[builder(default = true)] spawn_broker: bool, - #[builder(default = PhantomData)] + #[builder(setter(skip), default = PhantomData)] phantom_data: PhantomData<(&'a I, &'a OT, &'a S, &'a SP)>, } diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index e1467ea2ed..643682e946 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -425,12 +425,16 @@ unsafe fn _llmp_page_init(shmem: &mut SHM, sender: u32, allow_reinit let page = shmem2page_mut(shmem); #[cfg(all(feature = "llmp_debug", feature = "std"))] dbg!("_llmp_page_init: page {}", *page); - if (*page).magic == PAGE_INITIALIZED_MAGIC && !allow_reinit { - panic!( + + if !allow_reinit { + assert!( + (*page).magic != PAGE_INITIALIZED_MAGIC, "Tried to initialize page {:?} twice (for shmem {:?})", - page, shmem + page, + shmem ); - }; + } + (*page).magic = PAGE_INITIALIZED_MAGIC; (*page).sender = sender; ptr::write_volatile(ptr::addr_of_mut!((*page).current_msg_id), 0); @@ -898,18 +902,20 @@ where let map = self.out_maps.last_mut().unwrap(); let page = map.page_mut(); let last_msg = self.last_msg_sent; - if (*page).size_used + EOP_MSG_SIZE > (*page).size_total { - panic!("PROGRAM ABORT : BUG: EOP does not fit in page! page {:?}, size_current {:?}, size_total {:?}", page, + assert!((*page).size_used + EOP_MSG_SIZE <= (*page).size_total, + "PROGRAM ABORT : BUG: EOP does not fit in page! page {:?}, size_current {:?}, size_total {:?}", page, ptr::addr_of!((*page).size_used), ptr::addr_of!((*page).size_total)); - } + let mut ret: *mut LlmpMsg = if last_msg.is_null() { (*page).messages.as_mut_ptr() } else { llmp_next_msg_ptr_checked(map, last_msg, EOP_MSG_SIZE)? }; - if (*ret).tag == LLMP_TAG_UNINITIALIZED { - panic!("Did not call send() on last message!"); - } + assert!( + (*ret).tag != LLMP_TAG_UNINITIALIZED, + "Did not call send() on last message!" + ); + (*ret).buf_len = size_of::() as u64; // We don't need to pad the EOP message: it'll always be the last in this page. @@ -932,9 +938,10 @@ where let page = map.page_mut(); let last_msg = self.last_msg_sent; - if self.has_unsent_message { - panic!("Called alloc without callind send inbetween"); - } + assert!( + !self.has_unsent_message, + "Called alloc without calling send inbetween" + ); #[cfg(all(feature = "llmp_debug", feature = "std"))] println!( @@ -1009,12 +1016,12 @@ where unsafe fn send(&mut self, msg: *mut LlmpMsg, overwrite_client_id: bool) -> Result<(), Error> { // dbg!("Sending msg {:?}", msg); - if self.last_msg_sent == msg { - panic!("Message sent twice!"); - } - if (*msg).tag == LLMP_TAG_UNSET { - panic!("No tag set on message with id {}", (*msg).message_id); - } + assert!(self.last_msg_sent != msg, "Message sent twice!"); + assert!( + (*msg).tag != LLMP_TAG_UNSET, + "No tag set on message with id {}", + (*msg).message_id + ); // A client gets the sender id assigned to by the broker during the initial handshake. if overwrite_client_id { (*msg).sender = self.id; @@ -1369,14 +1376,14 @@ where #[cfg(feature = "std")] println!("Received end of page, allocating next"); // Handle end of page - if (*msg).buf_len < size_of::() as u64 { - panic!( - "Illegal message length for EOP (is {}/{}, expected {})", - (*msg).buf_len, - (*msg).buf_len_padded, - size_of::() - ); - } + assert!( + (*msg).buf_len >= size_of::() as u64, + "Illegal message length for EOP (is {}/{}, expected {})", + (*msg).buf_len, + (*msg).buf_len_padded, + size_of::() + ); + #[allow(clippy::cast_ptr_alignment)] let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; @@ -1427,9 +1434,11 @@ where let page = self.current_recv_map.page_mut(); let last_msg = self.last_msg_recvd; if !last_msg.is_null() { - if (*last_msg).tag == LLMP_TAG_END_OF_PAGE && !llmp_msg_in_page(page, last_msg) { - panic!("BUG: full page passed to await_message_blocking or reset failed"); - } + assert!( + !((*last_msg).tag == LLMP_TAG_END_OF_PAGE && !llmp_msg_in_page(page, last_msg)), + "BUG: full page passed to await_message_blocking or reset failed" + ); + current_msg_id = (*last_msg).message_id; } loop { @@ -1564,9 +1573,11 @@ where shmem: existing_map, }; unsafe { - if (*ret.page()).magic != PAGE_INITIALIZED_MAGIC { - panic!("Map was not priviously initialized at {:?}", &ret.shmem); - } + assert!( + (*ret.page()).magic == PAGE_INITIALIZED_MAGIC, + "Map was not priviously initialized at {:?}", + &ret.shmem + ); #[cfg(all(feature = "llmp_debug", feature = "std"))] dbg!("PAGE: {}", *ret.page()); } diff --git a/libafl/src/bolts/os/unix_shmem_server.rs b/libafl/src/bolts/os/unix_shmem_server.rs index 7b8b28d78b..23d3b3dc04 100644 --- a/libafl/src/bolts/os/unix_shmem_server.rs +++ b/libafl/src/bolts/os/unix_shmem_server.rs @@ -82,7 +82,7 @@ where { fn id(&self) -> ShMemId { let client_id = self.inner.id(); - ShMemId::from_string(&format!("{}:{}", self.server_fd, client_id.to_string())) + ShMemId::from_string(&format!("{}:{}", self.server_fd, client_id)) } fn len(&self) -> usize { diff --git a/libafl/src/bolts/os/unix_signals.rs b/libafl/src/bolts/os/unix_signals.rs index af8ae64c3e..9c9c96a0ef 100644 --- a/libafl/src/bolts/os/unix_signals.rs +++ b/libafl/src/bolts/os/unix_signals.rs @@ -194,13 +194,12 @@ pub unsafe fn setup_signal_handler(handler: &mut T) -> Res if SIGNAL_STACK_PTR.is_null() { SIGNAL_STACK_PTR = malloc(SIGNAL_STACK_SIZE); - if SIGNAL_STACK_PTR.is_null() { - // Rust always panics on OOM, so we will, too. - panic!( - "Failed to allocate signal stack with {} bytes!", - SIGNAL_STACK_SIZE - ); - } + // Rust always panics on OOM, so we will, too. + assert!( + !SIGNAL_STACK_PTR.is_null(), + "Failed to allocate signal stack with {} bytes!", + SIGNAL_STACK_SIZE + ); } let mut ss: stack_t = mem::zeroed(); ss.ss_size = SIGNAL_STACK_SIZE; diff --git a/libafl/src/bolts/serdeany.rs b/libafl/src/bolts/serdeany.rs index 16d0e843a0..674f8682f0 100644 --- a/libafl/src/bolts/serdeany.rs +++ b/libafl/src/bolts/serdeany.rs @@ -142,9 +142,7 @@ macro_rules! create_serde_registry_for_trait { where T: $trait_name + Serialize + serde::de::DeserializeOwned, { - if self.finalized { - panic!("Registry is already finalized!"); - } + assert!(!self.finalized, "Registry is already finalized!"); let deserializers = self.deserializers.get_or_insert_with(HashMap::default); deserializers.insert(unpack_type_id(TypeId::of::()), |de| { diff --git a/libafl/src/bolts/shmem.rs b/libafl/src/bolts/shmem.rs index f7a2dc6a13..d893ab56ca 100644 --- a/libafl/src/bolts/shmem.rs +++ b/libafl/src/bolts/shmem.rs @@ -700,16 +700,18 @@ pub mod unix_shmem { impl Drop for MmapShMem { fn drop(&mut self) { unsafe { - if self.map.is_null() { - panic!("Map should never be null for MmapShMem (on Drop)"); - } + assert!( + !self.map.is_null(), + "Map should never be null for MmapShMem (on Drop)" + ); munmap(self.map as *mut _, self.map_size); self.map = ptr::null_mut(); - if self.shm_fd == -1 { - panic!("FD should never be -1 for MmapShMem (on Drop)"); - } + assert!( + self.shm_fd != -1, + "FD should never be -1 for MmapShMem (on Drop)" + ); // None in case we didn't [`shm_open`] this ourselves, but someone sent us the FD. if let Some(filename_path) = self.filename_path { diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 281618910e..78e557c2df 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -467,9 +467,11 @@ where let mut events = vec![]; let self_id = self.llmp.sender.id; while let Some((client_id, tag, _flags, msg)) = self.llmp.recv_buf_with_flags()? { - if tag == _LLMP_TAG_EVENT_TO_BROKER { - panic!("EVENT_TO_BROKER parcel should not have arrived in the client!"); - } + assert!( + tag != _LLMP_TAG_EVENT_TO_BROKER, + "EVENT_TO_BROKER parcel should not have arrived in the client!" + ); + if client_id == self_id { continue; } @@ -729,8 +731,8 @@ where /// The type of manager to build #[builder(default = ManagerKind::Any)] kind: ManagerKind, - #[builder(setter(skip), default = PhantomData {})] - _phantom: PhantomData<(I, OT, S)>, + #[builder(setter(skip), default = PhantomData)] + phantom_data: PhantomData<(I, OT, S)>, } #[cfg(feature = "std")] @@ -856,6 +858,7 @@ where if !staterestorer.has_content() { #[cfg(unix)] + #[allow(clippy::manual_assert)] if child_status == 137 { // Out of Memory, see https://tldp.org/LDP/abs/html/exitcodes.html // and https://github.com/AFLplusplus/LibAFL/issues/32 for discussion. diff --git a/libafl/src/events/simple.rs b/libafl/src/events/simple.rs index 2555f8700a..6959983067 100644 --- a/libafl/src/events/simple.rs +++ b/libafl/src/events/simple.rs @@ -368,6 +368,7 @@ where if !staterestorer.has_content() { #[cfg(unix)] + #[allow(clippy::manual_assert)] if child_status == 137 { // Out of Memory, see https://tldp.org/LDP/abs/html/exitcodes.html // and https://github.com/AFLplusplus/LibAFL/issues/32 for discussion. diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 7ee67b7b2b..18e8700fd4 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -254,9 +254,8 @@ where .match_name_mut::>(&self.name) .unwrap(); - if size > map_state.history_map.len() { - panic!("The size of the associated map observer cannot exceed the size of the history map of the feedback. If you are running multiple instances of slightly different fuzzers (e.g. one with ASan and another without) synchronized using LLMP please check the `configuration` field of the LLMP manager."); - } + assert!(size <= map_state.history_map.len(), "The size of the associated map observer cannot exceed the size of the history map of the feedback. If you are running multiple instances of slightly different fuzzers (e.g. one with ASan and another without) synchronized using LLMP please check the `configuration` field of the LLMP manager."); + assert!(size <= observer.len()); if self.novelties.is_some() { diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 6c6a90b307..024542a34b 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -9,6 +9,11 @@ pub mod concolic; #[cfg(feature = "std")] pub use concolic::ConcolicFeedback; +#[cfg(feature = "nautilus")] +pub mod nautilus; +#[cfg(feature = "nautilus")] +pub use nautilus::*; + use alloc::string::{String, ToString}; use serde::{Deserialize, Serialize}; diff --git a/libafl/src/feedbacks/nautilus.rs b/libafl/src/feedbacks/nautilus.rs new file mode 100644 index 0000000000..6e49a7526e --- /dev/null +++ b/libafl/src/feedbacks/nautilus.rs @@ -0,0 +1,89 @@ +use grammartec::{chunkstore::ChunkStore, context::Context}; +use serde::{Deserialize, Serialize}; +use std::fs::create_dir_all; + +use crate::{ + bolts::tuples::Named, + corpus::Testcase, + events::EventFirer, + executors::ExitKind, + feedbacks::Feedback, + generators::NautilusContext, + inputs::NautilusInput, + observers::ObserversTuple, + state::{HasClientPerfStats, HasMetadata}, + Error, +}; + +#[derive(Serialize, Deserialize)] +pub struct NautilusChunksMetadata { + pub cks: ChunkStore, +} + +crate::impl_serdeany!(NautilusChunksMetadata); + +impl NautilusChunksMetadata { + #[must_use] + pub fn new(work_dir: String) -> Self { + create_dir_all(format!("{}/outputs/chunks", &work_dir)) + .expect("Could not create folder in workdir"); + Self { + cks: ChunkStore::new(work_dir), + } + } +} + +pub struct NautilusFeedback<'a> { + ctx: &'a Context, +} + +impl<'a> NautilusFeedback<'a> { + #[must_use] + pub fn new(context: &'a NautilusContext) -> Self { + Self { ctx: &context.ctx } + } +} + +impl<'a> Named for NautilusFeedback<'a> { + fn name(&self) -> &str { + "NautilusFeedback" + } +} + +impl<'a, S> Feedback for NautilusFeedback<'a> +where + S: HasMetadata + HasClientPerfStats, +{ + fn is_interesting( + &mut self, + _state: &mut S, + _manager: &mut EM, + _input: &NautilusInput, + _observers: &OT, + _exit_kind: &ExitKind, + ) -> Result + where + EM: EventFirer, + OT: ObserversTuple, + { + Ok(false) + } + + fn append_metadata( + &mut self, + state: &mut S, + testcase: &mut Testcase, + ) -> Result<(), Error> { + let input = testcase.load_input()?.clone(); + let meta = state + .metadata_mut() + .get_mut::() + .expect("NautilusChunksMetadata not in the state"); + meta.cks.add_tree(input.tree, self.ctx); + Ok(()) + } + + fn discard_metadata(&mut self, _state: &mut S, _input: &NautilusInput) -> Result<(), Error> { + Ok(()) + } +} diff --git a/libafl/src/generators/mod.rs b/libafl/src/generators/mod.rs index 68dc6f4c54..42d90d567b 100644 --- a/libafl/src/generators/mod.rs +++ b/libafl/src/generators/mod.rs @@ -13,6 +13,11 @@ use crate::{ pub mod gramatron; pub use gramatron::*; +#[cfg(feature = "nautilus")] +pub mod nautilus; +#[cfg(feature = "nautilus")] +pub use nautilus::*; + /// The maximum size of dummy bytes generated by _dummy generator methods const DUMMY_BYTES_MAX: usize = 64; diff --git a/libafl/src/generators/nautilus.rs b/libafl/src/generators/nautilus.rs new file mode 100644 index 0000000000..51be4da97c --- /dev/null +++ b/libafl/src/generators/nautilus.rs @@ -0,0 +1,75 @@ +use alloc::{string::String, vec::Vec}; +use std::{fs, io::BufReader, path::Path}; + +use crate::{generators::Generator, inputs::nautilus::NautilusInput, Error}; + +use grammartec::context::Context; +pub use grammartec::newtypes::NTermID; + +pub struct NautilusContext { + pub ctx: Context, +} + +impl NautilusContext { + /// Returns a new [`NautilusGenerator`] + #[must_use] + pub fn new(tree_depth: usize, rules: &[Vec]) -> Self { + assert!(!rules.is_empty()); + assert!(!rules[0].is_empty()); + let mut ctx = Context::new(); + for rule in rules { + ctx.add_rule(&rule[0], rule[1].as_bytes()); + } + let root = "{".to_string() + &rules[0][0] + "}"; + ctx.add_rule("START", root.as_bytes()); + ctx.initialize(tree_depth); + Self { ctx } + } + + #[must_use] + pub fn from_file>(tree_depth: usize, grammar_file: P) -> Self { + let file = fs::File::open(grammar_file).expect("Cannot open grammar file"); + let reader = BufReader::new(file); + let rules: Vec> = + serde_json::from_reader(reader).expect("Cannot parse grammar file"); + Self::new(tree_depth, &rules) + } +} + +#[derive(Clone)] +/// Generates random inputs from a grammar +pub struct NautilusGenerator<'a> { + pub ctx: &'a Context, +} + +impl<'a, S> Generator for NautilusGenerator<'a> { + fn generate(&mut self, _state: &mut S) -> Result { + let nonterm = self.nonterminal("START"); + let len = self.ctx.get_random_len_for_nt(&nonterm); + let mut input = NautilusInput::empty(); + self.generate_from_nonterminal(&mut input, nonterm, len); + Ok(input) + } + + fn generate_dummy(&self, _state: &mut S) -> NautilusInput { + NautilusInput::empty() + } +} + +impl<'a> NautilusGenerator<'a> { + /// Returns a new [`NautilusGenerator`] + #[must_use] + pub fn new(context: &'a NautilusContext) -> Self { + Self { ctx: &context.ctx } + } + + // TODO create from a python grammar + #[must_use] + pub fn nonterminal(&self, name: &str) -> NTermID { + self.ctx.nt_id(name) + } + + pub fn generate_from_nonterminal(&self, input: &mut NautilusInput, start: NTermID, len: usize) { + input.tree_mut().generate_from_nt(start, len, self.ctx); + } +} diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index b4a2d70974..f9a38c2837 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -9,6 +9,11 @@ pub use encoded::*; pub mod gramatron; pub use gramatron::*; +#[cfg(feature = "nautilus")] +pub mod nautilus; +#[cfg(feature = "nautilus")] +pub use nautilus::*; + use alloc::{ string::{String, ToString}, vec::Vec, diff --git a/libafl/src/inputs/nautilus.rs b/libafl/src/inputs/nautilus.rs new file mode 100644 index 0000000000..883afa0338 --- /dev/null +++ b/libafl/src/inputs/nautilus.rs @@ -0,0 +1,80 @@ +//use ahash::AHasher; +//use core::hash::Hasher; + +use alloc::{rc::Rc, string::String}; +use core::{cell::RefCell, convert::From}; +use serde::{Deserialize, Serialize}; + +use crate::{bolts::HasLen, generators::nautilus::NautilusContext, inputs::Input}; + +use grammartec::{ + newtypes::NodeID, + tree::{Tree, TreeLike}, +}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct NautilusInput { + /// The input representation as Tree + pub tree: Tree, +} + +impl Input for NautilusInput { + /// Generate a name for this input + #[must_use] + fn generate_name(&self, idx: usize) -> String { + /*let mut hasher = AHasher::new_with_keys(0, 0); + for term in &self.terms { + hasher.write(term.symbol.as_bytes()); + } + format!("{:016x}", hasher.finish())*/ + format!("id:{}", idx) + } +} + +/// Rc Ref-cell from Input +impl From for Rc> { + fn from(input: NautilusInput) -> Self { + Rc::new(RefCell::new(input)) + } +} + +impl HasLen for NautilusInput { + #[inline] + fn len(&self) -> usize { + self.tree.size() + } +} + +impl NautilusInput { + /// Creates a new codes input using the given terminals + #[must_use] + pub fn new(tree: Tree) -> Self { + Self { tree } + } + + #[must_use] + pub fn empty() -> Self { + Self { + tree: Tree { + rules: vec![], + sizes: vec![], + paren: vec![], + }, + } + } + + pub fn unparse(&self, context: &NautilusContext, bytes: &mut Vec) { + bytes.clear(); + self.tree.unparse(NodeID::from(0), &context.ctx, bytes); + } + + #[must_use] + pub fn tree(&self) -> &Tree { + &self.tree + } + + #[must_use] + pub fn tree_mut(&mut self) -> &mut Tree { + &mut self.tree + } +} diff --git a/libafl/src/mutators/gramatron.rs b/libafl/src/mutators/gramatron.rs index a85b58bac6..f0243f337c 100644 --- a/libafl/src/mutators/gramatron.rs +++ b/libafl/src/mutators/gramatron.rs @@ -67,7 +67,7 @@ where } #[derive(Serialize, Deserialize)] -struct GramatronIdxMapMetadata { +pub struct GramatronIdxMapMetadata { pub map: HashMap>, } diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index ca4d649f9b..f4eb777a9a 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -13,6 +13,11 @@ pub use mopt_mutator::*; pub mod gramatron; pub use gramatron::*; +#[cfg(feature = "nautilus")] +pub mod nautilus; +#[cfg(feature = "nautilus")] +pub use nautilus::*; + use crate::{ bolts::tuples::{HasConstLen, Named}, inputs::Input, diff --git a/libafl/src/mutators/nautilus.rs b/libafl/src/mutators/nautilus.rs new file mode 100644 index 0000000000..b1440bacad --- /dev/null +++ b/libafl/src/mutators/nautilus.rs @@ -0,0 +1,192 @@ +use core::marker::PhantomData; + +use crate::{ + bolts::tuples::Named, + corpus::Corpus, + feedbacks::NautilusChunksMetadata, + generators::nautilus::NautilusContext, + inputs::nautilus::NautilusInput, + mutators::{MutationResult, Mutator}, + state::{HasCorpus, HasMetadata}, + Error, +}; + +use grammartec::mutator::Mutator as BackingMutator; +use grammartec::{ + context::Context, + tree::{Tree, TreeMutation}, +}; + +pub struct NautilusRandomMutator<'a> { + ctx: &'a Context, + mutator: BackingMutator, +} + +impl<'a, S> Mutator for NautilusRandomMutator<'a> { + fn mutate( + &mut self, + _state: &mut S, + input: &mut NautilusInput, + _stage_idx: i32, + ) -> Result { + // TODO get rid of tmp + let mut tmp = vec![]; + self.mutator + .mut_random::<_, ()>( + &input.tree, + self.ctx, + &mut |t: &TreeMutation, _ctx: &Context| { + tmp.extend_from_slice(t.prefix); + tmp.extend_from_slice(t.repl); + tmp.extend_from_slice(t.postfix); + Ok(()) + }, + ) + .unwrap(); + if tmp.is_empty() { + Ok(MutationResult::Skipped) + } else { + input.tree = Tree::from_rule_vec(tmp, self.ctx); + Ok(MutationResult::Mutated) + } + } +} + +impl<'a> Named for NautilusRandomMutator<'a> { + fn name(&self) -> &str { + "NautilusRandomMutator" + } +} + +impl<'a> NautilusRandomMutator<'a> { + /// Creates a new [`NautilusRandomMutator`]. + #[must_use] + pub fn new(context: &'a NautilusContext) -> Self { + let mutator = BackingMutator::new(&context.ctx); + Self { + ctx: &context.ctx, + mutator, + } + } +} + +// TODO calculate reucursions only for new items in corpus +pub struct NautilusRecursionMutator<'a> { + ctx: &'a Context, + mutator: BackingMutator, +} + +impl<'a, S> Mutator for NautilusRecursionMutator<'a> { + fn mutate( + &mut self, + _state: &mut S, + input: &mut NautilusInput, + _stage_idx: i32, + ) -> Result { + // TODO don't calc recursions here + if let Some(ref mut recursions) = input.tree.calc_recursions(self.ctx) { + // TODO get rid of tmp + let mut tmp = vec![]; + self.mutator + .mut_random_recursion::<_, ()>( + &input.tree, + recursions, + self.ctx, + &mut |t: &TreeMutation, _ctx: &Context| { + tmp.extend_from_slice(t.prefix); + tmp.extend_from_slice(t.repl); + tmp.extend_from_slice(t.postfix); + Ok(()) + }, + ) + .unwrap(); + if !tmp.is_empty() { + input.tree = Tree::from_rule_vec(tmp, self.ctx); + return Ok(MutationResult::Mutated); + } + } + Ok(MutationResult::Skipped) + } +} + +impl<'a> Named for NautilusRecursionMutator<'a> { + fn name(&self) -> &str { + "NautilusRecursionMutator" + } +} + +impl<'a> NautilusRecursionMutator<'a> { + /// Creates a new [`NautilusRecursionMutator`]. + #[must_use] + pub fn new(context: &'a NautilusContext) -> Self { + let mutator = BackingMutator::new(&context.ctx); + Self { + ctx: &context.ctx, + mutator, + } + } +} + +pub struct NautilusSpliceMutator<'a, C> { + ctx: &'a Context, + mutator: BackingMutator, + phantom: PhantomData, +} + +impl<'a, S, C> Mutator for NautilusSpliceMutator<'a, C> +where + C: Corpus, + S: HasCorpus + HasMetadata, +{ + fn mutate( + &mut self, + state: &mut S, + input: &mut NautilusInput, + _stage_idx: i32, + ) -> Result { + let meta = state + .metadata() + .get::() + .expect("NautilusChunksMetadata not in the state"); + // TODO get rid of tmp + let mut tmp = vec![]; + self.mutator + .mut_splice::<_, ()>( + &input.tree, + self.ctx, + &meta.cks, + &mut |t: &TreeMutation, _ctx: &Context| { + tmp.extend_from_slice(t.prefix); + tmp.extend_from_slice(t.repl); + tmp.extend_from_slice(t.postfix); + Ok(()) + }, + ) + .unwrap(); + if tmp.is_empty() { + Ok(MutationResult::Skipped) + } else { + input.tree = Tree::from_rule_vec(tmp, self.ctx); + Ok(MutationResult::Mutated) + } + } +} + +impl<'a, C> Named for NautilusSpliceMutator<'a, C> { + fn name(&self) -> &str { + "NautilusSpliceMutator" + } +} + +impl<'a, C> NautilusSpliceMutator<'a, C> { + /// Creates a new [`NautilusSpliceMutator`]. + #[must_use] + pub fn new(context: &'a NautilusContext) -> Self { + let mutator = BackingMutator::new(&context.ctx); + Self { + ctx: &context.ctx, + mutator, + phantom: PhantomData, + } + } +} diff --git a/libafl_concolic/symcc_libafl/src/lib.rs b/libafl_concolic/symcc_libafl/src/lib.rs index b5cfb7e721..697fba0ced 100644 --- a/libafl_concolic/symcc_libafl/src/lib.rs +++ b/libafl_concolic/symcc_libafl/src/lib.rs @@ -21,9 +21,11 @@ mod clone { /// Checks out the repository into the given directory with the given URL and commit hash. /// Any errors will trigger a panic. pub fn clone_symcc_at_version(path: &Path, url: &str, commit: &str) { - if which("git").is_err() { - panic!("ERROR: unable to find git. Git is required to download SymCC."); - } + assert!( + which("git").is_ok(), + "ERROR: unable to find git. Git is required to download SymCC." + ); + let mut cmd = Command::new("git"); cmd.arg("clone").arg(url).arg(&path); let output = cmd.output().expect("failed to execute git clone"); diff --git a/libafl_frida/src/alloc.rs b/libafl_frida/src/alloc.rs index 7380444753..87b259d875 100644 --- a/libafl_frida/src/alloc.rs +++ b/libafl_frida/src/alloc.rs @@ -57,9 +57,12 @@ pub(crate) struct AllocationMetadata { impl Allocator { pub fn new(options: FridaOptions) -> Self { let ret = unsafe { sysconf(_SC_PAGESIZE) }; - if ret < 0 { - panic!("Failed to read pagesize {:?}", io::Error::last_os_error()); - } + assert!( + ret >= 0, + "Failed to read pagesize {:?}", + io::Error::last_os_error() + ); + #[allow(clippy::cast_sign_loss)] let page_size = ret as usize; // probe to find a usable shadow bit: @@ -200,9 +203,11 @@ impl Allocator { size }; if size > self.options.asan_max_allocation() { + #[allow(clippy::manual_assert)] if self.options.asan_max_allocation_panics() { - panic!("Allocation is too large: 0x{:x}", size); + panic!("ASAN: Allocation is too large: 0x{:x}", size); } + return std::ptr::null_mut(); } let rounded_up_size = self.round_up_to_page(size) + 2 * self.page_size; diff --git a/libafl_frida/src/asan_errors.rs b/libafl_frida/src/asan_errors.rs index c7baabe2fc..c9416872af 100644 --- a/libafl_frida/src/asan_errors.rs +++ b/libafl_frida/src/asan_errors.rs @@ -534,8 +534,9 @@ impl AsanErrors { } }; + #[allow(clippy::manual_assert)] if !self.options.asan_continue_after_error() { - panic!("Crashing target!"); + panic!("ASAN: Crashing target!"); } } } diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 4a6f341531..6e3b035139 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -109,23 +109,21 @@ impl FridaOptions { "drcov" => { options.enable_drcov = value.parse().unwrap(); #[cfg(not(target_arch = "aarch64"))] - if options.enable_drcov { - panic!( - "DrCov is not currently supported on targets other than aarch64" - ); - } + assert!( + !options.enable_drcov, + "DrCov is not currently supported on targets other than aarch64" + ); } "cmplog" => { options.enable_cmplog = value.parse().unwrap(); #[cfg(not(target_arch = "aarch64"))] - if options.enable_cmplog { - panic!( - "cmplog is not currently supported on targets other than aarch64" - ); - } + assert!( + !options.enable_cmplog, + "cmplog is not currently supported on targets other than aarch64" + ); - if !cfg!(feature = "cmplog") && options.enable_cmplog { - panic!("cmplog feature is disabled!"); + if options.enable_cmplog { + assert!(cfg!(feature = "cmplog"), "cmplog feature is disabled!"); } } "cmplog-cores" => { diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 86c3ada8ea..7bdcdf9b0a 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -333,6 +333,7 @@ where let state = inprocess_get_state::().unwrap(); let mut res = SyscallHookResult::new(None); for hook in unsafe { &SYSCALL_HOOKS } { + #[allow(clippy::type_complexity)] let func: fn( &mut QT, &mut S, @@ -585,6 +586,7 @@ where } #[allow(clippy::unused_self)] + #[allow(clippy::type_complexity)] pub fn hook_syscalls( &self, hook: fn( diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index 7244f0bc15..1bfd5b2a36 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -85,9 +85,11 @@ where let mut out_dir = self.output_dir.clone(); if fs::create_dir(&out_dir).is_err() { println!("Out dir at {:?} already exists.", &out_dir); - if !out_dir.is_dir() { - panic!("Out dir at {:?} is not a valid directory!", &out_dir); - } + assert!( + out_dir.is_dir(), + "Out dir at {:?} is not a valid directory!", + &out_dir + ); } let mut crashes = out_dir.clone(); crashes.push("crashes"); diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index ab55883fb2..2c3c4b4875 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -84,9 +84,11 @@ where let mut out_dir = self.output_dir.clone(); if fs::create_dir(&out_dir).is_err() { println!("Out dir at {:?} already exists.", &out_dir); - if !out_dir.is_dir() { - panic!("Out dir at {:?} is not a valid directory!", &out_dir); - } + assert!( + out_dir.is_dir(), + "Out dir at {:?} is not a valid directory!", + &out_dir + ); } let mut crashes = out_dir.clone(); crashes.push("crashes"); diff --git a/libafl_targets/src/libfuzzer.rs b/libafl_targets/src/libfuzzer.rs index aba87b65c4..60fda5d613 100644 --- a/libafl_targets/src/libfuzzer.rs +++ b/libafl_targets/src/libfuzzer.rs @@ -1,4 +1,4 @@ -//! (Libfuzzer)[https://www.llvm.org/docs/LibFuzzer.html]-style runtime wrapper for `LibAFL`. +//! [`Libfuzzer`](https://www.llvm.org/docs/LibFuzzer.html)-style runtime wrapper for `LibAFL`. //! This makes `LibAFL` interoperable with harnesses written for other fuzzers like `Libfuzzer` and [`AFLplusplus`](aflplus.plus). //! We will interact with a C++ target, so use external c functionality diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 39ad1e6313..750d041e4d 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -85,8 +85,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32 *start = MAX_EDGES_NUM as u32; start = start.offset(1); MAX_EDGES_NUM = MAX_EDGES_NUM.wrapping_add(1); - if MAX_EDGES_NUM > EDGES_MAP.len() { - panic!("The number of edges reported by SanitizerCoverage exceed the size of the edges map ({}). Use the LIBAFL_EDGES_MAP_SIZE env to increase it at compile time.", EDGES_MAP.len()); - } + + assert!((MAX_EDGES_NUM <= EDGES_MAP.len()), "The number of edges reported by SanitizerCoverage exceed the size of the edges map ({}). Use the LIBAFL_EDGES_MAP_SIZE env to increase it at compile time.", EDGES_MAP.len()); } } diff --git a/scripts/clippy.sh b/scripts/clippy.sh index e5495394b3..0ae23a5619 100755 --- a/scripts/clippy.sh +++ b/scripts/clippy.sh @@ -8,7 +8,7 @@ if [ "$1" != "--no-clean" ]; then echo "[+] Cleaning up previous builds..." cargo clean -p libafl fi -RUST_BACKTRACE=full cargo clippy --all --all-features --tests -- \ +RUST_BACKTRACE=full cargo +nightly clippy --all --all-features --tests -- -Z macro-backtrace \ -D clippy::pedantic \ -W clippy::similar_names \ -A clippy::type_repetition_in_bounds \ diff --git a/utils/README.md b/utils/README.md index cbf267f964..d3231fd3c7 100644 --- a/utils/README.md +++ b/utils/README.md @@ -9,3 +9,6 @@ In the `deexit` folder, you'll find a ldpreloadable library, that changes calls When a target exits, it quits, and LibAFL will not be able to catch this or recover. Abort, on the other hand, raises an error LibAFL's inprocess executor will be able to catch, thanks to its signal handlers. +## Gramatron: gramatron grammars and preprocessing utils + +See https://github.com/HexHive/Gramatron diff --git a/scripts/gramatron/README.md b/utils/gramatron/README.md similarity index 100% rename from scripts/gramatron/README.md rename to utils/gramatron/README.md diff --git a/scripts/gramatron/construct_automata.py b/utils/gramatron/construct_automata.py similarity index 100% rename from scripts/gramatron/construct_automata.py rename to utils/gramatron/construct_automata.py diff --git a/scripts/gramatron/construct_automata/Cargo.toml b/utils/gramatron/construct_automata/Cargo.toml similarity index 95% rename from scripts/gramatron/construct_automata/Cargo.toml rename to utils/gramatron/construct_automata/Cargo.toml index 50430e5e82..4e551a0ff6 100644 --- a/scripts/gramatron/construct_automata/Cargo.toml +++ b/utils/gramatron/construct_automata/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "construct_automata" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/scripts/gramatron/construct_automata/src/clap-config.yaml b/utils/gramatron/construct_automata/src/clap-config.yaml similarity index 100% rename from scripts/gramatron/construct_automata/src/clap-config.yaml rename to utils/gramatron/construct_automata/src/clap-config.yaml diff --git a/scripts/gramatron/construct_automata/src/main.rs b/utils/gramatron/construct_automata/src/main.rs similarity index 90% rename from scripts/gramatron/construct_automata/src/main.rs rename to utils/gramatron/construct_automata/src/main.rs index 9dc3c8960a..5e8c597ea5 100644 --- a/scripts/gramatron/construct_automata/src/main.rs +++ b/utils/gramatron/construct_automata/src/main.rs @@ -50,7 +50,7 @@ fn tokenize(rule: &str) -> (String, Vec, bool) { let ss = cap.get(3).map_or(vec![], |m| { m.as_str() .split_whitespace() - .map(|x| x.to_owned()) + .map(ToOwned::to_owned) .collect() }); if terminal == "\\n" { @@ -66,7 +66,7 @@ fn prepare_transitions( state_stacks: &mut Stacks, state_count: &mut usize, worklist: &mut VecDeque, - element: Element, + element: &Element, stack_limit: usize, ) { if element.items.is_empty() { @@ -88,7 +88,7 @@ fn prepare_transitions( let mut state_stack = state_stacks .q .get(&state) - .map_or(VecDeque::new(), |x| x.clone()); + .map_or(VecDeque::new(), Clone::clone); if !state_stack.is_empty() { state_stack.pop_front(); } @@ -109,7 +109,7 @@ fn prepare_transitions( // Check if a recursive transition state being created, if so make a backward // edge and don't add anything to the worklist - for (key, val) in state_stacks.s.iter() { + for (key, val) in &state_stacks.s { if state_stack_sorted == *val { transition.dest = *key; // i += 1; @@ -123,11 +123,9 @@ fn prepare_transitions( // If the generated state has a stack size > stack_limit then that state is abandoned // and not added to the FSA or the worklist for further expansion - if stack_limit > 0 { - if transition.stack.len() > stack_limit { - // TODO add to unexpanded_rules - continue; - } + if stack_limit > 0 && transition.stack.len() > stack_limit { + // TODO add to unexpanded_rules + continue; } // Create transitions for the non-recursive relations and add to the worklist @@ -153,11 +151,11 @@ fn get_states(pda: &[Transition]) -> (HashSet, HashSet, HashSet Automaton { //let mut culled_pda_unique = HashSet::new(); for final_state in &finals { - pda.iter().for_each(|transition| { + for transition in pda.iter() { if transition.dest == *final_state && transition.stack.len() > 0 { blocklist.insert(transition.dest); } else { culled_pda.push(transition); //culled_pda_unique.insert(transition); } - }); + } } // println!("culled_pda size: {} pda size: {}", culled_pda.len(), pda.len()); - let culled_finals: HashSet = finals.difference(&blocklist).map(|x| *x).collect(); + let culled_finals: HashSet = finals.difference(&blocklist).copied().collect(); assert!(culled_finals.len() == 1); - culled_pda.iter().for_each(|transition| { + for transition in &culled_pda { if blocklist.contains(&transition.dest) { - return; + continue; } num_transition += 1; let state = transition.source; @@ -218,7 +216,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton { culled_pda.len() ); } - }); + } /* culled_pda_unique.iter().for_each(|transition| { @@ -235,13 +233,13 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton { */ Automaton { - init_state: initial.iter().next().cloned().unwrap(), - final_state: culled_finals.iter().next().cloned().unwrap(), + init_state: initial.iter().next().copied().unwrap(), + final_state: culled_finals.iter().next().copied().unwrap(), pda: memoized, } } else { // Running FSA construction in exact approximation mode and postprocessing it like so - pda.iter().for_each(|transition| { + for transition in pda.iter() { num_transition += 1; let state = transition.source; if state >= memoized.len() { @@ -259,11 +257,11 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton { pda.len() ); } - }); + } Automaton { - init_state: initial.iter().next().cloned().unwrap(), - final_state: finals.iter().next().cloned().unwrap(), + init_state: initial.iter().next().copied().unwrap(), + final_state: finals.iter().next().copied().unwrap(), pda: memoized, } } @@ -298,7 +296,7 @@ fn main() { &mut state_stacks, &mut state_count, &mut worklist, - element, + &element, stack_limit, ); } diff --git a/scripts/gramatron/gnf_converter.py b/utils/gramatron/gnf_converter.py similarity index 100% rename from scripts/gramatron/gnf_converter.py rename to utils/gramatron/gnf_converter.py diff --git a/scripts/gramatron/grammars/js_grammar.json b/utils/gramatron/grammars/js_grammar.json similarity index 100% rename from scripts/gramatron/grammars/js_grammar.json rename to utils/gramatron/grammars/js_grammar.json diff --git a/scripts/gramatron/grammars/php_grammar.json b/utils/gramatron/grammars/php_grammar.json similarity index 100% rename from scripts/gramatron/grammars/php_grammar.json rename to utils/gramatron/grammars/php_grammar.json diff --git a/scripts/gramatron/grammars/ruby_grammar.json b/utils/gramatron/grammars/ruby_grammar.json similarity index 100% rename from scripts/gramatron/grammars/ruby_grammar.json rename to utils/gramatron/grammars/ruby_grammar.json