From 25386bfb5fcc7a9fb46e9b881bced5f07ea10700 Mon Sep 17 00:00:00 2001 From: Valentin Huber Date: Fri, 20 Dec 2024 16:55:35 +0100 Subject: [PATCH 01/25] =?UTF-8?q?Use=20#[expect(=E2=80=A6)]=20instead=20of?= =?UTF-8?q?=20#[allow(=E2=80=A6)],=20remove=20unnecessary=20allows=20(#278?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use expect instead of allow, remove unnecessary allows * Remove more whitelist lint warnings * tranisitioning more subprojects * Re-add some necessary allows * Re-add more required allows * Some more windows clippy fixes * Re-add more whitelist items for expect * More clippy whitelist fun * Reset changes to generated files * Reset generated files to correct version * Move libafl_concolic to expect instead of allow * Move libafl_frida to expect from allow * Move libafl_libfuzzer to expect from allow * Remove more whitelist items for macOS * Fix unknown clippy allow * Remove more unnecessary allow statements * moving fuzzers * Remove mistakenly added subdirs * fixing imports * Remove more unnecessary whitelisted lints * Fix test for /home/ubuntu/LibAFL/fuzzers/inprocess/libfuzzer_libpng_accounting * More clippy improvements for libafl_qemu * fmt * Some pedantic options * Fix more stuff * Remove Little-CMS again * Add note to static_mut_refs * Reset the changed testing routine since it is unnecessary --- fuzzers/baby/baby_fuzzer/src/main.rs | 6 +- .../baby_fuzzer_custom_executor/src/main.rs | 5 +- .../baby/baby_fuzzer_minimizing/src/main.rs | 5 +- .../baby_fuzzer_swap_differential/src/main.rs | 5 +- fuzzers/baby/baby_fuzzer_unicode/src/main.rs | 6 +- .../c_code_with_fork_executor/src/main.rs | 1 - .../src/main.rs | 1 - .../command_executor/build.rs | 7 +- .../command_executor/src/main.rs | 4 +- .../forkserver_executor/build.rs | 2 +- .../forkserver_executor/src/main.rs | 1 - .../rust_code_with_fork_executor/src/main.rs | 4 +- .../src/main.rs | 5 +- fuzzers/baby/tutorial/src/input.rs | 1 + .../frida_executable_libpng/src/fuzzer.rs | 2 +- .../frida_executable_libpng/src/lib.rs | 1 - .../binary_only/frida_libpng/src/fuzzer.rs | 2 +- .../frida_windows_gdiplus/src/fuzzer.rs | 2 +- .../fuzzbench_fork_qemu/src/fuzzer.rs | 2 +- .../intel_pt_baby_fuzzer/src/main.rs | 3 +- .../intel_pt_command_executor/src/main.rs | 3 +- fuzzers/binary_only/qemu_cmin/src/fuzzer.rs | 1 - .../binary_only/qemu_coverage/src/fuzzer.rs | 2 - .../binary_only/qemu_launcher/src/client.rs | 6 +- .../binary_only/qemu_launcher/src/harness.rs | 6 +- .../binary_only/qemu_launcher/src/instance.rs | 3 +- .../binary_only/qemu_launcher/src/options.rs | 1 - .../baby_fuzzer_with_forkexecutor/src/main.rs | 3 +- .../forkserver_libafl_cc/src/main.rs | 1 - .../forkserver/forkserver_simple/src/main.rs | 1 - .../fuzzbench_forkserver/src/main.rs | 2 +- .../fuzzbench_forkserver_cmplog/src/main.rs | 2 +- fuzzers/forkserver/libafl-fuzz/src/corpus.rs | 4 +- .../forkserver/libafl-fuzz/src/executor.rs | 2 +- .../libafl-fuzz/src/feedback/filepath.rs | 1 - .../src/feedback/persistent_record.rs | 1 - .../libafl-fuzz/src/feedback/seed.rs | 2 +- fuzzers/forkserver/libafl-fuzz/src/main.rs | 8 +- .../src/stages/mutational_stage.rs | 1 - .../fuzz_anything/baby_fuzzer_wasm/src/lib.rs | 12 +- fuzzers/fuzz_anything/baby_no_std/src/main.rs | 3 +- fuzzers/fuzz_anything/cargo_fuzz/src/lib.rs | 6 +- .../fuzz_anything/libafl_atheris/src/lib.rs | 1 - .../fuzz_anything/push_harness/src/main.rs | 4 +- .../push_stage_harness/src/main.rs | 4 +- fuzzers/inprocess/dynamic_analysis/build.rs | 6 +- fuzzers/inprocess/dynamic_analysis/src/lib.rs | 7 +- fuzzers/inprocess/fuzzbench/src/lib.rs | 2 +- fuzzers/inprocess/fuzzbench_ctx/src/lib.rs | 2 +- fuzzers/inprocess/fuzzbench_text/src/lib.rs | 6 +- .../inprocess/libfuzzer_libmozjpeg/src/lib.rs | 4 + fuzzers/inprocess/libfuzzer_libpng/src/lib.rs | 2 + .../libfuzzer_libpng_accounting/Cargo.toml | 1 + .../libfuzzer_libpng_accounting/src/lib.rs | 2 + .../libfuzzer_libpng_centralized/src/lib.rs | 2 +- .../libfuzzer_libpng_tcp_manager/src/lib.rs | 2 + .../baby_fuzzer_custom_input/src/main.rs | 3 +- .../baby_fuzzer_gramatron/src/main.rs | 2 +- .../baby_fuzzer_grimoire/src/main.rs | 5 +- .../baby_fuzzer_multi/src/main.rs | 2 +- .../baby_fuzzer_nautilus/src/main.rs | 5 +- .../baby_fuzzer_tokens/src/main.rs | 5 +- .../forkserver_simple_nautilus/src/main.rs | 1 - .../nautilus_sync/src/bin/libafl_cc.rs | 1 - .../structure_aware/nautilus_sync/src/lib.rs | 2 +- libafl/src/common/mod.rs | 2 - .../src/common/nautilus/grammartec/context.rs | 1 - .../src/common/nautilus/grammartec/mutator.rs | 5 +- .../common/nautilus/grammartec/newtypes.rs | 7 + .../grammartec/python_grammar_loader.rs | 6 +- .../nautilus/grammartec/recursion_info.rs | 4 +- libafl/src/common/nautilus/grammartec/rule.rs | 1 - libafl/src/common/nautilus/grammartec/tree.rs | 7 +- libafl/src/common/nautilus/mod.rs | 2 + .../src/common/nautilus/regex_mutator/mod.rs | 1 - libafl/src/corpus/inmemory_ondisk.rs | 3 + libafl/src/corpus/minimizer.rs | 2 +- libafl/src/corpus/testcase.rs | 3 +- libafl/src/events/broker_hooks/centralized.rs | 2 +- libafl/src/events/broker_hooks/mod.rs | 2 +- libafl/src/events/centralized.rs | 4 +- libafl/src/events/launcher.rs | 4 +- libafl/src/events/llmp/mgr.rs | 3 +- libafl/src/events/llmp/mod.rs | 1 - libafl/src/events/llmp/restarting.rs | 12 +- libafl/src/events/mod.rs | 4 +- libafl/src/events/multi_machine.rs | 3 +- libafl/src/events/simple.rs | 8 +- libafl/src/events/tcp.rs | 20 +- libafl/src/executors/command.rs | 1 - libafl/src/executors/differential.rs | 4 +- libafl/src/executors/forkserver.rs | 57 +++-- libafl/src/executors/hooks/inprocess.rs | 23 +- libafl/src/executors/hooks/timer.rs | 16 +- libafl/src/executors/hooks/unix.rs | 5 +- libafl/src/executors/hooks/windows.rs | 2 - libafl/src/executors/inprocess/mod.rs | 5 - libafl/src/executors/inprocess/stateful.rs | 5 +- libafl/src/executors/inprocess_fork/inner.rs | 2 - libafl/src/executors/inprocess_fork/mod.rs | 10 +- .../src/executors/inprocess_fork/stateful.rs | 5 +- libafl/src/executors/mod.rs | 4 +- libafl/src/feedbacks/capture_feedback.rs | 1 - libafl/src/feedbacks/concolic.rs | 1 - libafl/src/feedbacks/differential.rs | 1 - libafl/src/feedbacks/list.rs | 1 - libafl/src/feedbacks/map.rs | 17 +- libafl/src/feedbacks/mod.rs | 9 - libafl/src/feedbacks/nautilus.rs | 1 - libafl/src/feedbacks/new_hash_feedback.rs | 4 +- libafl/src/feedbacks/stdio.rs | 6 +- libafl/src/fuzzer/mod.rs | 1 - libafl/src/inputs/encoded.rs | 1 - libafl/src/inputs/generalized.rs | 2 +- libafl/src/lib.rs | 47 ++--- libafl/src/monitors/mod.rs | 15 +- libafl/src/monitors/prometheus.rs | 5 +- libafl/src/monitors/tui/mod.rs | 16 +- libafl/src/monitors/tui/ui.rs | 8 +- libafl/src/mutators/gramatron.rs | 14 +- libafl/src/mutators/mod.rs | 2 +- libafl/src/mutators/mopt_mutator.rs | 9 +- libafl/src/mutators/mutations.rs | 9 +- libafl/src/mutators/numeric.rs | 4 +- libafl/src/mutators/scheduled.rs | 2 +- libafl/src/mutators/token_mutations.rs | 28 +-- libafl/src/mutators/tuneable.rs | 5 +- libafl/src/mutators/unicode/mod.rs | 4 +- libafl/src/observers/cmp.rs | 5 +- libafl/src/observers/concolic/metadata.rs | 2 +- libafl/src/observers/concolic/mod.rs | 2 +- .../concolic/serialization_format.rs | 4 +- libafl/src/observers/list.rs | 1 - libafl/src/observers/map/const_map.rs | 2 +- libafl/src/observers/map/hitcount_map.rs | 5 +- libafl/src/observers/map/mod.rs | 2 +- libafl/src/observers/map/multi_map.rs | 1 - libafl/src/observers/map/owned_map.rs | 1 - libafl/src/observers/map/variable_map.rs | 2 +- libafl/src/observers/mod.rs | 3 +- libafl/src/observers/stacktrace.rs | 3 +- libafl/src/observers/value.rs | 4 +- libafl/src/schedulers/accounting.rs | 8 +- libafl/src/schedulers/minimizer.rs | 8 +- libafl/src/schedulers/powersched.rs | 2 +- .../src/schedulers/probabilistic_sampling.rs | 5 +- libafl/src/schedulers/testcase_score.rs | 11 +- libafl/src/schedulers/tuneable.rs | 2 +- libafl/src/schedulers/weighted.rs | 10 +- libafl/src/stages/afl_stats.rs | 9 +- libafl/src/stages/calibrate.rs | 8 +- libafl/src/stages/colorization.rs | 7 +- libafl/src/stages/concolic.rs | 2 +- libafl/src/stages/dump.rs | 4 +- libafl/src/stages/generalization.rs | 7 +- libafl/src/stages/mod.rs | 5 +- libafl/src/stages/mutational.rs | 10 +- libafl/src/stages/power.rs | 6 +- libafl/src/stages/push/mod.rs | 6 +- libafl/src/stages/push/mutational.rs | 4 +- libafl/src/stages/sync.rs | 4 +- libafl/src/stages/tmin.rs | 2 - libafl/src/stages/tracing.rs | 4 +- libafl/src/stages/tuneable.rs | 3 +- libafl/src/stages/verify_timeouts.rs | 2 +- libafl_bolts/src/cli.rs | 2 +- libafl_bolts/src/compress.rs | 1 - libafl_bolts/src/core_affinity.rs | 33 ++- libafl_bolts/src/lib.rs | 19 +- libafl_bolts/src/llmp.rs | 44 ++-- libafl_bolts/src/minibsod.rs | 34 +-- libafl_bolts/src/os/mod.rs | 2 +- libafl_bolts/src/os/unix_shmem_server.rs | 7 +- libafl_bolts/src/os/unix_signals.rs | 24 ++- libafl_bolts/src/ownedref.rs | 12 +- libafl_bolts/src/rands/loaded_dice.rs | 4 +- libafl_bolts/src/rands/mod.rs | 18 +- libafl_bolts/src/serdeany.rs | 50 +++-- libafl_bolts/src/shmem.rs | 21 +- libafl_bolts/src/staterestore.rs | 4 +- libafl_bolts/src/subrange.rs | 2 +- libafl_bolts/src/tuples.rs | 22 +- libafl_cc/build.rs | 6 +- libafl_cc/src/ar.rs | 5 +- libafl_cc/src/cfg.rs | 2 +- libafl_cc/src/clang.rs | 9 +- libafl_cc/src/lib.rs | 1 - libafl_cc/src/libtool.rs | 5 +- libafl_concolic/symcc_runtime/src/filter.rs | 9 +- .../symcc_runtime/src/filter/coverage.rs | 4 +- libafl_concolic/symcc_runtime/src/lib.rs | 14 +- libafl_concolic/symcc_runtime/src/tracing.rs | 7 +- libafl_frida/src/alloc.rs | 6 +- libafl_frida/src/asan/asan_rt.rs | 65 ++---- libafl_frida/src/asan/errors.rs | 33 ++- libafl_frida/src/asan/hook_funcs.rs | 197 +++++++++--------- libafl_frida/src/asan/mod.rs | 3 +- libafl_frida/src/cmplog_rt.rs | 27 ++- libafl_frida/src/coverage_rt.rs | 4 +- libafl_frida/src/helper.rs | 5 +- libafl_frida/src/lib.rs | 40 ++-- libafl_frida/src/pthread_hook.rs | 2 +- libafl_frida/src/utils.rs | 3 +- libafl_libfuzzer/build.rs | 2 +- libafl_libfuzzer/runtime/build.rs | 2 +- libafl_libfuzzer/runtime/src/lib.rs | 8 +- libafl_libfuzzer/runtime/src/merge.rs | 4 +- libafl_libfuzzer/runtime/src/options.rs | 4 +- libafl_libfuzzer/runtime/src/report.rs | 2 +- libafl_libfuzzer/src/lib.rs | 34 ++- libafl_libfuzzer_runtime/build.rs | 1 - libafl_qemu/build_linux.rs | 3 +- libafl_qemu/libafl_qemu_build/src/build.rs | 5 +- libafl_qemu/libafl_qemu_build/src/lib.rs | 1 - libafl_qemu/libafl_qemu_sys/src/lib.rs | 12 +- libafl_qemu/src/arch/aarch64.rs | 2 +- libafl_qemu/src/arch/arm.rs | 2 +- libafl_qemu/src/arch/hexagon.rs | 2 +- libafl_qemu/src/arch/i386.rs | 2 +- libafl_qemu/src/arch/mips.rs | 2 +- libafl_qemu/src/arch/ppc.rs | 2 +- libafl_qemu/src/arch/riscv.rs | 6 +- libafl_qemu/src/arch/x86_64.rs | 2 +- libafl_qemu/src/command/mod.rs | 4 +- libafl_qemu/src/command/parser.rs | 3 +- libafl_qemu/src/emu/builder.rs | 4 +- libafl_qemu/src/emu/drivers.rs | 5 +- libafl_qemu/src/emu/hooks.rs | 22 +- libafl_qemu/src/emu/mod.rs | 6 +- libafl_qemu/src/emu/systemmode.rs | 19 +- libafl_qemu/src/executor.rs | 5 +- libafl_qemu/src/lib.rs | 1 - libafl_qemu/src/modules/calls.rs | 11 +- libafl_qemu/src/modules/cmplog.rs | 4 +- libafl_qemu/src/modules/drcov.rs | 12 +- libafl_qemu/src/modules/edges/helpers.rs | 11 +- libafl_qemu/src/modules/edges/mod.rs | 2 +- libafl_qemu/src/modules/mod.rs | 6 +- libafl_qemu/src/modules/usermode/asan.rs | 20 +- .../src/modules/usermode/asan_guest.rs | 5 +- .../src/modules/usermode/injections.rs | 3 +- libafl_qemu/src/modules/usermode/snapshot.rs | 9 +- libafl_qemu/src/qemu/hooks.rs | 13 +- libafl_qemu/src/qemu/mod.rs | 23 +- libafl_qemu/src/qemu/systemmode.rs | 63 +++--- libafl_qemu/src/qemu/usermode.rs | 5 +- libafl_sugar/src/forkserver.rs | 7 +- libafl_sugar/src/inmemory.rs | 7 +- libafl_sugar/src/lib.rs | 3 - libafl_sugar/src/qemu.rs | 6 +- libafl_targets/build.rs | 4 +- libafl_targets/src/cmps/mod.rs | 10 +- libafl_targets/src/cmps/observers/aflpp.rs | 2 +- .../src/cmps/stages/aflpptracing.rs | 1 - libafl_targets/src/coverage.rs | 10 +- libafl_targets/src/lib.rs | 4 +- libafl_targets/src/libfuzzer/mod.rs | 8 +- libafl_targets/src/libfuzzer/mutators.rs | 4 +- libafl_targets/src/sancov_8bit.rs | 5 +- libafl_targets/src/sancov_pcguard.rs | 10 +- libafl_tinyinst/src/executor.rs | 2 +- scripts/dummy.rs | 2 +- .../parallellize_cargo_clippy_on_fuzzers.py | 101 +++++++++ utils/build_and_test_fuzzers/src/diffing.rs | 4 +- utils/desyscall/src/file.rs | 2 +- utils/desyscall/src/mmap.rs | 4 +- utils/drcov_utils/src/bin/drcov_dump_addrs.rs | 1 - utils/drcov_utils/src/bin/drcov_merge.rs | 3 +- utils/libafl_fmt/src/main.rs | 2 +- utils/libafl_jumper/src/main.rs | 2 +- 270 files changed, 1019 insertions(+), 1117 deletions(-) create mode 100644 scripts/parallellize_cargo_clippy_on_fuzzers.py diff --git a/fuzzers/baby/baby_fuzzer/src/main.rs b/fuzzers/baby/baby_fuzzer/src/main.rs index c98b028026..19d20a655f 100644 --- a/fuzzers/baby/baby_fuzzer/src/main.rs +++ b/fuzzers/baby/baby_fuzzer/src/main.rs @@ -24,6 +24,8 @@ use libafl_bolts::{current_nanos, nonzero, rands::StdRand, tuples::tuple_list, A /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; /// Assign a signal to the signals map @@ -31,7 +33,7 @@ fn signals_set(idx: usize) { unsafe { write(SIGNALS_PTR.add(idx), 1) }; } -#[allow(clippy::similar_names, clippy::manual_assert)] +#[expect(clippy::manual_assert)] pub fn main() { // The closure that we want to fuzz let mut harness = |input: &BytesInput| { @@ -61,6 +63,8 @@ pub fn main() { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; // Feedback to rate the interestingness of an input diff --git a/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs b/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs index f9c0b2e9ee..059aa6ef14 100644 --- a/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs @@ -26,7 +26,9 @@ use libafl_bolts::{current_nanos, nonzero, rands::StdRand, tuples::tuple_list, A /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; static mut SIGNALS_PTR: *mut u8 = &raw mut SIGNALS as _; -static SIGNALS_LEN: usize = unsafe { (*&raw const (SIGNALS)).len() }; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly +static SIGNALS_LEN: usize = unsafe { SIGNALS.len() }; /// Assign a signal to the signals map fn signals_set(idx: usize) { @@ -81,7 +83,6 @@ where } } -#[allow(clippy::similar_names, clippy::manual_assert)] pub fn main() { // Create an observation channel using the signals map let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS_LEN) }; diff --git a/fuzzers/baby/baby_fuzzer_minimizing/src/main.rs b/fuzzers/baby/baby_fuzzer_minimizing/src/main.rs index a61f3bf682..79524c2ecb 100644 --- a/fuzzers/baby/baby_fuzzer_minimizing/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_minimizing/src/main.rs @@ -7,6 +7,8 @@ use libafl_bolts::prelude::*; /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; /// Assign a signal to the signals map @@ -14,7 +16,6 @@ fn signals_set(idx: usize) { unsafe { write(SIGNALS_PTR.add(idx), 1) }; } -#[allow(clippy::similar_names)] pub fn main() -> Result<(), Error> { // The closure that we want to fuzz let mut harness = |input: &BytesInput| { @@ -34,6 +35,8 @@ pub fn main() -> Result<(), Error> { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; let factory = MapEqualityFactory::new(&observer); diff --git a/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs b/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs index 582e1cd56c..dab3133063 100644 --- a/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs @@ -61,8 +61,7 @@ mod slicemap { #[cfg(not(feature = "multimap"))] use slicemap::{HitcountsMapObserver, EDGES}; -#[allow(clippy::similar_names)] -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub fn main() { // The closure that we want to fuzz let mut first_harness = |input: &BytesInput| { @@ -144,6 +143,8 @@ pub fn main() { EDGES = core::slice::from_raw_parts_mut(alloc_zeroed(layout), num_edges * 2); } + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem on nightly let edges_ptr = unsafe { EDGES.as_mut_ptr() }; // create the base maps used to observe the different executors by splitting a slice diff --git a/fuzzers/baby/baby_fuzzer_unicode/src/main.rs b/fuzzers/baby/baby_fuzzer_unicode/src/main.rs index 77d5772b9d..fb9dfedfd8 100644 --- a/fuzzers/baby/baby_fuzzer_unicode/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_unicode/src/main.rs @@ -25,14 +25,16 @@ use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice}; /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 64] = [0; 64]; static mut SIGNALS_PTR: *mut u8 = (&raw mut SIGNALS).cast(); -static mut SIGNALS_LEN: usize = unsafe { (*&raw const SIGNALS).len() }; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly +static mut SIGNALS_LEN: usize = unsafe { SIGNALS.len() }; /// Assign a signal to the signals map fn signals_set(idx: usize) { unsafe { write(SIGNALS_PTR.add(idx), 1) }; } -#[allow(clippy::similar_names, clippy::manual_assert)] +#[expect(clippy::manual_assert)] pub fn main() { // The closure that we want to fuzz let mut harness = |input: &BytesInput| { diff --git a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs index 694aea946f..614dfba892 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs @@ -34,7 +34,6 @@ extern "C" { } -#[allow(clippy::similar_names)] pub fn main() { let mut shmem_provider = StdShMemProvider::new().unwrap(); unsafe { create_shmem_array() }; diff --git a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs index 88dece4d3e..43c3342286 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs @@ -26,7 +26,6 @@ extern "C" { } -#[allow(clippy::similar_names)] pub fn main() { let mut harness = |input: &BytesInput| { let target = input.target_bytes(); diff --git a/fuzzers/baby/backtrace_baby_fuzzers/command_executor/build.rs b/fuzzers/baby/backtrace_baby_fuzzers/command_executor/build.rs index 6fc42bbab3..7e6445d46c 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/command_executor/build.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/command_executor/build.rs @@ -2,9 +2,10 @@ use std::env; fn main() { let cwd = env::current_dir().unwrap().to_string_lossy().to_string(); - let mut cmd = cc::Build::new().get_compiler().to_command(); - cmd.args(["src/test_command.c", "-o"]) - .arg(&format!("{}/test_command", &cwd)) + let mut command = cc::Build::new().get_compiler().to_command(); + command + .args(["src/test_command.c", "-o"]) + .arg(format!("{}/test_command", &cwd)) .arg("-fsanitize=address") .status() .unwrap(); diff --git a/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs index 841115bd30..c239dafa2c 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs @@ -32,7 +32,6 @@ use libafl_bolts::{ AsSlice, AsSliceMut, }; -#[allow(clippy::similar_names)] pub fn main() { let mut shmem_provider = unix_shmem::UnixShMemProvider::new().unwrap(); let mut signals = shmem_provider.new_shmem(3).unwrap(); @@ -81,6 +80,7 @@ pub fn main() { let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); // Create the executor for an in-process function with just one observer + #[expect(clippy::items_after_statements)] #[derive(Debug)] struct MyExecutor { shmem_id: ShMemId, @@ -88,6 +88,8 @@ pub fn main() { } impl CommandConfigurator for MyExecutor { + #[allow(unknown_lints)] // stable doesn't even know of the lint + #[allow(clippy::zombie_processes)] // only a problem on nightly fn spawn_child(&mut self, input: &BytesInput) -> Result { let mut command = Command::new("./test_command"); diff --git a/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/build.rs b/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/build.rs index d894c1097a..8694d70b12 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/build.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/build.rs @@ -40,7 +40,7 @@ fn main() { Command::new(afl_gcc_path) .args(["src/program.c", "-o"]) - .arg(&format!("{}/target/release/program", &cwd)) + .arg(format!("{}/target/release/program", &cwd)) .arg("-fsanitize=address") .status() .unwrap(); diff --git a/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs index 220f822643..600056c412 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs @@ -28,7 +28,6 @@ use libafl_bolts::{ AsSliceMut, }; -#[allow(clippy::similar_names)] pub fn main() { const MAP_SIZE: usize = 65536; diff --git a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs index 88c6422598..9260055090 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs @@ -22,12 +22,11 @@ use libafl_bolts::{ nonzero, ownedref::OwnedRefMut, rands::StdRand, - shmem::{unix_shmem, ShMem, ShMemProvider}, + shmem::{unix_shmem, ShMemProvider}, tuples::tuple_list, AsSlice, AsSliceMut, }; -#[allow(clippy::similar_names)] pub fn main() { let mut shmem_provider = unix_shmem::UnixShMemProvider::new().unwrap(); let mut signals = shmem_provider.new_shmem(16).unwrap(); @@ -66,6 +65,7 @@ pub fn main() { }; // Create an observation channel using the signals map + let observer = unsafe { StdMapObserver::from_mut_ptr("signals", signals_ptr, signals_len) }; // Create a stacktrace observer let bt_observer = BacktraceObserver::new( diff --git a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs index 79578e729c..461a77d0ec 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs @@ -22,6 +22,8 @@ use libafl_bolts::{nonzero, rands::StdRand, tuples::tuple_list, AsSlice}; /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; /// Assign a signal to the signals map @@ -29,7 +31,6 @@ fn signals_set(idx: usize) { unsafe { write(SIGNALS_PTR.add(idx), 1) }; } -#[allow(clippy::similar_names)] pub fn main() { // The closure that we want to fuzz let mut harness = |input: &BytesInput| { @@ -59,6 +60,8 @@ pub fn main() { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; // Create a stacktrace observer to add the observers tuple let bt_observer = BacktraceObserver::owned( diff --git a/fuzzers/baby/tutorial/src/input.rs b/fuzzers/baby/tutorial/src/input.rs index 4c84e69026..f21eaa4199 100644 --- a/fuzzers/baby/tutorial/src/input.rs +++ b/fuzzers/baby/tutorial/src/input.rs @@ -1,3 +1,4 @@ +#![expect(unexpected_cfgs)] // deriving NewFuzzed etc. introduces these use std::hash::Hash; use lain::prelude::*; diff --git a/fuzzers/binary_only/frida_executable_libpng/src/fuzzer.rs b/fuzzers/binary_only/frida_executable_libpng/src/fuzzer.rs index 623e121a73..65493e720f 100644 --- a/fuzzers/binary_only/frida_executable_libpng/src/fuzzer.rs +++ b/fuzzers/binary_only/frida_executable_libpng/src/fuzzer.rs @@ -85,7 +85,7 @@ pub unsafe fn lib(main: extern "C" fn(i32, *const *const u8, *const *const u8) - } /// The actual fuzzer -#[allow(clippy::too_many_lines, clippy::too_many_arguments)] +#[expect(clippy::too_many_lines)] unsafe fn fuzz( options: &FuzzerOptions, mut frida_harness: &dyn Fn(&BytesInput) -> ExitKind, diff --git a/fuzzers/binary_only/frida_executable_libpng/src/lib.rs b/fuzzers/binary_only/frida_executable_libpng/src/lib.rs index da9fdeae51..1f72a04071 100644 --- a/fuzzers/binary_only/frida_executable_libpng/src/lib.rs +++ b/fuzzers/binary_only/frida_executable_libpng/src/lib.rs @@ -34,7 +34,6 @@ pub unsafe extern "C" fn main_hook( } #[no_mangle] -#[allow(clippy::similar_names)] pub unsafe extern "C" fn __libc_start_main( main: extern "C" fn(i32, *const *const u8, *const *const u8) -> i32, argc: i32, diff --git a/fuzzers/binary_only/frida_libpng/src/fuzzer.rs b/fuzzers/binary_only/frida_libpng/src/fuzzer.rs index 31973d11fc..6f49f06a72 100644 --- a/fuzzers/binary_only/frida_libpng/src/fuzzer.rs +++ b/fuzzers/binary_only/frida_libpng/src/fuzzer.rs @@ -66,7 +66,7 @@ pub fn main() { } /// The actual fuzzer -#[allow(clippy::too_many_lines, clippy::too_many_arguments)] +#[expect(clippy::too_many_lines)] unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { log::info!("Frida fuzzer starting up."); diff --git a/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs b/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs index c33fca2f81..41afe956b5 100644 --- a/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs +++ b/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs @@ -77,7 +77,7 @@ pub fn main() { } /// The actual fuzzer -#[allow(clippy::too_many_lines, clippy::too_many_arguments)] +#[expect(clippy::too_many_lines)] unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // 'While the stats are state, they are usually used in the broker - which is likely never restarted let monitor = MultiMonitor::new(|s| println!("{s}")); diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs index bce4a5c3cc..19e2ca5b54 100644 --- a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs @@ -243,7 +243,7 @@ fn fuzz( let cmplog = cmp_shmem.as_slice_mut(); // Beginning of a page should be properly aligned. - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] let cmplog_map_ptr = cmplog .as_mut_ptr() .cast::(); diff --git a/fuzzers/binary_only/intel_pt_baby_fuzzer/src/main.rs b/fuzzers/binary_only/intel_pt_baby_fuzzer/src/main.rs index cc84cfce2f..eaae1771c5 100644 --- a/fuzzers/binary_only/intel_pt_baby_fuzzer/src/main.rs +++ b/fuzzers/binary_only/intel_pt_baby_fuzzer/src/main.rs @@ -28,7 +28,8 @@ use proc_maps::get_process_maps; // Coverage map const MAP_SIZE: usize = 4096; static mut MAP: [u8; MAP_SIZE] = [0; MAP_SIZE]; -#[allow(static_mut_refs)] +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut MAP_PTR: *mut u8 = unsafe { MAP.as_mut_ptr() }; pub fn main() { diff --git a/fuzzers/binary_only/intel_pt_command_executor/src/main.rs b/fuzzers/binary_only/intel_pt_command_executor/src/main.rs index 8ef4c606ef..b8b110ca14 100644 --- a/fuzzers/binary_only/intel_pt_command_executor/src/main.rs +++ b/fuzzers/binary_only/intel_pt_command_executor/src/main.rs @@ -25,7 +25,8 @@ use libafl_intelpt::{IntelPT, PAGE_SIZE}; // Coverage map const MAP_SIZE: usize = 4096; static mut MAP: [u8; MAP_SIZE] = [0; MAP_SIZE]; -#[allow(static_mut_refs)] +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut MAP_PTR: *mut u8 = unsafe { MAP.as_mut_ptr() }; pub fn main() { diff --git a/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs b/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs index ba00041efd..bb6715fd6c 100644 --- a/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs @@ -172,7 +172,6 @@ pub fn fuzz() -> Result<(), Error> { let mut feedback = MaxMapFeedback::new(&edges_observer); - #[allow(clippy::let_unit_value)] let mut objective = (); let mut state = state.unwrap_or_else(|| { diff --git a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs index 45f80b0f47..d5826a4fa4 100644 --- a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs @@ -214,10 +214,8 @@ pub fn fuzz() { Err(Error::ShuttingDown)? } - #[allow(clippy::let_unit_value)] let mut feedback = (); - #[allow(clippy::let_unit_value)] let mut objective = (); let mut state = state.unwrap_or_else(|| { diff --git a/fuzzers/binary_only/qemu_launcher/src/client.rs b/fuzzers/binary_only/qemu_launcher/src/client.rs index cf399682c2..1016788ae6 100644 --- a/fuzzers/binary_only/qemu_launcher/src/client.rs +++ b/fuzzers/binary_only/qemu_launcher/src/client.rs @@ -27,7 +27,7 @@ use crate::{ options::FuzzerOptions, }; -#[allow(clippy::module_name_repetitions)] +#[expect(clippy::module_name_repetitions)] pub type ClientState = StdState, StdRand, OnDiskCorpus>; @@ -50,14 +50,14 @@ impl Client<'_> { Ok(args) } - #[allow(clippy::unused_self)] // Api should look the same as args above + #[expect(clippy::unused_self)] // Api should look the same as args above pub fn env(&self) -> Vec<(String, String)> { env::vars() .filter(|(k, _v)| k != "LD_LIBRARY_PATH") .collect::>() } - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub fn run( &self, state: Option, diff --git a/fuzzers/binary_only/qemu_launcher/src/harness.rs b/fuzzers/binary_only/qemu_launcher/src/harness.rs index 6376348d0c..2a26620235 100644 --- a/fuzzers/binary_only/qemu_launcher/src/harness.rs +++ b/fuzzers/binary_only/qemu_launcher/src/harness.rs @@ -21,12 +21,12 @@ pub const MAX_INPUT_SIZE: usize = 1_048_576; // 1MB impl Harness { /// Change environment #[inline] - #[allow(clippy::ptr_arg)] + #[expect(clippy::ptr_arg)] pub fn edit_env(_env: &mut Vec<(String, String)>) {} /// Change arguments #[inline] - #[allow(clippy::ptr_arg)] + #[expect(clippy::ptr_arg)] pub fn edit_args(_args: &mut Vec) {} /// Helper function to find the function we want to fuzz. @@ -80,7 +80,7 @@ impl Harness { /// If we need to do extra work after forking, we can do that here. #[inline] - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] pub fn post_fork(&self) {} pub fn run(&self, input: &BytesInput) -> ExitKind { diff --git a/fuzzers/binary_only/qemu_launcher/src/instance.rs b/fuzzers/binary_only/qemu_launcher/src/instance.rs index 317d21a36f..0bcebdbb96 100644 --- a/fuzzers/binary_only/qemu_launcher/src/instance.rs +++ b/fuzzers/binary_only/qemu_launcher/src/instance.rs @@ -73,7 +73,6 @@ pub struct Instance<'a, M: Monitor> { } impl Instance<'_, M> { - #[allow(clippy::similar_names)] // elf != self fn coverage_filter(&self, qemu: Qemu) -> Result { /* Conversion is required on 32-bit targets, but not on 64-bit ones */ if let Some(includes) = &self.options.include { @@ -106,7 +105,7 @@ impl Instance<'_, M> { } } - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub fn run(&mut self, modules: ET, state: Option) -> Result<(), Error> where ET: EmulatorModuleTuple + Debug, diff --git a/fuzzers/binary_only/qemu_launcher/src/options.rs b/fuzzers/binary_only/qemu_launcher/src/options.rs index 2465196e31..ea6823ac3e 100644 --- a/fuzzers/binary_only/qemu_launcher/src/options.rs +++ b/fuzzers/binary_only/qemu_launcher/src/options.rs @@ -11,7 +11,6 @@ use crate::version::Version; #[readonly::make] #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] -#[allow(clippy::module_name_repetitions)] #[command( name = format!("qemu_coverage-{}",env!("CPU_TARGET")), version = Version::default(), diff --git a/fuzzers/forkserver/baby_fuzzer_with_forkexecutor/src/main.rs b/fuzzers/forkserver/baby_fuzzer_with_forkexecutor/src/main.rs index ca36d11c97..1a84e91cc5 100644 --- a/fuzzers/forkserver/baby_fuzzer_with_forkexecutor/src/main.rs +++ b/fuzzers/forkserver/baby_fuzzer_with_forkexecutor/src/main.rs @@ -25,10 +25,10 @@ use libafl_bolts::{ AsSlice, AsSliceMut, }; -#[allow(clippy::similar_names)] pub fn main() { let mut shmem_provider = unix_shmem::UnixShMemProvider::new().unwrap(); let mut signals = shmem_provider.new_shmem(16).unwrap(); + let signals_len = signals.as_slice().len(); let signals_ptr = signals.as_slice_mut().as_mut_ptr(); @@ -64,6 +64,7 @@ pub fn main() { }; // Create an observation channel using the signals map + let observer = unsafe { StdMapObserver::from_mut_ptr("signals", signals_ptr, signals_len) }; // Create a stacktrace observer to add the observers tuple diff --git a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs index 34f97f5b28..6d5f7f3998 100644 --- a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs +++ b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs @@ -83,7 +83,6 @@ struct Opt { signal: Signal, } -#[allow(clippy::similar_names)] pub fn main() { env_logger::init(); diff --git a/fuzzers/forkserver/forkserver_simple/src/main.rs b/fuzzers/forkserver/forkserver_simple/src/main.rs index c026197738..c08b44084b 100644 --- a/fuzzers/forkserver/forkserver_simple/src/main.rs +++ b/fuzzers/forkserver/forkserver_simple/src/main.rs @@ -83,7 +83,6 @@ struct Opt { signal: Signal, } -#[allow(clippy::similar_names)] pub fn main() { env_logger::init(); const MAP_SIZE: usize = 65536; diff --git a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs index 9bead73df2..f47334b429 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs @@ -205,7 +205,7 @@ pub fn main() { } /// The actual fuzzer -#[allow(clippy::too_many_arguments)] +#[expect(clippy::too_many_arguments)] fn fuzz( corpus_dir: PathBuf, objective_dir: PathBuf, diff --git a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs index 4480972337..cd63d37f00 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs @@ -207,7 +207,7 @@ pub fn main() { } /// The actual fuzzer -#[allow(clippy::too_many_arguments)] +#[expect(clippy::too_many_arguments)] fn fuzz( corpus_dir: PathBuf, objective_dir: PathBuf, diff --git a/fuzzers/forkserver/libafl-fuzz/src/corpus.rs b/fuzzers/forkserver/libafl-fuzz/src/corpus.rs index ccf7d7ba88..a69efdb702 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/corpus.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/corpus.rs @@ -41,7 +41,7 @@ pub fn generate_base_filename(state: &mut LibaflFuzzState, id: CorpusId) -> Stri } // The function needs to be compatible with CustomFilepathToTestcaseFeedback -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] pub fn set_corpus_filepath( state: &mut LibaflFuzzState, testcase: &mut Testcase, @@ -58,7 +58,7 @@ pub fn set_corpus_filepath( } // The function needs to be compatible with CustomFilepathToTestcaseFeedback -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] pub fn set_solution_filepath( state: &mut LibaflFuzzState, testcase: &mut Testcase, diff --git a/fuzzers/forkserver/libafl-fuzz/src/executor.rs b/fuzzers/forkserver/libafl-fuzz/src/executor.rs index 06082e8a73..aa60fe982d 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/executor.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/executor.rs @@ -201,7 +201,7 @@ pub fn find_afl_binary(filename: &str, same_dir_as: Option) -> Result

::Input>, &Path) -> Result<(), Error>, { - #[allow(clippy::wrong_self_convention)] #[inline] fn is_interesting( &mut self, diff --git a/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs b/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs index c8db9e440c..ba1dda32a1 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs @@ -56,7 +56,6 @@ where S::Corpus: Corpus, I: Input, { - #[allow(clippy::wrong_self_convention)] #[inline] fn is_interesting( &mut self, diff --git a/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs b/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs index f1eb674feb..9f18cb5665 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs @@ -13,7 +13,7 @@ use crate::Opt; /// A wrapper feedback used to determine actions for initial seeds. /// Handles `AFL_EXIT_ON_SEED_ISSUES`, `AFL_IGNORE_SEED_ISSUES` & default afl-fuzz behavior /// then, essentially becomes benign -#[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)] +#[expect(clippy::module_name_repetitions, clippy::struct_excessive_bools)] #[derive(Debug)] pub struct SeedFeedback { /// Inner [`Feedback`] diff --git a/fuzzers/forkserver/libafl-fuzz/src/main.rs b/fuzzers/forkserver/libafl-fuzz/src/main.rs index 87dc0dd5b3..602b26cc1e 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/main.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/main.rs @@ -21,6 +21,7 @@ clippy::similar_names, clippy::too_many_lines, clippy::into_iter_without_iter, // broken + clippy::multiple_crate_versions )] #![cfg_attr(not(test), warn( missing_debug_implementations, @@ -105,7 +106,6 @@ const DEFER_SIG: &str = "##SIG_AFL_DEFER_FORKSRV##\0"; const SHMEM_ENV_VAR: &str = "__AFL_SHM_ID"; static AFL_HARNESS_FILE_INPUT: &str = "@@"; -#[allow(clippy::too_many_lines)] fn main() { env_logger::init(); let mut opt = Opt::parse(); @@ -202,7 +202,7 @@ fn main() { }; } -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] #[derive(Debug, Parser, Clone)] #[command( name = "afl-fuzz", @@ -358,7 +358,7 @@ struct Opt { non_instrumented_mode: bool, } -#[allow(dead_code, clippy::struct_excessive_bools)] +#[expect(dead_code, clippy::struct_excessive_bools)] #[derive(Debug, Clone)] pub struct CmplogOpts { file_size: CmplogFileSize, @@ -387,7 +387,7 @@ impl From<&str> for CmplogFileSize { } } -#[allow(clippy::unnecessary_wraps)] // we need to be compatible with Clap's value_parser +#[expect(clippy::unnecessary_wraps)] // we need to be compatible with Clap's value_parser fn parse_cmplog_args(s: &str) -> Result { Ok(CmplogOpts { file_size: s.into(), diff --git a/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs b/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs index efde3a29cb..7e91d65027 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs @@ -63,7 +63,6 @@ where P: Stage, { #[inline] - #[allow(clippy::let_and_return)] fn perform( &mut self, fuzzer: &mut Z, diff --git a/fuzzers/fuzz_anything/baby_fuzzer_wasm/src/lib.rs b/fuzzers/fuzz_anything/baby_fuzzer_wasm/src/lib.rs index 6af42b74d2..93d91961e0 100644 --- a/fuzzers/fuzz_anything/baby_fuzzer_wasm/src/lib.rs +++ b/fuzzers/fuzz_anything/baby_fuzzer_wasm/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(unexpected_cfgs)] // the wasm_bindgen introduces these on nightly only mod utils; use libafl::{ @@ -25,7 +26,11 @@ use crate::utils::set_panic_hook; // Defined for internal use by LibAFL #[no_mangle] -#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] +#[expect( + clippy::cast_sign_loss, + clippy::cast_possible_truncation, + clippy::missing_panics_doc +)] pub extern "C" fn external_current_millis() -> u64 { let window: Window = web_sys::window().expect("should be in browser to run this demo"); let performance: Performance = window @@ -34,7 +39,7 @@ pub extern "C" fn external_current_millis() -> u64 { performance.now() as u64 } -#[allow(clippy::missing_panics_doc)] +#[allow(clippy::missing_panics_doc)] // expect does not work, likely because of `wasm_bindgen` #[wasm_bindgen] pub fn fuzz() { set_panic_hook(); @@ -64,7 +69,6 @@ pub fn fuzz() { signals_set(1); if buf.len() > 1 && buf[1] == b'b' { signals_set(2); - #[allow(clippy::manual_assert)] if buf.len() > 2 && buf[2] == b'c' { // WASM cannot handle traps: https://webassembly.github.io/spec/core/intro/overview.html // in a "real" fuzzing campaign, you should prefer to setup trap handling in JS, @@ -77,6 +81,8 @@ pub fn fuzz() { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", signals.as_mut_ptr(), signals.len()) }; diff --git a/fuzzers/fuzz_anything/baby_no_std/src/main.rs b/fuzzers/fuzz_anything/baby_no_std/src/main.rs index 6567720ada..f64132105d 100644 --- a/fuzzers/fuzz_anything/baby_no_std/src/main.rs +++ b/fuzzers/fuzz_anything/baby_no_std/src/main.rs @@ -64,7 +64,6 @@ pub extern "C" fn external_current_millis() -> u64 { /// The main of this program. /// # Panics /// Will panic once the fuzzer finds the correct conditions. -#[allow(clippy::similar_names)] #[no_mangle] pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { // The closure that we want to fuzz @@ -76,7 +75,7 @@ pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { signals_set(1); if buf.len() > 1 && buf[1] == b'b' { signals_set(2); - #[allow(clippy::manual_assert)] + #[expect(clippy::manual_assert)] if buf.len() > 2 && buf[2] == b'c' { panic!("=)"); } diff --git a/fuzzers/fuzz_anything/cargo_fuzz/src/lib.rs b/fuzzers/fuzz_anything/cargo_fuzz/src/lib.rs index 05a12ff8ed..42e5c6edae 100644 --- a/fuzzers/fuzz_anything/cargo_fuzz/src/lib.rs +++ b/fuzzers/fuzz_anything/cargo_fuzz/src/lib.rs @@ -1,4 +1,8 @@ -#[allow(clippy::collapsible_if)] +#[expect( + clippy::collapsible_if, + clippy::manual_assert, + clippy::missing_panics_doc +)] pub fn do_thing(data: &[u8]) { if data.first() == Some(&b'a') { if data.get(1) == Some(&b'b') { diff --git a/fuzzers/fuzz_anything/libafl_atheris/src/lib.rs b/fuzzers/fuzz_anything/libafl_atheris/src/lib.rs index 9d64af0899..0d00e2778e 100644 --- a/fuzzers/fuzz_anything/libafl_atheris/src/lib.rs +++ b/fuzzers/fuzz_anything/libafl_atheris/src/lib.rs @@ -47,7 +47,6 @@ use libafl_targets::{extra_counters, CmpLogObserver}; /// The `harness_fn` parameter is the function that will be called by `LibAFL` for each iteration /// and jumps back into `Atheris'` instrumented python code. #[no_mangle] -#[allow(non_snake_case)] pub extern "C" fn LLVMFuzzerRunDriver( _argc: *const c_int, _argv: *const *const c_char, diff --git a/fuzzers/fuzz_anything/push_harness/src/main.rs b/fuzzers/fuzz_anything/push_harness/src/main.rs index 2dd1d9dfee..87c561b422 100644 --- a/fuzzers/fuzz_anything/push_harness/src/main.rs +++ b/fuzzers/fuzz_anything/push_harness/src/main.rs @@ -29,7 +29,6 @@ fn signals_set(idx: usize) { } /// This generates the input, using klo-routines. -#[allow(clippy::similar_names)] fn input_generator() { // The closure that produced the input for the generator let mut harness = |input: &BytesInput| { @@ -43,6 +42,7 @@ fn input_generator() { let signals_len = unsafe { *signals_ptr }.len(); // Create an observation channel using the signals map + let observer = unsafe { StdMapObserver::from_mut_ptr("signals", &raw mut SIGNALS as _, signals_len) }; @@ -111,7 +111,7 @@ fn input_generator() { /// the main function loops independently of the fuzzer. /// `Klo` internally switches between the `LibAFL` and harness coroutines to generate the inputs. -#[allow(clippy::manual_assert)] +#[expect(clippy::manual_assert)] pub fn main() { // Set up the Klo-routines harness let mut input_generator = input_generator; diff --git a/fuzzers/fuzz_anything/push_stage_harness/src/main.rs b/fuzzers/fuzz_anything/push_stage_harness/src/main.rs index e1eb51e1ff..a95fe17d34 100644 --- a/fuzzers/fuzz_anything/push_stage_harness/src/main.rs +++ b/fuzzers/fuzz_anything/push_stage_harness/src/main.rs @@ -31,9 +31,11 @@ fn signals_set(idx: usize) { unsafe { SIGNALS[idx] = 1 }; } -#[allow(clippy::similar_names, clippy::manual_assert)] +#[expect(clippy::manual_assert)] pub fn main() { // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS.as_mut_ptr(), SIGNALS.len()) }; diff --git a/fuzzers/inprocess/dynamic_analysis/build.rs b/fuzzers/inprocess/dynamic_analysis/build.rs index 863d3cb258..f9e1b126f3 100644 --- a/fuzzers/inprocess/dynamic_analysis/build.rs +++ b/fuzzers/inprocess/dynamic_analysis/build.rs @@ -7,7 +7,7 @@ fn main() { println!("cargo:warning=Downloading Little-CMS"); // Clone the Little-CMS repository if the directory doesn't exist let status = Command::new("git") - .args(&[ + .args([ "clone", "https://github.com/mm2/Little-CMS", lcms_dir.to_str().unwrap(), @@ -15,9 +15,7 @@ fn main() { .status() .expect("Failed to clone Little-CMS repository"); - if !status.success() { - panic!("Failed to clone Little-CMS repository"); - } + assert!(status.success(), "Failed to clone Little-CMS repository"); } // Tell Cargo that if the given file changes, to rerun this build script diff --git a/fuzzers/inprocess/dynamic_analysis/src/lib.rs b/fuzzers/inprocess/dynamic_analysis/src/lib.rs index 616bb8960e..35bc9e0c00 100644 --- a/fuzzers/inprocess/dynamic_analysis/src/lib.rs +++ b/fuzzers/inprocess/dynamic_analysis/src/lib.rs @@ -198,7 +198,7 @@ fn run_testcases(filenames: &[&str]) { } /// The actual fuzzer -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn fuzz( corpus_dir: PathBuf, objective_dir: PathBuf, @@ -252,8 +252,9 @@ fn fuzz( // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let func_list = - unsafe { OwnedMutPtr::from_raw_mut(Lazy::force_mut(&mut *&raw mut FUNCTION_LIST)) }; + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly + let func_list = unsafe { OwnedMutPtr::from_raw_mut(Lazy::force_mut(&mut FUNCTION_LIST)) }; let profiling_observer = ProfilingObserver::new("concatenated.json", func_list)?; let callhook = CallHook::new(); diff --git a/fuzzers/inprocess/fuzzbench/src/lib.rs b/fuzzers/inprocess/fuzzbench/src/lib.rs index 99b6e94b79..8851abe92d 100644 --- a/fuzzers/inprocess/fuzzbench/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench/src/lib.rs @@ -196,7 +196,7 @@ fn run_testcases(filenames: &[&str]) { } /// The actual fuzzer -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn fuzz( corpus_dir: PathBuf, objective_dir: PathBuf, diff --git a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs index 1fc485c250..8bf1081663 100644 --- a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs @@ -201,7 +201,7 @@ fn run_testcases(filenames: &[&str]) { } /// The actual fuzzer -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn fuzz( corpus_dir: PathBuf, objective_dir: PathBuf, diff --git a/fuzzers/inprocess/fuzzbench_text/src/lib.rs b/fuzzers/inprocess/fuzzbench_text/src/lib.rs index f717c19491..62426bead5 100644 --- a/fuzzers/inprocess/fuzzbench_text/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_text/src/lib.rs @@ -63,7 +63,7 @@ use nix::unistd::dup; /// The fuzzer main (as `no_mangle` C function) #[no_mangle] -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub extern "C" fn libafl_main() { // Registry the metadata types used in this fuzzer // Needed only on no_std @@ -258,7 +258,7 @@ fn run_testcases(filenames: &[&str]) { } /// The actual fuzzer -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn fuzz_binary( corpus_dir: PathBuf, objective_dir: PathBuf, @@ -469,7 +469,7 @@ fn fuzz_binary( } /// The actual fuzzer based on `Grimoire` -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn fuzz_text( corpus_dir: PathBuf, objective_dir: PathBuf, diff --git a/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs index 2384a53239..fa696fda5f 100644 --- a/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs @@ -81,10 +81,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let edges_observer = unsafe { std_edges_map_observer("edges") }; // Create an observation channel using the cmp map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem on nightly let cmps_observer = unsafe { StdMapObserver::from_mut_ptr("cmps", CMP_MAP.as_mut_ptr(), CMP_MAP.len()) }; // Create an observation channel using the allocations map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem on nightly let allocs_observer = unsafe { StdMapObserver::from_mut_ptr( "allocs", diff --git a/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs index e783ed5116..09d5357bfd 100644 --- a/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs @@ -79,6 +79,8 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re }; // Create an observation channel using the coverage map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem on nightly let edges_observer = unsafe { HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( "edges", diff --git a/fuzzers/inprocess/libfuzzer_libpng_accounting/Cargo.toml b/fuzzers/inprocess/libfuzzer_libpng_accounting/Cargo.toml index 2a83735cce..b6a72e565f 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_accounting/Cargo.toml +++ b/fuzzers/inprocess/libfuzzer_libpng_accounting/Cargo.toml @@ -25,6 +25,7 @@ which = "6.0.3" libafl = { path = "../../../libafl", features = [ "std", "derive", + "tcp_manager", "llmp_compression", "introspection", ] } diff --git a/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs index 474493963d..1619b1410a 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs @@ -139,6 +139,8 @@ pub extern "C" fn libafl_main() { let mut run_client = |state: Option<_>, mut restarting_mgr, _client_description| { // Create an observation channel using the coverage map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem on nightly let edges_observer = HitcountsMapObserver::new(unsafe { StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), MAX_EDGES_FOUND) }) diff --git a/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs index 62da02c185..1ffbabb60d 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs @@ -262,7 +262,7 @@ pub extern "C" fn libafl_main() { Ok(()) }; - let mut main_run_client = secondary_run_client.clone(); // clone it just for borrow checker + let mut main_run_client = secondary_run_client; // clone it just for borrow checker match CentralizedLauncher::builder() .shmem_provider(shmem_provider) diff --git a/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs index 033d6814cf..65a2044d19 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs @@ -77,6 +77,8 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re }; // Create an observation channel using the coverage map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem on nightly let edges_observer = unsafe { HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( "edges", diff --git a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs index 5e85ecf321..e741403416 100644 --- a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs @@ -53,7 +53,7 @@ fn signals_set(idx: usize) { unsafe { write(SIGNALS_PTR.add(idx), 1) }; } -#[allow(clippy::similar_names, clippy::manual_assert)] +#[expect(clippy::manual_assert)] pub fn main() { // The closure that we want to fuzz // The pseudo program under test uses all parts of the custom input @@ -87,6 +87,7 @@ pub fn main() { }; // Create an observation channel using the signals map + let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS_LEN) }; // Feedback to rate the interestingness of an input diff --git a/fuzzers/structure_aware/baby_fuzzer_gramatron/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_gramatron/src/main.rs index c07e1b2f16..f60f9596fb 100644 --- a/fuzzers/structure_aware/baby_fuzzer_gramatron/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_gramatron/src/main.rs @@ -45,7 +45,6 @@ fn read_automaton_from_file>(path: P) -> Automaton { postcard::from_bytes(&buffer).unwrap() } -#[allow(clippy::similar_names)] pub fn main() { let mut bytes = vec![]; @@ -59,6 +58,7 @@ pub fn main() { }; // Create an observation channel using the signals map + let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS_LEN) }; // Feedback to rate the interestingness of an input diff --git a/fuzzers/structure_aware/baby_fuzzer_grimoire/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_grimoire/src/main.rs index 60162e5919..9f3f4b9d40 100644 --- a/fuzzers/structure_aware/baby_fuzzer_grimoire/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_grimoire/src/main.rs @@ -25,6 +25,8 @@ use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice}; /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; /// Assign a signal to the signals map fn signals_set(idx: usize) { @@ -44,7 +46,6 @@ fn is_sub(mut haystack: &[T], needle: &[T]) -> bool { false } -#[allow(clippy::similar_names)] pub fn main() { let mut initial_inputs = vec![]; for entry in fs::read_dir("./corpus").unwrap() { @@ -83,6 +84,8 @@ pub fn main() { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()).track_novelties() }; diff --git a/fuzzers/structure_aware/baby_fuzzer_multi/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_multi/src/main.rs index 2cda5ebebd..5842936ff7 100644 --- a/fuzzers/structure_aware/baby_fuzzer_multi/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_multi/src/main.rs @@ -40,7 +40,7 @@ fn count_set(count: usize) { unsafe { LAST_COUNT[0] = count }; } -#[allow(clippy::similar_names, clippy::manual_assert)] +#[expect(clippy::manual_assert)] pub fn main() { // The closure that we want to fuzz let mut harness = |input: &MultipartInput| { diff --git a/fuzzers/structure_aware/baby_fuzzer_nautilus/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_nautilus/src/main.rs index 780ebef137..71dcb912f8 100644 --- a/fuzzers/structure_aware/baby_fuzzer_nautilus/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_nautilus/src/main.rs @@ -25,6 +25,8 @@ use libafl_bolts::{rands::StdRand, tuples::tuple_list}; /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; /* /// Assign a signal to the signals map @@ -33,7 +35,6 @@ fn signals_set(idx: usize) { } */ -#[allow(clippy::similar_names)] pub fn main() { let context = NautilusContext::from_file(15, "grammar.json").unwrap(); let mut bytes = vec![]; @@ -48,6 +49,8 @@ pub fn main() { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; // Feedback to rate the interestingness of an input diff --git a/fuzzers/structure_aware/baby_fuzzer_tokens/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_tokens/src/main.rs index a47f76d677..194c2acd72 100644 --- a/fuzzers/structure_aware/baby_fuzzer_tokens/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_tokens/src/main.rs @@ -20,6 +20,8 @@ use libafl_bolts::{rands::StdRand, tuples::tuple_list}; /// Coverage map with explicit assignments due to the lack of instrumentation static mut SIGNALS: [u8; 16] = [0; 16]; +// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 +#[allow(static_mut_refs)] // only a problem in nightly static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; /* @@ -29,7 +31,6 @@ fn signals_set(idx: usize) { } */ -#[allow(clippy::similar_names)] pub fn main() { let mut tokenizer = NaiveTokenizer::default(); let mut encoder_decoder = TokenInputEncoderDecoder::new(); @@ -67,6 +68,8 @@ pub fn main() { }; // Create an observation channel using the signals map + // TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786 + #[allow(static_mut_refs)] // only a problem in nightly let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; // Feedback to rate the interestingness of an input diff --git a/fuzzers/structure_aware/forkserver_simple_nautilus/src/main.rs b/fuzzers/structure_aware/forkserver_simple_nautilus/src/main.rs index 61dbede569..682a65a9a2 100644 --- a/fuzzers/structure_aware/forkserver_simple_nautilus/src/main.rs +++ b/fuzzers/structure_aware/forkserver_simple_nautilus/src/main.rs @@ -85,7 +85,6 @@ struct Opt { grammar: PathBuf, } -#[allow(clippy::similar_names)] pub fn main() { env_logger::init(); const MAP_SIZE: usize = 65536; diff --git a/fuzzers/structure_aware/nautilus_sync/src/bin/libafl_cc.rs b/fuzzers/structure_aware/nautilus_sync/src/bin/libafl_cc.rs index ff4d871f97..4f78a0875d 100644 --- a/fuzzers/structure_aware/nautilus_sync/src/bin/libafl_cc.rs +++ b/fuzzers/structure_aware/nautilus_sync/src/bin/libafl_cc.rs @@ -2,7 +2,6 @@ use std::env; use libafl_cc::{ClangWrapper, CompilerWrapper, ToolWrapper}; -#[allow(clippy::missing_panics_doc)] pub fn main() { let args: Vec = env::args().collect(); if args.len() > 1 { diff --git a/fuzzers/structure_aware/nautilus_sync/src/lib.rs b/fuzzers/structure_aware/nautilus_sync/src/lib.rs index 92fc4926a5..ebe5654e8b 100644 --- a/fuzzers/structure_aware/nautilus_sync/src/lib.rs +++ b/fuzzers/structure_aware/nautilus_sync/src/lib.rs @@ -98,7 +98,7 @@ struct Opt { /// The main fn, `no_mangle` as it is a C symbol #[no_mangle] -#[allow(clippy::missing_panics_doc, clippy::too_many_lines)] +#[expect(clippy::missing_panics_doc, clippy::too_many_lines)] pub extern "C" fn libafl_main() { // Registry the metadata types used in this fuzzer // Needed only on no_std diff --git a/libafl/src/common/mod.rs b/libafl/src/common/mod.rs index c3e75a9498..69345a1fa1 100644 --- a/libafl/src/common/mod.rs +++ b/libafl/src/common/mod.rs @@ -1,7 +1,5 @@ //! This module defines trait shared across different `LibAFL` modules -#![allow(unused, missing_docs)] - use alloc::boxed::Box; use core::any::type_name; diff --git a/libafl/src/common/nautilus/grammartec/context.rs b/libafl/src/common/nautilus/grammartec/context.rs index dc6c9badc9..c29901b9fd 100644 --- a/libafl/src/common/nautilus/grammartec/context.rs +++ b/libafl/src/common/nautilus/grammartec/context.rs @@ -1,5 +1,4 @@ use alloc::{borrow::ToOwned, string::String, vec::Vec}; -use core::num::NonZero; use hashbrown::HashMap; use libafl_bolts::{ diff --git a/libafl/src/common/nautilus/grammartec/mutator.rs b/libafl/src/common/nautilus/grammartec/mutator.rs index 2ec854f79c..dbc1aee927 100644 --- a/libafl/src/common/nautilus/grammartec/mutator.rs +++ b/libafl/src/common/nautilus/grammartec/mutator.rs @@ -27,7 +27,7 @@ impl Mutator { } //Return value indicates if minimization is complete: true: complete, false: not complete - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn minimize_tree( &mut self, rand: &mut R, @@ -353,7 +353,7 @@ mod tests { .iter() .map(|x| RuleIdOrCustom::Rule(*x)) .collect::>(); - let mut tree = Tree::from_rule_vec(rules, &ctx); + let tree = Tree::from_rule_vec(rules, &ctx); println!("tree: {tree:?}"); let mut mutator = Mutator::new(&ctx); @@ -529,7 +529,6 @@ mod tests { #[test] fn deterministic_splice() { - let mut rand = StdRand::new(); let mut ctx = Context::new(); let mut rand = StdRand::new(); let mut cks = ChunkStore::new("/tmp/".to_string()); diff --git a/libafl/src/common/nautilus/grammartec/newtypes.rs b/libafl/src/common/nautilus/grammartec/newtypes.rs index bd3e0a3bab..0e38a7af10 100644 --- a/libafl/src/common/nautilus/grammartec/newtypes.rs +++ b/libafl/src/common/nautilus/grammartec/newtypes.rs @@ -64,6 +64,7 @@ impl Add for NodeId { } impl NodeId { + #[expect(dead_code)] fn steps_between(start: Self, end: Self) -> Option { let start_i = start.to_i(); let end_i = end.to_i(); @@ -72,12 +73,18 @@ impl NodeId { } Some(end_i - start_i) } + + #[expect(dead_code)] fn add_one(self) -> Self { self.add(1) } + + #[expect(dead_code)] fn sub_one(self) -> Self { NodeId(self.0 - 1) } + + #[expect(dead_code)] fn add_usize(self, n: usize) -> Option { self.0.checked_add(n).map(NodeId::from) } diff --git a/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs b/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs index 75d1119d88..7ed7ab5f9b 100644 --- a/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs +++ b/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs @@ -2,7 +2,7 @@ use std::{string::String, vec::Vec}; use pyo3::{prelude::*, pyclass, types::IntoPyDict}; -use crate::{nautilus::grammartec::context::Context, Error}; +use crate::nautilus::grammartec::context::Context; #[pyclass] struct PyContext { @@ -23,7 +23,7 @@ impl PyContext { } } - fn rule(&mut self, py: Python, nt: &str, format: &Bound) -> PyResult<()> { + fn rule(&mut self, _py: Python, nt: &str, format: &Bound) -> PyResult<()> { if let Ok(s) = format.extract::<&str>() { self.ctx.add_rule(nt, s.as_bytes()); } else if let Ok(s) = format.extract::<&[u8]>() { @@ -36,7 +36,7 @@ impl PyContext { Ok(()) } - #[allow(clippy::needless_pass_by_value)] + #[expect(clippy::needless_pass_by_value)] fn script(&mut self, nt: &str, nts: Vec, script: PyObject) { self.ctx.add_script(nt, &nts, script); } diff --git a/libafl/src/common/nautilus/grammartec/recursion_info.rs b/libafl/src/common/nautilus/grammartec/recursion_info.rs index 49d7e5c99d..6933be1c59 100644 --- a/libafl/src/common/nautilus/grammartec/recursion_info.rs +++ b/libafl/src/common/nautilus/grammartec/recursion_info.rs @@ -53,7 +53,7 @@ impl RecursionInfo { // different recursions. Therefore we use the weight of the node to sample the endpoint of a path trough the // recursion tree. Then we just sample the length of this path uniformly as `(1.. weight)`. This // yields a uniform sample from the whole set of recursions inside the tree. If you read this, Good luck you are on your own. - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] fn find_parents( t: &Tree, nt: NTermId, @@ -82,7 +82,7 @@ impl RecursionInfo { res } - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] fn build_sampler(depths: &[usize]) -> Result { let mut weights = depths.iter().map(|x| *x as f64).collect::>(); let norm: f64 = weights.iter().sum(); diff --git a/libafl/src/common/nautilus/grammartec/rule.rs b/libafl/src/common/nautilus/grammartec/rule.rs index 7df06852b0..c3b6984d91 100644 --- a/libafl/src/common/nautilus/grammartec/rule.rs +++ b/libafl/src/common/nautilus/grammartec/rule.rs @@ -1,5 +1,4 @@ use alloc::{string::String, vec::Vec}; -use core::cell::OnceCell; use std::sync::OnceLock; use libafl_bolts::rands::Rand; diff --git a/libafl/src/common/nautilus/grammartec/tree.rs b/libafl/src/common/nautilus/grammartec/tree.rs index 30ea6992df..d330076736 100644 --- a/libafl/src/common/nautilus/grammartec/tree.rs +++ b/libafl/src/common/nautilus/grammartec/tree.rs @@ -6,7 +6,7 @@ use libafl_bolts::rands::Rand; use pyo3::{ prelude::{PyObject, PyResult, Python}, types::{PyAnyMethods, PyBytes, PyBytesMethods, PyString, PyStringMethods, PyTuple}, - FromPyObject, PyTypeInfo, + PyTypeInfo, }; use serde::{Deserialize, Serialize}; @@ -211,9 +211,11 @@ impl TreeLike for Tree { fn get_rule<'c>(&self, n: NodeId, ctx: &'c Context) -> &'c Rule { ctx.get_rule(self.get_rule_id(n)) } + fn get_custom_rule_data(&self, n: NodeId) -> &[u8] { self.rules[n.to_i()].data() } + fn get_rule_or_custom(&self, n: NodeId) -> &RuleIdOrCustom { &self.rules[n.to_i()] } @@ -240,6 +242,7 @@ impl Tree { self.rules[n.to_i()].id() } + #[expect(dead_code)] fn get_rule_or_custom(&self, n: NodeId) -> &RuleIdOrCustom { &self.rules[n.to_i()] } @@ -384,6 +387,7 @@ impl Tree { } } + #[expect(dead_code)] fn find_recursions_iter(&self, ctx: &Context) -> Vec<(NodeId, NodeId)> { let mut found_recursions = Vec::new(); //Only search for iterations for up to 10000 nodes @@ -442,6 +446,7 @@ impl TreeLike for TreeMutation<'_> { fn size(&self) -> usize { self.prefix.len() + self.repl.len() + self.postfix.len() } + fn get_rule_or_custom(&self, n: NodeId) -> &RuleIdOrCustom { self.get_at(n) } diff --git a/libafl/src/common/nautilus/mod.rs b/libafl/src/common/nautilus/mod.rs index 73f51b5c95..15b1ab2276 100644 --- a/libafl/src/common/nautilus/mod.rs +++ b/libafl/src/common/nautilus/mod.rs @@ -2,5 +2,7 @@ //! #![doc = include_str!("README.md")] +#[allow(missing_docs)] pub mod grammartec; +#[allow(missing_docs)] pub mod regex_mutator; diff --git a/libafl/src/common/nautilus/regex_mutator/mod.rs b/libafl/src/common/nautilus/regex_mutator/mod.rs index b7ece90ba3..00d4525fe1 100644 --- a/libafl/src/common/nautilus/regex_mutator/mod.rs +++ b/libafl/src/common/nautilus/regex_mutator/mod.rs @@ -53,7 +53,6 @@ fn append_unicode_range( cls: ClassUnicodeRange, ) { let mut chr_a_buf = [0; 4]; - #[allow(clippy::similar_names)] let mut chr_b_buf = [0; 4]; cls.start().encode_utf8(&mut chr_a_buf); cls.end().encode_utf8(&mut chr_b_buf); diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index e879881098..c2e0a5536b 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -470,11 +470,14 @@ impl InMemoryOnDiskCorpus { #[cfg(test)] mod tests { + #[cfg(not(miri))] use std::{env, fs, io::Write}; + #[cfg(not(miri))] use super::{create_new, try_create_new}; #[test] + #[cfg(not(miri))] fn test() { let tmp = env::temp_dir(); let path = tmp.join("testfile.tmp"); diff --git a/libafl/src/corpus/minimizer.rs b/libafl/src/corpus/minimizer.rs index c6599ca75d..0e513863df 100644 --- a/libafl/src/corpus/minimizer.rs +++ b/libafl/src/corpus/minimizer.rs @@ -64,7 +64,7 @@ where TS: TestcaseScore, { /// Do the minimization - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub fn minimize( &self, fuzzer: &mut Z, diff --git a/libafl/src/corpus/testcase.rs b/libafl/src/corpus/testcase.rs index 8c76399594..776de28c70 100644 --- a/libafl/src/corpus/testcase.rs +++ b/libafl/src/corpus/testcase.rs @@ -358,7 +358,6 @@ where } /// Get the `len` or calculate it, if not yet calculated. - #[allow(clippy::len_without_is_empty)] pub fn load_len>(&mut self, corpus: &C) -> Result { match &self.input { Some(i) => { @@ -389,7 +388,7 @@ impl From for Testcase { #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct SchedulerTestcaseMetadata { /// Number of bits set in bitmap, updated in `calibrate_case` diff --git a/libafl/src/events/broker_hooks/centralized.rs b/libafl/src/events/broker_hooks/centralized.rs index eaa6c6bb4b..831ae29fcb 100644 --- a/libafl/src/events/broker_hooks/centralized.rs +++ b/libafl/src/events/broker_hooks/centralized.rs @@ -89,7 +89,7 @@ where } /// Handle arriving events in the broker - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] fn handle_in_broker( _client_id: ClientId, event: &Event, diff --git a/libafl/src/events/broker_hooks/mod.rs b/libafl/src/events/broker_hooks/mod.rs index 90a4cedb2a..cc3d470b9d 100644 --- a/libafl/src/events/broker_hooks/mod.rs +++ b/libafl/src/events/broker_hooks/mod.rs @@ -104,7 +104,7 @@ where } /// Handle arriving events in the broker - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] fn handle_in_broker( monitor: &mut MT, client_id: ClientId, diff --git a/libafl/src/events/centralized.rs b/libafl/src/events/centralized.rs index e0b1a441f5..9d818e8686 100644 --- a/libafl/src/events/centralized.rs +++ b/libafl/src/events/centralized.rs @@ -27,8 +27,6 @@ use serde::{Deserialize, Serialize}; use super::NopEventManager; #[cfg(feature = "llmp_compression")] use crate::events::llmp::COMPRESS_THRESHOLD; -#[cfg(feature = "scalability_introspection")] -use crate::state::HasScalabilityMonitor; use crate::{ corpus::Corpus, events::{ @@ -278,7 +276,7 @@ where self.inner.should_send() } - #[allow(clippy::match_same_arms)] + #[expect(clippy::match_same_arms)] fn fire( &mut self, state: &mut Self::State, diff --git a/libafl/src/events/launcher.rs b/libafl/src/events/launcher.rs index 50a4e457ac..7dcba580fb 100644 --- a/libafl/src/events/launcher.rs +++ b/libafl/src/events/launcher.rs @@ -380,7 +380,7 @@ where /// Launch the broker and the clients and fuzz #[cfg(any(windows, not(feature = "fork")))] - #[allow(clippy::too_many_lines, clippy::match_wild_err_arm)] + #[expect(clippy::too_many_lines, clippy::match_wild_err_arm)] pub fn launch_with_hooks(&mut self, hooks: EMH) -> Result<(), Error> where S: State + HasExecutions, @@ -453,7 +453,7 @@ where for overcommit_i in 0..self.overcommit { index += 1; // Forward own stdio to child processes, if requested by user - #[allow(unused_mut)] + #[allow(unused_mut)] // mut only on certain cfgs let (mut stdout, mut stderr) = (Stdio::null(), Stdio::null()); #[cfg(unix)] { diff --git a/libafl/src/events/llmp/mgr.rs b/libafl/src/events/llmp/mgr.rs index 687d7e10d4..1b76f0813c 100644 --- a/libafl/src/events/llmp/mgr.rs +++ b/libafl/src/events/llmp/mgr.rs @@ -365,7 +365,7 @@ where let msg = TcpRequest::ClientQuit { client_id }; // Send this mesasge off and we are leaving. match send_tcp_msg(&mut stream, &msg) { - Ok(_) => (), + Ok(()) => (), Err(e) => log::error!("Failed to send tcp message {:#?}", e), } log::debug!("Asking he broker to be disconnected"); @@ -393,7 +393,6 @@ where SP: ShMemProvider, { // Handle arriving events in the client - #[allow(clippy::unused_self)] fn handle_in_client( &mut self, fuzzer: &mut Z, diff --git a/libafl/src/events/llmp/mod.rs b/libafl/src/events/llmp/mod.rs index 0175d33c6f..629ff6006a 100644 --- a/libafl/src/events/llmp/mod.rs +++ b/libafl/src/events/llmp/mod.rs @@ -341,7 +341,6 @@ where } /// Handle arriving events in the client - #[allow(clippy::unused_self)] pub fn process( &mut self, fuzzer: &mut Z, diff --git a/libafl/src/events/llmp/restarting.rs b/libafl/src/events/llmp/restarting.rs index 731c9e932d..4feeababcf 100644 --- a/libafl/src/events/llmp/restarting.rs +++ b/libafl/src/events/llmp/restarting.rs @@ -333,7 +333,7 @@ pub enum ManagerKind { /// /// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support. /// The restarter will spawn a new process each time the child crashes or timeouts. -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] pub fn setup_restarting_mgr_std( monitor: MT, broker_port: u16, @@ -364,7 +364,7 @@ where /// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support. /// The restarter will spawn a new process each time the child crashes or timeouts. /// This one, additionally uses the timeobserver for the adaptive serialization -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] pub fn setup_restarting_mgr_std_adaptive( monitor: MT, broker_port: u16, @@ -397,7 +397,6 @@ where /// The [`RestartingMgr`] is is a combination of a /// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The /// `restarter` will start a new process each time the child crashes or times out. -#[allow(clippy::default_trait_access, clippy::ignored_unit_patterns)] #[derive(TypedBuilder, Debug)] pub struct RestartingMgr { /// The shared memory provider to use for the broker or client spawned by the restarting @@ -439,7 +438,7 @@ pub struct RestartingMgr { phantom_data: PhantomData<(EMH, S)>, } -#[allow(clippy::type_complexity, clippy::too_many_lines)] +#[expect(clippy::type_complexity, clippy::too_many_lines)] impl RestartingMgr where EMH: EventManagerHooksTuple + Copy + Clone, @@ -612,15 +611,12 @@ where return Err(Error::shutting_down()); } - #[allow(clippy::manual_assert)] if !staterestorer.has_content() && !self.serialize_state.oom_safe() { if let Err(err) = mgr.detach_from_broker(self.broker_port) { log::error!("Failed to detach from broker: {err}"); } #[cfg(unix)] - if child_status == 9 { - panic!("Target received SIGKILL!. This could indicate the target crashed due to OOM, user sent SIGKILL, or the target was in an unrecoverable situation and could not save state to restart"); - } + assert_ne!(9, child_status, "Target received SIGKILL!. This could indicate the target crashed due to OOM, user sent SIGKILL, or the target was in an unrecoverable situation and could not save state to restart"); // Storing state in the last round did not work panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {child_status})"); } diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 81ab7f7d32..93dddc4f07 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -11,13 +11,11 @@ pub mod centralized; #[cfg(all(unix, feature = "std"))] pub use centralized::*; #[cfg(feature = "std")] -#[allow(clippy::ignored_unit_patterns)] pub mod launcher; -#[allow(clippy::ignored_unit_patterns)] + pub mod llmp; pub use llmp::*; #[cfg(feature = "tcp_manager")] -#[allow(clippy::ignored_unit_patterns)] pub mod tcp; pub mod broker_hooks; diff --git a/libafl/src/events/multi_machine.rs b/libafl/src/events/multi_machine.rs index f55e41ea24..51f8d7a145 100644 --- a/libafl/src/events/multi_machine.rs +++ b/libafl/src/events/multi_machine.rs @@ -122,7 +122,6 @@ impl NodeId { /// The state of the hook shared between the background threads and the main thread. #[derive(Debug)] -#[allow(dead_code)] pub struct TcpMultiMachineState { node_descriptor: NodeDescriptor, /// the parent to which the testcases should be forwarded when deemed interesting @@ -364,7 +363,7 @@ where /// Read a [`TcpMultiMachineMsg`] from a stream. /// Expects a message written by [`TcpMultiMachineState::write_msg`]. /// If there is nothing to read from the stream, return asap with Ok(None). - #[allow(clippy::uninit_vec)] + #[expect(clippy::uninit_vec)] async fn read_msg<'a, I: Input + 'a>( stream: &mut TcpStream, ) -> Result>, Error> { diff --git a/libafl/src/events/simple.rs b/libafl/src/events/simple.rs index 5289eaa2f7..122bdd3fb6 100644 --- a/libafl/src/events/simple.rs +++ b/libafl/src/events/simple.rs @@ -200,7 +200,7 @@ where } /// Handle arriving events in the broker - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] fn handle_in_broker( monitor: &mut MT, event: &Event, @@ -273,7 +273,6 @@ where } // Handle arriving events in the client - #[allow(clippy::needless_pass_by_value, clippy::unused_self)] fn handle_in_client(&mut self, state: &mut S, event: Event) -> Result<(), Error> { match event { Event::CustomBuf { buf, tag } => { @@ -299,7 +298,6 @@ where /// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The /// `restarter` will start a new process each time the child crashes or times out. #[cfg(feature = "std")] -#[allow(clippy::default_trait_access)] #[derive(Debug)] pub struct SimpleRestartingEventManager where @@ -433,7 +431,6 @@ where } #[cfg(feature = "std")] -#[allow(clippy::type_complexity, clippy::too_many_lines)] impl SimpleRestartingEventManager where S: UsesInput + Stoppable, @@ -451,7 +448,6 @@ where /// Launch the simple restarting manager. /// This [`EventManager`] is simple and single threaded, /// but can still used shared maps to recover from crashes and timeouts. - #[allow(clippy::similar_names)] pub fn launch(mut monitor: MT, shmem_provider: &mut SP) -> Result<(Option, Self), Error> where S: DeserializeOwned + Serialize + HasCorpus + HasSolutions, @@ -519,7 +515,7 @@ where return Err(Error::shutting_down()); } - #[allow(clippy::manual_assert)] + #[expect(clippy::manual_assert)] if !staterestorer.has_content() { #[cfg(unix)] if child_status == 9 { diff --git a/libafl/src/events/tcp.rs b/libafl/src/events/tcp.rs index 5b4ac815db..c16c3eaf93 100644 --- a/libafl/src/events/tcp.rs +++ b/libafl/src/events/tcp.rs @@ -112,9 +112,9 @@ where } /// Run in the broker until all clients exit - // TODO: remove allow(clippy::needless_return) when clippy is fixed + // TODO: remove expect(clippy::needless_return) when clippy is fixed #[tokio::main(flavor = "current_thread")] - #[allow(clippy::too_many_lines, clippy::needless_return)] + #[expect(clippy::too_many_lines)] pub async fn broker_loop(&mut self) -> Result<(), Error> { let (tx_bc, rx) = broadcast::channel(65536); let (tx, mut rx_mpsc) = mpsc::channel(65536); @@ -289,10 +289,9 @@ where let event_bytes = &buf[4..]; #[cfg(feature = "tcp_compression")] - let event_bytes = GzipCompressor::new().decompress(event_bytes)?; + let event_bytes = &GzipCompressor::new().decompress(event_bytes)?; - #[allow(clippy::needless_borrow)] // make decompressed vec and slice compatible - let event: Event = postcard::from_bytes(&event_bytes)?; + let event: Event = postcard::from_bytes(event_bytes)?; match Self::handle_in_broker(&mut self.monitor, client_id, &event)? { BrokerEventResult::Forward => { tx_bc.send(buf).expect("Could not send"); @@ -311,7 +310,7 @@ where } /// Handle arriving events in the broker - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] fn handle_in_broker( monitor: &mut MT, client_id: ClientId, @@ -593,7 +592,6 @@ where } // Handle arriving events in the client - #[allow(clippy::unused_self)] fn handle_in_client( &mut self, fuzzer: &mut Z, @@ -789,7 +787,6 @@ where let buf = self.compressor.decompress(buf)?; // make decompressed vec and slice compatible - #[allow(clippy::needless_borrow)] let event = postcard::from_bytes(&buf)?; self.handle_in_client(fuzzer, executor, state, other_client_id, event)?; @@ -1067,7 +1064,7 @@ pub enum TcpManagerKind { /// /// The [`TcpRestartingEventManager`] is a combination of restarter and runner, that can be used on systems with and without `fork` support. /// The restarter will spawn a new process each time the child crashes or timeouts. -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] pub fn setup_restarting_mgr_tcp( monitor: MT, broker_port: u16, @@ -1099,7 +1096,6 @@ where /// The [`TcpRestartingMgr`] is a combination of a /// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The /// `restarter` will start a new process each time the child crashes or times out. -#[allow(clippy::default_trait_access, clippy::ignored_unit_patterns)] #[derive(TypedBuilder, Debug)] pub struct TcpRestartingMgr where @@ -1142,7 +1138,7 @@ where phantom_data: PhantomData, } -#[allow(clippy::type_complexity, clippy::too_many_lines)] +#[expect(clippy::type_complexity, clippy::too_many_lines)] impl TcpRestartingMgr where EMH: EventManagerHooksTuple + Copy + Clone, @@ -1289,7 +1285,7 @@ where return Err(Error::shutting_down()); } - #[allow(clippy::manual_assert)] + #[expect(clippy::manual_assert)] if !staterestorer.has_content() && self.serialize_state { #[cfg(unix)] if child_status == 137 { diff --git a/libafl/src/executors/command.rs b/libafl/src/executors/command.rs index 9218dfd18a..375af104e6 100644 --- a/libafl/src/executors/command.rs +++ b/libafl/src/executors/command.rs @@ -80,7 +80,6 @@ pub enum InputLocation { /// A simple Configurator that takes the most common parameters /// Writes the input either to stdio or to a file /// Use [`CommandExecutor::builder()`] to use this configurator. -#[allow(clippy::struct_excessive_bools)] #[derive(Debug)] pub struct StdCommandConfigurator { /// If set to true, the child output will remain visible diff --git a/libafl/src/executors/differential.rs b/libafl/src/executors/differential.rs index 95b0e093cb..4c5ae3fb5a 100644 --- a/libafl/src/executors/differential.rs +++ b/libafl/src/executors/differential.rs @@ -208,7 +208,7 @@ where B: MatchName, DOT: MatchName, { - #[allow(deprecated)] + #[expect(deprecated)] fn match_name(&self, name: &str) -> Option<&T> { if let Some(t) = self.primary.as_ref().match_name::(name) { Some(t) @@ -219,7 +219,7 @@ where } } - #[allow(deprecated)] + #[expect(deprecated)] fn match_name_mut(&mut self, name: &str) -> Option<&mut T> { if let Some(t) = self.primary.as_mut().match_name_mut::(name) { Some(t) diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 2b0e8dec82..db8c0a8430 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -54,43 +54,43 @@ use crate::{ }; const FORKSRV_FD: i32 = 198; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_NEW_ERROR: i32 = 0xeffe0000_u32 as i32; const FS_NEW_VERSION_MIN: u32 = 1; const FS_NEW_VERSION_MAX: u32 = 1; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_OPT_ENABLED: i32 = 0x80000001_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_NEW_OPT_MAPSIZE: i32 = 1_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_OPT_MAPSIZE: i32 = 0x40000000_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_OPT_SHDMEM_FUZZ: i32 = 0x01000000_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_NEW_OPT_SHDMEM_FUZZ: i32 = 2_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_NEW_OPT_AUTODTCT: i32 = 0x00000800_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_OPT_AUTODTCT: i32 = 0x10000000_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_MAP_SIZE: i32 = 1_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_MAP_ADDR: i32 = 2_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_SHM_OPEN: i32 = 4_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_SHMAT: i32 = 8_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_MMAP: i32 = 16_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_OLD_CMPLOG: i32 = 32_u32 as i32; -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] const FS_ERROR_OLD_CMPLOG_QEMU: i32 = 64_u32 as i32; /// Forkserver message. We'll reuse it in a testcase. @@ -209,7 +209,7 @@ impl ConfigTarget for Command { } } - #[allow(trivial_numeric_casts, clippy::cast_possible_wrap)] + #[expect(trivial_numeric_casts)] fn setlimit(&mut self, memlimit: u64) -> &mut Self { if memlimit == 0 { return self; @@ -315,10 +315,10 @@ const fn fs_opt_get_mapsize(x: i32) -> i32 { ((x & 0x00fffffe) >> 1) + 1 } -#[allow(clippy::fn_params_excessive_bools)] +#[expect(clippy::fn_params_excessive_bools)] impl Forkserver { /// Create a new [`Forkserver`] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn new( target: OsString, args: Vec, @@ -351,7 +351,7 @@ impl Forkserver { /// Create a new [`Forkserver`] that will kill child processes /// with the given `kill_signal`. /// Using `Forkserver::new(..)` will default to [`Signal::SIGTERM`]. - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn with_kill_signal( target: OsString, args: Vec, @@ -540,7 +540,7 @@ impl Forkserver { #[allow( clippy::uninit_vec, reason = "The vec will be filled right after setting the length." - )] + )] // expect for some reason does not work unsafe { buf.set_len(size); } @@ -806,7 +806,7 @@ where /// The builder for `ForkserverExecutor` #[derive(Debug)] -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] pub struct ForkserverExecutorBuilder<'a, TC, SP> { program: Option, arguments: Vec, @@ -839,7 +839,7 @@ where /// Else this forkserver will pass the input to the target via `stdin` /// in case no input file is specified. /// If `debug_child` is set, the child will print to `stdout`/`stderr`. - #[allow(clippy::pedantic)] + #[expect(clippy::pedantic)] pub fn build(mut self, observers: OT) -> Result, Error> where OT: ObserversTuple, @@ -902,7 +902,7 @@ where } /// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size. - #[allow(clippy::pedantic)] + #[expect(clippy::pedantic)] pub fn build_dynamic_map( mut self, mut map_observer: A, @@ -967,7 +967,7 @@ where }) } - #[allow(clippy::pedantic)] + #[expect(clippy::pedantic)] fn build_helper(&mut self) -> Result<(Forkserver, InputFile, Option), Error> where SP: ShMemProvider, @@ -1040,8 +1040,8 @@ where } /// Intialize forkserver > v4.20c - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_possible_wrap)] + #[expect(clippy::cast_sign_loss)] fn initialize_forkserver( &mut self, status: i32, @@ -1139,8 +1139,7 @@ where } /// Intialize old forkserver. < v4.20c - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn initialize_old_forkserver( &mut self, status: i32, @@ -1214,7 +1213,7 @@ where Ok(()) } - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn set_map_size(&mut self, fsrv_map_size: i32) -> Result { // When 0, we assume that map_size was filled by the user or const /* TODO autofill map size from the observer diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index 876016b972..36ec47bbc5 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -25,19 +25,19 @@ use crate::executors::hooks::timer::TimerStruct; use crate::executors::hooks::unix::unix_signal_handler; #[cfg(windows)] use crate::state::State; +#[cfg(any(unix, windows))] +use crate::{corpus::Corpus, observers::ObserversTuple, state::UsesState}; use crate::{ - corpus::Corpus, events::{EventFirer, EventRestarter}, executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers}, feedbacks::Feedback, inputs::UsesInput, - observers::ObserversTuple, - state::{HasCorpus, HasExecutions, HasSolutions, UsesState}, + state::{HasCorpus, HasExecutions, HasSolutions}, Error, HasObjective, }; /// The inmem executor's handlers. -#[allow(missing_debug_implementations)] +#[expect(missing_debug_implementations)] pub struct InProcessHooks { /// On crash C function pointer #[cfg(feature = "std")] @@ -128,7 +128,7 @@ where } #[cfg(all(unix, feature = "std"))] - #[allow(unused)] + #[allow(unused_variables)] // depends on the features fn handle_timeout(&mut self, data: &mut InProcessExecutorHandlerData) -> bool { #[cfg(not(target_os = "linux"))] { @@ -197,8 +197,7 @@ where { fn init(&mut self, _state: &mut S) {} /// Call before running a target. - #[allow(clippy::unused_self)] - #[allow(unused_variables)] + #[expect(unused_variables)] fn pre_exec(&mut self, state: &mut S, input: &S::Input) { #[cfg(feature = "std")] unsafe { @@ -212,7 +211,6 @@ where } /// Call after running a target. - #[allow(clippy::unused_self)] fn post_exec(&mut self, _state: &mut S, _input: &S::Input) { // timeout stuff // # Safety @@ -228,7 +226,7 @@ where { /// Create new [`InProcessHooks`]. #[cfg(unix)] - #[allow(unused_variables)] + #[allow(unused_variables)] // for `exec_tmout` without `std` pub fn new(exec_tmout: Duration) -> Result where E: Executor + HasObservers + HasInProcessHooks, @@ -243,7 +241,8 @@ where // # Safety // We get a pointer to `GLOBAL_STATE` that will be initialized at this point in time. // This unsafe is needed in stable but not in nightly. Remove in the future(?) - #[allow(unused_unsafe)] + #[expect(unused_unsafe)] + #[cfg(all(not(miri), unix, feature = "std"))] let data = unsafe { &raw mut GLOBAL_STATE }; #[cfg(feature = "std")] unix_signal_handler::setup_panic_hook::(); @@ -271,7 +270,7 @@ where /// Create new [`InProcessHooks`]. #[cfg(windows)] - #[allow(unused)] + #[allow(unused_variables)] // for `exec_tmout` without `std` pub fn new(exec_tmout: Duration) -> Result where E: Executor + HasObservers + HasInProcessHooks, @@ -329,7 +328,7 @@ where /// Create a new [`InProcessHooks`] #[cfg(all(not(unix), not(windows)))] - #[allow(unused_variables)] + #[expect(unused_variables)] pub fn new(exec_tmout: Duration) -> Result where E: Executor + HasObservers + HasInProcessHooks, diff --git a/libafl/src/executors/hooks/timer.rs b/libafl/src/executors/hooks/timer.rs index bf0639f389..3f335848be 100644 --- a/libafl/src/executors/hooks/timer.rs +++ b/libafl/src/executors/hooks/timer.rs @@ -38,7 +38,7 @@ pub(crate) struct Timeval { #[cfg(all(unix, not(target_os = "linux")))] impl core::fmt::Debug for Timeval { - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, @@ -69,7 +69,7 @@ extern "C" { /// The strcut about all the internals of the timer. /// This struct absorb all platform specific differences about timer. -#[allow(missing_debug_implementations)] +#[expect(missing_debug_implementations)] pub struct TimerStruct { // timeout time (windows) #[cfg(windows)] @@ -103,7 +103,7 @@ pub struct TimerStruct { } #[cfg(windows)] -#[allow(non_camel_case_types)] +#[expect(non_camel_case_types)] type PTP_TIMER_CALLBACK = unsafe extern "system" fn( param0: PTP_CALLBACK_INSTANCE, param1: *mut c_void, @@ -201,8 +201,6 @@ impl TimerStruct { #[cfg(target_os = "linux")] #[must_use] - #[allow(unused_unsafe)] - #[allow(unused_mut)] /// Create a `TimerStruct` with the specified timeout pub fn new(exec_tmout: Duration) -> Self { let milli_sec = exec_tmout.as_millis(); @@ -218,9 +216,10 @@ impl TimerStruct { it_interval, it_value, }; + #[allow(unused_mut)] // miri doesn't mutate this let mut timerid: libc::timer_t = null_mut(); + #[cfg(not(miri))] unsafe { - #[cfg(not(miri))] // creates a new per-process interval timer libc::timer_create(libc::CLOCK_MONOTONIC, null_mut(), &raw mut timerid); } @@ -264,7 +263,7 @@ impl TimerStruct { } #[cfg(windows)] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] /// Set timer pub fn set_timer(&mut self) { unsafe { @@ -324,7 +323,6 @@ impl TimerStruct { /// Disable the timer #[cfg(target_os = "linux")] - #[allow(unused_variables)] pub fn unset_timer(&mut self) { // # Safety // Just API calls, no user-provided inputs @@ -351,9 +349,9 @@ impl TimerStruct { } } } else { + #[cfg(not(miri))] unsafe { let disarmed: libc::itimerspec = zeroed(); - #[cfg(not(miri))] libc::timer_settime(self.timerid, 0, &raw const disarmed, null_mut()); } } diff --git a/libafl/src/executors/hooks/unix.rs b/libafl/src/executors/hooks/unix.rs index 25ece10a70..e0f63d91a8 100644 --- a/libafl/src/executors/hooks/unix.rs +++ b/libafl/src/executors/hooks/unix.rs @@ -122,7 +122,7 @@ pub mod unix_signal_handler { /// # Safety /// Well, signal handling is not safe #[cfg(unix)] - #[allow(clippy::needless_pass_by_value)] + #[allow(clippy::needless_pass_by_value)] // nightly no longer requires this pub unsafe fn inproc_timeout_handler( _signal: Signal, _info: &mut siginfo_t, @@ -179,8 +179,7 @@ pub mod unix_signal_handler { /// /// # Safety /// Well, signal handling is not safe - #[allow(clippy::too_many_lines)] - #[allow(clippy::needless_pass_by_value)] + #[allow(clippy::needless_pass_by_value)] // nightly no longer requires this pub unsafe fn inproc_crash_handler( signal: Signal, _info: &mut siginfo_t, diff --git a/libafl/src/executors/hooks/windows.rs b/libafl/src/executors/hooks/windows.rs index ec2aef5a04..f0554848e9 100644 --- a/libafl/src/executors/hooks/windows.rs +++ b/libafl/src/executors/hooks/windows.rs @@ -154,7 +154,6 @@ pub mod windows_exception_handler { impl ExceptionHandler for InProcessExecutorHandlerData { /// # Safety /// Will dereference `EXCEPTION_POINTERS` and access `GLOBAL_STATE`. - #[allow(clippy::not_unsafe_ptr_arg_deref)] unsafe fn handle( &mut self, _code: ExceptionCode, @@ -316,7 +315,6 @@ pub mod windows_exception_handler { /// /// # Safety /// Well, exception handling is not safe - #[allow(clippy::too_many_lines)] pub unsafe fn inproc_crash_handler( exception_pointers: *mut EXCEPTION_POINTERS, data: &mut InProcessExecutorHandlerData, diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index 366532cbf7..431ab3ed0a 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -2,8 +2,6 @@ //! It should usually be paired with extra error-handling, such as a restarting event manager, to be effective. //! //! Needs the `fork` feature flag. -#![allow(clippy::needless_pass_by_value)] - use alloc::boxed::Box; use core::{ borrow::BorrowMut, @@ -57,7 +55,6 @@ pub type OwnedInProcessExecutor = GenericInProcessExecutor< >; /// The inmem executor simply calls a target function, then returns afterwards. -#[allow(dead_code)] pub struct GenericInProcessExecutor where H: FnMut(&S::Input) -> ExitKind + ?Sized, @@ -426,7 +423,6 @@ where } #[inline] -#[allow(clippy::too_many_arguments)] /// Save state if it is an objective pub fn run_observers_and_save_state( executor: &mut E, @@ -550,7 +546,6 @@ mod tests { } #[test] - #[allow(clippy::let_unit_value)] fn test_inmem_exec() { let mut harness = |_buf: &NopInput| ExitKind::Ok; let rand = XkcdRand::new(); diff --git a/libafl/src/executors/inprocess/stateful.rs b/libafl/src/executors/inprocess/stateful.rs index 159d87fac5..b24d3b54b0 100644 --- a/libafl/src/executors/inprocess/stateful.rs +++ b/libafl/src/executors/inprocess/stateful.rs @@ -44,7 +44,6 @@ pub type OwnedInProcessExecutor = StatefulGenericInProcessExecutor< /// The inmem executor simply calls a target function, then returns afterwards. /// The harness can access the internal state of the executor. -#[allow(dead_code)] pub struct StatefulGenericInProcessExecutor where H: FnMut(&mut ES, &mut S, &S::Input) -> ExitKind + ?Sized, @@ -318,7 +317,7 @@ where /// Create a new in mem executor with the default timeout and use batch mode(5 sec) #[cfg(all(feature = "std", target_os = "linux"))] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn batched_timeout_generic( user_hooks: HT, harness_fn: HB, @@ -357,7 +356,7 @@ where /// * `observers` - the observers observing the target during execution /// /// This may return an error on unix, if signal handler setup fails - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn with_timeout_generic( user_hooks: HT, harness_fn: HB, diff --git a/libafl/src/executors/inprocess_fork/inner.rs b/libafl/src/executors/inprocess_fork/inner.rs index e34d1eb56b..ad4b08b348 100644 --- a/libafl/src/executors/inprocess_fork/inner.rs +++ b/libafl/src/executors/inprocess_fork/inner.rs @@ -254,7 +254,6 @@ where /// Creates a new [`GenericInProcessForkExecutorInner`] with custom hooks #[cfg(target_os = "linux")] - #[allow(clippy::too_many_arguments)] pub fn with_hooks( userhooks: HT, observers: OT, @@ -279,7 +278,6 @@ where /// Creates a new [`GenericInProcessForkExecutorInner`], non linux #[cfg(not(target_os = "linux"))] - #[allow(clippy::too_many_arguments)] pub fn with_hooks( userhooks: HT, observers: OT, diff --git a/libafl/src/executors/inprocess_fork/mod.rs b/libafl/src/executors/inprocess_fork/mod.rs index e313405bdc..485f6cdfdf 100644 --- a/libafl/src/executors/inprocess_fork/mod.rs +++ b/libafl/src/executors/inprocess_fork/mod.rs @@ -57,7 +57,6 @@ where S: HasSolutions, Z: HasObjective, { - #[allow(clippy::too_many_arguments)] /// The constructor for `InProcessForkExecutor` pub fn new( harness_fn: &'a mut H, @@ -147,7 +146,6 @@ where HT: ExecutorHooksTuple, EM: EventFirer + EventRestarter, { - #[allow(unreachable_code)] #[inline] fn run_target( &mut self, @@ -190,7 +188,7 @@ where Z: HasObjective, { /// Creates a new [`GenericInProcessForkExecutor`] with custom hooks - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn with_hooks( userhooks: HT, harness_fn: &'a mut H, @@ -301,7 +299,7 @@ pub mod child_signal_handlers { /// The function should only be called from a child crash handler. /// It will dereference the `data` pointer and assume it's valid. #[cfg(unix)] - #[allow(clippy::needless_pass_by_value)] + #[allow(clippy::needless_pass_by_value)] // nightly no longer requires this pub(crate) unsafe fn child_crash_handler( _signal: Signal, _info: &mut siginfo_t, @@ -325,9 +323,9 @@ pub mod child_signal_handlers { } #[cfg(unix)] - #[allow(clippy::needless_pass_by_value)] + #[allow(clippy::needless_pass_by_value)] // nightly no longer requires this pub(crate) unsafe fn child_timeout_handler( - _signal: Signal, + #[cfg(unix)] _signal: Signal, _info: &mut siginfo_t, _context: Option<&mut ucontext_t>, data: &mut InProcessForkExecutorGlobalData, diff --git a/libafl/src/executors/inprocess_fork/stateful.rs b/libafl/src/executors/inprocess_fork/stateful.rs index 027f272abd..82757511f7 100644 --- a/libafl/src/executors/inprocess_fork/stateful.rs +++ b/libafl/src/executors/inprocess_fork/stateful.rs @@ -38,7 +38,7 @@ where OT: ObserversTuple, S: State, { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] /// The constructor for `InProcessForkExecutor` pub fn new( harness_fn: &'a mut H, @@ -126,7 +126,6 @@ where SP: ShMemProvider, Z: HasObjective, { - #[allow(unreachable_code)] #[inline] fn run_target( &mut self, @@ -166,7 +165,7 @@ where S: State, { /// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn with_hooks( userhooks: HT, harness_fn: &'a mut H, diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index a15ce0e1ef..ed4f3c6634 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -45,7 +45,7 @@ pub mod hooks; #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub enum ExitKind { /// The run exited normally. @@ -71,7 +71,7 @@ pub enum ExitKind { #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub enum DiffExitKind { /// The run exited normally. diff --git a/libafl/src/feedbacks/capture_feedback.rs b/libafl/src/feedbacks/capture_feedback.rs index ea112e264e..c7d37b89cc 100644 --- a/libafl/src/feedbacks/capture_feedback.rs +++ b/libafl/src/feedbacks/capture_feedback.rs @@ -41,7 +41,6 @@ where S: HasCorpus + HasMetadata, I: Debug + Serialize + DeserializeOwned + Default + 'static + Clone, { - #[allow(clippy::wrong_self_convention)] #[inline] fn is_interesting( &mut self, diff --git a/libafl/src/feedbacks/concolic.rs b/libafl/src/feedbacks/concolic.rs index 93cdd658f2..79b99ba99a 100644 --- a/libafl/src/feedbacks/concolic.rs +++ b/libafl/src/feedbacks/concolic.rs @@ -31,7 +31,6 @@ pub struct ConcolicFeedback<'map> { impl<'map> ConcolicFeedback<'map> { /// Creates a concolic feedback from an observer - #[allow(unused)] #[must_use] pub fn from_observer(observer: &ConcolicObserver<'map>) -> Self { Self { diff --git a/libafl/src/feedbacks/differential.rs b/libafl/src/feedbacks/differential.rs index 54c3f6ffc7..c5d537a5b3 100644 --- a/libafl/src/feedbacks/differential.rs +++ b/libafl/src/feedbacks/differential.rs @@ -145,7 +145,6 @@ where OT: MatchName, C: DiffComparator, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, diff --git a/libafl/src/feedbacks/list.rs b/libafl/src/feedbacks/list.rs index d1590a957d..0a1f76b256 100644 --- a/libafl/src/feedbacks/list.rs +++ b/libafl/src/feedbacks/list.rs @@ -129,7 +129,6 @@ where S: HasNamedMetadata, T: Debug + Eq + Hash + for<'a> Deserialize<'a> + Serialize + Default + Copy + 'static, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, state: &mut S, diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index e54269a7cf..7e8cb9700a 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -216,7 +216,7 @@ where /// A testcase metadata holding a list of indexes of a map #[derive(Debug, Serialize, Deserialize)] -#[allow(clippy::unsafe_derive_deserialize)] // for SerdeAny +#[expect(clippy::unsafe_derive_deserialize)] // for SerdeAny pub struct MapIndexesMetadata { /// The list of indexes. pub list: Vec, @@ -261,7 +261,7 @@ impl MapIndexesMetadata { /// A testcase metadata holding a list of indexes of a map #[derive(Debug, Serialize, Deserialize)] -#[allow(clippy::unsafe_derive_deserialize)] // for SerdeAny +#[expect(clippy::unsafe_derive_deserialize)] // for SerdeAny pub struct MapNoveltiesMetadata { /// A `list` of novelties. pub list: Vec, @@ -296,7 +296,7 @@ impl MapNoveltiesMetadata { /// The state of [`MapFeedback`] #[derive(Default, Serialize, Deserialize, Clone, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] // for SerdeAny +#[expect(clippy::unsafe_derive_deserialize)] // for SerdeAny pub struct MapFeedbackMetadata { /// Contains information about untouched entries pub history_map: Vec, @@ -374,7 +374,7 @@ pub struct MapFeedback { #[cfg(feature = "track_hit_feedbacks")] last_result: Option, /// Phantom Data of Reducer - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] phantom: PhantomData (N, O, R)>, } @@ -543,8 +543,6 @@ where OT: MatchName, S: HasNamedMetadata + UsesInput, { - #[allow(clippy::wrong_self_convention)] - #[allow(clippy::needless_range_loop)] fn is_interesting( &mut self, state: &mut S, @@ -564,7 +562,7 @@ impl Named for MapFeedback { } } -#[allow(clippy::ptr_arg)] +#[expect(clippy::ptr_arg)] fn create_stats_name(name: &Cow<'static, str>) -> Cow<'static, str> { if name.chars().all(char::is_lowercase) { name.clone() @@ -616,8 +614,6 @@ where O: MapObserver + for<'a> AsSlice<'a, Entry = u8> + for<'a> AsIter<'a, Item = u8>, C: CanTrack + AsRef, { - #[allow(clippy::wrong_self_convention)] - #[allow(clippy::needless_range_loop)] fn is_interesting_u8_simd_optimized(&mut self, state: &mut S, observers: &OT) -> bool where S: HasNamedMetadata, @@ -739,9 +735,6 @@ where N: IsNovel, C: AsRef, { - #[allow(clippy::wrong_self_convention)] - #[allow(clippy::needless_range_loop)] - #[allow(clippy::trivially_copy_pass_by_ref)] fn is_interesting_default(&mut self, state: &mut S, observers: &OT) -> bool where S: HasNamedMetadata, diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 5a2e463583..5fbf13f64a 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -71,7 +71,6 @@ pub trait StateInitializer { /// indicating the "interestingness" of the last run. pub trait Feedback: StateInitializer + Named { /// `is_interesting ` return if an input is worth the addition to the corpus - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, @@ -86,8 +85,6 @@ pub trait Feedback: StateInitializer + Named { /// Returns if the result of a run is interesting and the value input should be stored in a corpus. /// It also keeps track of introspection stats. #[cfg(feature = "introspection")] - #[allow(clippy::too_many_arguments)] - #[allow(clippy::wrong_self_convention)] fn is_interesting_introspection( &mut self, state: &mut S, @@ -135,7 +132,6 @@ pub trait Feedback: StateInitializer + Named { /// /// Precondition: `testcase` must contain an input. #[inline] - #[allow(unused_variables)] fn append_metadata( &mut self, _state: &mut S, @@ -220,7 +216,6 @@ where B: Feedback, FL: FeedbackLogic, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, state: &mut S, @@ -247,7 +242,6 @@ where } #[cfg(feature = "introspection")] - #[allow(clippy::wrong_self_convention)] fn is_interesting_introspection( &mut self, state: &mut S, @@ -640,7 +634,6 @@ impl Feedback for NotFeedback where A: Feedback, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, state: &mut S, @@ -840,7 +833,6 @@ impl Feedback for ExitKindFeedback where L: ExitKindLogic, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, @@ -977,7 +969,6 @@ impl StateInitializer for ConstFeedback {} impl Feedback for ConstFeedback { #[inline] - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, diff --git a/libafl/src/feedbacks/nautilus.rs b/libafl/src/feedbacks/nautilus.rs index 5cc4986a5a..b070d57c9e 100644 --- a/libafl/src/feedbacks/nautilus.rs +++ b/libafl/src/feedbacks/nautilus.rs @@ -96,7 +96,6 @@ where S: HasMetadata + HasCorpus, S::Corpus: Corpus, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, diff --git a/libafl/src/feedbacks/new_hash_feedback.rs b/libafl/src/feedbacks/new_hash_feedback.rs index b33d14790e..5fa7a4b825 100644 --- a/libafl/src/feedbacks/new_hash_feedback.rs +++ b/libafl/src/feedbacks/new_hash_feedback.rs @@ -32,7 +32,7 @@ pub trait HashSetState { /// The state of [`NewHashFeedback`] #[derive(Default, Serialize, Deserialize, Clone, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct NewHashFeedbackMetadata { /// Contains information about untouched entries hash_set: HashSet, @@ -104,7 +104,6 @@ impl NewHashFeedback where O: ObserverWithHashField + Named, { - #[allow(clippy::wrong_self_convention)] fn has_interesting_backtrace_hash_observation( &mut self, state: &mut S, @@ -156,7 +155,6 @@ where OT: MatchName, S: HasNamedMetadata, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, state: &mut S, diff --git a/libafl/src/feedbacks/stdio.rs b/libafl/src/feedbacks/stdio.rs index b4a140e228..2d3106b761 100644 --- a/libafl/src/feedbacks/stdio.rs +++ b/libafl/src/feedbacks/stdio.rs @@ -19,8 +19,7 @@ use crate::{ /// Metadata for [`StdOutToMetadataFeedback`]. #[derive(Debug, Serialize, Deserialize)] pub struct StdOutMetadata { - #[allow(missing_docs)] - pub stdout: String, + stdout: String, } impl_serdeany!(StdOutMetadata); @@ -104,8 +103,7 @@ impl StdOutToMetadataFeedback { /// Metadata for [`StdErrToMetadataFeedback`]. #[derive(Debug, Serialize, Deserialize)] pub struct StdErrMetadata { - #[allow(missing_docs)] - pub stderr: String, + stderr: String, } impl_serdeany!(StdErrMetadata); diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 44804c7178..5b5728e3b0 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -78,7 +78,6 @@ pub trait ExecutionProcessor { ) -> Result; /// Process `ExecuteInputResult`. Add to corpus, solution or ignore - #[allow(clippy::too_many_arguments)] fn process_execution( &mut self, state: &mut S, diff --git a/libafl/src/inputs/encoded.rs b/libafl/src/inputs/encoded.rs index e3f5897e18..b602cd0e94 100644 --- a/libafl/src/inputs/encoded.rs +++ b/libafl/src/inputs/encoded.rs @@ -34,7 +34,6 @@ where /// Trait to decode encoded input to bytes pub trait InputDecoder { /// Decode encoded input to bytes - #[allow(clippy::ptr_arg)] // we reuse the alloced `Vec` fn decode(&self, input: &EncodedInput, bytes: &mut Vec) -> Result<(), Error>; } diff --git a/libafl/src/inputs/generalized.rs b/libafl/src/inputs/generalized.rs index 48c7e09b45..91b7c00365 100644 --- a/libafl/src/inputs/generalized.rs +++ b/libafl/src/inputs/generalized.rs @@ -26,7 +26,7 @@ pub enum GeneralizedItem { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct GeneralizedInputMetadata { generalized: Vec, diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 2ed3ed5371..58464b3ee6 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -9,43 +9,41 @@ Welcome to `LibAFL` #![cfg_attr(nightly, feature(specialization))] // For `std::simd` #![cfg_attr(nightly, feature(portable_simd))] -#![cfg_attr(not(test), warn( - missing_debug_implementations, - missing_docs, - //trivial_casts, - trivial_numeric_casts, - unused_extern_crates, - unused_import_braces, - unused_qualifications, - //unused_results -))] -#![cfg_attr(test, deny( - missing_debug_implementations, - missing_docs, - //trivial_casts, - trivial_numeric_casts, - unused_extern_crates, - unused_import_braces, - unused_qualifications, - unused_must_use, - //unused_results -))] +#![cfg_attr( + not(test), + warn( + missing_debug_implementations, + missing_docs, + trivial_numeric_casts, + unused_extern_crates, + unused_import_braces, + unused_qualifications, + ) +)] #![cfg_attr( test, deny( bad_style, dead_code, improper_ctypes, - non_shorthand_field_patterns, + missing_debug_implementations, + missing_docs, no_mangle_generic_items, + non_shorthand_field_patterns, overflowing_literals, path_statements, patterns_in_fns_without_body, + trivial_numeric_casts, unconditional_recursion, - unused, + unfulfilled_lint_expectations, unused_allocation, unused_comparisons, + unused_extern_crates, + unused_import_braces, + unused_must_use, unused_parens, + unused_qualifications, + unused, while_true ) )] @@ -59,7 +57,7 @@ pub extern crate alloc; // Re-export derive(SerdeAny) #[cfg(feature = "derive")] -#[allow(unused_imports)] +#[expect(unused_imports)] #[macro_use] extern crate libafl_derive; #[cfg(feature = "derive")] @@ -131,7 +129,6 @@ mod tests { }; #[test] - #[allow(clippy::similar_names)] fn test_fuzzer() { // # Safety // No concurrency per testcase diff --git a/libafl/src/monitors/mod.rs b/libafl/src/monitors/mod.rs index 0a6cf0f6bc..48d31e1005 100644 --- a/libafl/src/monitors/mod.rs +++ b/libafl/src/monitors/mod.rs @@ -174,7 +174,7 @@ impl UserStatsValue { } /// Divide by the number of elements - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] pub fn stats_div(&mut self, divisor: usize) -> Option { match self { Self::Number(x) => Some(Self::Float(*x as f64 / divisor as f64)), @@ -186,7 +186,7 @@ impl UserStatsValue { } /// min user stats with the other - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] pub fn stats_max(&mut self, other: &Self) -> Option { match (self, other) { (Self::Number(x), Self::Number(y)) => { @@ -224,7 +224,7 @@ impl UserStatsValue { } /// min user stats with the other - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] pub fn stats_min(&mut self, other: &Self) -> Option { match (self, other) { (Self::Number(x), Self::Number(y)) => { @@ -262,7 +262,7 @@ impl UserStatsValue { } /// add user stats with the other - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] pub fn stats_add(&mut self, other: &Self) -> Option { match (self, other) { (Self::Number(x), Self::Number(y)) => Some(Self::Number(*x + *y)), @@ -412,7 +412,7 @@ impl ClientStats { } /// Get the calculated executions per second for this client - #[allow(clippy::cast_precision_loss, clippy::cast_sign_loss)] + #[expect(clippy::cast_precision_loss, clippy::cast_sign_loss)] #[cfg(feature = "afl_exec_sec")] pub fn execs_per_sec(&mut self, cur_time: Duration) -> f64 { if self.executions == 0 { @@ -443,7 +443,7 @@ impl ClientStats { } /// Get the calculated executions per second for this client - #[allow(clippy::cast_precision_loss, clippy::cast_sign_loss)] + #[expect(clippy::cast_precision_loss, clippy::cast_sign_loss)] #[cfg(not(feature = "afl_exec_sec"))] pub fn execs_per_sec(&mut self, cur_time: Duration) -> f64 { if self.executions == 0 { @@ -535,7 +535,6 @@ pub trait Monitor { } /// Executions per second - #[allow(clippy::cast_sign_loss)] #[inline] fn execs_per_sec(&mut self) -> f64 { let cur_time = current_time(); @@ -1234,7 +1233,7 @@ impl ClientPerfMonitor { #[cfg(feature = "introspection")] impl fmt::Display for ClientPerfMonitor { - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { // Calculate the elapsed time from the monitor let elapsed: f64 = self.elapsed_cycles() as f64; diff --git a/libafl/src/monitors/prometheus.rs b/libafl/src/monitors/prometheus.rs index 8dcf8d769d..e3f01f01ee 100644 --- a/libafl/src/monitors/prometheus.rs +++ b/libafl/src/monitors/prometheus.rs @@ -117,7 +117,6 @@ where self.aggregator.aggregate(name, &self.client_stats); } - #[allow(clippy::cast_sign_loss)] fn display(&mut self, event_msg: &str, sender_id: ClientId) { // Update the prometheus metrics // The gauges must take signed i64's, with max value of 2^63-1 so it is @@ -196,7 +195,7 @@ where for (key, val) in &self.aggregator.aggregated { // print global aggregated custom stats write!(global_fmt, ", {key}: {val}").unwrap(); - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] let value: f64 = match val { UserStatsValue::Number(n) => *n as f64, UserStatsValue::Float(f) => *f, @@ -303,7 +302,7 @@ where write!(fmt, ", {key}: {val}").unwrap(); // Update metrics added to the user_stats hashmap by feedback event-fires // You can filter for each custom stat in promQL via labels of both the stat name and client id - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] let value: f64 = match val.value() { UserStatsValue::Number(n) => *n as f64, UserStatsValue::Float(f) => *f, diff --git a/libafl/src/monitors/tui/mod.rs b/libafl/src/monitors/tui/mod.rs index 77cbbe0ee9..0e3d93f232 100644 --- a/libafl/src/monitors/tui/mod.rs +++ b/libafl/src/monitors/tui/mod.rs @@ -32,7 +32,7 @@ use typed_builder::TypedBuilder; use super::{ClientPerfMonitor, PerfFeature}; use crate::monitors::{Aggregator, AggregatorOps, ClientStats, Monitor, UserStats, UserStatsValue}; -#[allow(missing_docs)] +#[expect(missing_docs)] pub mod ui; use ui::TuiUi; @@ -143,7 +143,7 @@ pub struct PerfTuiContext { #[cfg(feature = "introspection")] impl PerfTuiContext { /// Get the data for performance metrics - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] pub fn grab_data(&mut self, m: &ClientPerfMonitor) { // Calculate the elapsed time from the monitor let elapsed: f64 = m.elapsed_cycles() as f64; @@ -230,7 +230,7 @@ impl ProcessTiming { } /// The geometry of a single data point -#[allow(missing_docs)] +#[expect(missing_docs)] #[derive(Debug, Default, Clone)] pub struct ItemGeometry { pub pending: u64, @@ -251,7 +251,7 @@ impl ItemGeometry { } /// The context for a single client tracked in this [`TuiMonitor`] -#[allow(missing_docs)] +#[expect(missing_docs)] #[derive(Debug, Default, Clone)] pub struct ClientTuiContext { pub corpus: u64, @@ -322,7 +322,7 @@ impl ClientTuiContext { } /// The [`TuiContext`] for this [`TuiMonitor`] -#[allow(missing_docs)] +#[expect(missing_docs)] #[derive(Debug, Clone)] pub struct TuiContext { pub graphs: Vec, @@ -393,7 +393,7 @@ pub struct TuiMonitor { } impl From for TuiMonitor { - #[allow(deprecated)] + #[expect(deprecated)] fn from(builder: TuiMonitorConfig) -> Self { Self::with_time( TuiUi::with_version(builder.title, builder.version, builder.enhanced_graphics), @@ -427,7 +427,7 @@ impl Monitor for TuiMonitor { self.start_time = time; } - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn display(&mut self, event_msg: &str, sender_id: ClientId) { let cur_time = current_time(); @@ -523,7 +523,7 @@ impl TuiMonitor { note = "Please use TuiMonitor::builder() instead of creating TuiUi directly." )] #[must_use] - #[allow(deprecated)] + #[expect(deprecated)] pub fn new(tui_ui: TuiUi) -> Self { Self::with_time(tui_ui, current_time()) } diff --git a/libafl/src/monitors/tui/ui.rs b/libafl/src/monitors/tui/ui.rs index e4c07c9116..e209909f40 100644 --- a/libafl/src/monitors/tui/ui.rs +++ b/libafl/src/monitors/tui/ui.rs @@ -129,7 +129,7 @@ impl TuiUi { } } - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn draw_overall_ui(&mut self, f: &mut Frame, app: &Arc>, area: Rect) { let top_layout = Layout::default() .direction(Direction::Vertical) @@ -254,7 +254,7 @@ impl TuiUi { )) .borders(Borders::ALL); - #[allow(unused_mut)] + #[allow(unused_mut)] // cfg dependent let mut client_area = client_block.inner(area); f.render_widget(client_block, area); @@ -292,7 +292,7 @@ impl TuiUi { self.draw_client_results_text(f, app, right_bottom_layout); } - #[allow(clippy::too_many_lines, clippy::cast_precision_loss)] + #[expect(clippy::too_many_lines, clippy::cast_precision_loss)] fn draw_time_chart( &mut self, title: &str, @@ -776,7 +776,7 @@ impl TuiUi { .widths([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]); f.render_widget(table, area); } - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] fn draw_logs(&mut self, f: &mut Frame, app: &Arc>, area: Rect) { let app = app.read().unwrap(); let logs: Vec = app diff --git a/libafl/src/mutators/gramatron.rs b/libafl/src/mutators/gramatron.rs index 987a81f210..605c0f2358 100644 --- a/libafl/src/mutators/gramatron.rs +++ b/libafl/src/mutators/gramatron.rs @@ -83,7 +83,7 @@ where #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct GramatronIdxMapMetadata { /// The map containing a vec for each terminal @@ -95,7 +95,6 @@ libafl_bolts::impl_serdeany!(GramatronIdxMapMetadata); impl GramatronIdxMapMetadata { /// Creates a new [`struct@GramatronIdxMapMetadata`]. #[must_use] - #[allow(clippy::or_fun_call)] pub fn new(input: &GramatronInput) -> Self { let mut map = HashMap::default(); for i in 0..input.terminals().len() { @@ -226,12 +225,11 @@ where return Ok(MutationResult::Skipped); }; - #[allow(clippy::cast_sign_loss, clippy::pedantic)] - let mut first = state.rand_mut().below(minus_one) as i64; - #[allow(clippy::cast_sign_loss, clippy::pedantic)] - let mut second = state - .rand_mut() - .between(first as usize + 1, chosen_nums - 1) as i64; + let first = state.rand_mut().below(minus_one); + let second = state.rand_mut().between(first + 1, chosen_nums - 1); + + let mut first: isize = first.try_into().unwrap(); + let mut second: isize = second.try_into().unwrap(); let mut idx_1 = 0; let mut idx_2 = 0; diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index f3875c7b43..22dec0d64f 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -77,7 +77,7 @@ impl From for MutationId { } impl From for MutationId { - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn from(value: i32) -> Self { debug_assert!(value >= 0); MutationId(value as usize) diff --git a/libafl/src/mutators/mopt_mutator.rs b/libafl/src/mutators/mopt_mutator.rs index ae90267358..c3d0a827a9 100644 --- a/libafl/src/mutators/mopt_mutator.rs +++ b/libafl/src/mutators/mopt_mutator.rs @@ -29,7 +29,7 @@ use crate::{ #[derive(Serialize, Deserialize, Clone)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct MOpt { /// Random number generator @@ -189,7 +189,6 @@ impl MOpt { } /// initialize pso - #[allow(clippy::cast_precision_loss)] pub fn pso_initialize(&mut self) -> Result<(), Error> { if self.g_now > self.g_max { self.g_now = 0.0; @@ -245,7 +244,7 @@ impl MOpt { /// Update the `PSO` algorithm parameters /// See - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] pub fn pso_update(&mut self) -> Result<(), Error> { self.g_now += 1.0; if self.g_now > self.g_max { @@ -311,7 +310,6 @@ impl MOpt { /// This function is used to decide the operator that we want to apply next /// see - #[allow(clippy::cast_precision_loss)] pub fn select_algorithm(&mut self) -> Result { let mut res = 0; let mut sentry = 0; @@ -381,7 +379,7 @@ where self.scheduled_mutate(state, input) } - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] fn post_exec(&mut self, state: &mut S, _new_corpus_id: Option) -> Result<(), Error> { let before = self.finds_before; let after = state.corpus().count() + state.solutions().count(); @@ -430,7 +428,6 @@ where } } - #[allow(clippy::cast_lossless)] if mopt.pilot_time > mopt.period_pilot { let new_finds = mopt.total_finds - mopt.finds_until_last_swarm; let f = (new_finds as f64) / ((mopt.pilot_time as f64) / (PERIOD_PILOT_COEF)); diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 6cf41e1b37..e9f729a0d9 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -340,7 +340,7 @@ macro_rules! add_mutator_impl { #[derive(Default, Debug)] pub struct $name; - #[allow(trivial_numeric_casts)] + #[allow(trivial_numeric_casts)] // only for some calls of the macro impl Mutator for $name where S: HasRand, @@ -413,7 +413,7 @@ macro_rules! interesting_mutator_impl { S: HasRand, I: HasMutatorBytes, { - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { if input.bytes().len() < size_of::<$size>() { Ok(MutationResult::Skipped) @@ -882,7 +882,7 @@ pub struct BytesSwapMutator { tmp_buf: Vec, } -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] impl Mutator for BytesSwapMutator where S: HasRand, @@ -1475,7 +1475,6 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { let mut first_diff: i64 = -1; let mut last_diff: i64 = -1; for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() { - #[allow(clippy::cast_possible_wrap)] if this_el != other_el { if first_diff < 0 { first_diff = i64::try_from(i).unwrap(); @@ -1497,7 +1496,7 @@ where ::Input: HasMutatorBytes, I: HasMutatorBytes, { - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut()); // We don't want to use the testcase we're already using for splicing diff --git a/libafl/src/mutators/numeric.rs b/libafl/src/mutators/numeric.rs index 748fd64faf..47b1513a88 100644 --- a/libafl/src/mutators/numeric.rs +++ b/libafl/src/mutators/numeric.rs @@ -150,7 +150,7 @@ macro_rules! impl_numeric_cast_randomize { } #[inline] - #[allow(trivial_numeric_casts, clippy::cast_possible_wrap)] + #[allow(trivial_numeric_casts, clippy::cast_possible_wrap)] // only for some macro calls fn randomize(&mut self, rand: &mut R) { *self = rand.next() as $t; } @@ -191,7 +191,7 @@ macro_rules! impl_numeric_128_bits_randomize { } #[inline] - #[allow(trivial_numeric_casts, clippy::cast_possible_wrap)] + #[allow(trivial_numeric_casts, clippy::cast_possible_wrap)] // only for some macro calls fn randomize(&mut self, rand: &mut R) { *self = (u128::from(rand.next()) << 64 | u128::from(rand.next())) as $t; } diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index dc3d76a02e..79c6cfd3fd 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -30,7 +30,7 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct LogMutationMetadata { /// A list of logs diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 00c8a0975f..5d5d3c8e12 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -36,7 +36,7 @@ use crate::{ }; /// A state metadata holding a list of tokens -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Tokens { // We keep a vec and a set, set for faster deduplication, vec for access @@ -145,7 +145,7 @@ impl Tokens { /// Adds a token to a dictionary, checking it is not a duplicate /// Returns `false` if the token was already present and did not get added. - #[allow(clippy::ptr_arg)] + #[expect(clippy::ptr_arg)] pub fn add_token(&mut self, token: &Vec) -> bool { if !self.tokens_set.insert(token.clone()) { return false; @@ -437,7 +437,7 @@ where S: HasMetadata + HasRand + HasMaxSize, I: HasMutatorBytes, { - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let size = input.bytes().len(); let Some(size) = NonZero::new(size) else { @@ -638,7 +638,7 @@ where S: HasMetadata + HasRand + HasMaxSize, I: HasMutatorBytes, { - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let Some(size) = NonZero::new(input.bytes().len()) else { return Ok(MutationResult::Skipped); @@ -847,12 +847,13 @@ impl AFLppRedQueen { } /// Cmplog Pattern Matching - #[allow(clippy::cast_sign_loss)] - #[allow(clippy::too_many_arguments)] - #[allow(clippy::too_many_lines)] - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::if_not_else)] - #[allow(clippy::cast_precision_loss)] + #[expect( + clippy::cast_sign_loss, + clippy::too_many_arguments, + clippy::too_many_lines, + clippy::cast_possible_wrap, + clippy::cast_precision_loss + )] pub fn cmp_extend_encoding( &self, pattern: u64, @@ -1244,7 +1245,7 @@ impl AFLppRedQueen { } /// rtn part from AFL++ - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn rtn_extend_encoding( &self, pattern: &[u8], @@ -1307,8 +1308,7 @@ where S: HasMetadata + HasRand + HasMaxSize + HasCorpus + HasCurrentCorpusId, I: HasMutatorBytes + From>, { - #[allow(clippy::needless_range_loop)] - #[allow(clippy::too_many_lines)] + #[expect(clippy::needless_range_loop, clippy::too_many_lines)] fn multi_mutate( &mut self, state: &mut S, @@ -1932,7 +1932,7 @@ impl AFLppRedQueen { } } - #[allow(clippy::needless_range_loop)] + #[expect(clippy::needless_range_loop)] fn try_add_autotokens(tokens: &mut Tokens, b: &[u8], shape: usize) { let mut cons_ff = 0; let mut cons_0 = 0; diff --git a/libafl/src/mutators/tuneable.rs b/libafl/src/mutators/tuneable.rs index 29b4647a10..c03e35e89e 100644 --- a/libafl/src/mutators/tuneable.rs +++ b/libafl/src/mutators/tuneable.rs @@ -25,7 +25,7 @@ use crate::{ #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct TuneableScheduledMutatorMetadata { /// The offsets of mutators to run, in order. Clear to fall back to random, @@ -137,7 +137,6 @@ where } else { // We will sample using the mutation probabilities. // Doing this outside of the original if branch to make the borrow checker happy. - #[allow(clippy::cast_precision_loss)] let coin = state.rand_mut().next_float() as f32; let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap(); @@ -156,7 +155,6 @@ where // Assumption: we can not reach this code path without previously adding this metadatum. let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap(); - #[allow(clippy::cast_possible_truncation)] if !metadata.mutation_ids.is_empty() { // using pre-set ids. let ret = metadata.mutation_ids[metadata.next_id.0]; @@ -174,7 +172,6 @@ where if !metadata.mutation_probabilities_cumulative.is_empty() { // We will sample using the mutation probabilities. // Doing this outside of the original if branch to make the borrow checker happy. - #[allow(clippy::cast_precision_loss)] let coin = state.rand_mut().next_float() as f32; let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap(); diff --git a/libafl/src/mutators/unicode/mod.rs b/libafl/src/mutators/unicode/mod.rs index d73e5fd58a..c719377736 100644 --- a/libafl/src/mutators/unicode/mod.rs +++ b/libafl/src/mutators/unicode/mod.rs @@ -24,9 +24,7 @@ use crate::{ }; /// Unicode category data, as used by string analysis and mutators. -#[allow(unused)] -#[allow(missing_docs)] -#[allow(clippy::redundant_static_lifetimes)] +#[expect(missing_docs, clippy::redundant_static_lifetimes)] pub mod unicode_categories; /// Input which contains the context necessary to perform unicode mutations diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index de35f6e1f3..58fb3dd738 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -88,7 +88,7 @@ impl CmpValues { #[derive(Debug, Default, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct CmpValuesMetadata { /// A `list` of values. @@ -262,7 +262,6 @@ where fn post_exec(&mut self, state: &mut S, _input: &I, _exit_kind: &ExitKind) -> Result<(), Error> { if self.add_meta { - #[allow(clippy::option_if_let_else)] // we can't mutate state in a closure let meta = state.metadata_or_insert_with(CmpValuesMetadata::new); meta.add_from(self.usable_count(), self.cmp_map_mut()); @@ -359,7 +358,7 @@ struct cmp_map { #[derive(Debug, Default, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct AFLppCmpValuesMetadata { /// The first map of `AFLppCmpLogVals` retrieved by running the un-mutated input diff --git a/libafl/src/observers/concolic/metadata.rs b/libafl/src/observers/concolic/metadata.rs index cb9d34a795..624baf66e6 100644 --- a/libafl/src/observers/concolic/metadata.rs +++ b/libafl/src/observers/concolic/metadata.rs @@ -6,7 +6,7 @@ use crate::observers::concolic::{serialization_format::MessageFileReader, SymExp /// A metadata holding a buffer of a concolic trace. #[derive(Default, Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct ConcolicMetadata { /// Constraints data buffer: Vec, diff --git a/libafl/src/observers/concolic/mod.rs b/libafl/src/observers/concolic/mod.rs index 9031b0f8aa..d4edf13ddc 100644 --- a/libafl/src/observers/concolic/mod.rs +++ b/libafl/src/observers/concolic/mod.rs @@ -57,8 +57,8 @@ impl From for Location { /// `SymExpr` represents a message in the serialization format. /// The messages in the format are a perfect mirror of the methods that are called on the runtime during execution. #[cfg(feature = "std")] -#[derive(Serialize, Deserialize, Debug, PartialEq)] #[allow(missing_docs)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub enum SymExpr { InputByte { offset: usize, diff --git a/libafl/src/observers/concolic/serialization_format.rs b/libafl/src/observers/concolic/serialization_format.rs index 72735bb702..9c7bcba2ad 100644 --- a/libafl/src/observers/concolic/serialization_format.rs +++ b/libafl/src/observers/concolic/serialization_format.rs @@ -109,7 +109,7 @@ impl MessageFileReader { /// This transforms the given message from it's serialized form into its in-memory form, making relative references /// absolute and counting the `SymExprRef`s. - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn transform_message(&mut self, message: &mut SymExpr) -> SymExprRef { let ret = self.current_id; match message { @@ -283,7 +283,7 @@ impl MessageFileWriter { /// Writes a message to the stream and returns the [`SymExprRef`] that should be used to refer back to this message. /// May error when the underlying `Write` errors or when there is a serialization error. - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub fn write_message(&mut self, mut message: SymExpr) -> Result { let current_id = self.id_counter; match &mut message { diff --git a/libafl/src/observers/list.rs b/libafl/src/observers/list.rs index 752ab23f12..125e7db064 100644 --- a/libafl/src/observers/list.rs +++ b/libafl/src/observers/list.rs @@ -9,7 +9,6 @@ use crate::observers::Observer; /// A simple observer with a list of things. #[derive(Serialize, Deserialize, Debug)] #[serde(bound = "T: Serialize + for<'a> Deserialize<'a>")] -#[allow(clippy::unsafe_derive_deserialize)] pub struct ListObserver { name: Cow<'static, str>, /// The list diff --git a/libafl/src/observers/map/const_map.rs b/libafl/src/observers/map/const_map.rs index d383bc0cc3..ba2fe4ccce 100644 --- a/libafl/src/observers/map/const_map.rs +++ b/libafl/src/observers/map/const_map.rs @@ -20,7 +20,7 @@ use crate::{ /// Use a const size to speedup `Feedback::is_interesting` when the user can /// know the size of the map at compile time. #[derive(Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct ConstMapObserver<'a, T, const N: usize> { map: OwnedMutSizedSlice<'a, T, N>, initial: T, diff --git a/libafl/src/observers/map/hitcount_map.rs b/libafl/src/observers/map/hitcount_map.rs index 56a6dbfc6e..1e369b0882 100644 --- a/libafl/src/observers/map/hitcount_map.rs +++ b/libafl/src/observers/map/hitcount_map.rs @@ -95,7 +95,7 @@ where } #[inline] - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> { let mut map = self.as_slice_mut(); let mut len = map.len(); @@ -130,7 +130,7 @@ where let count_class_lookup_16 = &raw mut COUNT_CLASS_LOOKUP_16; // 2022-07: Adding `enumerate` here increases execution speed/register allocation on x86_64. - #[allow(clippy::unused_enumerate_index)] + #[expect(clippy::unused_enumerate_index)] for (_i, item) in map16[0..cnt].iter_mut().enumerate() { unsafe { let count_class_lookup_16 = &mut *count_class_lookup_16; @@ -357,7 +357,6 @@ where } #[inline] - #[allow(clippy::cast_ptr_alignment)] fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> { for mut item in self.as_iter_mut() { *item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) }; diff --git a/libafl/src/observers/map/mod.rs b/libafl/src/observers/map/mod.rs index d73dedfbb3..3d85a867bf 100644 --- a/libafl/src/observers/map/mod.rs +++ b/libafl/src/observers/map/mod.rs @@ -437,7 +437,7 @@ where /// that will get updated by the target. /// A well-known example is the AFL-Style coverage map. #[derive(Clone, Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct StdMapObserver<'a, T, const DIFFERENTIAL: bool> { map: OwnedMutSlice<'a, T>, initial: T, diff --git a/libafl/src/observers/map/multi_map.rs b/libafl/src/observers/map/multi_map.rs index 7c0bf533b9..ce7a04f786 100644 --- a/libafl/src/observers/map/multi_map.rs +++ b/libafl/src/observers/map/multi_map.rs @@ -22,7 +22,6 @@ use crate::{ /// The Multi Map Observer merge different maps into one observer #[derive(Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] pub struct MultiMapObserver<'a, T, const DIFFERENTIAL: bool> { maps: Vec>, intervals: IntervalTree, diff --git a/libafl/src/observers/map/owned_map.rs b/libafl/src/observers/map/owned_map.rs index 66d0fc7e8b..4ade2a948f 100644 --- a/libafl/src/observers/map/owned_map.rs +++ b/libafl/src/observers/map/owned_map.rs @@ -18,7 +18,6 @@ use crate::{ /// Exact copy of `StdMapObserver` that owns its map #[derive(Serialize, Deserialize, Debug, Clone)] -#[allow(clippy::unsafe_derive_deserialize)] pub struct OwnedMapObserver { map: Vec, initial: T, diff --git a/libafl/src/observers/map/variable_map.rs b/libafl/src/observers/map/variable_map.rs index ec1a5feda3..d98cca17dc 100644 --- a/libafl/src/observers/map/variable_map.rs +++ b/libafl/src/observers/map/variable_map.rs @@ -21,7 +21,7 @@ use crate::{ /// Overlooking a variable bitmap #[derive(Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct VariableMapObserver<'a, T> { map: OwnedMutSlice<'a, T>, size: OwnedMutPtr, diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index d312b1e693..6cd5c103ab 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -201,7 +201,7 @@ pub trait ObserverWithHashField { /// cleanup in `Observer::post_exec`. For individual executions, use /// `DifferentialObserver::{pre,post}_observe_{first,second}` as necessary for first and second, /// respectively. -#[allow(unused_variables)] +#[expect(unused_variables)] pub trait DifferentialObserver: Observer { /// Perform an operation with the first set of observers before they are `pre_exec`'d. fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { @@ -309,7 +309,6 @@ mod instant_serializer { use serde::{Deserialize, Deserializer, Serialize, Serializer}; - #[allow(clippy::trivially_copy_pass_by_ref)] pub fn serialize(instant: &Instant, serializer: S) -> Result where S: Serializer, diff --git a/libafl/src/observers/stacktrace.rs b/libafl/src/observers/stacktrace.rs index 9c6b13958e..c379db4bce 100644 --- a/libafl/src/observers/stacktrace.rs +++ b/libafl/src/observers/stacktrace.rs @@ -17,7 +17,7 @@ use std::{ use backtrace::Backtrace; use libafl_bolts::{ownedref::OwnedRefMut, Named}; -#[allow(unused_imports)] +#[allow(unused_imports)] // expect breaks here for some reason #[cfg(feature = "casr")] use libcasr::{ asan::AsanStacktrace, @@ -111,7 +111,6 @@ pub enum HarnessType { } /// An observer looking at the backtrace after the harness crashes -#[allow(clippy::unsafe_derive_deserialize)] #[derive(Serialize, Deserialize, Debug)] pub struct BacktraceObserver<'a> { observer_name: Cow<'static, str>, diff --git a/libafl/src/observers/value.rs b/libafl/src/observers/value.rs index 47fcde05a2..37d0a35960 100644 --- a/libafl/src/observers/value.rs +++ b/libafl/src/observers/value.rs @@ -23,7 +23,7 @@ use crate::{ /// The intent is that the value is something with interior mutability which the target could write to even though this /// observer has a reference to it. Use [`RefCellValueObserver`] if using a [`RefCell`] around the value. #[derive(Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct ValueObserver<'a, T> { /// The name of this observer. name: Cow<'static, str>, @@ -83,7 +83,7 @@ impl ObserverWithHashField for ValueObserver<'_, T> { /// A simple observer with a single [`RefCell`]'d value. #[derive(Serialize, Deserialize, Debug)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub struct RefCellValueObserver<'a, T> { /// The name of this observer. name: Cow<'static, str>, diff --git a/libafl/src/schedulers/accounting.rs b/libafl/src/schedulers/accounting.rs index 13c167cd99..23bb60d2c0 100644 --- a/libafl/src/schedulers/accounting.rs +++ b/libafl/src/schedulers/accounting.rs @@ -26,7 +26,7 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct AccountingIndexesMetadata { /// The list of indexes. @@ -77,7 +77,7 @@ impl AccountingIndexesMetadata { #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct TopAccountingMetadata { /// map index -> corpus index @@ -178,8 +178,7 @@ where O: CanTrack, { /// Update the `Corpus` score - #[allow(clippy::unused_self)] - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] pub fn update_accounting_score(&self, state: &mut S, id: CorpusId) -> Result<(), Error> where S: HasCorpus + HasMetadata, @@ -267,7 +266,6 @@ where } /// Cull the `Corpus` - #[allow(clippy::unused_self)] pub fn accounting_cull(&self, state: &S) -> Result<(), Error> where S: HasCorpus + HasMetadata, diff --git a/libafl/src/schedulers/minimizer.rs b/libafl/src/schedulers/minimizer.rs index bbee468aa8..17f6dcc307 100644 --- a/libafl/src/schedulers/minimizer.rs +++ b/libafl/src/schedulers/minimizer.rs @@ -26,7 +26,7 @@ pub const DEFAULT_SKIP_NON_FAVORED_PROB: f64 = 0.95; #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct IsFavoredMetadata {} @@ -36,7 +36,7 @@ libafl_bolts::impl_serdeany!(IsFavoredMetadata); #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct TopRatedsMetadata { /// map index -> corpus index @@ -248,8 +248,7 @@ where M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, { /// Update the [`Corpus`] score using the [`MinimizerScheduler`] - #[allow(clippy::unused_self)] - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] pub fn update_score(&self, state: &mut S, id: CorpusId) -> Result<(), Error> where F: TestcaseScore, @@ -327,7 +326,6 @@ where } /// Cull the [`Corpus`] using the [`MinimizerScheduler`] - #[allow(clippy::unused_self)] pub fn cull(&self, state: &S) -> Result<(), Error> where S: HasCorpus + HasMetadata, diff --git a/libafl/src/schedulers/powersched.rs b/libafl/src/schedulers/powersched.rs index 8da02f38c2..df9cf8194f 100644 --- a/libafl/src/schedulers/powersched.rs +++ b/libafl/src/schedulers/powersched.rs @@ -29,7 +29,7 @@ libafl_bolts::impl_serdeany!(SchedulerMetadata); #[derive(Serialize, Deserialize, Clone, Debug)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct SchedulerMetadata { /// Powerschedule strategy diff --git a/libafl/src/schedulers/probabilistic_sampling.rs b/libafl/src/schedulers/probabilistic_sampling.rs index ccd6b0e6c3..a7772a232f 100644 --- a/libafl/src/schedulers/probabilistic_sampling.rs +++ b/libafl/src/schedulers/probabilistic_sampling.rs @@ -25,7 +25,7 @@ pub struct ProbabilitySamplingScheduler { #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct ProbabilityMetadata { /// corpus index -> probability @@ -63,8 +63,6 @@ impl ProbabilitySamplingScheduler { } /// Calculate the score and store in `ProbabilityMetadata` - #[allow(clippy::cast_precision_loss)] - #[allow(clippy::unused_self)] pub fn store_probability(&self, state: &mut S, id: CorpusId) -> Result<(), Error> where F: TestcaseScore, @@ -144,7 +142,6 @@ where } /// Gets the next entry - #[allow(clippy::cast_precision_loss)] fn next(&mut self, state: &mut S) -> Result { if state.corpus().count() == 0 { Err(Error::empty(String::from( diff --git a/libafl/src/schedulers/testcase_score.rs b/libafl/src/schedulers/testcase_score.rs index d406bc4233..b6a2e77d30 100644 --- a/libafl/src/schedulers/testcase_score.rs +++ b/libafl/src/schedulers/testcase_score.rs @@ -34,7 +34,7 @@ where S: HasCorpus, ::Input: HasLen, { - #[allow(clippy::cast_precision_loss, clippy::cast_lossless)] + #[expect(clippy::cast_precision_loss)] fn compute( state: &S, entry: &mut Testcase<::Input>, @@ -60,12 +60,7 @@ where S: HasCorpus + HasMetadata, { /// Compute the `power` we assign to each corpus entry - #[allow( - clippy::cast_precision_loss, - clippy::too_many_lines, - clippy::cast_sign_loss, - clippy::cast_lossless - )] + #[expect(clippy::cast_precision_loss, clippy::too_many_lines)] fn compute( state: &S, entry: &mut Testcase<::Input>, @@ -282,7 +277,7 @@ where S: HasCorpus + HasMetadata, { /// Compute the `weight` used in weighted corpus entry selection algo - #[allow(clippy::cast_precision_loss, clippy::cast_lossless)] + #[expect(clippy::cast_precision_loss)] fn compute( state: &S, entry: &mut Testcase<::Input>, diff --git a/libafl/src/schedulers/tuneable.rs b/libafl/src/schedulers/tuneable.rs index b677e71896..7505cc1ccf 100644 --- a/libafl/src/schedulers/tuneable.rs +++ b/libafl/src/schedulers/tuneable.rs @@ -18,7 +18,7 @@ use crate::{ #[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny struct TuneableSchedulerMetadata { next: Option, diff --git a/libafl/src/schedulers/weighted.rs b/libafl/src/schedulers/weighted.rs index 6ee0162018..38d14e9b60 100644 --- a/libafl/src/schedulers/weighted.rs +++ b/libafl/src/schedulers/weighted.rs @@ -31,7 +31,7 @@ use crate::{ /// The Metadata for `WeightedScheduler` #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny #[derive(Serialize, Deserialize, Clone, Debug)] pub struct WeightedScheduleMetadata { @@ -156,12 +156,7 @@ where } /// Create a new alias table when the fuzzer finds a new corpus entry - #[allow( - clippy::unused_self, - clippy::similar_names, - clippy::cast_precision_loss, - clippy::cast_lossless - )] + #[expect(clippy::cast_precision_loss)] pub fn create_alias_table(&self, state: &mut S) -> Result<(), Error> where F: TestcaseScore, @@ -336,7 +331,6 @@ where on_evaluation_metadata_default(self, state, observers) } - #[allow(clippy::similar_names, clippy::cast_precision_loss)] fn next(&mut self, state: &mut S) -> Result { if self.table_invalidated { self.create_alias_table(state)?; diff --git a/libafl/src/stages/afl_stats.rs b/libafl/src/stages/afl_stats.rs index ece9ba1b73..78f78bc739 100644 --- a/libafl/src/stages/afl_stats.rs +++ b/libafl/src/stages/afl_stats.rs @@ -254,7 +254,7 @@ where C: AsRef + Named, Z::Scheduler: HasQueueCycles, { - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn perform( &mut self, fuzzer: &mut Z, @@ -321,7 +321,6 @@ where } else { 0 }; - #[allow(clippy::similar_names)] let stats = AFLFuzzerStats { start_time: self.start_time, last_update: self.last_report_time.as_secs(), @@ -356,7 +355,7 @@ where time_wo_finds: (current_time() - self.last_find).as_secs(), corpus_variable: 0, stability: self.calculate_stability(unstable_entries_in_map, filled_entries_in_map), - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] bitmap_cvg: (filled_entries_in_map as f64 / map_size as f64) * 100.0, saved_crashes: self.saved_crashes, saved_hangs: self.saved_hangs, @@ -532,8 +531,8 @@ where } } - #[allow(clippy::cast_precision_loss)] - #[allow(clippy::unused_self)] + #[expect(clippy::cast_precision_loss)] + #[expect(clippy::unused_self)] fn calculate_stability(&self, unstable_entries: usize, filled_entries: u64) -> f64 { ((filled_entries as f64 - unstable_entries as f64) / filled_entries as f64) * 100.0 } diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index 3cdbc2fd47..50c07aeb09 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -31,7 +31,7 @@ use crate::{ /// Formula is same as AFL++: number of unstable entries divided by the number of filled entries. #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny #[derive(Serialize, Deserialize, Clone, Debug)] pub struct UnstableEntriesMetadata { @@ -106,11 +106,7 @@ where ::Input: Input, { #[inline] - #[allow( - clippy::let_and_return, - clippy::too_many_lines, - clippy::cast_precision_loss - )] + #[expect(clippy::too_many_lines, clippy::cast_precision_loss)] fn perform( &mut self, fuzzer: &mut Z, diff --git a/libafl/src/stages/colorization.rs b/libafl/src/stages/colorization.rs index 732bbce1c2..5b97301439 100644 --- a/libafl/src/stages/colorization.rs +++ b/libafl/src/stages/colorization.rs @@ -65,7 +65,6 @@ pub const COLORIZATION_STAGE_NAME: &str = "colorization"; pub struct ColorizationStage { map_observer_handle: Handle, name: Cow<'static, str>, - #[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, O, E, S, Z)>, } @@ -94,7 +93,6 @@ where C: AsRef + Named, { #[inline] - #[allow(clippy::let_and_return)] fn perform( &mut self, fuzzer: &mut Z, @@ -124,7 +122,7 @@ where #[derive(Debug, Serialize, Deserialize)] #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny pub struct TaintMetadata { input_vec: Vec, @@ -175,7 +173,6 @@ where ::Input: HasMutatorBytes + Clone, { #[inline] - #[allow(clippy::let_and_return)] fn colorize( fuzzer: &mut Z, executor: &mut E, @@ -346,7 +343,7 @@ where } /// Replace bytes with random values but following certain rules - #[allow(clippy::needless_range_loop)] + #[expect(clippy::needless_range_loop)] fn type_replace(bytes: &mut [u8], state: &mut S) { let len = bytes.len(); for idx in 0..len { diff --git a/libafl/src/stages/concolic.rs b/libafl/src/stages/concolic.rs index d4b6641f6a..2f2ebd0876 100644 --- a/libafl/src/stages/concolic.rs +++ b/libafl/src/stages/concolic.rs @@ -111,7 +111,7 @@ impl<'a, EM, TE, S, Z> ConcolicTracingStage<'a, EM, TE, S, Z> { } #[cfg(feature = "concolic_mutation")] -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn generate_mutations(iter: impl Iterator) -> Vec> { use hashbrown::HashMap; use z3::{ diff --git a/libafl/src/stages/dump.rs b/libafl/src/stages/dump.rs index ca9f133cba..32d8365d88 100644 --- a/libafl/src/stages/dump.rs +++ b/libafl/src/stages/dump.rs @@ -23,7 +23,7 @@ use crate::{ /// Metadata used to store information about disk dump indexes for names #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny #[derive(Default, Serialize, Deserialize, Clone, Debug)] pub struct DumpToDiskMetadata { @@ -98,7 +98,7 @@ where } /// Default `generate_filename` function. - #[allow(clippy::trivially_copy_pass_by_ref)] + #[expect(clippy::trivially_copy_pass_by_ref)] fn generate_filename( testcase: &Testcase<::Input>, id: &CorpusId, diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index 123c6162ac..00e1fbacf3 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -51,7 +51,6 @@ pub static GENERALIZATION_STAGE_NAME: &str = "generalization"; pub struct GeneralizationStage { name: Cow<'static, str>, map_observer_handle: Handle, - #[allow(clippy::type_complexity)] phantom: PhantomData<(EM, O, OT, S, Z)>, } @@ -78,7 +77,7 @@ where EM: UsesState, { #[inline] - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn perform( &mut self, fuzzer: &mut Z, @@ -405,7 +404,7 @@ where payload.retain(|&x| !(x.is_none() & core::mem::replace(&mut previous, x.is_none()))); } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] fn find_gaps( &self, fuzzer: &mut Z, @@ -443,7 +442,7 @@ where Ok(()) } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] fn find_gaps_in_closures( &self, fuzzer: &mut Z, diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 3e66848e9b..da01ae7886 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -180,7 +180,6 @@ where Some(idx) if idx == StageId(Self::LEN) => { // perform the stage, but don't set it - #[allow(clippy::similar_names)] let stage = &mut self.0; stage.perform_restartable(fuzzer, executor, state, manager)?; @@ -194,7 +193,6 @@ where _ => { state.set_current_stage_id(StageId(Self::LEN))?; - #[allow(clippy::similar_names)] let stage = &mut self.0; stage.perform_restartable(fuzzer, executor, state, manager)?; @@ -558,7 +556,7 @@ mod test { impl_serdeany!(TestProgress); impl TestProgress { - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] fn should_restart(state: &mut S, _stage: &ST) -> Result where S: HasMetadata, @@ -630,7 +628,6 @@ mod test { } } - #[allow(clippy::similar_names)] let mut state = StdState::nop()?; let stage = StageWithOneTry; diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index b5347eccd2..61ac616eee 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -27,7 +27,7 @@ use crate::{ // TODO multi mutators stage /// Action performed after the un-transformed input is executed (e.g., updating metadata) -#[allow(unused_variables)] +#[expect(unused_variables)] pub trait MutatedTransformPost: Sized { /// Perform any post-execution steps necessary for the transformed input (e.g., updating metadata) #[inline] @@ -108,7 +108,6 @@ pub struct StdMutationalStage { mutator: M, /// The maximum amount of iterations we should do each round max_iterations: NonZeroUsize, - #[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, I, S, Z)>, } @@ -164,7 +163,6 @@ where S::Corpus: Corpus, { #[inline] - #[allow(clippy::let_and_return)] fn perform( &mut self, fuzzer: &mut Z, @@ -244,7 +242,6 @@ where } /// Runs this (mutational) stage for the given testcase - #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... fn perform_mutational( &mut self, fuzzer: &mut Z, @@ -298,7 +295,6 @@ where pub struct MultiMutationalStage { name: Cow<'static, str>, mutator: M, - #[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, I, S, Z)>, } @@ -334,8 +330,6 @@ where } #[inline] - #[allow(clippy::let_and_return)] - #[allow(clippy::cast_possible_wrap)] fn perform( &mut self, fuzzer: &mut Z, @@ -350,7 +344,6 @@ where drop(testcase); let generated = self.mutator.multi_mutate(state, &input, None)?; - // println!("Generated {}", generated.len()); for new_input in generated { // Time is measured directly the `evaluate_input` function let (untransformed, post) = new_input.try_transform_into(state)?; @@ -358,7 +351,6 @@ where self.mutator.multi_post_exec(state, corpus_id)?; post.post_exec(state, corpus_id)?; } - // println!("Found {}", found); Ok(()) } diff --git a/libafl/src/stages/power.rs b/libafl/src/stages/power.rs index abd05b0b01..e3d64def59 100644 --- a/libafl/src/stages/power.rs +++ b/libafl/src/stages/power.rs @@ -39,7 +39,6 @@ pub struct PowerMutationalStage { name: Cow<'static, str>, /// The mutators we use mutator: M, - #[allow(clippy::type_complexity)] phantom: PhantomData<(E, F, EM, I, S, Z)>, } @@ -68,7 +67,7 @@ where } /// Gets the number of iterations as a random number - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn iterations(&self, state: &mut S) -> Result { // Update handicap let mut testcase = state.current_testcase_mut()?; @@ -98,7 +97,7 @@ where ::Input: Input, { #[inline] - #[allow(clippy::let_and_return)] + #[expect(clippy::let_and_return)] fn perform( &mut self, fuzzer: &mut Z, @@ -155,7 +154,6 @@ where } /// Runs this (mutational) stage for the given testcase - #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... fn perform_mutational( &mut self, fuzzer: &mut Z, diff --git a/libafl/src/stages/push/mod.rs b/libafl/src/stages/push/mod.rs index b2caf3c2ad..eba9d9797e 100644 --- a/libafl/src/stages/push/mod.rs +++ b/libafl/src/stages/push/mod.rs @@ -70,7 +70,7 @@ pub struct PushStageHelper { /// This gets reset to `false` after one iteration of the stage is done. pub initialized: bool, /// The shared state, keeping track of the corpus and the fuzzer - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub shared_state: Rc>>>, /// If the last iteration failed pub errored: bool, @@ -87,7 +87,7 @@ pub struct PushStageHelper { impl PushStageHelper { /// Create a new [`PushStageHelper`] #[must_use] - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub fn new( shared_state: Rc>>>, exit_kind_ref: Rc>>, @@ -110,7 +110,6 @@ impl PushStageHelper { /// Takes the shared state from this helper, replacing it with `None` #[inline] - #[allow(clippy::type_complexity)] pub fn take_shared_state(&mut self) -> Option> { let shared_state_ref = &mut (*self.shared_state).borrow_mut(); shared_state_ref.take() @@ -207,7 +206,6 @@ pub trait PushStage { } /// Allows us to use a [`PushStage`] as a normal [`Stage`] -#[allow(clippy::type_complexity)] #[derive(Debug)] pub struct PushStageAdapter { name: Cow<'static, str>, diff --git a/libafl/src/stages/push/mutational.rs b/libafl/src/stages/push/mutational.rs index 76d28cfb09..fd0dd57be3 100644 --- a/libafl/src/stages/push/mutational.rs +++ b/libafl/src/stages/push/mutational.rs @@ -63,7 +63,7 @@ where ::Input: Clone + Debug, { /// Gets the number of iterations as a random number - #[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later + #[expect(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later fn iterations(&self, state: &mut S, _corpus_id: CorpusId) -> Result { Ok(1 + state .rand_mut() @@ -232,7 +232,7 @@ where { /// Creates a new default mutational stage #[must_use] - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub fn new( mutator: M, shared_state: Rc< diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index 7f51ed6f13..5d8ecd6c5b 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -27,7 +27,7 @@ pub const SYNC_FROM_DISK_STAGE_NAME: &str = "sync"; /// Metadata used to store information about disk sync time #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny #[derive(Serialize, Deserialize, Debug)] pub struct SyncFromDiskMetadata { @@ -201,7 +201,7 @@ where /// Metadata used to store information about the last sent testcase with `SyncFromBrokerStage` #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny #[derive(Serialize, Deserialize, Debug)] pub struct SyncFromBrokerMetadata { diff --git a/libafl/src/stages/tmin.rs b/libafl/src/stages/tmin.rs index ff449b19fa..2e3a2d4490 100644 --- a/libafl/src/stages/tmin.rs +++ b/libafl/src/stages/tmin.rs @@ -53,7 +53,6 @@ pub struct StdTMinMutationalStage { runs: usize, /// The progress helper for this stage, keeping track of resumes after timeouts/crashes restart_helper: ExecutionCountRestartHelper, - #[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, F, S, Z)>, } @@ -166,7 +165,6 @@ where } /// Runs this (mutational) stage for new objectives - #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... fn perform_minification( &mut self, fuzzer: &mut Z, diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 68f0fdfe76..acb81782c0 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -27,7 +27,6 @@ use crate::{ pub struct TracingStage { name: Cow<'static, str>, tracer_executor: TE, - #[allow(clippy::type_complexity)] phantom: PhantomData<(EM, TE, S, Z)>, } @@ -43,7 +42,7 @@ where + UsesInput::Input>, EM: UsesState, //delete me { - #[allow(rustdoc::broken_intra_doc_links)] + #[expect(rustdoc::broken_intra_doc_links)] /// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your /// own stage and you need to manage [`super::NestedStageRetryCountRestartHelper`] differently /// see [`super::ConcolicTracingStage`]'s implementation as an example of usage. @@ -151,7 +150,6 @@ impl TracingStage { #[derive(Clone, Debug)] pub struct ShadowTracingStage { name: Cow<'static, str>, - #[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, SOT, S, Z)>, } diff --git a/libafl/src/stages/tuneable.rs b/libafl/src/stages/tuneable.rs index 25a2ec82ef..9c3aeab6af 100644 --- a/libafl/src/stages/tuneable.rs +++ b/libafl/src/stages/tuneable.rs @@ -25,7 +25,7 @@ use crate::{ #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) + expect(clippy::unsafe_derive_deserialize) )] // for SerdeAny #[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)] struct TuneableMutationalStageMetadata { @@ -209,7 +209,6 @@ where ::Input: Input, { #[inline] - #[allow(clippy::let_and_return)] fn perform( &mut self, fuzzer: &mut Z, diff --git a/libafl/src/stages/verify_timeouts.rs b/libafl/src/stages/verify_timeouts.rs index 9d62f61b57..74e3e88c16 100644 --- a/libafl/src/stages/verify_timeouts.rs +++ b/libafl/src/stages/verify_timeouts.rs @@ -1,4 +1,4 @@ -#![allow(clippy::too_long_first_doc_paragraph)] +#![expect(clippy::too_long_first_doc_paragraph)] //! Stage that re-runs captured Timeouts with double the timeout to verify //! Note: To capture the timeouts, use in conjunction with `CaptureTimeoutFeedback` //! Note: Will NOT work with in process executors due to the potential for restarts/crashes when diff --git a/libafl_bolts/src/cli.rs b/libafl_bolts/src/cli.rs index 51cc199b76..8c9486ffe6 100644 --- a/libafl_bolts/src/cli.rs +++ b/libafl_bolts/src/cli.rs @@ -122,7 +122,7 @@ pub enum FridaScriptBackend { subcommand_precedence_over_arg(true), args_conflicts_with_subcommands(true) )] -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] pub struct FuzzerOptions { /// Timeout for each target execution (milliseconds) #[arg(short, long, default_value = "1000", value_parser = parse_timeout, help_heading = "Fuzz Options")] diff --git a/libafl_bolts/src/compress.rs b/libafl_bolts/src/compress.rs index 74a9a18327..e4e261ac0a 100644 --- a/libafl_bolts/src/compress.rs +++ b/libafl_bolts/src/compress.rs @@ -61,7 +61,6 @@ impl GzipCompressor { } /// Decompression. - #[allow(clippy::unused_self)] pub fn decompress(&self, buf: &[u8]) -> Result, Error> { let decompressed = decompress_to_vec(buf); diff --git a/libafl_bolts/src/core_affinity.rs b/libafl_bolts/src/core_affinity.rs index e921425e81..dcb4de85c1 100644 --- a/libafl_bolts/src/core_affinity.rs +++ b/libafl_bolts/src/core_affinity.rs @@ -251,7 +251,6 @@ mod linux { use super::CoreId; use crate::Error; - #[allow(trivial_numeric_casts)] pub fn get_core_ids() -> Result, Error> { let full_set = get_affinity_mask()?; let mut core_ids: Vec = Vec::new(); @@ -361,14 +360,14 @@ mod linux { // FIXME: no sense of cpu granularity (yet ?) #[cfg(target_os = "haiku")] -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] #[inline] fn get_core_ids_helper() -> Result, Error> { haiku::get_core_ids() } #[cfg(target_os = "haiku")] -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] #[inline] fn set_for_current_helper(_core_id: CoreId) -> Result<(), Error> { Ok(()) @@ -381,7 +380,7 @@ mod haiku { use crate::core_affinity::{CoreId, Error}; - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] pub fn get_core_ids() -> Result, Error> { Ok((0..(usize::from(available_parallelism()?))) .map(CoreId) @@ -460,18 +459,15 @@ mod windows { } } - #[allow(trivial_numeric_casts)] - #[allow(clippy::cast_ptr_alignment)] - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_ptr_alignment)] pub fn get_num_logical_cpus_ex_windows() -> Option { use std::{ptr, slice}; - #[allow(non_upper_case_globals)] + #[expect(non_upper_case_globals)] const RelationProcessorCore: u32 = 0; #[repr(C)] - #[allow(non_camel_case_types)] - #[allow(dead_code)] + #[allow(non_camel_case_types)] // expect breaks for some reason struct GROUP_AFFINITY { mask: usize, group: u16, @@ -479,8 +475,7 @@ mod windows { } #[repr(C)] - #[allow(non_camel_case_types)] - #[allow(dead_code)] + #[allow(non_camel_case_types)] // expect breaks for some reason struct PROCESSOR_RELATIONSHIP { flags: u8, efficiency_class: u8, @@ -490,8 +485,7 @@ mod windows { } #[repr(C)] - #[allow(non_camel_case_types)] - #[allow(dead_code)] + #[allow(non_camel_case_types)] // expect breaks for some reason struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX { relationship: u32, size: u32, @@ -626,7 +620,6 @@ mod apple { ) -> kern_return_t; } - #[allow(clippy::unnecessary_wraps)] pub fn get_core_ids() -> Result, Error> { Ok((0..(usize::from(available_parallelism()?))) .map(CoreId) @@ -659,7 +652,7 @@ mod apple { } #[cfg(target_arch = "aarch64")] - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] pub fn set_for_current(_core_id: CoreId) -> Result<(), Error> { // This is the best we can do, unlike on intel architecture // the system does not allow to pin a process/thread to specific cpu. @@ -703,7 +696,7 @@ mod netbsd { use super::CoreId; use crate::Error; - #[allow(trivial_numeric_casts)] + #[expect(trivial_numeric_casts)] pub fn get_core_ids() -> Result, Error> { Ok((0..(usize::from(available_parallelism()?))) .map(CoreId) @@ -746,7 +739,7 @@ fn get_core_ids_helper() -> Result, Error> { } #[cfg(target_os = "openbsd")] -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] #[inline] fn set_for_current_helper(_: CoreId) -> Result<(), Error> { Ok(()) // There is no notion of cpu affinity on this platform @@ -760,7 +753,7 @@ mod openbsd { use super::CoreId; use crate::Error; - #[allow(trivial_numeric_casts)] + #[expect(trivial_numeric_casts)] pub fn get_core_ids() -> Result, Error> { Ok((0..(usize::from(available_parallelism()?))) .map(CoreId) @@ -788,7 +781,7 @@ mod solaris { use super::CoreId; use crate::Error; - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] pub fn get_core_ids() -> Result, Error> { Ok((0..(usize::from(available_parallelism()?))) .map(CoreId) diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 79b27e7d05..2a3a68bff5 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -228,7 +228,7 @@ fn display_error_backtrace(f: &mut fmt::Formatter, err: &ErrorBacktrace) -> fmt: write!(f, "\nBacktrace: {err:?}") } #[cfg(not(feature = "errors_backtrace"))] -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] fn display_error_backtrace(_f: &mut fmt::Formatter, _err: &ErrorBacktrace) -> fmt::Result { fmt::Result::Ok(()) } @@ -588,7 +588,6 @@ impl From for Error { #[cfg(feature = "alloc")] impl From for Error { - #[allow(unused_variables)] fn from(err: FromUtf8Error) -> Self { Self::unknown(format!("Could not convert byte / utf-8: {err:?}")) } @@ -596,7 +595,6 @@ impl From for Error { #[cfg(feature = "alloc")] impl From for Error { - #[allow(unused_variables)] fn from(err: Utf8Error) -> Self { Self::unknown(format!("Could not convert byte / utf-8: {err:?}")) } @@ -604,35 +602,34 @@ impl From for Error { #[cfg(feature = "std")] impl From for Error { - #[allow(unused_variables)] fn from(err: VarError) -> Self { Self::empty(format!("Could not get env var: {err:?}")) } } impl From for Error { - #[allow(unused_variables)] + #[allow(unused_variables)] // err is unused without std fn from(err: ParseIntError) -> Self { Self::unknown(format!("Failed to parse Int: {err:?}")) } } impl From for Error { - #[allow(unused_variables)] + #[allow(unused_variables)] // err is unused without std fn from(err: TryFromIntError) -> Self { Self::illegal_state(format!("Expected conversion failed: {err:?}")) } } impl From for Error { - #[allow(unused_variables)] + #[allow(unused_variables)] // err is unused without std fn from(err: TryFromSliceError) -> Self { Self::illegal_argument(format!("Could not convert slice: {err:?}")) } } impl From for Error { - #[allow(unused_variables)] + #[allow(unused_variables)] // err is unused without std fn from(err: SetLoggerError) -> Self { Self::illegal_state(format!("Failed to register logger: {err:?}")) } @@ -640,7 +637,7 @@ impl From for Error { #[cfg(windows)] impl From for Error { - #[allow(unused_variables)] + #[allow(unused_variables)] // err is unused without std fn from(err: windows_result::Error) -> Self { Self::unknown(format!("Windows API error: {err:?}")) } @@ -1100,7 +1097,7 @@ impl log::Log for SimpleFdLogger { /// # Safety /// The function is arguably safe, but it might have undesirable side effects since it closes `stdout` and `stderr`. #[cfg(all(unix, feature = "std"))] -#[allow(unused_qualifications)] +#[expect(unused_qualifications)] pub unsafe fn dup_and_mute_outputs() -> Result<(RawFd, RawFd), Error> { let old_stdout = stdout().as_raw_fd(); let old_stderr = stderr().as_raw_fd(); @@ -1159,7 +1156,7 @@ macro_rules! nonnull_raw_mut { } #[cfg(feature = "python")] -#[allow(missing_docs)] +#[allow(missing_docs)] // expect somehow breaks here pub mod pybind { use pyo3::{pymodule, types::PyModule, Bound, PyResult}; diff --git a/libafl_bolts/src/llmp.rs b/libafl_bolts/src/llmp.rs index 07abd68aa4..614d502557 100644 --- a/libafl_bolts/src/llmp.rs +++ b/libafl_bolts/src/llmp.rs @@ -397,14 +397,14 @@ impl Listener { /// Get sharedmem from a page #[inline] -#[allow(clippy::cast_ptr_alignment)] +#[expect(clippy::cast_ptr_alignment)] unsafe fn shmem2page_mut(afl_shmem: &mut SHM) -> *mut LlmpPage { afl_shmem.as_mut_ptr() as *mut LlmpPage } /// Get sharedmem from a page #[inline] -#[allow(clippy::cast_ptr_alignment)] +#[expect(clippy::cast_ptr_alignment)] unsafe fn shmem2page(afl_shmem: &SHM) -> *const LlmpPage { afl_shmem.as_ptr() as *const LlmpPage } @@ -591,7 +591,7 @@ unsafe fn llmp_next_msg_ptr_checked( /// # Safety /// Will dereference the `last_msg` ptr #[inline] -#[allow(clippy::cast_ptr_alignment)] +#[expect(clippy::cast_ptr_alignment)] unsafe fn llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg { /* DBG("llmp_next_msg_ptr %p %lu + %lu\n", last_msg, last_msg->buf_len_padded, sizeof(llmp_message)); */ (last_msg as *mut u8) @@ -1411,7 +1411,7 @@ where * to consume */ let out = self.alloc_eop()?; - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] let end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*end_of_page_msg).map_size = new_map_shmem.shmem.len(); (*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_array(); @@ -1737,7 +1737,7 @@ where size_of::() ); - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; /* The pageinfo points to the map we're about to unmap. @@ -1808,7 +1808,7 @@ where } /// Returns the next message, tag, buf, if available, else None - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] #[inline] pub fn recv_buf(&mut self) -> Result, Error> { if let Some((sender, tag, _flags, buf)) = self.recv_buf_with_flags()? { @@ -1819,7 +1819,7 @@ where } /// Receive the buffer, also reading the LLMP internal message flags - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] #[inline] pub fn recv_buf_with_flags(&mut self) -> Result, Error> { // # Safety @@ -1838,7 +1838,6 @@ where } /// Receive the buffer, also reading the LLMP internal message flags - #[allow(clippy::type_complexity)] #[inline] pub fn recv_buf_blocking_with_flags(&mut self) -> Result<(ClientId, Tag, Flags, &[u8]), Error> { // # Safety @@ -1989,7 +1988,7 @@ where /// /// # Safety /// This dereferences msg, make sure to pass a proper pointer to it. - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] pub unsafe fn msg_to_offset(&self, msg: *const LlmpMsg) -> Result { let page = self.page(); if llmp_msg_in_page(page, msg) { @@ -2033,7 +2032,7 @@ where /// Gets this message from this page, at the indicated offset. /// Will return [`crate::Error::illegal_argument`] error if the offset is out of bounds. - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] pub fn msg_from_offset(&mut self, offset: u64) -> Result<*mut LlmpMsg, Error> { let offset = offset as usize; @@ -2206,7 +2205,6 @@ impl SignalHandler for LlmpShutdownSignalHandler { #[cfg(all(windows, feature = "std"))] impl CtrlHandler for LlmpShutdownSignalHandler { - #[allow(clippy::not_unsafe_ptr_arg_deref)] fn handle(&mut self, ctrl_type: u32) -> bool { log::info!("LLMP: Received shutdown signal, ctrl_type {:?}", ctrl_type); unsafe { @@ -2653,8 +2651,8 @@ where /// Returns `true` if new messages were broker-ed /// It is supposed that the message is never unmapped. #[inline] - #[allow(clippy::cast_ptr_alignment)] - #[allow(clippy::too_many_lines)] + #[expect(clippy::cast_ptr_alignment)] + #[expect(clippy::too_many_lines)] unsafe fn handle_new_msgs(&mut self, client_id: ClientId) -> Result { let mut new_messages = false; @@ -3039,7 +3037,7 @@ where /// Internal function, returns true when shuttdown is requested by a `SIGINT` signal #[inline] #[cfg(any(unix, all(windows, feature = "std")))] - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] fn is_shutting_down(&self) -> bool { // # Safety // No user-provided potentially unsafe parameters. @@ -3050,7 +3048,7 @@ where /// Always returns true on platforms, where no shutdown signal handlers are supported #[inline] #[cfg(not(any(unix, all(windows, feature = "std"))))] - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] fn is_shutting_down(&self) -> bool { false } @@ -3086,7 +3084,7 @@ where /// Announces a new client on the given shared map. /// Called from a background thread, typically. /// Upon receiving this message, the broker should map the announced page and start tracking it for new messages. - #[allow(dead_code)] + #[cfg(feature = "std")] fn announce_new_client( sender: &mut LlmpSender, shmem_description: &ShMemDescription, @@ -3096,7 +3094,7 @@ where .alloc_next(size_of::()) .expect("Could not allocate a new message in shared map."); (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*pageinfo).shm_str = *shmem_description.id.as_array(); (*pageinfo).map_size = shmem_description.size; @@ -3114,7 +3112,7 @@ where .alloc_next(size_of::()) .expect("Could not allocate a new message in shared map."); (*msg).tag = LLMP_TAG_CLIENT_EXIT; - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] let exitinfo = (*msg).buf.as_mut_ptr() as *mut LlmpClientExitInfo; (*exitinfo).client_id = client_id; sender.send(msg, true) @@ -3127,7 +3125,7 @@ where /// This function returns the [`ShMemDescription`] the client uses to place incoming messages. /// The thread exits, when the remote broker disconnects. #[cfg(feature = "std")] - #[allow(clippy::let_and_return, clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn b2b_thread_on( mut stream: TcpStream, b2b_client_id: ClientId, @@ -3470,7 +3468,7 @@ where /// Reattach to a vacant client map. /// It is essential, that the broker (or someone else) kept a pointer to the `out_shmem` /// else reattach will get a new, empty page, from the OS, or fail - #[allow(clippy::needless_pass_by_value)] + #[allow(clippy::needless_pass_by_value)] // no longer necessary on nightly pub fn on_existing_shmem( shmem_provider: SP, _current_out_shmem: SP::ShMem, @@ -3674,7 +3672,7 @@ where } /// Returns the next message, tag, buf, if available, else None - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] #[inline] pub fn recv_buf(&mut self) -> Result, Error> { self.receiver.recv_buf() @@ -3687,13 +3685,12 @@ where } /// Receive a `buf` from the broker, including the `flags` used during transmission. - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub fn recv_buf_with_flags(&mut self) -> Result, Error> { self.receiver.recv_buf_with_flags() } /// Receive a `buf` from the broker, including the `flags` used during transmission. - #[allow(clippy::type_complexity)] pub fn recv_buf_blocking_with_flags(&mut self) -> Result<(ClientId, Tag, Flags, &[u8]), Error> { self.receiver.recv_buf_blocking_with_flags() } @@ -3797,7 +3794,6 @@ mod tests { #[serial] #[cfg_attr(miri, ignore)] fn test_llmp_connection() { - #[allow(unused_variables)] let shmem_provider = StdShMemProvider::new().unwrap(); let mut broker = match LlmpConnection::on_port(shmem_provider.clone(), 1337).unwrap() { IsClient { client: _ } => panic!("Could not bind to port as broker"), diff --git a/libafl_bolts/src/minibsod.rs b/libafl_bolts/src/minibsod.rs index 757f5ebd7f..b2b2e384a7 100644 --- a/libafl_bolts/src/minibsod.rs +++ b/libafl_bolts/src/minibsod.rs @@ -29,7 +29,6 @@ use crate::os::unix_signals::{ucontext_t, Signal}; any(target_os = "linux", target_os = "android"), target_arch = "x86_64" ))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -65,7 +64,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(any(target_os = "linux", target_os = "android"), target_arch = "x86"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -144,7 +142,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "freebsd", target_arch = "aarch64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -168,7 +165,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -192,7 +188,7 @@ pub fn dump_registers( } /// Write the content of all important registers -#[allow(clippy::unnecessary_wraps, clippy::similar_names)] +#[expect(clippy::unnecessary_wraps, clippy::similar_names)] #[cfg(all(target_vendor = "apple", target_arch = "x86_64"))] pub fn dump_registers( writer: &mut BufWriter, @@ -228,7 +224,6 @@ pub fn dump_registers( any(target_os = "freebsd", target_os = "dragonfly"), target_arch = "x86_64" ))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -258,7 +253,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "netbsd", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -368,7 +362,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "openbsd", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -396,7 +389,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "openbsd", target_arch = "aarch64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -419,7 +411,6 @@ pub fn dump_registers( any(target_os = "solaris", target_os = "illumos"), target_arch = "x86_64" ))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -455,7 +446,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "windows", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, context: &CONTEXT, @@ -484,7 +474,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "windows", target_arch = "x86"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, context: &CONTEXT, @@ -504,7 +493,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "windows", target_arch = "aarch64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, context: &CONTEXT, @@ -531,7 +519,6 @@ pub fn dump_registers( /// Write the content of all important registers #[cfg(all(target_os = "haiku", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, @@ -558,7 +545,7 @@ pub fn dump_registers( Ok(()) } -#[allow(clippy::unnecessary_wraps)] +#[expect(clippy::unnecessary_wraps)] #[cfg(not(any( target_vendor = "apple", target_os = "linux", @@ -670,7 +657,6 @@ fn write_crash( } #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] -#[allow(clippy::similar_names)] fn write_crash( writer: &mut BufWriter, signal: Signal, @@ -687,7 +673,6 @@ fn write_crash( } #[cfg(all(target_vendor = "apple", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] fn write_crash( writer: &mut BufWriter, signal: Signal, @@ -709,7 +694,6 @@ fn write_crash( } #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] fn write_crash( writer: &mut BufWriter, signal: Signal, @@ -725,7 +709,6 @@ fn write_crash( } #[cfg(all(target_os = "dragonfly", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] fn write_crash( writer: &mut BufWriter, signal: Signal, @@ -741,7 +724,6 @@ fn write_crash( } #[cfg(all(target_os = "openbsd", target_arch = "x86_64"))] -#[allow(clippy::similar_names)] fn write_crash( writer: &mut BufWriter, signal: Signal, @@ -757,7 +739,6 @@ fn write_crash( } #[cfg(all(target_os = "openbsd", target_arch = "aarch64"))] -#[allow(clippy::similar_names)] fn write_crash( writer: &mut BufWriter, signal: Signal, @@ -883,7 +864,7 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er } #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] -#[allow(clippy::cast_ptr_alignment)] +#[expect(clippy::cast_ptr_alignment)] fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Error> { let mut s: usize = 0; #[cfg(target_os = "freebsd")] @@ -1003,7 +984,6 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er } #[cfg(target_vendor = "apple")] -#[allow(non_camel_case_types)] fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Error> { let mut ptask = std::mem::MaybeUninit::::uninit(); // We start by the lowest virtual address from the userland' standpoint @@ -1105,7 +1085,7 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er /// Generates a mini-BSOD given a signal and context. #[cfg(unix)] -#[allow(clippy::non_ascii_literal, clippy::too_many_lines)] +#[expect(clippy::non_ascii_literal)] pub fn generate_minibsod( writer: &mut BufWriter, signal: Signal, @@ -1132,11 +1112,7 @@ pub fn generate_minibsod( /// Generates a mini-BSOD given an `EXCEPTION_POINTERS` structure. #[cfg(windows)] -#[allow( - clippy::non_ascii_literal, - clippy::too_many_lines, - clippy::not_unsafe_ptr_arg_deref -)] +#[expect(clippy::non_ascii_literal, clippy::not_unsafe_ptr_arg_deref)] pub fn generate_minibsod( writer: &mut BufWriter, exception_pointers: *mut EXCEPTION_POINTERS, diff --git a/libafl_bolts/src/os/mod.rs b/libafl_bolts/src/os/mod.rs index 1c4d83862c..655d79e234 100644 --- a/libafl_bolts/src/os/mod.rs +++ b/libafl_bolts/src/os/mod.rs @@ -28,7 +28,7 @@ use std::{fs::File, os::fd::AsRawFd, sync::OnceLock}; // Allow a few extra features we need for the whole module #[cfg(all(windows, feature = "std"))] -#[allow(missing_docs, overflowing_literals)] +#[expect(missing_docs, overflowing_literals)] pub mod windows_exceptions; #[cfg(unix)] use libc::pid_t; diff --git a/libafl_bolts/src/os/unix_shmem_server.rs b/libafl_bolts/src/os/unix_shmem_server.rs index d8adfb2059..831b729d37 100644 --- a/libafl_bolts/src/os/unix_shmem_server.rs +++ b/libafl_bolts/src/os/unix_shmem_server.rs @@ -119,7 +119,7 @@ where SP: ShMemProvider, { /// Send a request to the server, and wait for a response - #[allow(clippy::similar_names)] // id and fd + #[expect(clippy::similar_names)] // id and fd fn send_receive(&mut self, request: ServedShMemRequest) -> Result<(i32, i32), Error> { //let bt = Backtrace::new(); //log::info!("Sending {:?} with bt:\n{:?}", request, bt); @@ -409,7 +409,6 @@ where }; } - #[allow(clippy::mutex_atomic)] let syncpair = Arc::new((Mutex::new(ShMemServiceStatus::Starting), Condvar::new())); let childsyncpair = Arc::clone(&syncpair); let join_handle = thread::spawn(move || { @@ -472,7 +471,7 @@ where } /// The struct for the worker, handling incoming requests for [`ShMem`]. -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] struct ServedShMemServiceWorker where SP: ShMemProvider, @@ -567,7 +566,7 @@ where if client.maps.contains_key(&description_id) { // Using let else here as self needs to be accessed in the else branch. - #[allow(clippy::option_if_let_else)] + #[expect(clippy::option_if_let_else)] Ok(ServedShMemResponse::Mapping( if let Some(map) = client .maps diff --git a/libafl_bolts/src/os/unix_signals.rs b/libafl_bolts/src/os/unix_signals.rs index acd8a5f48e..e06be190f4 100644 --- a/libafl_bolts/src/os/unix_signals.rs +++ b/libafl_bolts/src/os/unix_signals.rs @@ -28,7 +28,7 @@ pub const CTRL_C_EXIT: i32 = 100; /// ARMv7-specific representation of a saved context #[cfg(target_arch = "arm")] #[derive(Debug)] -#[allow(non_camel_case_types)] +#[expect(non_camel_case_types)] #[repr(C)] pub struct mcontext_t { /// Signal Number @@ -78,7 +78,7 @@ pub struct mcontext_t { /// User Context Struct on `arm` `linux` #[cfg(all(target_os = "linux", target_arch = "arm"))] #[derive(Debug)] -#[allow(non_camel_case_types)] +#[expect(non_camel_case_types)] #[repr(C)] pub struct ucontext_t { /// Flags @@ -106,7 +106,8 @@ pub struct ucontext_t { #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] #[derive(Debug)] #[repr(C)] -#[allow(clippy::pub_underscore_fields)] +#[expect(clippy::pub_underscore_fields)] +#[allow(non_camel_case_types)] // expect breaks for some reason pub struct arm_exception_state64 { /// Virtual Fault Address pub __far: u64, @@ -131,7 +132,8 @@ pub struct arm_exception_state64 { #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] #[derive(Debug)] #[repr(C)] -#[allow(clippy::pub_underscore_fields)] +#[expect(clippy::pub_underscore_fields)] +#[allow(non_camel_case_types)] // expect breaks for some reason pub struct arm_thread_state64 { /// General purpose registers x0-x28 pub __x: [u64; 29], @@ -157,9 +159,9 @@ pub struct arm_thread_state64 { /// ```` #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] #[derive(Debug)] -#[allow(non_camel_case_types)] #[repr(C, align(16))] -//#[repr(align(16))] +#[allow(non_camel_case_types)] // expect breaks for some reason + //#[repr(align(16))] pub struct arm_neon_state64 { /// opaque pub opaque: [u8; (32 * 16) + (2 * size_of::())], @@ -174,10 +176,10 @@ pub struct arm_neon_state64 { ///}; /// ``` #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] -#[allow(non_camel_case_types)] #[derive(Debug)] #[repr(C)] -#[allow(clippy::pub_underscore_fields)] +#[expect(clippy::pub_underscore_fields)] +#[allow(non_camel_case_types)] // expect breaks for some reason pub struct mcontext64 { /// `_STRUCT_ARM_EXCEPTION_STATE64` pub __es: arm_exception_state64, @@ -197,8 +199,8 @@ pub struct mcontext64 { /// ``` #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] #[derive(Debug)] -#[allow(non_camel_case_types)] #[repr(C)] +#[allow(non_camel_case_types)] // expect breaks for some reason pub struct sigaltstack { /// signal stack base pub ss_sp: *mut c_void, @@ -226,8 +228,8 @@ pub struct sigaltstack { /// ``` #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] #[derive(Debug)] -#[allow(non_camel_case_types)] #[repr(C)] +#[allow(non_camel_case_types)] // expect breaks for some reason pub struct ucontext_t { /// onstack pub uc_onstack: c_int, @@ -515,7 +517,7 @@ pub unsafe fn setup_signal_handler( /// We wrap it here, as it seems to be (currently) /// not available on `MacOS` in the `libc` crate. #[cfg(unix)] -#[allow(clippy::inline_always)] // we assume that inlining will destroy less state +#[expect(clippy::inline_always)] // we assume that inlining will destroy less state #[inline(always)] pub fn ucontext() -> Result { let mut ucontext = unsafe { mem::zeroed() }; diff --git a/libafl_bolts/src/ownedref.rs b/libafl_bolts/src/ownedref.rs index f882554646..c271dba53e 100644 --- a/libafl_bolts/src/ownedref.rs +++ b/libafl_bolts/src/ownedref.rs @@ -447,7 +447,7 @@ where /// Wrap a slice and convert to a Vec on serialize. /// We use a hidden inner enum so the public API can be safe, /// unless the user uses the unsafe [`OwnedSlice::from_raw_parts`] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Serialize, Deserialize)] pub struct OwnedSlice<'a, T: 'a + Sized> { inner: OwnedSliceInner<'a, T>, @@ -671,7 +671,7 @@ where } /// Wrap a mutable slice and convert to a Vec on serialize -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Serialize, Deserialize)] pub struct OwnedMutSlice<'a, T: 'a + Sized> { inner: OwnedMutSliceInner<'a, T>, @@ -860,7 +860,7 @@ impl<'a, T> From<&'a mut [T]> for OwnedMutSlice<'a, T> { } /// Create a new [`OwnedMutSlice`] from a reference to ref to a slice -#[allow(clippy::mut_mut)] // This makes use in some iterators easier +#[expect(clippy::mut_mut)] // This makes use in some iterators easier impl<'a, T> From<&'a mut &'a mut [T]> for OwnedMutSlice<'a, T> { fn from(r: &'a mut &'a mut [T]) -> Self { Self { @@ -912,7 +912,7 @@ where } /// Wrap a mutable slice of constant size N and convert to a Box on serialize -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Serialize, Deserialize)] pub struct OwnedMutSizedSlice<'a, T: 'a + Sized, const N: usize> { inner: OwnedMutSizedSliceInner<'a, T, N>, @@ -1046,7 +1046,7 @@ where } /// Create a new [`OwnedMutSizedSlice`] from a reference to a boxed sized slice -#[allow(clippy::mut_mut)] // This makes use in some iterators easier +// This makes use in some iterators easier impl<'a, T, const N: usize> From<&'a mut Box<[T; N]>> for OwnedMutSizedSlice<'a, T, N> { fn from(r: &'a mut Box<[T; N]>) -> Self { Self { @@ -1065,7 +1065,7 @@ impl<'a, T, const N: usize> From<&'a mut [T; N]> for OwnedMutSizedSlice<'a, T, N } /// Create a new [`OwnedMutSizedSlice`] from a reference to ref to a slice -#[allow(clippy::mut_mut)] // This makes use in some iterators easier +#[expect(clippy::mut_mut)] // This makes use in some iterators easier impl<'a, T, const N: usize> From<&'a mut &'a mut [T; N]> for OwnedMutSizedSlice<'a, T, N> { fn from(r: &'a mut &'a mut [T; N]) -> Self { Self { diff --git a/libafl_bolts/src/rands/loaded_dice.rs b/libafl_bolts/src/rands/loaded_dice.rs index 474515e14f..d03b1ab5d9 100644 --- a/libafl_bolts/src/rands/loaded_dice.rs +++ b/libafl_bolts/src/rands/loaded_dice.rs @@ -81,7 +81,7 @@ impl LoadedDiceSampler { } /// Create the table for this [`LoadedDiceSampler`] - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] fn construct_table(probs: &[f64]) -> Vec { let mut res = vec![]; let n = probs.len() as f64; @@ -116,7 +116,7 @@ mod tests { use crate::rands::{Rand, StdRand}; #[test] - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] fn test_loaded_dice() { let mut rng = StdRand::with_seed(1337); let len = rng.between(3, 9); diff --git a/libafl_bolts/src/rands/mod.rs b/libafl_bolts/src/rands/mod.rs index d2ba03ee5e..a6a8730c95 100644 --- a/libafl_bolts/src/rands/mod.rs +++ b/libafl_bolts/src/rands/mod.rs @@ -18,7 +18,7 @@ static SEED_COUNTER: AtomicUsize = AtomicUsize::new(0); /// Return a pseudo-random seed. For `no_std` environments, a single deterministic sequence is used. #[must_use] -#[allow(unreachable_code)] +#[expect(unreachable_code)] pub fn random_seed() -> u64 { #[cfg(feature = "std")] return random_seed_from_random_state(); @@ -34,7 +34,6 @@ fn random_seed_deterministic() -> u64 { splitmix64(&mut seed) } -#[allow(dead_code)] #[cfg(feature = "std")] fn random_seed_from_random_state() -> u64 { use std::{ @@ -115,7 +114,7 @@ pub trait Rand: Debug + Serialize + DeserializeOwned { /// Gets a value between 0.0 (inclusive) and 1.0 (exclusive) #[inline] - #[allow(clippy::cast_precision_loss)] + #[expect(clippy::cast_precision_loss)] fn next_float(&mut self) -> f64 { // both 2^53 and 2^-53 can be represented in f64 exactly const MAX: u64 = 1u64 << 53; @@ -370,7 +369,7 @@ impl Rand for Lehmer64Rand { } #[inline] - #[allow(clippy::unreadable_literal)] + #[expect(clippy::unreadable_literal)] fn next(&mut self) -> u64 { self.s *= 0xda942042e4dd58b5; (self.s >> 64) as u64 @@ -418,7 +417,7 @@ impl Rand for RomuTrioRand { } #[inline] - #[allow(clippy::unreadable_literal)] + #[expect(clippy::unreadable_literal)] fn next(&mut self) -> u64 { let xp = self.x_state; let yp = self.y_state; @@ -457,7 +456,7 @@ impl Rand for RomuDuoJrRand { } #[inline] - #[allow(clippy::unreadable_literal)] + #[expect(clippy::unreadable_literal)] fn next(&mut self) -> u64 { let xp = self.x_state; self.x_state = 15241094284759029579_u64.wrapping_mul(self.y_state); @@ -516,7 +515,6 @@ impl Rand for Sfc64Rand { /// fake rand, for testing purposes #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] -#[allow(clippy::upper_case_acronyms)] pub struct XkcdRand { val: u64, } @@ -675,8 +673,6 @@ mod tests { } #[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -#[allow(missing_docs)] /// `Rand` Python bindings pub mod pybind { use pyo3::prelude::*; @@ -685,7 +681,7 @@ pub mod pybind { use super::{random_seed, Rand, StdRand}; #[pyclass(unsendable, name = "StdRand")] - #[allow(clippy::unsafe_derive_deserialize)] + #[expect(clippy::unsafe_derive_deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)] /// Python class for StdRand pub struct PythonStdRand { @@ -721,7 +717,7 @@ pub mod pybind { /// Rand Trait binding #[pyclass(unsendable, name = "Rand")] - #[allow(clippy::unsafe_derive_deserialize)] + #[expect(clippy::unsafe_derive_deserialize)] #[derive(Serialize, Deserialize, Debug)] pub struct PythonRand { wrapper: PythonRandWrapper, diff --git a/libafl_bolts/src/serdeany.rs b/libafl_bolts/src/serdeany.rs index ccc34a59cc..6e2f8ffcb3 100644 --- a/libafl_bolts/src/serdeany.rs +++ b/libafl_bolts/src/serdeany.rs @@ -86,7 +86,7 @@ pub type DeserializeCallback = fn(&mut dyn erased_serde::Deserializer) -> Result, erased_serde::Error>; /// Callback struct for deserialization of a [`SerdeAny`] type. -#[allow(missing_debug_implementations)] +#[expect(missing_debug_implementations)] pub struct DeserializeCallbackSeed where B: ?Sized, @@ -141,7 +141,7 @@ pub mod serdeany_registry { /// Visitor object used internally for the [`crate::serdeany::SerdeAny`] registry. #[derive(Debug)] pub struct BoxDynVisitor {} - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] impl<'de> serde::de::Visitor<'de> for BoxDynVisitor { type Value = Box; @@ -172,17 +172,15 @@ pub mod serdeany_registry { } } - #[allow(unused_qualifications)] struct Registry { deserializers: Option, finalized: bool, } - #[allow(unused_qualifications)] impl Registry { pub fn register(&mut self) where - T: crate::serdeany::SerdeAny + Serialize + serde::de::DeserializeOwned, + T: SerdeAny + Serialize + de::DeserializeOwned, { assert!(!self.finalized, "Registry is already finalized!"); @@ -217,7 +215,7 @@ pub mod serdeany_registry { #[derive(Debug)] pub struct RegistryBuilder {} - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] impl RegistryBuilder { /// Register a given struct type for trait object (de)serialization /// @@ -249,7 +247,7 @@ pub mod serdeany_registry { /// A (de)serializable anymap containing (de)serializable trait objects registered /// in the registry - #[allow(clippy::unsafe_derive_deserialize)] + #[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Serialize, Deserialize)] pub struct SerdeAnyMap { map: HashMap>, @@ -264,7 +262,7 @@ pub mod serdeany_registry { } } - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] impl SerdeAnyMap { /// Get an element from the map. #[must_use] @@ -335,7 +333,7 @@ pub mod serdeany_registry { /// Get an entry to an element in this map. #[inline] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] pub fn raw_entry_mut( &mut self, ) -> hashbrown::hash_map::RawEntryMut< @@ -430,8 +428,8 @@ pub mod serdeany_registry { } /// A serializable [`HashMap`] wrapper for [`crate::serdeany::SerdeAny`] types, addressable by name. - #[allow(clippy::unsafe_derive_deserialize)] - #[allow(unused_qualifications)] + #[expect(clippy::unsafe_derive_deserialize)] + #[expect(unused_qualifications)] #[derive(Debug, Serialize, Deserialize)] pub struct NamedSerdeAnyMap { map: HashMap>>, @@ -446,7 +444,7 @@ pub mod serdeany_registry { } } - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] impl NamedSerdeAnyMap { /// Get an element by name #[must_use] @@ -505,9 +503,9 @@ pub mod serdeany_registry { /// Get all elements of a type contained in this map. #[must_use] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] #[inline] - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub fn get_all( &self, ) -> Option< @@ -523,7 +521,7 @@ pub mod serdeany_registry { #[cfg(not(feature = "stable_anymap"))] let type_repr = &type_repr; - #[allow(clippy::manual_map)] + #[expect(clippy::manual_map)] match self.map.get(type_repr) { None => None, Some(h) => Some(h.values().map(|x| x.as_any().downcast_ref::().unwrap())), @@ -532,8 +530,8 @@ pub mod serdeany_registry { /// Get all elements contained in this map, as mut. #[inline] - #[allow(unused_qualifications)] - #[allow(clippy::type_complexity)] + #[expect(unused_qualifications)] + #[expect(clippy::type_complexity)] pub fn get_all_mut( &mut self, ) -> Option< @@ -549,7 +547,7 @@ pub mod serdeany_registry { #[cfg(not(feature = "stable_anymap"))] let type_repr = &type_repr; - #[allow(clippy::manual_map)] + #[expect(clippy::manual_map)] match self.map.get_mut(type_repr) { None => None, Some(h) => Some( @@ -561,7 +559,7 @@ pub mod serdeany_registry { /// Run `func` for each element in this map. #[inline] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] pub fn for_each< F: FnMut(&TypeRepr, &Box) -> Result<(), Error>, >( @@ -594,7 +592,7 @@ pub mod serdeany_registry { /// Insert an element into this map. #[inline] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] pub fn insert(&mut self, name: &str, val: T) where T: crate::serdeany::SerdeAny, @@ -604,7 +602,7 @@ pub mod serdeany_registry { /// Get a reference to the type map. #[inline] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] fn outer_map_mut( &mut self, ) -> &mut hashbrown::hash_map::HashMap> @@ -638,7 +636,7 @@ pub mod serdeany_registry { /// Get an entry to an element into this map. /// Prefer [`Self::raw_entry_mut`] as it won't need an owned key. #[inline] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] fn entry( &mut self, name: String, @@ -656,7 +654,7 @@ pub mod serdeany_registry { /// Get a raw entry to an element into this map. #[inline] - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] fn raw_entry_mut( &mut self, name: &str, @@ -758,7 +756,7 @@ pub mod serdeany_registry { } } -#[allow(unused_qualifications)] +#[expect(unused_qualifications)] impl Serialize for dyn crate::serdeany::SerdeAny { fn serialize(&self, se: S) -> Result where @@ -783,7 +781,7 @@ impl Serialize for dyn crate::serdeany::SerdeAny { } } -#[allow(unused_qualifications)] +#[expect(unused_qualifications)] impl<'de> Deserialize<'de> for Box { fn deserialize(deserializer: D) -> Result, D::Error> where @@ -920,7 +918,7 @@ macro_rules! impl_serdeany { /// /// # Safety /// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock. - #[allow(unused)] + #[expect(unused)] pub unsafe fn register() { $crate::create_manual_register!($struct_name); } diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index 571169ed1b..5f1c00e7f2 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -771,7 +771,7 @@ pub mod unix_shmem { } } - #[allow(clippy::unnecessary_wraps)] + #[allow(clippy::unnecessary_wraps)] // cfg dependent fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result { // # Safety // No user-provided potentially unsafe parameters. @@ -1012,7 +1012,7 @@ pub mod unix_shmem { impl CommonUnixShMem { /// Create a new shared memory mapping, using shmget/shmat - #[allow(unused_qualifications)] + #[expect(unused_qualifications)] pub fn new(map_size: usize) -> Result { #[cfg(any(target_os = "solaris", target_os = "illumos"))] const SHM_R: libc::c_int = 0o400; @@ -1164,9 +1164,9 @@ pub mod unix_shmem { map_size: usize, } + #[allow(non_camel_case_types)] // expect somehow breaks here #[derive(Copy, Clone)] #[repr(C)] - #[allow(non_camel_case_types)] struct ashmem_pin { pub offset: c_uint, pub len: c_uint, @@ -1209,7 +1209,7 @@ pub mod unix_shmem { //return Err(Error::unknown("Failed to set the ashmem mapping's name".to_string())); //}; - #[allow(trivial_numeric_casts)] + #[expect(trivial_numeric_casts)] if ioctl(fd, ASHMEM_SET_SIZE as _, map_size) != 0 { close(fd); return Err(Error::unknown( @@ -1244,7 +1244,7 @@ pub mod unix_shmem { pub fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result { unsafe { let fd: i32 = id.to_string().parse().unwrap(); - #[allow(trivial_numeric_casts, clippy::cast_sign_loss)] + #[expect(trivial_numeric_casts, clippy::cast_sign_loss)] if ioctl(fd, ASHMEM_GET_SIZE as _) as u32 as usize != map_size { return Err(Error::unknown( "The mapping's size differs from the requested size".to_string(), @@ -1299,13 +1299,13 @@ pub mod unix_shmem { /// [`Drop`] implementation for [`AshmemShMem`], which cleans up the mapping. #[cfg(unix)] impl Drop for AshmemShMem { - #[allow(trivial_numeric_casts)] + #[expect(trivial_numeric_casts)] fn drop(&mut self) { unsafe { let fd: i32 = self.id.to_string().parse().unwrap(); - #[allow(trivial_numeric_casts)] - #[allow(clippy::cast_sign_loss)] + #[expect(trivial_numeric_casts)] + #[expect(clippy::cast_sign_loss)] let length = ioctl(fd, ASHMEM_GET_SIZE as _) as u32; let ap = ashmem_pin { @@ -1400,7 +1400,7 @@ pub mod unix_shmem { }; let fd = fd.into_raw_fd(); - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] if ftruncate(fd, map_size as i64) == -1 { close(fd); return Err(Error::last_os_error(format!( @@ -1438,7 +1438,7 @@ pub mod unix_shmem { "Failed to map the memfd mapping".to_string(), )); } - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] if stat.st_size as usize != map_size { return Err(Error::unknown( "The mapping's size differs from the requested size".to_string(), @@ -1490,7 +1490,6 @@ pub mod unix_shmem { /// [`Drop`] implementation for [`MemfdShMem`], which cleans up the mapping. #[cfg(unix)] impl Drop for MemfdShMem { - #[allow(trivial_numeric_casts)] fn drop(&mut self) { let fd = i32::from(self.id); diff --git a/libafl_bolts/src/staterestore.rs b/libafl_bolts/src/staterestore.rs index 1542c3b089..fbe27c492e 100644 --- a/libafl_bolts/src/staterestore.rs +++ b/libafl_bolts/src/staterestore.rs @@ -216,7 +216,7 @@ where 0, "Beginning of the page is not aligned at {ptr:?}!" ); - #[allow(clippy::cast_ptr_alignment)] // Beginning of the page will always be aligned + #[expect(clippy::cast_ptr_alignment)] // Beginning of the page will always be aligned unsafe { &mut *(ptr as *mut StateShMemContent) } @@ -224,7 +224,7 @@ where /// The content is either the name of the tmpfile, or the serialized bytes directly, if they fit on a single page. fn content(&self) -> &StateShMemContent { - #[allow(clippy::cast_ptr_alignment)] // Beginning of the page will always be aligned + #[expect(clippy::cast_ptr_alignment)] // Beginning of the page will always be aligned let ptr = self.shmem.as_slice().as_ptr() as *const StateShMemContent; unsafe { &*(ptr) } } diff --git a/libafl_bolts/src/subrange.rs b/libafl_bolts/src/subrange.rs index 6b9ddf12b8..58a356148e 100644 --- a/libafl_bolts/src/subrange.rs +++ b/libafl_bolts/src/subrange.rs @@ -198,7 +198,7 @@ impl<'a, T> PartialSubRangeSlice<'a, T> { /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. #[must_use] pub fn partial(self) -> Option> { - #[allow(clippy::match_wildcard_for_single_variants)] + #[expect(clippy::match_wildcard_for_single_variants)] match self { PartialSubRangeSlice::Partial(partial_slice) => Some(partial_slice), _ => None, diff --git a/libafl_bolts/src/tuples.rs b/libafl_bolts/src/tuples.rs index 05280f3298..f9497799a7 100644 --- a/libafl_bolts/src/tuples.rs +++ b/libafl_bolts/src/tuples.rs @@ -44,7 +44,7 @@ pub fn type_eq() -> bool { } // specialized implementation: Copy is only implemented if the types are the same - #[allow(clippy::mismatching_type_param_order)] + #[expect(clippy::mismatching_type_param_order)] impl Copy for W<'_, T, T> {} let detected = Cell::new(true); @@ -485,7 +485,7 @@ impl MatchName for () { } #[cfg(feature = "alloc")] -#[allow(deprecated)] +#[expect(deprecated)] impl MatchName for (Head, Tail) where Head: Named, @@ -585,7 +585,7 @@ pub trait MatchNameRef { } #[cfg(feature = "alloc")] -#[allow(deprecated)] +#[expect(deprecated)] impl MatchNameRef for M where M: MatchName, @@ -769,10 +769,8 @@ impl Map for () { /// Iterate over a tuple, executing the given `expr` for each element. #[macro_export] -#[allow(clippy::items_after_statements)] macro_rules! tuple_for_each { ($fn_name:ident, $trait_name:path, $tuple_name:ident, $body:expr) => { - #[allow(clippy::items_after_statements)] mod $fn_name { pub trait ForEach { fn for_each(&self); @@ -787,7 +785,7 @@ macro_rules! tuple_for_each { Head: $trait_name, Tail: tuple_list::TupleList + ForEach, { - #[allow(clippy::redundant_closure_call)] + #[allow(clippy::redundant_closure_call)] // macro may be called on a closure or a function fn for_each(&self) { ($body)(&self.0); self.1.for_each(); @@ -806,7 +804,6 @@ macro_rules! tuple_for_each { #[macro_export] macro_rules! tuple_for_each_mut { ($fn_name:ident, $trait_name:path, $tuple_name:ident, $body:expr) => { - #[allow(clippy::items_after_statements)] mod $fn_name { pub trait ForEachMut { fn for_each_mut(&mut self); @@ -821,7 +818,7 @@ macro_rules! tuple_for_each_mut { Head: $trait_name, Tail: tuple_list::TupleList + ForEachMut, { - #[allow(clippy::redundant_closure_call)] + #[allow(clippy::redundant_closure_call)] // macro may be called on a closure or a function fn for_each_mut(&mut self) { ($body)(&mut self.0); self.1.for_each_mut(); @@ -874,7 +871,7 @@ mod test { use crate::tuples::{type_eq, Map, MappingFunctor}; #[test] - #[allow(unused_qualifications)] // for type name tests + // for type name tests fn test_type_eq_simple() { // test eq assert!(type_eq::()); @@ -885,13 +882,13 @@ mod test { #[test] #[cfg(feature = "alloc")] - #[allow(unused_qualifications)] // for type name tests + #[expect(unused_qualifications)] // for type name tests fn test_type_eq() { // An alias for equality testing type OwnedMutSliceAlias<'a> = OwnedMutSlice<'a, u8>; // A function for lifetime testing - #[allow(clippy::extra_unused_lifetimes)] + #[expect(clippy::extra_unused_lifetimes)] fn test_lifetimes<'a, 'b>() { assert!(type_eq::, OwnedMutSlice<'b, u8>>()); assert!(type_eq::, OwnedMutSlice<'a, u8>>()); @@ -937,14 +934,13 @@ mod test { let mapped = orig.map(MyMapper); // this won't compile if the mapped type is not correct - #[allow(clippy::no_effect_underscore_binding)] + #[expect(clippy::no_effect_underscore_binding)] let _type_assert: tuple_list_type!(W, W, W) = mapped; } /// Function that tests the tuple macros #[test] #[cfg(feature = "std")] - #[allow(clippy::items_after_statements)] fn test_macros() { let mut t = tuple_list!(1, "a"); diff --git a/libafl_cc/build.rs b/libafl_cc/build.rs index 15f1403ec0..c602457e58 100644 --- a/libafl_cc/build.rs +++ b/libafl_cc/build.rs @@ -143,8 +143,7 @@ fn find_llvm_version() -> Option { None } -#[allow(clippy::too_many_arguments)] -#[allow(unused)] +#[expect(clippy::too_many_arguments)] fn build_pass( bindir_path: &Path, out_dir: &Path, @@ -224,8 +223,7 @@ fn build_pass( } } -#[allow(clippy::single_element_loop)] -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = Path::new(&out_dir); diff --git a/libafl_cc/src/ar.rs b/libafl_cc/src/ar.rs index eb528c1962..373d6b4b2c 100644 --- a/libafl_cc/src/ar.rs +++ b/libafl_cc/src/ar.rs @@ -6,7 +6,7 @@ use std::{env, path::PathBuf, str::FromStr}; use crate::{Error, ToolWrapper, LIB_EXT, LIB_PREFIX}; /// Wrap Clang -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] #[derive(Debug)] pub struct ArWrapper { is_silent: bool, @@ -21,9 +21,8 @@ pub struct ArWrapper { base_args: Vec, } -#[allow(clippy::match_same_arms)] // for the linking = false wip for "shared" +#[expect(clippy::match_same_arms)] // for the linking = false wip for "shared" impl ToolWrapper for ArWrapper { - #[allow(clippy::too_many_lines)] fn parse_args(&mut self, args: &[S]) -> Result<&'_ mut Self, Error> where S: AsRef, diff --git a/libafl_cc/src/cfg.rs b/libafl_cc/src/cfg.rs index 49789f3c5c..f22a19e0b1 100644 --- a/libafl_cc/src/cfg.rs +++ b/libafl_cc/src/cfg.rs @@ -256,7 +256,7 @@ where } /// Load a CFG from string generated by ``AFLCoverage`` pass. - #[allow(unused_must_use)] + #[expect(unused_must_use)] #[must_use] pub fn from_content(content: &str) -> ControlFlowGraph { let mut reader = CfgFileReader::new(); diff --git a/libafl_cc/src/clang.rs b/libafl_cc/src/clang.rs index 42d5b137b8..d8c57a9e10 100644 --- a/libafl_cc/src/clang.rs +++ b/libafl_cc/src/clang.rs @@ -24,7 +24,6 @@ fn dll_extension<'a>() -> &'a str { include!(concat!(env!("OUT_DIR"), "/clang_constants.rs")); /// The supported LLVM passes -#[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LLVMPasses { //CmpLogIns, @@ -84,7 +83,7 @@ impl LLVMPasses { } /// Wrap Clang -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] #[derive(Debug)] pub struct ClangWrapper { is_silent: bool, @@ -115,9 +114,9 @@ pub struct ClangWrapper { passes_linking_args: Vec, } -#[allow(clippy::match_same_arms)] // for the linking = false wip for "shared" +#[expect(clippy::match_same_arms)] // for the linking = false wip for "shared" impl ToolWrapper for ClangWrapper { - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn parse_args(&mut self, args: &[S]) -> Result<&'_ mut Self, Error> where S: AsRef, @@ -326,7 +325,7 @@ impl ToolWrapper for ClangWrapper { self.command_for_configuration(crate::Configuration::Default) } - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn command_for_configuration( &mut self, configuration: crate::Configuration, diff --git a/libafl_cc/src/lib.rs b/libafl_cc/src/lib.rs index 8d71910c03..76de3f3dd2 100644 --- a/libafl_cc/src/lib.rs +++ b/libafl_cc/src/lib.rs @@ -224,7 +224,6 @@ pub trait ToolWrapper { fn command(&mut self) -> Result, Error>; /// Command to run the compiler for a given `Configuration` - #[allow(clippy::too_many_lines)] fn command_for_configuration( &mut self, configuration: Configuration, diff --git a/libafl_cc/src/libtool.rs b/libafl_cc/src/libtool.rs index 4117efc0af..0829b34292 100644 --- a/libafl_cc/src/libtool.rs +++ b/libafl_cc/src/libtool.rs @@ -6,7 +6,7 @@ use std::{env, path::PathBuf, str::FromStr}; use crate::{Error, ToolWrapper, LIB_EXT, LIB_PREFIX}; /// Wrap Clang -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] #[derive(Debug)] pub struct LibtoolWrapper { is_silent: bool, @@ -22,9 +22,8 @@ pub struct LibtoolWrapper { base_args: Vec, } -#[allow(clippy::match_same_arms)] // for the linking = false wip for "shared" +#[expect(clippy::match_same_arms)] // for the linking = false wip for "shared" impl ToolWrapper for LibtoolWrapper { - #[allow(clippy::too_many_lines)] fn parse_args(&mut self, args: &[S]) -> Result<&'_ mut Self, Error> where S: AsRef, diff --git a/libafl_concolic/symcc_runtime/src/filter.rs b/libafl_concolic/symcc_runtime/src/filter.rs index 6059c93c8d..1b9c2aa690 100644 --- a/libafl_concolic/symcc_runtime/src/filter.rs +++ b/libafl_concolic/symcc_runtime/src/filter.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; +// required for the import the macro `invoke_macro_with_rust_runtime_exports` that is dynamically generated in build.rs #[allow(clippy::wildcard_imports)] use crate::*; @@ -17,19 +18,19 @@ macro_rules! rust_filter_function_declaration { // push_path_constraint is not caught by the following case (because it has not return value), // but still needs to return something (pub fn push_path_constraint($( $arg:ident : $type:ty ),*$(,)?), $c_name:ident;) => { - #[allow(unused_variables)] + #[allow(unused_variables)] // only unused for some macro invocations fn push_path_constraint(&mut self, $($arg : $type),*) -> bool { true } }; (pub fn $name:ident($( $arg:ident : $type:ty ),*$(,)?) -> $ret:ty, $c_name:ident;) => { - #[allow(unused_variables)] + #[allow(unused_variables)] // only unused for some macro invocations fn $name(&mut self, $( $arg : $type),*) -> bool {true} }; (pub fn $name:ident($( $arg:ident : $type:ty ),*$(,)?), $c_name:ident;) => { - #[allow(unused_variables)] + #[allow(unused_variables)] // only unused for some macro invocations fn $name(&mut self, $( $arg : $type),*) {} }; } @@ -84,7 +85,7 @@ pub trait Filter { /// /// It applies the filter before passing expressions to the inner runtime. /// It also implements [`Runtime`], allowing for composing multiple [`Filter`]'s in a chain. -#[allow(clippy::module_name_repetitions)] +#[expect(clippy::module_name_repetitions)] pub struct FilterRuntime { filter: F, runtime: RT, diff --git a/libafl_concolic/symcc_runtime/src/filter/coverage.rs b/libafl_concolic/symcc_runtime/src/filter/coverage.rs index 1a56557a93..1d5e907abd 100644 --- a/libafl_concolic/symcc_runtime/src/filter/coverage.rs +++ b/libafl_concolic/symcc_runtime/src/filter/coverage.rs @@ -70,7 +70,6 @@ impl CallStackCoverage bool { self.is_interesting } @@ -139,6 +138,7 @@ macro_rules! call_stack_coverage_filter_function_implementation { }; } +// required for the import the macro `invoke_macro_with_rust_runtime_exports` that is dynamically generated in build.rs #[allow(clippy::wildcard_imports)] use crate::*; @@ -189,7 +189,7 @@ where } fn register_location_on_hitmap(&mut self, location: usize) { - #[allow(clippy::cast_possible_truncation)] // we cannot have more than usize elements.. + #[expect(clippy::cast_possible_truncation)] // we cannot have more than usize elements.. let hash = (self.build_hasher.hash_one(location) % usize::MAX as u64) as usize; let val = unsafe { // # Safety diff --git a/libafl_concolic/symcc_runtime/src/lib.rs b/libafl_concolic/symcc_runtime/src/lib.rs index 7caea28316..7746364cb6 100644 --- a/libafl_concolic/symcc_runtime/src/lib.rs +++ b/libafl_concolic/symcc_runtime/src/lib.rs @@ -135,7 +135,7 @@ macro_rules! unwrap_option { macro_rules! export_rust_runtime_fn { // special case for expression_unreachable, because we need to be convert pointer+length to slice (pub fn expression_unreachable(expressions: *mut RSymExpr, num_elements: usize), $c_name:ident; $rt_cb:path) => { - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn _rsym_expression_unreachable(expressions: *mut RSymExpr, num_elements: usize) { let slice = core::slice::from_raw_parts(expressions, num_elements); @@ -146,7 +146,7 @@ macro_rules! export_rust_runtime_fn { }; // special case for push_path_constraint, we are not returning a new expression while taking an expression as argument (pub fn push_path_constraint(constraint: RSymExpr, taken: bool, site_id: usize), $c_name:ident; $rt_cb:path) => { - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn _rsym_push_path_constraint(constraint: Option, taken: bool, site_id: usize) { if let Some(constraint) = constraint { @@ -160,7 +160,7 @@ macro_rules! export_rust_runtime_fn { (pub fn build_integer_from_buffer( buffer: *mut ::std::os::raw::c_void, num_bits: ::std::os::raw::c_uint$(,)?) -> RSymExpr,$c_name:ident; $rt_cb:path) => { - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn _rsym_build_integer_from_buffer(buffer: *mut ::std::os::raw::c_void, num_bits: ::std::os::raw::c_uint) { $rt_cb(|rt| { @@ -170,7 +170,7 @@ macro_rules! export_rust_runtime_fn { }; // all other methods are handled by this (pub fn $name:ident($( $arg:ident : $(::)?$($type:ident)::+ ),*$(,)?)$( -> $($ret:ident)::+)?, $c_name:ident; $rt_cb:path) => { - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn $c_name( $($arg: $crate::make_symexpr_optional!($($type)::+),)* )$( -> $crate::make_symexpr_optional!($($ret)::+))? { $rt_cb(|rt| { @@ -185,12 +185,12 @@ macro_rules! export_rust_runtime_fn { macro_rules! impl_nop_runtime_fn { // special case for expression_unreachable, because it has a different signature in our runtime trait than in the c interface. (pub fn expression_unreachable(expressions: *mut RSymExpr, num_elements: usize), $c_name:ident;) => { - #[allow(clippy::default_trait_access)] + // #[expect(clippy::default_trait_access)] fn expression_unreachable(&mut self, _exprs: &[RSymExpr]) {std::default::Default::default()} }; (pub fn $name:ident($( $arg:ident : $type:ty ),*$(,)?)$( -> $ret:ty)?, $c_name:ident;) => { - #[allow(clippy::default_trait_access)] + // #[expect(clippy::default_trait_access)] fn $name(&mut self, $( _ : $type),*)$( -> Option<$ret>)? {std::default::Default::default()} }; } @@ -222,7 +222,7 @@ impl OptionalRuntime { macro_rules! rust_runtime_function_declaration { (pub fn expression_unreachable(expressions: *mut RSymExpr, num_elements: usize), $c_name:ident;) => { - #[allow(clippy::default_trait_access)] + // #[expect(clippy::default_trait_access)] fn expression_unreachable(&mut self, exprs: &[RSymExpr]) { if let Some(inner) = &mut self.inner { inner.expression_unreachable(exprs); diff --git a/libafl_concolic/symcc_runtime/src/tracing.rs b/libafl_concolic/symcc_runtime/src/tracing.rs index 428b194d12..d456407340 100644 --- a/libafl_concolic/symcc_runtime/src/tracing.rs +++ b/libafl_concolic/symcc_runtime/src/tracing.rs @@ -25,7 +25,7 @@ impl TracingRuntime { } } - #[allow(clippy::unnecessary_wraps)] + #[expect(clippy::unnecessary_wraps)] fn write_message(&mut self, message: SymExpr) -> Option { Some(self.writer.write_message(message).unwrap()) } @@ -35,14 +35,14 @@ impl TracingRuntime { /// according to [`concolic::SymExpr`]. macro_rules! expression_builder { ($method_name:ident ( $($param_name:ident : $param_type:ty ),+ ) => $message:ident) => { - #[allow(clippy::missing_safety_doc)] + // #[expect(clippy::missing_safety_doc)] #[no_mangle] fn $method_name(&mut self, $( $param_name : $param_type, )+ ) -> Option { self.write_message(SymExpr::$message { $($param_name,)+ }) } }; ($method_name:ident () => $message:ident) => { - #[allow(clippy::missing_safety_doc)] + // #[expect(clippy::missing_safety_doc)] #[no_mangle] fn $method_name(&mut self) -> Option { self.write_message(SymExpr::$message) @@ -63,7 +63,6 @@ macro_rules! binary_expression_builder { } impl Runtime for TracingRuntime { - #[allow(clippy::missing_safety_doc)] #[no_mangle] fn build_integer_from_buffer( &mut self, diff --git a/libafl_frida/src/alloc.rs b/libafl_frida/src/alloc.rs index c8b69e47b9..97114765dd 100644 --- a/libafl_frida/src/alloc.rs +++ b/libafl_frida/src/alloc.rs @@ -169,7 +169,7 @@ impl Allocator { /// Allocate a new allocation of the given size. #[must_use] - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] pub unsafe fn alloc(&mut self, size: usize, _alignment: usize) -> *mut c_void { log::trace!("alloc"); let mut is_malloc_zero = false; @@ -180,7 +180,7 @@ impl Allocator { size }; if size > self.max_allocation { - #[allow(clippy::manual_assert)] + #[expect(clippy::manual_assert)] if self.max_allocation_panics { panic!("ASAN: Allocation is too large: 0x{size:x}"); } @@ -258,7 +258,7 @@ impl Allocator { } /// Releases the allocation at the given address. - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] pub unsafe fn release(&mut self, ptr: *mut c_void) { log::trace!("release {:?}", ptr); let Some(metadata) = self.allocations.get_mut(&(ptr as usize)) else { diff --git a/libafl_frida/src/asan/asan_rt.rs b/libafl_frida/src/asan/asan_rt.rs index 5256475a25..0fd25d79d2 100644 --- a/libafl_frida/src/asan/asan_rt.rs +++ b/libafl_frida/src/asan/asan_rt.rs @@ -236,7 +236,6 @@ impl AsanRuntime { } /// Reset all allocations so that they can be reused for new allocation requests. - #[allow(clippy::unused_self)] pub fn reset_allocations(&mut self) { self.allocator.reset(); } @@ -259,13 +258,11 @@ impl AsanRuntime { /// Returns the `AsanErrors` from the recent run. /// Will block if some other thread holds on to the `ASAN_ERRORS` Mutex. - #[allow(clippy::unused_self)] pub fn errors(&mut self) -> MutexGuard<'static, AsanErrors> { ASAN_ERRORS.lock().unwrap() } /// Make sure the specified memory is unpoisoned - #[allow(clippy::unused_self)] pub fn unpoison(&mut self, address: usize, size: usize) { self.allocator .map_shadow_for_region(address, address + size, true); @@ -296,7 +293,6 @@ impl AsanRuntime { } /// Unpoison all the memory that is currently mapped with read/write permissions. - #[allow(clippy::unused_self)] pub fn unpoison_all_existing_memory(&mut self) { self.allocator.unpoison_all_existing_memory(); } @@ -312,7 +308,6 @@ impl AsanRuntime { /// Register the current thread with the runtime, implementing shadow memory for its stack and /// tls mappings. - #[allow(clippy::unused_self)] #[cfg(not(target_vendor = "apple"))] pub fn register_thread(&mut self) { let (stack_start, stack_end) = Self::current_stack(); @@ -329,7 +324,6 @@ impl AsanRuntime { } /// Register the current thread with the runtime, implementing shadow memory for its stack mapping. - #[allow(clippy::unused_self)] #[cfg(target_vendor = "apple")] pub fn register_thread(&mut self) { let (stack_start, stack_end) = Self::current_stack(); @@ -459,7 +453,7 @@ impl AsanRuntime { } /// Register the required hooks - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub fn register_hooks(&mut self, gum: &Gum) { let mut interceptor = Interceptor::obtain(gum); let module = Module::obtain(gum); @@ -475,7 +469,7 @@ impl AsanRuntime { let _ = [<$name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap(); - #[allow(non_snake_case)] + #[allow(non_snake_case)] // depends on the values the macro is invoked with unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); @@ -515,7 +509,7 @@ impl AsanRuntime { let _ = [<$lib_ident:snake:upper _ $name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap(); - #[allow(non_snake_case)] + #[expect(non_snake_case)] unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); @@ -545,7 +539,7 @@ impl AsanRuntime { }; } - #[allow(unused_macro_rules)] + #[expect(unused_macro_rules)] macro_rules! hook_func_with_check { //No library case ($name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty) => { @@ -559,7 +553,7 @@ impl AsanRuntime { let _ = [<$name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap_or_else(|e| println!("{:?}", e)); - #[allow(non_snake_case)] + #[allow(non_snake_case)] // depends on the values the macro is invoked with unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); @@ -599,7 +593,7 @@ impl AsanRuntime { let _ = [<$lib_ident:snake:upper _ $name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap_or_else(|e| println!("{:?}", e)); - #[allow(non_snake_case)] + #[expect(non_snake_case)] unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); @@ -1255,8 +1249,8 @@ impl AsanRuntime { } #[cfg(target_arch = "x86_64")] - #[allow(clippy::cast_sign_loss)] - #[allow(clippy::too_many_lines)] + #[expect(clippy::cast_sign_loss)] + #[expect(clippy::too_many_lines)] extern "system" fn handle_trap(&mut self) { self.disable_hooks(); @@ -1326,7 +1320,6 @@ impl AsanRuntime { }; // log::trace!("{:x}", base_value); - #[allow(clippy::option_if_let_else)] let error = if fault_address >= stack_start && fault_address < stack_end { match access_type { Some(typ) => match typ { @@ -1425,8 +1418,8 @@ impl AsanRuntime { } #[cfg(target_arch = "aarch64")] - #[allow(clippy::cast_sign_loss)] // for displacement - #[allow(clippy::too_many_lines)] + #[expect(clippy::cast_sign_loss)] // for displacement + #[expect(clippy::too_many_lines)] extern "system" fn handle_trap(&mut self) { self.disable_hooks(); let mut actual_pc = self.regs[31]; @@ -1470,14 +1463,13 @@ impl AsanRuntime { } }; - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] let fault_address = (self.regs[base_reg as usize] as isize + displacement as isize) as usize; let backtrace = Backtrace::new(); let (stack_start, stack_end) = Self::current_stack(); - #[allow(clippy::option_if_let_else)] let error = if fault_address >= stack_start && fault_address < stack_end { if insn.opcode.to_string().starts_with('l') { AsanError::StackOobRead(( @@ -1549,7 +1541,7 @@ impl AsanRuntime { } #[cfg(target_arch = "x86_64")] - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] fn register_idx(&self, reg: X86Register) -> Option<(u16, u16)> { match reg { X86Register::Eax => Some((0, 32)), @@ -1671,7 +1663,6 @@ impl AsanRuntime { */ #[cfg(target_arch = "x86_64")] - #[allow(clippy::unused_self)] fn generate_shadow_check_blob(&mut self, size: u32) -> Box<[u8]> { let shadow_bit = self.allocator.shadow_bit(); // Rcx, Rax, Rdi, Rdx, Rsi, R8 are used, so we save them in emit_shadow_check @@ -1716,7 +1707,6 @@ impl AsanRuntime { } #[cfg(target_arch = "aarch64")] - #[allow(clippy::unused_self)] fn generate_shadow_check_blob(&mut self, width: u32) -> Box<[u8]> { /*x0 contains the shadow address x0 and x1 are saved by the asan_check @@ -1759,7 +1749,6 @@ impl AsanRuntime { } #[cfg(target_arch = "aarch64")] - #[allow(clippy::unused_self)] fn generate_shadow_check_large_blob(&mut self, width: u32) -> Box<[u8]> { //x0 contains the shadow address //x0 and x1 are saved by the asan_check @@ -1807,9 +1796,6 @@ impl AsanRuntime { // Five registers, Rdi, Rsi, Rdx, Rcx, Rax are saved in emit_shadow_check before entering this function // So we retrieve them after saving other registers #[cfg(target_arch = "x86_64")] - #[allow(clippy::similar_names)] - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::too_many_lines)] fn generate_instrumentation_blobs(&mut self) { let mut ops_report = dynasmrt::VecAssembler::::new(0); dynasm!(ops_report @@ -1897,9 +1883,7 @@ impl AsanRuntime { /// /// Generate the instrumentation blobs for the current arch. #[cfg(target_arch = "aarch64")] - #[allow(clippy::similar_names)] // We allow things like dword and qword - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::too_many_lines)] + #[expect(clippy::cast_possible_wrap)] fn generate_instrumentation_blobs(&mut self) { let mut ops_report = dynasmrt::VecAssembler::::new(0); dynasm!(ops_report @@ -2116,7 +2100,7 @@ impl AsanRuntime { #[cfg(target_arch = "aarch64")] #[must_use] #[inline] - #[allow(clippy::similar_names, clippy::type_complexity)] + #[expect(clippy::similar_names, clippy::type_complexity)] pub fn asan_is_interesting_instruction( decoder: InstDecoder, _address: u64, @@ -2179,7 +2163,7 @@ impl AsanRuntime { // println!("{:?} {}", instr, memory_access_size); //abuse the fact that the last operand is always the mem operand - #[allow(clippy::let_and_return)] + #[expect(clippy::let_and_return)] match instr.operands[operands_len - 1] { Operand::RegRegOffset(reg1, reg2, size, shift, shift_size) => { let ret = Some(( @@ -2216,7 +2200,6 @@ impl AsanRuntime { #[cfg(target_arch = "x86_64")] #[inline] #[must_use] - #[allow(clippy::result_unit_err)] pub fn asan_is_interesting_instruction( decoder: InstDecoder, address: u64, @@ -2280,8 +2263,8 @@ impl AsanRuntime { /// Emits a asan shadow byte check. #[inline] - #[allow(clippy::too_many_lines)] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_lines)] + #[expect(clippy::too_many_arguments)] #[cfg(target_arch = "x86_64")] pub fn emit_shadow_check( &mut self, @@ -2464,7 +2447,7 @@ impl AsanRuntime { /// Emit a shadow memory check into the instruction stream #[cfg(target_arch = "aarch64")] #[inline] - #[allow(clippy::too_many_lines, clippy::too_many_arguments)] + #[expect(clippy::too_many_lines, clippy::too_many_arguments)] pub fn emit_shadow_check( &mut self, _address: u64, @@ -2479,7 +2462,7 @@ impl AsanRuntime { i32::try_from(frida_gum_sys::GUM_RED_ZONE_SIZE).is_ok(), "GUM_RED_ZONE_SIZE is bigger than i32::max" ); - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] let redzone_size = frida_gum_sys::GUM_RED_ZONE_SIZE as i32; let writer = output.writer(); @@ -2571,14 +2554,14 @@ impl AsanRuntime { if extender_encoding != -1 && shift_amount < 0b1000 { // emit add extended register: https://developer.arm.com/documentation/ddi0602/latest/Base-Instructions/ADD--extended-register---Add--extended-register-- - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] writer.put_bytes( &(0x8b210000 | ((extender_encoding as u32) << 13) | (shift_amount << 10)) .to_le_bytes(), ); //add x0, x0, w1, [shift] #[amount] } else if shift_encoding != -1 { //https://developer.arm.com/documentation/ddi0602/2024-03/Base-Instructions/ADD--shifted-register---Add--shifted-register-- add shifted register - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] writer.put_bytes( &(0x8b010000 | ((shift_encoding as u32) << 22) | (shift_amount << 10)) .to_le_bytes(), @@ -2602,10 +2585,9 @@ impl AsanRuntime { 0 }; - #[allow(clippy::comparison_chain)] + #[expect(clippy::comparison_chain)] if displacement < 0 { if displacement > -4096 { - #[allow(clippy::cast_sign_loss)] let displacement = displacement.unsigned_abs(); // Subtract the displacement into x0 writer.put_sub_reg_reg_imm( @@ -2614,7 +2596,6 @@ impl AsanRuntime { u64::from(displacement), ); } else { - #[allow(clippy::cast_sign_loss)] let displacement = displacement.unsigned_abs(); let displacement_hi = displacement / 4096; let displacement_lo = displacement % 4096; @@ -2626,7 +2607,7 @@ impl AsanRuntime { ); //sub x0, x0, #[displacement 4096] } } else if displacement > 0 { - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] let displacement = displacement as u32; if displacement < 4096 { // Add the displacement into x0 diff --git a/libafl_frida/src/asan/errors.rs b/libafl_frida/src/asan/errors.rs index b41b0b42ce..bdd062d262 100644 --- a/libafl_frida/src/asan/errors.rs +++ b/libafl_frida/src/asan/errors.rs @@ -50,7 +50,7 @@ pub(crate) struct AsanReadWriteError { pub backtrace: Backtrace, } -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] #[derive(Debug, Clone, Serialize, Deserialize, SerdeAny)] pub(crate) enum AsanError { OobRead(AsanReadWriteError), @@ -108,7 +108,7 @@ impl AsanError { } /// A struct holding errors that occurred during frida address sanitizer runs -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, SerdeAny)] pub struct AsanErrors { continue_on_error: bool, @@ -153,7 +153,7 @@ impl AsanErrors { } /// Report an error - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub(crate) fn report_error(&mut self, error: AsanError) { let mut out_stream = default_output_stream(); let output = out_stream.as_mut(); @@ -168,7 +168,7 @@ impl AsanErrors { ); })); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " Memory error detected! ").unwrap(); output .set_color(ColorSpec::new().set_fg(Some(Color::Red))) @@ -201,7 +201,7 @@ impl AsanErrors { } output.reset().unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " REGISTERS ").unwrap(); #[cfg(target_arch = "aarch64")] for reg in 0..=30 { @@ -248,7 +248,7 @@ impl AsanErrors { #[cfg(target_arch = "x86_64")] writeln!(output, "rip: 0x{:016x}", error.pc).unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " CODE ").unwrap(); #[cfg(target_arch = "aarch64")] @@ -291,7 +291,7 @@ impl AsanErrors { .print_trace(&error.backtrace, output) .unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap(); let fault_address: i64 = fault_address.try_into().unwrap(); let metadata_address: i64 = error.metadata.address.try_into().unwrap(); @@ -322,7 +322,7 @@ impl AsanErrors { } if error.metadata.freed { - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " FREE INFO ").unwrap(); if let Some(backtrace) = &mut release_site_backtrace { writeln!(output, "free site backtrace:").unwrap(); @@ -357,7 +357,7 @@ impl AsanErrors { writeln!(output, " at 0x{_pc:x}").unwrap(); } - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " REGISTERS ").unwrap(); for reg in 0..29 { let val = cpu_context.reg(reg); @@ -384,7 +384,7 @@ impl AsanErrors { output.reset().unwrap(); backtrace_printer.print_trace(backtrace, output).unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap(); writeln!( output, @@ -405,7 +405,7 @@ impl AsanErrors { backtrace.resolve(); backtrace_printer.print_trace(backtrace, output).unwrap(); } - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " FREE INFO ").unwrap(); if let Some(backtrace) = &mut release_site_backtrace { writeln!(output, "previous free site backtrace:").unwrap(); @@ -422,7 +422,7 @@ impl AsanErrors { writeln!(output, " of {ptr:#016x}").unwrap(); output.reset().unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap(); writeln!( output, @@ -463,7 +463,7 @@ impl AsanErrors { } output.reset().unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " REGISTERS ").unwrap(); #[cfg(target_arch = "aarch64")] @@ -512,7 +512,7 @@ impl AsanErrors { #[cfg(target_arch = "x86_64")] writeln!(output, "Rip: 0x{pc:016x}").unwrap(); - #[allow(clippy::non_ascii_literal)] + #[expect(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " CODE ").unwrap(); #[cfg(target_arch = "aarch64")] @@ -557,7 +557,7 @@ impl AsanErrors { self.errors.push(error); - #[allow(clippy::manual_assert)] + #[expect(clippy::manual_assert)] if !self.continue_on_error { panic!("ASAN: Crashing target!"); } @@ -569,7 +569,7 @@ pub static ASAN_ERRORS: Mutex = Mutex::new(AsanErrors::new(true)); /// An observer for frida address sanitizer `AsanError`s for a `Frida` executor run #[derive(Debug, Serialize, Deserialize)] -#[allow(clippy::unsafe_derive_deserialize)] +#[expect(clippy::unsafe_derive_deserialize)] pub enum AsanErrorsObserver { /// Observer referencing a list behind a [`OwnedPtr`] pointer. Ptr(OwnedPtr), @@ -653,7 +653,6 @@ where S: State + Debug, OT: MatchNameRef, { - #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, diff --git a/libafl_frida/src/asan/hook_funcs.rs b/libafl_frida/src/asan/hook_funcs.rs index 3d5a122f61..d7e391c5b5 100644 --- a/libafl_frida/src/asan/hook_funcs.rs +++ b/libafl_frida/src/asan/hook_funcs.rs @@ -1,5 +1,3 @@ -#![allow(clippy::used_underscore_items)] - //! The allocator hooks for address sanitizer. use std::ffi::c_void; @@ -22,7 +20,7 @@ extern "system" { extern "system" { fn memset(s: *mut c_void, c: i32, n: usize) -> *mut c_void; } -#[allow(clippy::not_unsafe_ptr_arg_deref)] +#[expect(clippy::not_unsafe_ptr_arg_deref)] impl AsanRuntime { #[inline] #[allow(non_snake_case)] @@ -65,7 +63,7 @@ impl AsanRuntime { ) } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_CreateFileMappingW( &mut self, @@ -95,7 +93,7 @@ impl AsanRuntime { ) } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LdrLoadDll( &mut self, @@ -118,7 +116,7 @@ impl AsanRuntime { result } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LdrpCallInitRoutine( &mut self, @@ -140,7 +138,7 @@ impl AsanRuntime { 0 } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LoadLibraryExW( &mut self, @@ -157,7 +155,7 @@ impl AsanRuntime { } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlCreateHeap( &mut self, @@ -179,7 +177,7 @@ impl AsanRuntime { 0xc0debeef as *mut c_void } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlDestroyHeap( &mut self, @@ -190,7 +188,7 @@ impl AsanRuntime { } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_HeapAlloc( &mut self, @@ -213,7 +211,7 @@ impl AsanRuntime { ret } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlAllocateHeap( &mut self, @@ -236,7 +234,7 @@ impl AsanRuntime { ret } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_HeapReAlloc( &mut self, @@ -280,7 +278,7 @@ impl AsanRuntime { ret } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlReAllocateHeap( &mut self, @@ -325,7 +323,7 @@ impl AsanRuntime { ret } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_RtlFreeHeap( &mut self, @@ -336,7 +334,7 @@ impl AsanRuntime { self.allocator_mut().is_managed(ptr) } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlFreeHeap( &mut self, @@ -349,7 +347,7 @@ impl AsanRuntime { 0 } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_HeapFree( &mut self, @@ -360,7 +358,7 @@ impl AsanRuntime { self.allocator_mut().is_managed(ptr) } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_HeapFree( &mut self, @@ -373,7 +371,7 @@ impl AsanRuntime { true } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_HeapSize( &mut self, @@ -384,7 +382,7 @@ impl AsanRuntime { self.allocator_mut().is_managed(ptr) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_HeapSize( &mut self, @@ -396,7 +394,7 @@ impl AsanRuntime { self.allocator().get_usable_size(ptr) } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_RtlSizeHeap( &mut self, @@ -407,7 +405,7 @@ impl AsanRuntime { self.allocator_mut().is_managed(ptr) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlSizeHeap( &mut self, @@ -419,7 +417,7 @@ impl AsanRuntime { self.allocator().get_usable_size(ptr) } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_RtlValidateHeap( &mut self, @@ -430,7 +428,7 @@ impl AsanRuntime { self.allocator_mut().is_managed(ptr) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_RtlValidateHeap( &mut self, @@ -442,7 +440,7 @@ impl AsanRuntime { true } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalAlloc( &mut self, @@ -459,7 +457,7 @@ impl AsanRuntime { } ret } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalReAlloc( &mut self, @@ -479,14 +477,14 @@ impl AsanRuntime { ret } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_LocalFree(&mut self, mem: *mut c_void) -> bool { let res = self.allocator_mut().is_managed(mem); res } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalFree( &mut self, @@ -497,12 +495,12 @@ impl AsanRuntime { mem } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_LocalHandle(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalHandle( &mut self, @@ -511,13 +509,13 @@ impl AsanRuntime { ) -> *mut c_void { mem } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_LocalLock(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalLock( &mut self, @@ -526,12 +524,12 @@ impl AsanRuntime { ) -> *mut c_void { mem } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_LocalUnlock(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalUnlock( &mut self, @@ -540,12 +538,12 @@ impl AsanRuntime { ) -> bool { false } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_LocalSize(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalSize( &mut self, @@ -554,12 +552,12 @@ impl AsanRuntime { ) -> usize { self.allocator_mut().get_usable_size(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_LocalFlags(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_LocalFlags( &mut self, @@ -569,7 +567,7 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalAlloc( &mut self, @@ -589,7 +587,7 @@ impl AsanRuntime { } ret } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalReAlloc( &mut self, @@ -609,12 +607,12 @@ impl AsanRuntime { ret } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_GlobalFree(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalFree( &mut self, @@ -625,12 +623,12 @@ impl AsanRuntime { mem } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_GlobalHandle(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalHandle( &mut self, @@ -639,13 +637,13 @@ impl AsanRuntime { ) -> *mut c_void { mem } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_GlobalLock(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalLock( &mut self, @@ -654,12 +652,12 @@ impl AsanRuntime { ) -> *mut c_void { mem } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_GlobalUnlock(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalUnlock( &mut self, @@ -668,12 +666,12 @@ impl AsanRuntime { ) -> bool { false } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_GlobalSize(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalSize( &mut self, @@ -682,12 +680,12 @@ impl AsanRuntime { ) -> usize { self.allocator_mut().get_usable_size(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_check_GlobalFlags(&mut self, mem: *mut c_void) -> bool { self.allocator_mut().is_managed(mem) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_GlobalFlags( &mut self, @@ -715,7 +713,7 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, 8) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__Znam( &mut self, @@ -725,7 +723,7 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, 8) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__ZnamRKSt9nothrow_t( &mut self, @@ -736,7 +734,7 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, 8) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__ZnamSt11align_val_t( &mut self, @@ -747,7 +745,7 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, alignment) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__ZnamSt11align_val_tRKSt9nothrow_t( &mut self, @@ -763,7 +761,9 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, alignment) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] + #[allow(unknown_lints)] // the compiler is contradicting itself + #[expect(clippy::used_underscore_items)] #[inline] pub fn hook__Znwm( &mut self, @@ -785,7 +785,7 @@ impl AsanRuntime { } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__ZnwmRKSt9nothrow_t( &mut self, @@ -796,7 +796,9 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, 8) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] + #[allow(unknown_lints)] // the compiler is contradicting itself + #[expect(clippy::used_underscore_items)] #[inline] pub fn hook__ZnwmSt11align_val_t( &mut self, @@ -817,7 +819,7 @@ impl AsanRuntime { result } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__ZnwmSt11align_val_tRKSt9nothrow_t( &mut self, @@ -833,7 +835,7 @@ impl AsanRuntime { unsafe { self.allocator_mut().alloc(size, alignment) } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__o_malloc( &mut self, @@ -859,7 +861,7 @@ impl AsanRuntime { ret } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook__o_calloc( &mut self, @@ -877,9 +879,8 @@ impl AsanRuntime { ret } - #[allow(non_snake_case)] #[inline] - #[allow(clippy::cmp_null)] + #[expect(clippy::cmp_null)] pub fn hook_realloc( &mut self, _original: extern "C" fn(ptr: *mut c_void, size: usize) -> *mut c_void, @@ -898,9 +899,9 @@ impl AsanRuntime { } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] - #[allow(clippy::cmp_null)] + #[expect(clippy::cmp_null)] pub fn hook__o_realloc( &mut self, _original: extern "C" fn(ptr: *mut c_void, size: usize) -> *mut c_void, @@ -919,15 +920,15 @@ impl AsanRuntime { } } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] pub fn hook_check__o_free(&mut self, ptr: *mut c_void) -> bool { self.allocator_mut().is_managed(ptr) } - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[inline] - #[allow(clippy::cmp_null)] + #[expect(clippy::cmp_null)] pub fn hook__o_free( &mut self, _original: extern "C" fn(ptr: *mut c_void) -> usize, @@ -944,7 +945,7 @@ impl AsanRuntime { } #[inline] - #[allow(clippy::cmp_null)] + #[expect(clippy::cmp_null)] pub fn hook_free( &mut self, _original: extern "C" fn(ptr: *mut c_void) -> usize, @@ -992,7 +993,7 @@ impl AsanRuntime { } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] #[cfg(windows)] pub fn hook_MapViewOfFile( &mut self, @@ -1020,8 +1021,8 @@ impl AsanRuntime { ret } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdaPv( &mut self, @@ -1034,8 +1035,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdaPvm( &mut self, @@ -1049,8 +1050,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdaPvmSt11align_val_t( &mut self, @@ -1065,8 +1066,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdaPvRKSt9nothrow_t( &mut self, @@ -1080,8 +1081,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdaPvSt11align_val_tRKSt9nothrow_t( &mut self, @@ -1100,8 +1101,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdaPvSt11align_val_t( &mut self, @@ -1115,8 +1116,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdlPv( &mut self, @@ -1129,8 +1130,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdlPvm( &mut self, @@ -1144,8 +1145,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdlPvmSt11align_val_t( &mut self, @@ -1160,8 +1161,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdlPvRKSt9nothrow_t( &mut self, @@ -1175,8 +1176,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdlPvSt11align_val_tRKSt9nothrow_t( &mut self, @@ -1195,8 +1196,8 @@ impl AsanRuntime { 0 } - #[allow(non_snake_case)] - #[allow(clippy::cmp_null)] + #[expect(non_snake_case)] + #[expect(clippy::cmp_null)] #[inline] pub fn hook__ZdlPvSt11align_val_t( &mut self, @@ -1211,7 +1212,7 @@ impl AsanRuntime { } #[inline] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn hook_mmap( &mut self, original: extern "C" fn( @@ -1254,7 +1255,7 @@ impl AsanRuntime { } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] pub fn hook__write( &mut self, original: extern "C" fn(fd: i32, buf: *const c_void, count: usize) -> usize, @@ -1285,7 +1286,7 @@ impl AsanRuntime { } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] pub fn hook__read( &mut self, original: extern "C" fn(fd: i32, buf: *mut c_void, count: usize) -> usize, @@ -1952,7 +1953,7 @@ impl AsanRuntime { } #[inline] - #[allow(non_snake_case)] + #[expect(non_snake_case)] pub fn hook__strdup( &mut self, original: extern "C" fn(s: *const c_char) -> *mut c_char, diff --git a/libafl_frida/src/asan/mod.rs b/libafl_frida/src/asan/mod.rs index 040461d325..cb63dc3875 100644 --- a/libafl_frida/src/asan/mod.rs +++ b/libafl_frida/src/asan/mod.rs @@ -1,5 +1,6 @@ //! Address sanitization using [`frida`](https://frida.re/) pub mod asan_rt; pub mod errors; -#[allow(missing_docs)] + +#[allow(missing_docs)] // cfg dependent pub mod hook_funcs; diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index 7e9e8fa724..687ab5ce8e 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -62,7 +62,7 @@ use yaxpeax_x86::long_mode::InstDecoder; /// # Panic /// In debug mode, will panic on wraparound (which should never happen in practice) #[cfg(all(feature = "cmplog", target_arch = "aarch64"))] -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] fn gum_red_zone_size_i32() -> i32 { debug_assert!( i32::try_from(frida_gum_sys::GUM_RED_ZONE_SIZE).is_ok(), @@ -161,7 +161,7 @@ impl CmpLogRuntime { } /// Call the external function that populates the `cmplog_map` with the relevant values - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] #[cfg(target_arch = "aarch64")] extern "C" fn populate_lists(&mut self, op1: u64, op2: u64, retaddr: u64) { // log::trace!( @@ -177,7 +177,6 @@ impl CmpLogRuntime { } } - #[allow(clippy::unused_self)] #[cfg(target_arch = "x86_64")] extern "C" fn populate_lists(size: u8, op1: u64, op2: u64, retaddr: u64) { // log::trace!( @@ -194,7 +193,7 @@ impl CmpLogRuntime { } /// Generate the instrumentation blobs for the current arch. - #[allow(clippy::similar_names)] + #[expect(clippy::similar_names)] #[cfg(target_arch = "aarch64")] fn generate_instrumentation_blobs(&mut self) { macro_rules! blr_to_populate { @@ -307,7 +306,7 @@ impl CmpLogRuntime { ); } - #[allow(clippy::similar_names)] + #[expect(clippy::similar_names)] #[cfg(all(windows, target_arch = "x86_64"))] fn generate_instrumentation_blobs(&mut self) { macro_rules! save_registers { @@ -343,7 +342,6 @@ impl CmpLogRuntime { self.restore_registers = Some(restore_registers.finalize().unwrap().into_boxed_slice()); } - #[allow(clippy::similar_names)] #[cfg(all(unix, target_arch = "x86_64"))] fn generate_instrumentation_blobs(&mut self) { macro_rules! save_registers { @@ -405,7 +403,7 @@ impl CmpLogRuntime { /// Emit the instrumentation code which is responsible for operands value extraction and cmplog map population #[cfg(all(feature = "cmplog", target_arch = "x86_64"))] - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] #[inline] pub fn emit_comparison_handling( &self, @@ -557,7 +555,7 @@ impl CmpLogRuntime { /// Emit the instrumentation code which is responsible for operands value extraction and cmplog map population #[cfg(all(feature = "cmplog", target_arch = "aarch64"))] - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] #[inline] pub fn emit_comparison_handling( &self, @@ -639,7 +637,6 @@ impl CmpLogRuntime { } #[cfg(all(feature = "cmplog", target_arch = "x86_64"))] - #[allow(clippy::similar_names)] #[inline] /// Check if the current instruction is cmplog relevant one(any opcode which sets the flags) #[must_use] @@ -692,7 +689,7 @@ impl CmpLogRuntime { OpKind::Memory => { // can't use try_into here, since we need to cast u64 to i64 // which is fine in this case - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] CmplogOperandType::Mem( instruction.memory_base(), instruction.memory_index(), @@ -714,7 +711,7 @@ impl CmpLogRuntime { | OpKind::Immediate32to64 => CmplogOperandType::Imm(instruction.immediate(1)), OpKind::Memory => { - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] CmplogOperandType::Mem( instruction.memory_base(), instruction.memory_index(), @@ -747,7 +744,7 @@ impl CmpLogRuntime { } #[cfg(all(feature = "cmplog", target_arch = "aarch64"))] - #[allow(clippy::similar_names, clippy::type_complexity)] + #[expect(clippy::similar_names, clippy::type_complexity)] #[inline] /// Check if the current instruction is cmplog relevant one(any opcode which sets the flags) #[must_use] @@ -821,10 +818,10 @@ impl CmpLogRuntime { } // cbz marked as special since there is only 1 operand - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] let special_case = matches!(instr.opcode, Opcode::CBZ | Opcode::CBNZ); - #[allow(clippy::cast_sign_loss, clippy::similar_names)] + #[expect(clippy::cast_sign_loss, clippy::similar_names)] let operand1 = match instr.operands[0] { //the only possibilities are registers for the first operand //precompute the aarch64 frida register because it is ambiguous if register=31 means xzr or sp in yaxpeax @@ -837,7 +834,7 @@ impl CmpLogRuntime { _ => panic!("First argument is not a register"), //this should never be possible in arm64 }; - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] let operand2 = if special_case { Some((CmplogOperandType::Imm(0), None)) } else { diff --git a/libafl_frida/src/coverage_rt.rs b/libafl_frida/src/coverage_rt.rs index 3a6226b6de..f73a78ea17 100644 --- a/libafl_frida/src/coverage_rt.rs +++ b/libafl_frida/src/coverage_rt.rs @@ -55,8 +55,8 @@ impl FridaRuntime for CoverageRuntime { impl CoverageRuntime { /// Create a new coverage runtime - #[must_use] #[allow(clippy::large_stack_arrays)] + #[must_use] pub fn new() -> Self { Self(Rc::pin(RefCell::new(CoverageRuntimeInner { map: [0_u8; MAP_SIZE], @@ -74,7 +74,7 @@ impl CoverageRuntime { /// every time we need a copy that is within a direct branch of the start of the transformed basic /// block. #[cfg(target_arch = "aarch64")] - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] pub fn generate_inline_code(&mut self, h64: u64) -> Box<[u8]> { let mut borrow = self.0.borrow_mut(); let prev_loc_ptr = &raw mut borrow.previous_pc; diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 5c03edb6c0..d7148a6a7b 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -141,7 +141,7 @@ pub enum SkipRange { pub struct FridaInstrumentationHelperBuilder { stalker_enabled: bool, disable_excludes: bool, - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] instrument_module_predicate: Option bool>>, skip_module_predicate: Box bool>, skip_ranges: Vec, @@ -488,7 +488,6 @@ where println!("msg: {msg:}, bytes: {bytes:x?}"); } - #[allow(clippy::too_many_lines)] fn build_transformer( gum: &'a Gum, ranges: &Rc>>, @@ -508,7 +507,7 @@ where }) } - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn transform( basic_block: StalkerIterator, output: &StalkerOutput, diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index acc6a148be..aa4ad95744 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -24,26 +24,22 @@ Additional documentation is available in [the `LibAFL` book](https://aflplus.plu unused_extern_crates, unused_import_braces, unused_qualifications, + unfulfilled_lint_expectations, unused_must_use, - //unused_results -))] -#![cfg_attr( - test, - deny( - bad_style, - dead_code, - improper_ctypes, - non_shorthand_field_patterns, - no_mangle_generic_items, - overflowing_literals, - path_statements, - patterns_in_fns_without_body, - unconditional_recursion, - unused, - unused_allocation, - unused_comparisons, - unused_parens, - while_true + bad_style, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + unconditional_recursion, + unused, + unused_allocation, + unused_comparisons, + unused_parens, + while_true ) )] @@ -81,7 +77,7 @@ pub mod utils; use libafl_bolts::core_affinity::{get_core_ids, CoreId, Cores}; /// A representation of the various Frida options #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] pub struct FridaOptions { enable_asan: bool, enable_asan_leak_detection: bool, @@ -104,7 +100,7 @@ impl FridaOptions { /// # Panics /// Panics, if no `=` sign exists in input, or or `value` behind `=` has zero length. #[must_use] - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] pub fn parse_env_options() -> Self { let mut options = Self::default(); let mut asan_cores = None; @@ -370,7 +366,7 @@ mod tests { static GUM: OnceLock = OnceLock::new(); - #[allow(clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] unsafe fn test_asan(options: &FuzzerOptions) { // The names of the functions to run let tests = vec![ diff --git a/libafl_frida/src/pthread_hook.rs b/libafl_frida/src/pthread_hook.rs index 284a7bcdaa..f6c83d8b7d 100644 --- a/libafl_frida/src/pthread_hook.rs +++ b/libafl_frida/src/pthread_hook.rs @@ -5,7 +5,7 @@ const PTHREAD_INTROSPECTION_THREAD_START: libc::c_uint = 2; const PTHREAD_INTROSPECTION_THREAD_TERMINATE: libc::c_uint = 3; const PTHREAD_INTROSPECTION_THREAD_DESTROY: libc::c_uint = 4; -#[allow(non_camel_case_types)] +#[expect(non_camel_case_types)] type pthread_introspection_hook_t = extern "C" fn( event: libc::c_uint, thread: libc::pthread_t, diff --git a/libafl_frida/src/utils.rs b/libafl_frida/src/utils.rs index 364b32a527..2b59e366d9 100644 --- a/libafl_frida/src/utils.rs +++ b/libafl_frida/src/utils.rs @@ -192,7 +192,6 @@ pub fn get_register(context: &CpuContext, reg: X86Register) -> u64 { #[cfg(target_arch = "x86_64")] #[must_use] #[inline] -#[allow(clippy::unused_self)] pub fn writer_register(reg: RegSpec) -> X86Register { for (reg1, reg2) in &X86_64_REGS { // println!("reg1:{:#?} reg2:{:#?}", reg1, reg); @@ -277,7 +276,7 @@ pub fn immediate_value(operand: &Operand) -> Option { Operand::ImmediateI32 { imm } => Some(i64::from(*imm)), Operand::ImmediateU32 { imm } => Some(i64::from(*imm)), Operand::ImmediateI64 { imm } => Some(*imm), - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] Operand::ImmediateU64 { imm } => Some(*imm as i64), _ => None, } diff --git a/libafl_libfuzzer/build.rs b/libafl_libfuzzer/build.rs index 1293fe89b6..46342c7405 100644 --- a/libafl_libfuzzer/build.rs +++ b/libafl_libfuzzer/build.rs @@ -13,7 +13,7 @@ const NAMESPACE: &str = "🐇"; const NAMESPACE: &str = "__libafl"; const NAMESPACE_LEN: usize = NAMESPACE.len(); -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn main() -> Result<(), Box> { if cfg!(any(clippy, docsrs)) { return Ok(()); // skip when clippy or docs is running diff --git a/libafl_libfuzzer/runtime/build.rs b/libafl_libfuzzer/runtime/build.rs index f3926213dc..619ad9b3fe 100644 --- a/libafl_libfuzzer/runtime/build.rs +++ b/libafl_libfuzzer/runtime/build.rs @@ -1,6 +1,6 @@ use std::{env, path::Path}; -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); diff --git a/libafl_libfuzzer/runtime/src/lib.rs b/libafl_libfuzzer/runtime/src/lib.rs index 36096e05df..e7331d660b 100644 --- a/libafl_libfuzzer/runtime/src/lib.rs +++ b/libafl_libfuzzer/runtime/src/lib.rs @@ -107,7 +107,7 @@ mod harness_wrap { pub(crate) use harness_wrap::libafl_libfuzzer_test_one_input; -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] struct CustomMutationStatus { std_mutational: bool, std_no_mutate: bool, @@ -512,11 +512,11 @@ macro_rules! fuzz_with { grimoire, ); - #[allow(clippy::unnecessary_mut_passed)] // the functions may not require these many `mut`s + #[expect(clippy::unnecessary_mut_passed)] // the functions may not require these many `mut`s $operation(&$options, &mut fuzzer, &mut stages, &mut executor, &mut state, &mut mgr) }; - #[allow(clippy::redundant_closure_call)] + #[expect(clippy::redundant_closure_call)] $and_then(closure) }}; @@ -592,7 +592,7 @@ pub const STDERR_FD_VAR: &str = "_LIBAFL_LIBFUZZER_STDERR_FD"; /// Will dereference all parameters. /// This will then call the (potentially unsafe) harness. /// The fuzzer itself should catch any side effects and, hence be reasonably safe, if the `harness_fn` parameter is correct. -#[allow(non_snake_case, clippy::similar_names, clippy::missing_safety_doc)] +#[expect(non_snake_case, clippy::similar_names, clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn LLVMFuzzerRunDriver( argc: *mut c_int, diff --git a/libafl_libfuzzer/runtime/src/merge.rs b/libafl_libfuzzer/runtime/src/merge.rs index 506e0a2e41..c5400a6a27 100644 --- a/libafl_libfuzzer/runtime/src/merge.rs +++ b/libafl_libfuzzer/runtime/src/merge.rs @@ -36,7 +36,7 @@ use crate::{ schedulers::MergeScheduler, }; -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub fn merge( options: &LibfuzzerOptions, harness: &extern "C" fn(*const u8, usize) -> c_int, @@ -236,7 +236,7 @@ pub fn merge( .on_remove(&mut state, id, &Some(testcase))?; } else { // False-positive: file_path is used just below - #[allow(clippy::needless_borrows_for_generic_args)] + #[expect(clippy::needless_borrows_for_generic_args)] rename(&file_path, &new_file_path)?; *file_path = new_file_path; } diff --git a/libafl_libfuzzer/runtime/src/options.rs b/libafl_libfuzzer/runtime/src/options.rs index 8126c50aa4..656422480c 100644 --- a/libafl_libfuzzer/runtime/src/options.rs +++ b/libafl_libfuzzer/runtime/src/options.rs @@ -100,7 +100,7 @@ impl Default for ArtifactPrefix { } #[derive(Debug, Clone)] -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] pub struct LibfuzzerOptions { fuzzer_name: String, mode: LibfuzzerMode, @@ -234,7 +234,7 @@ impl LibfuzzerOptions { } #[derive(Debug, Default)] -#[allow(clippy::struct_excessive_bools)] +#[expect(clippy::struct_excessive_bools)] struct LibfuzzerOptionsBuilder<'a> { mode: Option, artifact_prefix: Option<&'a str>, diff --git a/libafl_libfuzzer/runtime/src/report.rs b/libafl_libfuzzer/runtime/src/report.rs index 8c22b28bde..e196fcd267 100644 --- a/libafl_libfuzzer/runtime/src/report.rs +++ b/libafl_libfuzzer/runtime/src/report.rs @@ -13,7 +13,7 @@ use libafl::{ use crate::{fuzz_with, options::LibfuzzerOptions}; -#[allow(clippy::unnecessary_wraps, clippy::cast_precision_loss)] +#[expect(clippy::unnecessary_wraps, clippy::cast_precision_loss)] fn do_report( _options: &LibfuzzerOptions, _fuzzer: &mut F, diff --git a/libafl_libfuzzer/src/lib.rs b/libafl_libfuzzer/src/lib.rs index 188d9be378..057c831c86 100644 --- a/libafl_libfuzzer/src/lib.rs +++ b/libafl_libfuzzer/src/lib.rs @@ -94,25 +94,21 @@ unused_import_braces, unused_qualifications, unused_must_use, - //unused_results -))] -#![cfg_attr( - test, - deny( - bad_style, - dead_code, - improper_ctypes, - non_shorthand_field_patterns, - no_mangle_generic_items, - overflowing_literals, - path_statements, - patterns_in_fns_without_body, - unconditional_recursion, - unused, - unused_allocation, - unused_comparisons, - unused_parens, - while_true + unfulfilled_lint_expectations, + bad_style, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + unconditional_recursion, + unused, + unused_allocation, + unused_comparisons, + unused_parens, + while_true ) )] diff --git a/libafl_libfuzzer_runtime/build.rs b/libafl_libfuzzer_runtime/build.rs index f3926213dc..cfffcfc9c7 100644 --- a/libafl_libfuzzer_runtime/build.rs +++ b/libafl_libfuzzer_runtime/build.rs @@ -1,6 +1,5 @@ use std::{env, path::Path}; -#[allow(clippy::too_many_lines)] fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); diff --git a/libafl_qemu/build_linux.rs b/libafl_qemu/build_linux.rs index 239ec2ede2..bbe796047e 100644 --- a/libafl_qemu/build_linux.rs +++ b/libafl_qemu/build_linux.rs @@ -13,7 +13,7 @@ static LIBAFL_QEMU_RUNTIME_TEST: &str = r#" void __libafl_qemu_testfile() {} "#; -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub fn build() { // Note: Unique features are checked in libafl_qemu_sys println!( @@ -133,7 +133,6 @@ pub fn build() { .expect("Could not copy libafl_qemu.h to out directory."); fs::copy( - libafl_qemu_arch_hdr.clone(), include_dir.join(libafl_qemu_arch_hdr_name), ) diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index 9b854d34f5..70c17de121 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -13,7 +13,6 @@ pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; pub const QEMU_REVISION: &str = "06bf8facec33548840413fba1b20858f58e38e2d"; -#[allow(clippy::module_name_repetitions)] pub struct BuildResult { pub qemu_path: PathBuf, pub build_dir: PathBuf, @@ -59,7 +58,7 @@ fn get_config_signature(config_cmd: &Command) -> String { signature_string } -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn configure_qemu( cc_compiler: &cc::Tool, cpp_compiler: &cc::Tool, @@ -245,7 +244,7 @@ fn build_qemu( cmd } -#[allow(clippy::too_many_lines, clippy::missing_panics_doc)] +#[expect(clippy::too_many_lines, clippy::missing_panics_doc)] #[must_use] pub fn build( cpu_target: &str, diff --git a/libafl_qemu/libafl_qemu_build/src/lib.rs b/libafl_qemu/libafl_qemu_build/src/lib.rs index 57445cfe46..b51076c9b1 100644 --- a/libafl_qemu/libafl_qemu_build/src/lib.rs +++ b/libafl_qemu/libafl_qemu_build/src/lib.rs @@ -386,7 +386,6 @@ pub fn store_generated_content_if_different( //} #[rustversion::nightly] -#[allow(unused)] pub fn maybe_generate_stub_bindings( cpu_target: &str, emulation_mode: &str, diff --git a/libafl_qemu/libafl_qemu_sys/src/lib.rs b/libafl_qemu/libafl_qemu_sys/src/lib.rs index 8c524fe5bf..4f1bc18138 100644 --- a/libafl_qemu/libafl_qemu_sys/src/lib.rs +++ b/libafl_qemu/libafl_qemu_sys/src/lib.rs @@ -53,14 +53,14 @@ macro_rules! extern_c_checked { ($visibility:vis static $c_var:ident : $c_var_ty:ty; $($tail:tt)*) => { paste! { - #[allow(non_camel_case_types)] - #[allow(unused)] + #[expect(non_camel_case_types)] + #[expect(unused)] struct [<__ $c_var:upper _STRUCT__>] { member: *const $c_var_ty } unsafe impl Sync for [<__ $c_var:upper _STRUCT__>] {} #[cfg_attr(nightly, used(linker))] - #[allow(unused_unsafe)] + #[expect(unused_unsafe)] static [<__ $c_var:upper __>]: [<__ $c_var:upper _STRUCT__>] = unsafe { [<__ $c_var:upper _STRUCT__>] { member: &raw const $c_var } }; } @@ -73,14 +73,14 @@ macro_rules! extern_c_checked { ($visibility:vis static mut $c_var:ident : $c_var_ty:ty; $($tail:tt)*) => { paste! { - #[allow(non_camel_case_types)] - #[allow(unused)] + #[expect(non_camel_case_types)] + #[expect(unused)] struct [<__ $c_var:upper _STRUCT__>] { member: *const $c_var_ty } unsafe impl Sync for [<__ $c_var:upper _STRUCT__>] {} #[cfg_attr(nightly, used(linker))] - #[allow(unused_unsafe)] + #[expect(unused_unsafe)] static mut [<__ $c_var:upper __>]: [<__ $c_var:upper _STRUCT__>] = unsafe { [<__ $c_var:upper _STRUCT__>] { member: &raw const $c_var } }; } diff --git a/libafl_qemu/src/arch/aarch64.rs b/libafl_qemu/src/arch/aarch64.rs index f68fe27b35..aad7624b14 100644 --- a/libafl_qemu/src/arch/aarch64.rs +++ b/libafl_qemu/src/arch/aarch64.rs @@ -67,7 +67,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Fp: Regs = Regs::X29; pub const Lr: Regs = Regs::X30; diff --git a/libafl_qemu/src/arch/arm.rs b/libafl_qemu/src/arch/arm.rs index 18955bb964..ad7918f412 100644 --- a/libafl_qemu/src/arch/arm.rs +++ b/libafl_qemu/src/arch/arm.rs @@ -51,7 +51,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Sp: Regs = Regs::R13; pub const Lr: Regs = Regs::R14; diff --git a/libafl_qemu/src/arch/hexagon.rs b/libafl_qemu/src/arch/hexagon.rs index 113313dd6c..479ff2588e 100644 --- a/libafl_qemu/src/arch/hexagon.rs +++ b/libafl_qemu/src/arch/hexagon.rs @@ -82,7 +82,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Sp: Regs = Regs::R29; pub const Fp: Regs = Regs::R30; diff --git a/libafl_qemu/src/arch/i386.rs b/libafl_qemu/src/arch/i386.rs index 56bbd28562..239010bf9d 100644 --- a/libafl_qemu/src/arch/i386.rs +++ b/libafl_qemu/src/arch/i386.rs @@ -43,7 +43,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Sp: Regs = Regs::Esp; pub const Pc: Regs = Regs::Eip; diff --git a/libafl_qemu/src/arch/mips.rs b/libafl_qemu/src/arch/mips.rs index f770b96817..e9adfc714c 100644 --- a/libafl_qemu/src/arch/mips.rs +++ b/libafl_qemu/src/arch/mips.rs @@ -67,7 +67,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Zero: Regs = Regs::R0; } diff --git a/libafl_qemu/src/arch/ppc.rs b/libafl_qemu/src/arch/ppc.rs index 4bc7a64cb8..373d0e15c8 100644 --- a/libafl_qemu/src/arch/ppc.rs +++ b/libafl_qemu/src/arch/ppc.rs @@ -106,7 +106,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Pc: Regs = Regs::Nip; pub const Sp: Regs = Regs::R1; diff --git a/libafl_qemu/src/arch/riscv.rs b/libafl_qemu/src/arch/riscv.rs index 99daa56f4b..8dc4bac0a2 100644 --- a/libafl_qemu/src/arch/riscv.rs +++ b/libafl_qemu/src/arch/riscv.rs @@ -13,11 +13,11 @@ pub use syscall_numbers::riscv32::*; pub use syscall_numbers::riscv64::*; // QEMU specific -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] pub const SYS_syscalls: c_long = 447; -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] pub const SYS_riscv_flush_icache: c_long = SYS_arch_specific_syscall + 15; -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] pub const SYS_riscv_hwprobe: c_long = SYS_arch_specific_syscall + 14; use crate::{sync_exit::ExitArgs, CallingConvention, QemuRWError, QemuRWErrorKind}; diff --git a/libafl_qemu/src/arch/x86_64.rs b/libafl_qemu/src/arch/x86_64.rs index 119c5a9c62..0fbf62019f 100644 --- a/libafl_qemu/src/arch/x86_64.rs +++ b/libafl_qemu/src/arch/x86_64.rs @@ -49,7 +49,7 @@ pub fn get_exit_arch_regs() -> &'static EnumMap { } /// alias registers -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals)] impl Regs { pub const Sp: Regs = Regs::Rsp; pub const Pc: Regs = Regs::Rip; diff --git a/libafl_qemu/src/command/mod.rs b/libafl_qemu/src/command/mod.rs index ae87cfcc3f..f107171a19 100644 --- a/libafl_qemu/src/command/mod.rs +++ b/libafl_qemu/src/command/mod.rs @@ -231,7 +231,7 @@ where /// - `ret_reg`: The register in which the guest return value should be written, if any. /// Returns /// - `InnerHandlerResult`: How the high-level handler should behave - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] fn run( &self, emu: &mut Emulator, @@ -592,7 +592,7 @@ where ) -> Result>, EmulatorDriverError> { emu.modules_mut() .modules_mut() - .allow_page_id_all(self.page_id.clone()); + .allow_page_id_all(self.page_id); Ok(None) } } diff --git a/libafl_qemu/src/command/parser.rs b/libafl_qemu/src/command/parser.rs index 97914b266d..8183cafb4a 100644 --- a/libafl_qemu/src/command/parser.rs +++ b/libafl_qemu/src/command/parser.rs @@ -276,7 +276,7 @@ where type OutputCommand = LqprintfCommand; const COMMAND_ID: c_uint = bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_LQPRINTF.0; - #[allow(clippy::uninit_vec)] + #[expect(clippy::uninit_vec)] fn parse( qemu: Qemu, arch_regs_map: &'static EnumMap, @@ -316,7 +316,6 @@ where type OutputCommand = TestCommand; const COMMAND_ID: c_uint = bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_TEST.0; - #[allow(clippy::cast_sign_loss)] fn parse( qemu: Qemu, arch_regs_map: &'static EnumMap, diff --git a/libafl_qemu/src/emu/builder.rs b/libafl_qemu/src/emu/builder.rs index 67396d2c10..6adb97c12a 100644 --- a/libafl_qemu/src/emu/builder.rs +++ b/libafl_qemu/src/emu/builder.rs @@ -60,7 +60,7 @@ where S::Input: HasTargetBytes, { #[must_use] - #[allow(clippy::should_implement_trait)] + #[expect(clippy::should_implement_trait)] pub fn default() -> Self { Self { modules: tuple_list!(), @@ -79,6 +79,8 @@ where S: State + HasExecutions + Unpin, S::Input: HasTargetBytes, { + #[expect(clippy::should_implement_trait)] + #[must_use] pub fn default() -> Self { Self { modules: (), diff --git a/libafl_qemu/src/emu/drivers.rs b/libafl_qemu/src/emu/drivers.rs index 0fe0c6f161..41ccda5e50 100644 --- a/libafl_qemu/src/emu/drivers.rs +++ b/libafl_qemu/src/emu/drivers.rs @@ -85,7 +85,7 @@ where fn pre_qemu_exec(_emulator: &mut Emulator, _input: &S::Input) {} /// Just after QEMU exits - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] fn post_qemu_exec( _emulator: &mut Emulator, _state: &mut S, @@ -109,7 +109,7 @@ where } #[derive(Clone, Debug, Default, TypedBuilder)] -#[allow(clippy::struct_excessive_bools)] +#[allow(clippy::struct_excessive_bools)] // cfg dependent pub struct StdEmulatorDriver { #[builder(default = OnceCell::new())] snapshot_id: OnceCell, @@ -233,7 +233,6 @@ where }, }; - #[allow(clippy::type_complexity)] let (command, ret_reg): (Option, Option) = match &mut exit_reason { EmulatorExitResult::QemuExit(shutdown_cause) => match shutdown_cause { QemuShutdownCause::HostSignal(signal) => { diff --git a/libafl_qemu/src/emu/hooks.rs b/libafl_qemu/src/emu/hooks.rs index bb07522b60..6f7a8b625e 100644 --- a/libafl_qemu/src/emu/hooks.rs +++ b/libafl_qemu/src/emu/hooks.rs @@ -398,7 +398,7 @@ where } } - #[allow(clippy::similar_names)] + #[expect(clippy::similar_names)] pub fn reads( &mut self, generation_hook: ReadGenHook, @@ -486,7 +486,7 @@ where } } - #[allow(clippy::similar_names)] + #[expect(clippy::similar_names)] pub fn writes( &mut self, generation_hook: WriteGenHook, @@ -767,7 +767,6 @@ where ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - #[allow(clippy::type_complexity)] pub fn syscalls(&mut self, hook: PreSyscallHook) -> Option { match hook { Hook::Function(f) => Some(self.syscalls_function(f)), @@ -780,7 +779,6 @@ where } } - #[allow(clippy::type_complexity)] pub fn syscalls_function(&mut self, hook: PreSyscallHookFn) -> PreSyscallHookId { // # Safety // Will dereference the hook as [`FatPtr`]. @@ -790,7 +788,6 @@ where } } - #[allow(clippy::type_complexity)] pub fn syscalls_closure(&mut self, hook: PreSyscallHookClosure) -> PreSyscallHookId { // # Safety // Will dereference the hook as [`FatPtr`]. @@ -821,7 +818,6 @@ where } } - #[allow(clippy::type_complexity)] pub fn after_syscalls(&mut self, hook: PostSyscallHook) -> Option { match hook { Hook::Function(f) => Some(self.after_syscalls_function(f)), @@ -834,7 +830,6 @@ where } } - #[allow(clippy::type_complexity)] pub fn after_syscalls_function(&mut self, hook: PostSyscallHookFn) -> PostSyscallHookId { // # Safety // Will dereference the hook as [`FatPtr`]. This should be ok. @@ -844,7 +839,6 @@ where } } - #[allow(clippy::type_complexity)] pub fn after_syscalls_closure( &mut self, hook: PostSyscallHookClosure, @@ -999,7 +993,6 @@ where .blocks(generation_hook, post_generation_hook, execution_hook) } - #[allow(clippy::similar_names)] pub fn reads( &mut self, generation_hook: ReadGenHook, @@ -1019,7 +1012,6 @@ where ) } - #[allow(clippy::similar_names)] pub fn writes( &mut self, generation_hook: WriteGenHook, @@ -1221,14 +1213,13 @@ where ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - #[allow(clippy::type_complexity)] pub fn syscalls(&mut self, hook: PreSyscallHook) -> Option { self.hooks.syscalls(hook) } /// # Safety /// Calls through to the, potentially unsafe, `syscalls_function` - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub unsafe fn syscalls_function( &mut self, hook: fn( @@ -1250,7 +1241,7 @@ where /// # Safety /// Calls through to the, potentially unsafe, `syscalls_closure` - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub unsafe fn syscalls_closure( &mut self, hook: Box< @@ -1272,14 +1263,13 @@ where self.hooks.syscalls_closure(hook) } - #[allow(clippy::type_complexity)] pub fn after_syscalls(&mut self, hook: PostSyscallHook) -> Option { self.hooks.after_syscalls(hook) } /// # Safety /// Calls through to the, potentially unsafe, `after_syscalls_function` - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub unsafe fn after_syscalls_function( &mut self, hook: fn( @@ -1300,7 +1290,7 @@ where self.hooks.after_syscalls_function(hook) } - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub fn after_syscalls_closure( &mut self, hook: Box< diff --git a/libafl_qemu/src/emu/mod.rs b/libafl_qemu/src/emu/mod.rs index 0fcf92e3f6..8e05864d96 100644 --- a/libafl_qemu/src/emu/mod.rs +++ b/libafl_qemu/src/emu/mod.rs @@ -119,7 +119,7 @@ pub struct InputLocation { } #[derive(Debug)] -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] pub struct Emulator where CM: CommandManager, @@ -140,7 +140,7 @@ where S: UsesInput, { #[must_use] - #[allow(clippy::match_wildcard_for_single_variants)] + #[expect(clippy::match_wildcard_for_single_variants)] pub fn end_of_run(&self) -> Option { match self { EmulatorDriverResult::EndOfRun(exit_kind) => Some(*exit_kind), @@ -321,7 +321,6 @@ where ET: EmulatorModuleTuple, S: UsesInput + Unpin, { - #[allow(clippy::must_use_candidate, clippy::similar_names)] pub fn new( qemu_args: &[String], modules: ET, @@ -471,7 +470,6 @@ where } } -#[allow(clippy::unused_self)] impl Emulator where CM: CommandManager, diff --git a/libafl_qemu/src/emu/systemmode.rs b/libafl_qemu/src/emu/systemmode.rs index 450144e393..786a32cfe1 100644 --- a/libafl_qemu/src/emu/systemmode.rs +++ b/libafl_qemu/src/emu/systemmode.rs @@ -63,12 +63,14 @@ impl Default for FastSnapshotManager { } impl FastSnapshotManager { + #[must_use] pub fn new() -> Self { Self { snapshots: HashMap::new(), } } - + #[allow(clippy::missing_safety_doc)] + #[must_use] pub unsafe fn get(&self, id: &SnapshotId) -> FastSnapshotPtr { *self.snapshots.get(id).unwrap() } @@ -86,10 +88,12 @@ impl Default for QemuSnapshotManager { } impl QemuSnapshotManager { + #[must_use] pub fn new(is_sync: bool) -> Self { Self { is_sync } } + #[must_use] pub fn snapshot_id_to_name(&self, snapshot_id: &SnapshotId) -> String { format!("__libafl_qemu_snapshot_{}", snapshot_id.inner()) } @@ -168,21 +172,23 @@ where S: UsesInput, { /// Write a value to a phsical guest address, including ROM areas. + #[allow(clippy::missing_safety_doc)] pub unsafe fn write_phys_mem(&self, paddr: GuestPhysAddr, buf: &[u8]) { - self.qemu.write_phys_mem(paddr, buf) + self.qemu.write_phys_mem(paddr, buf); } /// Read a value from a physical guest address. + #[allow(clippy::missing_safety_doc)] pub unsafe fn read_phys_mem(&self, paddr: GuestPhysAddr, buf: &mut [u8]) { - self.qemu.read_phys_mem(paddr, buf) + self.qemu.read_phys_mem(paddr, buf); } pub fn save_snapshot(&self, name: &str, sync: bool) { - self.qemu.save_snapshot(name, sync) + self.qemu.save_snapshot(name, sync); } pub fn load_snapshot(&self, name: &str, sync: bool) { - self.qemu.load_snapshot(name, sync) + self.qemu.load_snapshot(name, sync); } #[must_use] @@ -199,8 +205,9 @@ where self.qemu.create_fast_snapshot_filter(track, device_filter) } + #[allow(clippy::missing_safety_doc)] pub unsafe fn restore_fast_snapshot(&self, snapshot: FastSnapshotPtr) { - self.qemu.restore_fast_snapshot(snapshot) + self.qemu.restore_fast_snapshot(snapshot); } pub fn list_devices(&self) -> Vec { diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index b5ce9791c5..5c1978d720 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -9,6 +9,8 @@ use std::ptr; #[cfg(feature = "systemmode")] use std::sync::atomic::{AtomicBool, Ordering}; +#[cfg(any(feature = "usermode", feature = "fork"))] +use libafl::inputs::UsesInput; use libafl::{ corpus::Corpus, events::{EventFirer, EventRestarter}, @@ -20,7 +22,6 @@ use libafl::{ }, feedbacks::Feedback, fuzzer::HasObjective, - inputs::UsesInput, observers::ObserversTuple, state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState}, Error, ExecutionProcessor, HasScheduler, @@ -355,7 +356,7 @@ where Z: HasObjective, Z::Objective: Feedback, { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn new( emulator: Emulator, harness_fn: &'a mut H, diff --git a/libafl_qemu/src/lib.rs b/libafl_qemu/src/lib.rs index 6f27560e56..e27b7df3c4 100644 --- a/libafl_qemu/src/lib.rs +++ b/libafl_qemu/src/lib.rs @@ -71,7 +71,6 @@ use pyo3::prelude::*; #[cfg(feature = "python")] #[pymodule] #[pyo3(name = "libafl_qemu")] -#[allow(clippy::items_after_statements, clippy::too_many_lines)] pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> { use pyo3::types::PyString; diff --git a/libafl_qemu/src/modules/calls.rs b/libafl_qemu/src/modules/calls.rs index 1e280a0720..01687ef90f 100644 --- a/libafl_qemu/src/modules/calls.rs +++ b/libafl_qemu/src/modules/calls.rs @@ -269,6 +269,7 @@ where emulator_modules.get_mut::().unwrap().collectors = collectors; } + #[allow(clippy::needless_pass_by_value)] // no longer a problem in nightly fn gen_blocks_calls( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -298,7 +299,7 @@ where let mut ret_addrs: Vec = Vec::new(); if let Some(h) = emulator_modules.modules().match_first_type::() { - #[allow(unused_mut)] + #[allow(unused_mut)] // cfg dependent let mut code = { #[cfg(feature = "usermode")] unsafe { @@ -492,7 +493,7 @@ impl<'a> CallTraceCollector for OnCrashBacktraceCollector<'a> where 'a: 'static, { - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] fn on_call( &mut self, _emulator_modules: &mut EmulatorModules, @@ -506,7 +507,7 @@ where self.callstack_hash ^= pc as u64 + call_len as u64; } - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] fn on_ret( &mut self, _emulator_modules: &mut EmulatorModules, @@ -587,7 +588,7 @@ impl FullBacktraceCollector { } impl CallTraceCollector for FullBacktraceCollector { - #[allow(clippy::unnecessary_cast)] + #[allow(clippy::unnecessary_cast)] // dependent on the target instruction size fn on_call( &mut self, _emulator_modules: &mut EmulatorModules, @@ -606,7 +607,7 @@ impl CallTraceCollector for FullBacktraceCollector { } } - #[allow(clippy::unnecessary_cast)] + #[allow(clippy::unnecessary_cast)] // dependent on the target instruction size fn on_ret( &mut self, _emulator_modules: &mut EmulatorModules, diff --git a/libafl_qemu/src/modules/cmplog.rs b/libafl_qemu/src/modules/cmplog.rs index b595971374..cdc4247510 100644 --- a/libafl_qemu/src/modules/cmplog.rs +++ b/libafl_qemu/src/modules/cmplog.rs @@ -202,6 +202,7 @@ where })) } +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_hashed_cmp_ids( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -295,6 +296,7 @@ impl CmpLogRoutinesModule { } } + #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn gen_blocks_calls( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -321,7 +323,7 @@ impl CmpLogRoutinesModule { let qemu = emulator_modules.qemu(); if let Some(h) = emulator_modules.get::() { - #[allow(unused_mut)] + #[allow(unused_mut)] // cfg dependent let mut code = { #[cfg(feature = "usermode")] unsafe { diff --git a/libafl_qemu/src/modules/drcov.rs b/libafl_qemu/src/modules/drcov.rs index e40d3dda0e..299cbffbcd 100644 --- a/libafl_qemu/src/modules/drcov.rs +++ b/libafl_qemu/src/modules/drcov.rs @@ -120,7 +120,7 @@ impl DrCovModule { } impl DrCovModule { #[must_use] - #[allow(clippy::let_underscore_untyped)] + #[expect(clippy::let_underscore_untyped)] pub fn new( filter: F, filename: PathBuf, @@ -168,7 +168,7 @@ impl DrCovModule { continue 'pcs_full; } if *idm == *id { - #[allow(clippy::unnecessary_cast)] // for GuestAddr -> u64 + #[expect(clippy::unnecessary_cast)] // for GuestAddr -> u64 match lengths.get(pc) { Some(block_length) => { drcov_vec.push(DrCovBasicBlock::new( @@ -217,7 +217,7 @@ impl DrCovModule { continue 'pcs; } - #[allow(clippy::unnecessary_cast)] // for GuestAddr -> u64 + #[expect(clippy::unnecessary_cast)] // for GuestAddr -> u64 match lengths.get(pc) { Some(block_length) => { drcov_vec.push(DrCovBasicBlock::new( @@ -287,7 +287,7 @@ where let mut module_mapping: RangeMap = RangeMap::new(); - #[allow(clippy::unnecessary_cast)] // for GuestAddr -> u64 + #[expect(clippy::unnecessary_cast)] // for GuestAddr -> u64 for (i, (r, p)) in qemu .mappings() .filter_map(|m| { @@ -398,7 +398,7 @@ where meta.current_id = id + 1; if drcov_module.full_trace { // GuestAddress is u32 for 32 bit guests - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] Some(id as u64) } else { None @@ -407,6 +407,7 @@ where } } +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_block_lengths( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -429,6 +430,7 @@ pub fn gen_block_lengths( .insert(pc, block_length); } +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn exec_trace_block( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, diff --git a/libafl_qemu/src/modules/edges/helpers.rs b/libafl_qemu/src/modules/edges/helpers.rs index 760fce7272..c3cadf508c 100644 --- a/libafl_qemu/src/modules/edges/helpers.rs +++ b/libafl_qemu/src/modules/edges/helpers.rs @@ -149,13 +149,13 @@ mod generators { } } // GuestAddress is u32 for 32 bit guests - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] Some(id as u64) } } } - #[allow(clippy::unnecessary_cast)] + #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_hashed_edge_ids( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -193,7 +193,7 @@ mod generators { let mask = get_mask::() as u64; - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] let id = (hash_me(src as u64) ^ hash_me(dest as u64)) & mask; if !IS_CONST_MAP { @@ -209,7 +209,8 @@ mod generators { } } - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] + #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_hashed_block_ids( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -255,8 +256,6 @@ mod generators { } } - // GuestAddress is u32 for 32 bit guests - #[allow(clippy::unnecessary_cast)] Some(id) } } diff --git a/libafl_qemu/src/modules/edges/mod.rs b/libafl_qemu/src/modules/edges/mod.rs index db2538ca7e..35e4a0fcc9 100644 --- a/libafl_qemu/src/modules/edges/mod.rs +++ b/libafl_qemu/src/modules/edges/mod.rs @@ -380,7 +380,7 @@ mod tests { /// /// StdEdgeCoverageModule::builder().build().unwrap(); /// ``` - #[allow(unused)] + #[expect(unused)] pub fn does_not_build() {} #[test] diff --git a/libafl_qemu/src/modules/mod.rs b/libafl_qemu/src/modules/mod.rs index 04b80a84ee..b2fc689d79 100644 --- a/libafl_qemu/src/modules/mod.rs +++ b/libafl_qemu/src/modules/mod.rs @@ -14,7 +14,7 @@ pub use usermode::*; #[cfg(feature = "systemmode")] pub mod systemmode; #[cfg(feature = "systemmode")] -#[allow(unused_imports)] +#[expect(unused_imports)] pub use systemmode::*; pub mod edges; @@ -328,8 +328,8 @@ where #[cfg(feature = "systemmode")] fn allow_page_id_all(&mut self, page_id: GuestPhysAddr) { - self.0.page_filter_mut().register(page_id.clone()); - self.1.allow_page_id_all(page_id) + self.0.page_filter_mut().register(page_id); + self.1.allow_page_id_all(page_id); } } diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index 45ee1e8626..96674a899d 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -1,5 +1,5 @@ #![allow(clippy::cast_possible_wrap)] - +#![allow(clippy::needless_pass_by_value)] // default compiler complains about Option<&mut T> otherwise, and this is used extensively. use std::{borrow::Cow, env, fs, path::PathBuf, sync::Mutex}; use hashbrown::{HashMap, HashSet}; @@ -328,7 +328,7 @@ impl AsanGiovese { #[inline] #[must_use] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] pub fn is_invalid_access(qemu: Qemu, addr: GuestAddr, n: usize) -> bool { unsafe { if n == 0 { @@ -380,7 +380,7 @@ impl AsanGiovese { } #[inline] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] pub fn poison(&mut self, qemu: Qemu, addr: GuestAddr, n: usize, poison_byte: i8) -> bool { unsafe { if n == 0 { @@ -425,8 +425,8 @@ impl AsanGiovese { } #[inline] - #[allow(clippy::must_use_candidate)] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::must_use_candidate)] + #[expect(clippy::cast_sign_loss)] pub fn unpoison(qemu: Qemu, addr: GuestAddr, n: usize) -> bool { unsafe { let n = n as isize; @@ -453,7 +453,7 @@ impl AsanGiovese { } #[inline] - #[allow(clippy::mut_from_ref)] + #[expect(clippy::mut_from_ref)] fn get_shadow_page(qemu: &Qemu, page: GuestAddr) -> &mut [i8] { unsafe { let h = qemu.g2h::<*const c_void>(page) as isize; @@ -840,7 +840,6 @@ impl AsanModule { self.rt.deallocation(qemu, pc, addr); } - #[allow(clippy::unused_self)] #[must_use] pub fn is_poisoned(&self, qemu: Qemu, addr: GuestAddr, size: usize) -> bool { AsanGiovese::is_invalid_access(qemu, addr, size) @@ -912,7 +911,6 @@ impl AsanModule { self.rt.poison(qemu, addr, size, poison.into()); } - #[allow(clippy::unused_self)] pub fn unpoison(&mut self, qemu: Qemu, addr: GuestAddr, size: usize) { AsanGiovese::unpoison(qemu, addr, size); } @@ -1296,7 +1294,7 @@ pub fn trace_write_n_asan_snapshot( h.access(addr, size); } -#[allow(clippy::too_many_arguments)] +#[expect(clippy::too_many_arguments)] pub fn qasan_fake_syscall( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -1534,8 +1532,8 @@ mod addr2line_legacy { /// # Safety /// Will access the global [`FullBacktraceCollector`]. /// Calling this function concurrently might be racey. -#[allow(clippy::unnecessary_cast)] -#[allow(clippy::too_many_lines)] +#[expect(clippy::unnecessary_cast)] +#[expect(clippy::too_many_lines)] pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &AsanError) { let mut regions = HashMap::new(); for region in qemu.mappings() { diff --git a/libafl_qemu/src/modules/usermode/asan_guest.rs b/libafl_qemu/src/modules/usermode/asan_guest.rs index 567d98048e..eb03668685 100644 --- a/libafl_qemu/src/modules/usermode/asan_guest.rs +++ b/libafl_qemu/src/modules/usermode/asan_guest.rs @@ -205,6 +205,7 @@ where } } +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn gen_readwrite_guest_asan( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -240,9 +241,10 @@ where } #[cfg(feature = "clippy")] -#[allow(unused_variables)] +#[expect(unused_variables)] unsafe fn libafl_tcg_gen_asan(addr: *mut TCGTemp, size: usize) {} +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn guest_trace_error_asan( _emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -255,6 +257,7 @@ fn guest_trace_error_asan( panic!("I really shouldn't be here"); } +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn guest_trace_error_n_asan( _emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, diff --git a/libafl_qemu/src/modules/usermode/injections.rs b/libafl_qemu/src/modules/usermode/injections.rs index 9d62e7b017..086e293c6f 100644 --- a/libafl_qemu/src/modules/usermode/injections.rs +++ b/libafl_qemu/src/modules/usermode/injections.rs @@ -343,7 +343,8 @@ where } } -#[allow(clippy::too_many_arguments)] +#[expect(clippy::too_many_arguments)] +#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn syscall_hook( // Our instantiated [`EmulatorModules`] emulator_modules: &mut EmulatorModules, diff --git a/libafl_qemu/src/modules/usermode/snapshot.rs b/libafl_qemu/src/modules/usermode/snapshot.rs index d887f8e1ef..776fc749da 100644 --- a/libafl_qemu/src/modules/usermode/snapshot.rs +++ b/libafl_qemu/src/modules/usermode/snapshot.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_pass_by_value)] // default compiler complains about Option<&mut T> otherwise, and this is used extensively. use std::{cell::UnsafeCell, mem::MaybeUninit, sync::Mutex}; use hashbrown::{HashMap, HashSet}; @@ -191,7 +192,6 @@ impl SnapshotModule { false } - #[allow(clippy::uninit_assumed_init)] pub fn snapshot(&mut self, qemu: Qemu) { log::info!("Start snapshot"); self.brk = qemu.get_brk(); @@ -753,8 +753,7 @@ pub fn trace_write_n_snapshot( h.access(addr, size); } -#[allow(clippy::too_many_arguments)] -#[allow(non_upper_case_globals)] +#[expect(clippy::too_many_arguments)] pub fn filter_mmap_snapshot( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, @@ -781,8 +780,8 @@ where SyscallHookResult::new(None) } -#[allow(clippy::too_many_arguments, clippy::too_many_lines)] -#[allow(non_upper_case_globals)] +#[expect(clippy::too_many_arguments)] +#[expect(non_upper_case_globals)] pub fn trace_mmap_snapshot( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, diff --git a/libafl_qemu/src/qemu/hooks.rs b/libafl_qemu/src/qemu/hooks.rs index 4165742d17..ea59e6d3e0 100644 --- a/libafl_qemu/src/qemu/hooks.rs +++ b/libafl_qemu/src/qemu/hooks.rs @@ -755,7 +755,6 @@ impl QemuHooks { } // TODO set T lifetime to be like Emulator - #[allow(clippy::missing_transmute_annotations)] pub fn add_instruction_hooks>( &self, data: T, @@ -786,7 +785,6 @@ impl QemuHooks { } } - #[allow(clippy::missing_transmute_annotations)] pub fn add_edge_hooks>( &self, data: T, @@ -803,7 +801,6 @@ impl QemuHooks { } } - #[allow(clippy::missing_transmute_annotations)] pub fn add_block_hooks>( &self, data: T, @@ -822,7 +819,6 @@ impl QemuHooks { } } - #[allow(clippy::missing_transmute_annotations)] pub fn add_cpu_run_hooks>( &self, data: T, @@ -850,7 +846,6 @@ impl QemuHooks { /// /// If there is no specialized hook for a given read width, the `exec_n` will be /// called and its last argument will specify the access width - #[allow(clippy::missing_transmute_annotations)] pub fn add_read_hooks>( &self, data: T, @@ -885,7 +880,6 @@ impl QemuHooks { } // TODO add MemOp info - #[allow(clippy::missing_transmute_annotations)] pub fn add_write_hooks>( &self, data: T, @@ -919,7 +913,6 @@ impl QemuHooks { } } - #[allow(clippy::missing_transmute_annotations)] pub fn add_cmp_hooks>( &self, data: T, @@ -941,7 +934,6 @@ impl QemuHooks { } } - #[allow(clippy::missing_transmute_annotations)] pub fn add_backdoor_hook>( &self, data: T, @@ -971,7 +963,6 @@ impl QemuHooks { #[cfg(feature = "usermode")] impl QemuHooks { - #[allow(clippy::type_complexity)] pub fn add_pre_syscall_hook>( &self, data: T, @@ -1007,7 +998,6 @@ impl QemuHooks { } } - #[allow(clippy::type_complexity)] pub fn add_post_syscall_hook>( &self, data: T, @@ -1045,8 +1035,7 @@ impl QemuHooks { } } - #[allow(clippy::type_complexity)] - #[allow(clippy::unused_self)] + #[expect(clippy::unused_self)] pub(crate) fn set_crash_hook(self, callback: extern "C" fn(i32)) { unsafe { libafl_dump_core_hook = Some(callback); diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index d9fc7ce657..52916c38fb 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -41,7 +41,6 @@ pub use usermode::*; #[cfg(feature = "systemmode")] mod systemmode; #[cfg(feature = "systemmode")] -#[allow(unused_imports)] pub use systemmode::*; mod hooks; @@ -112,7 +111,7 @@ pub enum QemuRWErrorCause { } #[derive(Debug, Clone)] -#[allow(dead_code)] +#[expect(dead_code)] pub struct QemuRWError { kind: QemuRWErrorKind, cause: QemuRWErrorCause, @@ -180,7 +179,7 @@ pub struct QemuMemoryChunk { cpu: Option, } -#[allow(clippy::vec_box)] +#[expect(clippy::vec_box)] static mut GDB_COMMANDS: Vec> = Vec::new(); unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { @@ -339,10 +338,9 @@ pub trait ArchExtras { T: Into; } -#[allow(clippy::unused_self)] impl CPU { #[must_use] - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] pub fn index(&self) -> usize { unsafe { libafl_qemu_cpu_index(self.ptr) as usize } } @@ -572,7 +570,6 @@ impl From for HookData { } } -#[allow(clippy::unused_self)] impl Qemu { /// For more details about the parameters check /// [the QEMU documentation](https://www.qemu.org/docs/master/about/). @@ -580,7 +577,7 @@ impl Qemu { QemuConfig::builder() } - #[allow(clippy::must_use_candidate, clippy::similar_names)] + #[expect(clippy::similar_names)] pub fn init(args: &[String]) -> Result { if args.is_empty() { return Err(QemuInitError::EmptyArgs); @@ -598,7 +595,7 @@ impl Qemu { QEMU_IS_INITIALIZED = true; } - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] let argc = argc as i32; let args: Vec = args @@ -733,8 +730,8 @@ impl Qemu { } #[must_use] - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::cast_sign_loss)] + #[allow(clippy::cast_possible_wrap)] // platform dependent + #[expect(clippy::cast_sign_loss)] pub fn num_cpus(&self) -> usize { unsafe { libafl_qemu_num_cpus() as usize } } @@ -750,7 +747,7 @@ impl Qemu { } #[must_use] - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] pub fn cpu_from_index(&self, index: usize) -> CPU { unsafe { CPU { @@ -883,7 +880,7 @@ impl Qemu { /// # Safety /// /// Calling this multiple times concurrently will access static variables and is unsafe. - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub unsafe fn add_gdb_cmd(&self, callback: Box bool>) { let fat: Box = Box::new(transmute::< Box FnMut(&'a Qemu, &'b str) -> bool>, @@ -1118,7 +1115,7 @@ pub mod pybind { #[pymethods] impl Qemu { - #[allow(clippy::needless_pass_by_value)] + #[expect(clippy::needless_pass_by_value)] #[new] fn new(args: Vec) -> PyResult { let qemu = diff --git a/libafl_qemu/src/qemu/systemmode.rs b/libafl_qemu/src/qemu/systemmode.rs index c481ecd16f..c76898a293 100644 --- a/libafl_qemu/src/qemu/systemmode.rs +++ b/libafl_qemu/src/qemu/systemmode.rs @@ -16,8 +16,8 @@ use libc::EXIT_SUCCESS; use num_traits::Zero; use crate::{ - FastSnapshotPtr, GuestAddrKind, MemAccessInfo, Qemu, QemuMemoryChunk, QemuRWError, - QemuRWErrorCause, QemuRWErrorKind, QemuSnapshotCheckResult, CPU, + FastSnapshotPtr, GuestAddrKind, MemAccessInfo, Qemu, QemuMemoryChunk, QemuSnapshotCheckResult, + CPU, }; pub(super) extern "C" fn qemu_cleanup_atexit() { @@ -33,7 +33,7 @@ pub enum DeviceSnapshotFilter { } #[derive(Debug, Clone)] -#[allow(dead_code)] +#[expect(dead_code)] pub struct PhysMemoryChunk { addr: GuestPhysAddr, size: usize, @@ -48,7 +48,7 @@ pub struct PhysMemoryIter { cpu: CPU, } -#[allow(dead_code)] +#[expect(dead_code)] pub struct HostMemoryIter<'a> { addr: GuestPhysAddr, // This address is correct when the iterator enters next, except if the remaining len is 0 remaining_len: usize, @@ -96,6 +96,7 @@ impl CPU { page as GuestVirtAddr, attrs.as_mut_ptr(), ); + #[expect(clippy::cast_sign_loss)] if paddr == (-1i64 as GuestPhysAddr) { None } else { @@ -147,15 +148,13 @@ impl CPU { /// if a problem occurred during the operation, there will be no feedback pub unsafe fn read_mem_unchecked(&self, addr: GuestAddr, buf: &mut [u8]) { // TODO use gdbstub's target_cpu_memory_rw_debug - unsafe { - libafl_qemu_sys::cpu_memory_rw_debug( - self.ptr, - addr as GuestVirtAddr, - buf.as_mut_ptr() as *mut _, - buf.len(), - false, - ) - }; + libafl_qemu_sys::cpu_memory_rw_debug( + self.ptr, + addr as GuestVirtAddr, + buf.as_mut_ptr() as *mut _, + buf.len(), + false, + ); } /// Write a value to a guest address, taking into account the potential MMU / MPU. @@ -163,22 +162,21 @@ impl CPU { /// # Safety /// no check is done on the correctness of the operation. /// if a problem occurred during the operation, there will be no feedback - pub fn write_mem_unchecked(&self, addr: GuestAddr, buf: &[u8]) { + pub unsafe fn write_mem_unchecked(&self, addr: GuestAddr, buf: &[u8]) { // TODO use gdbstub's target_cpu_memory_rw_debug - unsafe { - libafl_qemu_sys::cpu_memory_rw_debug( - self.ptr, - addr as GuestVirtAddr, - buf.as_ptr() as *mut _, - buf.len(), - true, - ) - }; + libafl_qemu_sys::cpu_memory_rw_debug( + self.ptr, + addr as GuestVirtAddr, + buf.as_ptr() as *mut _, + buf.len(), + true, + ); } } -#[allow(clippy::unused_self)] +#[expect(clippy::unused_self)] impl Qemu { + #[must_use] pub fn guest_page_size(&self) -> usize { 4096 } @@ -215,6 +213,7 @@ impl Qemu { ); } + #[expect(clippy::trivially_copy_pass_by_ref)] pub(super) unsafe fn run_inner(&self) { vm_start(); qemu_main_loop(); @@ -222,12 +221,12 @@ impl Qemu { pub fn save_snapshot(&self, name: &str, sync: bool) { let s = CString::new(name).expect("Invalid snapshot name"); - unsafe { libafl_save_qemu_snapshot(s.as_ptr() as *mut i8, sync) }; + unsafe { libafl_save_qemu_snapshot(s.as_ptr().cast_mut(), sync) }; } pub fn load_snapshot(&self, name: &str, sync: bool) { let s = CString::new(name).expect("Invalid snapshot name"); - unsafe { libafl_load_qemu_snapshot(s.as_ptr() as *mut i8, sync) }; + unsafe { libafl_load_qemu_snapshot(s.as_ptr().cast_mut(), sync) }; } #[must_use] @@ -259,10 +258,13 @@ impl Qemu { } } + #[expect(clippy::missing_safety_doc)] pub unsafe fn restore_fast_snapshot(&self, snapshot: FastSnapshotPtr) { - libafl_qemu_sys::syx_snapshot_root_restore(snapshot) + libafl_qemu_sys::syx_snapshot_root_restore(snapshot); } + #[allow(clippy::missing_safety_doc)] + #[must_use] pub unsafe fn check_fast_snapshot( &self, ref_snapshot: FastSnapshotPtr, @@ -272,6 +274,7 @@ impl Qemu { QemuSnapshotCheckResult::new(check_result.nb_inconsistencies) } + #[must_use] pub fn list_devices(&self) -> Vec { let mut r = vec![]; unsafe { @@ -301,6 +304,7 @@ impl Qemu { } impl QemuMemoryChunk { + #[must_use] pub fn phys_iter(&self, qemu: Qemu) -> PhysMemoryIter { PhysMemoryIter { addr: self.addr, @@ -314,7 +318,8 @@ impl QemuMemoryChunk { } } - #[allow(clippy::map_flatten)] + #[expect(clippy::map_flatten)] + #[must_use] pub fn host_iter(&self, qemu: Qemu) -> Box> { Box::new( self.phys_iter(qemu) @@ -330,12 +335,14 @@ impl QemuMemoryChunk { ) } + #[must_use] pub fn to_host_segmented_buf(&self, qemu: Qemu) -> SegmentedBuf<&[u8]> { self.host_iter(qemu).collect() } } impl PhysMemoryChunk { + #[must_use] pub fn new(addr: GuestPhysAddr, size: usize, qemu: Qemu, cpu: CPU) -> Self { Self { addr, diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index 619202db02..e621adaf09 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -40,7 +40,6 @@ impl GuestMaps { impl Iterator for GuestMaps { type Item = MapInfo; - #[allow(clippy::uninit_assumed_init)] fn next(&mut self) -> Option { unsafe { let mut ret = MaybeUninit::uninit(); @@ -123,7 +122,7 @@ impl CPU { } } -#[allow(clippy::unused_self)] +#[expect(clippy::unused_self)] impl Qemu { #[must_use] pub fn mappings(&self) -> GuestMaps { @@ -195,7 +194,7 @@ impl Qemu { unsafe { mmap_next_start = start }; } - #[allow(clippy::cast_sign_loss)] + #[expect(clippy::cast_sign_loss)] fn mmap( self, addr: GuestAddr, diff --git a/libafl_sugar/src/forkserver.rs b/libafl_sugar/src/forkserver.rs index 07541cf847..59e62f0651 100644 --- a/libafl_sugar/src/forkserver.rs +++ b/libafl_sugar/src/forkserver.rs @@ -76,10 +76,9 @@ pub struct ForkserverBytesCoverageSugar<'a> { iterations: Option, } -#[allow(clippy::similar_names)] impl ForkserverBytesCoverageSugar<'_> { /// Runs the fuzzer. - #[allow(clippy::too_many_lines, clippy::similar_names)] + #[expect(clippy::too_many_lines)] pub fn run(&mut self) { // a large initial map size that should be enough // to house all potential coverage maps for our targets @@ -336,7 +335,7 @@ pub mod pybind { impl ForkserverBytesCoverageSugar { /// Create a new [`ForkserverBytesCoverageSugar`] #[new] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[pyo3(signature = ( input_dirs, output_dir, @@ -370,7 +369,7 @@ pub mod pybind { } /// Run the fuzzer - #[allow(clippy::needless_pass_by_value)] + #[expect(clippy::needless_pass_by_value)] pub fn run(&self, program: String, arguments: Vec) { forkserver::ForkserverBytesCoverageSugar::builder() .input_dirs(&self.input_dirs) diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index dfac4dd2d6..d1eb465d2d 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -109,13 +109,12 @@ where } } -#[allow(clippy::similar_names)] impl InMemoryBytesCoverageSugar<'_, H> where H: FnMut(&[u8]), { /// Run the fuzzer - #[allow(clippy::too_many_lines, clippy::similar_names)] + #[expect(clippy::too_many_lines)] pub fn run(&mut self) { let conf = match self.configuration.as_ref() { Some(name) => EventConfig::from_name(name), @@ -393,7 +392,7 @@ pub mod pybind { impl InMemoryBytesCoverageSugar { /// Create a new [`InMemoryBytesCoverageSugar`] #[new] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[pyo3(signature = ( input_dirs, output_dir, @@ -427,7 +426,7 @@ pub mod pybind { } /// Run the fuzzer - #[allow(clippy::needless_pass_by_value)] + #[expect(clippy::needless_pass_by_value)] pub fn run(&self, harness: PyObject) { inmemory::InMemoryBytesCoverageSugar::builder() .input_dirs(&self.input_dirs) diff --git a/libafl_sugar/src/lib.rs b/libafl_sugar/src/lib.rs index aefb6e0224..c9839203f8 100644 --- a/libafl_sugar/src/lib.rs +++ b/libafl_sugar/src/lib.rs @@ -41,18 +41,15 @@ ) )] -#[allow(clippy::ignored_unit_patterns)] pub mod inmemory; pub use inmemory::InMemoryBytesCoverageSugar; #[cfg(target_os = "linux")] -#[allow(clippy::ignored_unit_patterns)] pub mod qemu; #[cfg(target_os = "linux")] pub use qemu::QemuBytesCoverageSugar; #[cfg(target_family = "unix")] -#[allow(clippy::ignored_unit_patterns)] pub mod forkserver; #[cfg(target_family = "unix")] pub use forkserver::ForkserverBytesCoverageSugar; diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index e0126c3b01..124342d999 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -117,7 +117,7 @@ where H: FnMut(&[u8]), { /// Run the fuzzer - #[allow(clippy::too_many_lines, clippy::similar_names)] + #[expect(clippy::too_many_lines)] pub fn run(&mut self, qemu: Qemu) { let conf = match self.configuration.as_ref() { Some(name) => EventConfig::from_name(name), @@ -498,7 +498,7 @@ pub mod pybind { impl QemuBytesCoverageSugar { /// Create a new [`QemuBytesCoverageSugar`] #[new] - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[pyo3(signature = ( input_dirs, output_dir, @@ -532,7 +532,7 @@ pub mod pybind { } /// Run the fuzzer - #[allow(clippy::needless_pass_by_value)] + #[expect(clippy::needless_pass_by_value)] pub fn run(&self, qemu: &Qemu, harness: PyObject) { qemu::QemuBytesCoverageSugar::builder() .input_dirs(&self.input_dirs) diff --git a/libafl_targets/build.rs b/libafl_targets/build.rs index 3f92a0004c..4f78848682 100644 --- a/libafl_targets/build.rs +++ b/libafl_targets/build.rs @@ -13,14 +13,14 @@ fn enable_nightly() { #[rustversion::not(nightly)] fn enable_nightly() {} -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] fn main() { println!("cargo:rustc-check-cfg=cfg(nightly)"); enable_nightly(); let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = out_dir.to_string_lossy().to_string(); //let out_dir_path = Path::new(&out_dir); - #[allow(unused_variables)] + #[allow(unused_variables)] // feature dependent let src_dir = Path::new("src"); let dest_path = Path::new(&out_dir).join("constants.rs"); diff --git a/libafl_targets/src/cmps/mod.rs b/libafl_targets/src/cmps/mod.rs index 5ebe68ccce..21818e9368 100644 --- a/libafl_targets/src/cmps/mod.rs +++ b/libafl_targets/src/cmps/mod.rs @@ -63,7 +63,7 @@ pub use libafl_cmplog_map_ptr as CMPLOG_MAP_PTR; /// Value indicating if cmplog is enabled. #[no_mangle] -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals)] // expect breaks here for some reason pub static mut libafl_cmplog_enabled: u8 = 0; pub use libafl_cmplog_enabled as CMPLOG_ENABLED; @@ -424,8 +424,7 @@ impl CmpMap for CmpLogMap { /// The global `CmpLog` map for the current `LibAFL` run. #[no_mangle] -#[allow(clippy::large_stack_arrays)] -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals)] // expect breaks here for some reason pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap { headers: [CmpLogHeader { hits: 0, @@ -440,7 +439,6 @@ pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap { /// The globale `CmpLog` map, aflpp style #[no_mangle] #[cfg(feature = "cmplog_extended_instrumentation")] -#[allow(clippy::large_stack_arrays)] pub static mut libafl_cmplog_map_extended: AFLppCmpLogMap = AFLppCmpLogMap { headers: [AFLppCmpLogHeader::new_with_raw_value(0); CMPLOG_MAP_W], vals: AFLppCmpLogVals { @@ -478,7 +476,7 @@ impl HasLen for AFLppCmpLogMap { impl AFLppCmpLogMap { #[must_use] - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] /// Instantiate a new boxed zeroed `AFLppCmpLogMap`. This should be used to create a new /// map, because it is so large it cannot be allocated on the stack with default /// runtime configuration. @@ -525,7 +523,7 @@ impl Serialize for AFLppCmpLogMap { } impl<'de> Deserialize<'de> for AFLppCmpLogMap { - #[allow(clippy::cast_ptr_alignment)] + #[expect(clippy::cast_ptr_alignment)] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/libafl_targets/src/cmps/observers/aflpp.rs b/libafl_targets/src/cmps/observers/aflpp.rs index c07df26968..28efe97849 100644 --- a/libafl_targets/src/cmps/observers/aflpp.rs +++ b/libafl_targets/src/cmps/observers/aflpp.rs @@ -174,7 +174,7 @@ impl<'a> AFLppCmpLogObserver<'a> { where S: HasMetadata, { - #[allow(clippy::option_if_let_else)] // we can't mutate state in a closure + #[expect(clippy::option_if_let_else)] // we can't mutate state in a closure let meta = if let Some(meta) = state.metadata_map_mut().get_mut::() { meta diff --git a/libafl_targets/src/cmps/stages/aflpptracing.rs b/libafl_targets/src/cmps/stages/aflpptracing.rs index 99f37ffb12..7d20d04e3f 100644 --- a/libafl_targets/src/cmps/stages/aflpptracing.rs +++ b/libafl_targets/src/cmps/stages/aflpptracing.rs @@ -23,7 +23,6 @@ pub struct AFLppCmplogTracingStage<'a, EM, TE, S, Z> { name: Cow<'static, str>, tracer_executor: TE, cmplog_observer_handle: Handle>, - #[allow(clippy::type_complexity)] phantom: PhantomData<(EM, TE, S, Z)>, } /// The name for aflpp tracing stage diff --git a/libafl_targets/src/coverage.rs b/libafl_targets/src/coverage.rs index c93e5f3a4e..d272348deb 100644 --- a/libafl_targets/src/coverage.rs +++ b/libafl_targets/src/coverage.rs @@ -16,19 +16,19 @@ use crate::{ACCOUNTING_MAP_SIZE, DDG_MAP_SIZE, EDGES_MAP_ALLOCATED_SIZE, EDGES_M /// The map for edges. #[no_mangle] -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals)] // expect breaks here for some reason pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_ALLOCATED_SIZE] = [0; EDGES_MAP_ALLOCATED_SIZE]; pub use __afl_area_ptr_local as EDGES_MAP; /// The map for data dependency #[no_mangle] -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals)] // expect breaks here for some reason pub static mut __ddg_area_ptr_local: [u8; DDG_MAP_SIZE] = [0; DDG_MAP_SIZE]; pub use __ddg_area_ptr_local as DDG_MAP; /// The map for accounting mem writes. #[no_mangle] -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals)] // expect breaks here for some reason pub static mut __afl_acc_memop_ptr_local: [u32; ACCOUNTING_MAP_SIZE] = [0; ACCOUNTING_MAP_SIZE]; pub use __afl_acc_memop_ptr_local as ACCOUNTING_MEMOP_MAP; @@ -78,7 +78,7 @@ pub fn autotokens() -> Result { /// The actual size we use for the map of edges. /// This is used for forkserver backend -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals)] // expect breaks here for some reason #[no_mangle] pub static mut __afl_map_size: usize = EDGES_MAP_DEFAULT_SIZE; @@ -221,7 +221,7 @@ mod swap { /// Observer to be used with `DiffExecutor`s when executing a differential target that shares /// the AFL map in order to swap out the maps (and thus allow for map observing the two targets /// separately). - #[allow(clippy::unsafe_derive_deserialize)] + #[expect(clippy::unsafe_derive_deserialize)] #[derive(Debug, Serialize, Deserialize)] pub struct DifferentialAFLMapSwapObserver<'a, 'b> { first_map: OwnedMutSlice<'a, u8>, diff --git a/libafl_targets/src/lib.rs b/libafl_targets/src/lib.rs index 74a6c5fce4..43fc18b731 100644 --- a/libafl_targets/src/lib.rs +++ b/libafl_targets/src/lib.rs @@ -45,7 +45,8 @@ #[cfg(feature = "std")] #[macro_use] extern crate std; -#[allow(unused_imports)] + +#[allow(unused_imports)] // for no-std #[macro_use] extern crate alloc; @@ -75,7 +76,6 @@ pub use sancov_cmp::*; /// Module containing bindings to the various sanitizer interface headers #[cfg(feature = "sanitizer_interfaces")] -#[allow(clippy::mixed_attributes_style)] pub mod sanitizer_ifaces { #![allow(non_snake_case)] #![allow(non_camel_case_types)] diff --git a/libafl_targets/src/libfuzzer/mod.rs b/libafl_targets/src/libfuzzer/mod.rs index 31bae56d35..f5d9d41bdb 100644 --- a/libafl_targets/src/libfuzzer/mod.rs +++ b/libafl_targets/src/libfuzzer/mod.rs @@ -26,13 +26,13 @@ extern "C" { /// /// # Safety /// Calls the libfuzzer-style init function which is native code. -#[allow(clippy::similar_names)] -#[allow(clippy::must_use_candidate)] // nobody uses that return code... +#[expect(clippy::similar_names)] +#[expect(clippy::must_use_candidate)] // nobody uses that return code... pub unsafe fn libfuzzer_initialize(args: &[String]) -> i32 { let args: Vec = args.iter().map(|x| x.clone() + "\0").collect(); let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect(); assert!(argv.len() < i32::MAX as usize); - #[allow(clippy::cast_possible_wrap)] + #[expect(clippy::cast_possible_wrap)] let argc = argv.len() as i32; unsafe { let argv_ptr = argv.as_ptr(); @@ -44,7 +44,7 @@ pub unsafe fn libfuzzer_initialize(args: &[String]) -> i32 { /// /// # Safety /// Calls the libfuzzer harness. We actually think the target is unsafe and crashes eventually, that's why we do all this fuzzing. -#[allow(clippy::must_use_candidate)] +#[expect(clippy::must_use_candidate)] pub unsafe fn libfuzzer_test_one_input(buf: &[u8]) -> i32 { unsafe { LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()) } } diff --git a/libafl_targets/src/libfuzzer/mutators.rs b/libafl_targets/src/libfuzzer/mutators.rs index 95f01443e8..a57b7fa751 100644 --- a/libafl_targets/src/libfuzzer/mutators.rs +++ b/libafl_targets/src/libfuzzer/mutators.rs @@ -67,7 +67,7 @@ thread_local! { /// Mutator which is available for user-defined mutator/crossover /// See: [Structure-Aware Fuzzing with libFuzzer](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md) -#[allow(non_snake_case)] +#[allow(non_snake_case)] // expect breaks here for some reason #[no_mangle] pub extern "C" fn LLVMFuzzerMutate(data: *mut u8, size: usize, max_size: usize) -> usize { MUTATOR.with(|mutator| { @@ -110,7 +110,7 @@ impl<'a, M, S> MutatorProxy<'a, M, S> { /// Create a weak version of the proxy, which will become unusable when the custom mutator /// is no longer permitted to be executed. - #[allow(clippy::type_complexity)] + #[allow(clippy::type_complexity)] // no longer a problem in nightly fn weak(&self) -> WeakMutatorProxy FnMut(&'b mut S)) -> bool, M, S> { let state = Rc::downgrade(&self.state); WeakMutatorProxy { diff --git a/libafl_targets/src/sancov_8bit.rs b/libafl_targets/src/sancov_8bit.rs index b4ef07bcde..ae1e916af8 100644 --- a/libafl_targets/src/sancov_8bit.rs +++ b/libafl_targets/src/sancov_8bit.rs @@ -40,8 +40,7 @@ pub unsafe fn extra_counters() -> Vec> { /// # Safety /// Start and stop are being dereferenced. #[no_mangle] -#[allow(clippy::cast_sign_loss)] -#[allow(clippy::not_unsafe_ptr_arg_deref)] +#[expect(clippy::cast_sign_loss)] pub unsafe extern "C" fn __sanitizer_cov_8bit_counters_init(start: *mut u8, stop: *mut u8) { unsafe { let counter_maps = &mut *counter_maps_ptr_mut(); @@ -129,7 +128,7 @@ mod observers { /// The [`CountersMultiMapObserver`] observes all the counters that may be set by /// `SanitizerCoverage` in [`super::COUNTERS_MAPS`] #[derive(Serialize, Deserialize, Debug)] - #[allow(clippy::unsafe_derive_deserialize)] + #[expect(clippy::unsafe_derive_deserialize)] pub struct CountersMultiMapObserver { intervals: IntervalTree, len: usize, diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 3fc2e63adc..cb7aa2a142 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -23,7 +23,7 @@ use libafl::executors::{hooks::ExecutorHook, HasObservers}; use crate::coverage::EDGES_MAP; use crate::coverage::MAX_EDGES_FOUND; #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] -#[allow(unused)] +#[allow(unused_imports)] // only used in an unused function use crate::EDGES_MAP_DEFAULT_SIZE; #[cfg(feature = "pointer_maps")] use crate::{coverage::EDGES_MAP_PTR, EDGES_MAP_ALLOCATED_SIZE}; @@ -35,7 +35,7 @@ compile_error!( ); #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] -#[allow(unused)] +#[allow(unused_imports)] // only used in an unused function use core::ops::ShlAssign; #[cfg(feature = "sancov_ngram4")] @@ -180,7 +180,7 @@ where } #[rustversion::nightly] -#[allow(unused)] +#[expect(unused)] #[inline] #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] unsafe fn update_ngram(pos: usize) -> usize { @@ -224,9 +224,9 @@ extern "C" { /// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position. /// Should usually not be called directly. #[no_mangle] -#[allow(unused_assignments)] +#[allow(unused_assignments)] // cfg dependent pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) { - #[allow(unused_mut)] + #[allow(unused_mut)] // cfg dependent let mut pos = *guard as usize; #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] diff --git a/libafl_tinyinst/src/executor.rs b/libafl_tinyinst/src/executor.rs index b4b22d58fe..f699ab337d 100644 --- a/libafl_tinyinst/src/executor.rs +++ b/libafl_tinyinst/src/executor.rs @@ -82,7 +82,7 @@ where } } - #[allow(unused_assignments)] + #[expect(unused_assignments)] let mut status = RunResult::OK; unsafe { status = self.tinyinst.run(); diff --git a/scripts/dummy.rs b/scripts/dummy.rs index 7a0f064f28..464dee6f2e 100644 --- a/scripts/dummy.rs +++ b/scripts/dummy.rs @@ -1,5 +1,5 @@ /// Dummy file for Docker build caching /// Just here as dummy in docker -#[allow(dead_code)] +#[expect(dead_code)] fn main() { panic!("This is the CI dummy file - it should never run!") } \ No newline at end of file diff --git a/scripts/parallellize_cargo_clippy_on_fuzzers.py b/scripts/parallellize_cargo_clippy_on_fuzzers.py new file mode 100644 index 0000000000..8122d06d5c --- /dev/null +++ b/scripts/parallellize_cargo_clippy_on_fuzzers.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys +import argparse +from pathlib import Path +from concurrent.futures import ThreadPoolExecutor, as_completed +import multiprocessing +import logging + + +def main(): + # Parse command-line arguments + parser = argparse.ArgumentParser(description="Run Clippy on fuzzers in parallel.") + parser.add_argument( + "--dry-run", action="store_true", help="Show commands without executing." + ) + parser.add_argument( + "--pedantic", action="store_true", help="Activate all clippy warnings" + ) + args = parser.parse_args() + + # Setup logging + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s", + handlers=[logging.StreamHandler(sys.stdout)], + ) + if args.dry_run: + logging.info("Dry-run mode enabled. Commands will not be executed.") + + # Set directories + script_dir = Path(__file__).resolve().parent + libafl_dir = script_dir.parent + os.chdir(libafl_dir) + logging.debug(f"Changed directory to {libafl_dir}") + + # Initialize git submodules + cmd = "git submodule update --init" + logging.info(f"Running: {cmd}") + if not args.dry_run: + subprocess.run(cmd, shell=True, check=True) + + # Find fuzzer directories + fuzzers = list((libafl_dir / "fuzzers").glob("*/*")) + fuzzers.extend(list((libafl_dir / "fuzzers/baby/backtrace_baby_fuzzers").glob("*"))) + + fuzzers = [f for f in fuzzers if "nyx_" not in f.name and f.is_dir()] + logging.debug(f"Found {len(fuzzers)} fuzzers.") + + # Function to run commands + def run_clippy(fuzzer: Path): + if not (fuzzer / "Cargo.toml").is_file(): + logging.info(f"No Cargo.toml for {fuzzer}, skipping…") + return True + + options = "-D clippy::pedantic" if args.pedantic else "" + + cmd_default = f"cargo clippy -- -D warnings {options}" + cmd_nightly = f"cargo +nightly clippy -- -D warnings {options}" + for cmd in [cmd_default, cmd_nightly]: + logging.info(f"[{fuzzer}] Running: {cmd}") + if args.dry_run: + continue + result = subprocess.run( + cmd, + shell=True, + cwd=fuzzer, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + if result.returncode != 0: + logging.error( + f"[{fuzzer}] Command failed: cd {fuzzer}; {cmd}\n{result.stderr}" + ) + return False + else: + logging.info(f"[{fuzzer}] Clippy passed.") + + return True + + # Run Clippy in parallel + with ThreadPoolExecutor(max_workers=multiprocessing.cpu_count()) as executor: + futures = {executor.submit(run_clippy, fuzzer): fuzzer for fuzzer in fuzzers} + success = True + for future in as_completed(futures): + if not future.result(): + success = False + + if success: + logging.info("All fuzzers passed Clippy.") + sys.exit(0) + else: + logging.error("Some fuzzers failed Clippy.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/utils/build_and_test_fuzzers/src/diffing.rs b/utils/build_and_test_fuzzers/src/diffing.rs index 8b770e38cb..707ca3690f 100644 --- a/utils/build_and_test_fuzzers/src/diffing.rs +++ b/utils/build_and_test_fuzzers/src/diffing.rs @@ -35,7 +35,7 @@ pub fn get_diffing_files(commits: &[String]) -> HashSet { files } -#[allow(clippy::implicit_hasher)] +#[expect(clippy::implicit_hasher)] #[must_use] pub fn get_diffing_crates(diffing_files: &HashSet) -> HashSet { // TODO maybe consider using a combination of this and https://docs.rs/cargo/0.28.0/cargo/sources/path/struct.PathSource.html @@ -99,7 +99,7 @@ pub fn find_all_crates() -> HashSet { crates } -#[allow(clippy::implicit_hasher)] +#[expect(clippy::implicit_hasher)] pub fn extend_diffing_crates_with_deps( diffing_crates: &mut HashSet, all_crates: &HashSet, diff --git a/utils/desyscall/src/file.rs b/utils/desyscall/src/file.rs index 0e146d9396..9a0ffaa17e 100644 --- a/utils/desyscall/src/file.rs +++ b/utils/desyscall/src/file.rs @@ -11,7 +11,7 @@ extern "C" { /// # Safety /// Call to functions using syscalls -#[allow(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap)] #[no_mangle] pub unsafe extern "C" fn write(fd: c_int, buf: Pointer, count: size_t) -> ssize_t { let ctx = Context::get(); diff --git a/utils/desyscall/src/mmap.rs b/utils/desyscall/src/mmap.rs index 948d425cf0..f101ec18e7 100644 --- a/utils/desyscall/src/mmap.rs +++ b/utils/desyscall/src/mmap.rs @@ -42,7 +42,7 @@ extern "C" { /// # Safety /// Call to functions using syscalls #[no_mangle] -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] #[cfg(not(windows))] pub unsafe extern "C" fn mmap( addr: Pointer, @@ -162,7 +162,7 @@ pub unsafe extern "C" fn mmap( } let mut reminder_next = None; - #[allow(clippy::comparison_chain)] + #[expect(clippy::comparison_chain)] if let Some(p) = prev.take() { if p.0 < end { fail = true; diff --git a/utils/drcov_utils/src/bin/drcov_dump_addrs.rs b/utils/drcov_utils/src/bin/drcov_dump_addrs.rs index 533dea3186..262cdaf6b1 100644 --- a/utils/drcov_utils/src/bin/drcov_dump_addrs.rs +++ b/utils/drcov_utils/src/bin/drcov_dump_addrs.rs @@ -9,7 +9,6 @@ use libafl_targets::drcov::DrCovReader; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] -#[allow(clippy::module_name_repetitions)] #[command( name = "drcov_dump_addrs", about, diff --git a/utils/drcov_utils/src/bin/drcov_merge.rs b/utils/drcov_utils/src/bin/drcov_merge.rs index 6069cd451d..13d3d4a4d3 100644 --- a/utils/drcov_utils/src/bin/drcov_merge.rs +++ b/utils/drcov_utils/src/bin/drcov_merge.rs @@ -1,11 +1,10 @@ use std::path::PathBuf; -use clap::{ArgAction, Parser}; +use clap::Parser; use libafl_targets::drcov::DrCovReader; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] -#[allow(clippy::module_name_repetitions)] #[command( name = "drcov_merge", about, diff --git a/utils/libafl_fmt/src/main.rs b/utils/libafl_fmt/src/main.rs index 336a409c00..b716c5a78a 100644 --- a/utils/libafl_fmt/src/main.rs +++ b/utils/libafl_fmt/src/main.rs @@ -352,7 +352,7 @@ async fn get_version_string(path: &str, args: &[&str]) -> Result ! { #[cfg(feature = "std")] println!("Hex: {addr:#x}"); - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation)] let addr = addr as usize; let entrypoint = addr as *mut c_void; From 03f7fc93ad17811a1a1153c0e1d6d541bc9400ba Mon Sep 17 00:00:00 2001 From: Valentin Huber Date: Mon, 23 Dec 2024 11:39:51 +0100 Subject: [PATCH 02/25] Fix empty multipart (#2789) --- libafl/src/mutators/multi.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libafl/src/mutators/multi.rs b/libafl/src/mutators/multi.rs index 032e35433c..66dd1ab672 100644 --- a/libafl/src/mutators/multi.rs +++ b/libafl/src/mutators/multi.rs @@ -198,6 +198,10 @@ where let mut other_testcase = state.corpus().get(id)?.borrow_mut(); let other = other_testcase.load_input(state.corpus())?; + if other.names().is_empty() { + return Ok(MutationResult::Skipped); + } + let choice = name_choice % other.names().len(); let name = &other.names()[choice]; @@ -324,6 +328,10 @@ where let mut other_testcase = state.corpus().get(id)?.borrow_mut(); let other = other_testcase.load_input(state.corpus())?; + if other.names().is_empty() { + return Ok(MutationResult::Skipped); + } + let choice = name_choice % other.names().len(); let name = &other.names()[choice]; From 54202c3ef3a4ca5b39473d4d5e30914ca51551ab Mon Sep 17 00:00:00 2001 From: Valentin Huber Date: Mon, 23 Dec 2024 13:25:14 +0100 Subject: [PATCH 03/25] Add macros to libafl_bolts tuples for mapping and merging types (#2788) * Add macros * Use the macros for havoc_mutations * Fix docs * improve merge_tuple_list_type to accept n items --- libafl/src/mutators/havoc_mutations.rs | 105 ++++----------------- libafl_bolts/src/shmem.rs | 9 +- libafl_bolts/src/tuples.rs | 123 +++++++++++++++++++++++-- 3 files changed, 136 insertions(+), 101 deletions(-) diff --git a/libafl/src/mutators/havoc_mutations.rs b/libafl/src/mutators/havoc_mutations.rs index 7399ba7930..f2d1c512e3 100644 --- a/libafl/src/mutators/havoc_mutations.rs +++ b/libafl/src/mutators/havoc_mutations.rs @@ -1,11 +1,12 @@ //! [`crate::mutators::Mutator`] collection equivalent to AFL++'s havoc mutations -use libafl_bolts::tuples::{Map, Merge}; -use tuple_list::{tuple_list, tuple_list_type}; +use libafl_bolts::{ + map_tuple_list_type, merge_tuple_list_type, + tuples::{tuple_list, tuple_list_type, Map, Merge}, +}; -use super::{MappingMutator, ToMappingMutator}; use crate::mutators::{ - mapping::{OptionalMutator, ToOptionalMutator}, + mapping::{ToMappingMutator, ToOptionalMutator}, mutations::{ BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator, ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator, @@ -56,96 +57,22 @@ pub type MappedHavocCrossoverType = tuple_list_type!( ); /// Tuple type of the mutations that compose the Havoc mutator -pub type HavocMutationsType = tuple_list_type!( - BitFlipMutator, - ByteFlipMutator, - ByteIncMutator, - ByteDecMutator, - ByteNegMutator, - ByteRandMutator, - ByteAddMutator, - WordAddMutator, - DwordAddMutator, - QwordAddMutator, - ByteInterestingMutator, - WordInterestingMutator, - DwordInterestingMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesExpandMutator, - BytesInsertMutator, - BytesRandInsertMutator, - BytesSetMutator, - BytesRandSetMutator, - BytesCopyMutator, - BytesInsertCopyMutator, - BytesSwapMutator, - CrossoverInsertMutator, - CrossoverReplaceMutator, -); +pub type HavocMutationsType = + merge_tuple_list_type!(HavocMutationsNoCrossoverType, HavocCrossoverType); /// Tuple type of the mutations that compose the Havoc mutator for mapped input types -pub type MappedHavocMutationsType = tuple_list_type!( - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, - MappingMutator, F1>, - MappingMutator, F1>, +pub type MappedHavocMutationsType = map_tuple_list_type!( + merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType), + ToMappingMutator ); /// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts -pub type OptionMappedHavocMutationsType = tuple_list_type!( - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator, F1>, - MappingMutator>, F1>, - MappingMutator>, F1>, +pub type OptionMappedHavocMutationsType = map_tuple_list_type!( + map_tuple_list_type!( + merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType), + ToOptionalMutator + ), + ToMappingMutator ); /// Get the mutations that compose the Havoc mutator (only applied to single inputs) diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index 5f1c00e7f2..7df2bbe154 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -624,12 +624,12 @@ where /// Is needed on top. #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] pub mod unix_shmem { - /// Mmap [`ShMem`] for Unix - #[cfg(not(target_os = "android"))] - pub use default::MmapShMem; /// Mmap [`ShMemProvider`] for Unix #[cfg(not(target_os = "android"))] pub use default::MmapShMemProvider; + /// Mmap [`ShMem`] for Unix + #[cfg(not(target_os = "android"))] + pub use default::{MmapShMem, MAX_MMAP_FILENAME_LEN}; #[cfg(doc)] use crate::shmem::{ShMem, ShMemProvider}; @@ -669,7 +669,8 @@ pub mod unix_shmem { Error, }; - const MAX_MMAP_FILENAME_LEN: usize = 20; + /// The size of the buffer of the filename of mmap mapped memory regions + pub const MAX_MMAP_FILENAME_LEN: usize = 20; /// Mmap-based The sharedmap impl for unix using [`shm_open`] and [`mmap`]. /// Default on `MacOS` and `iOS`, where we need a central point to unmap diff --git a/libafl_bolts/src/tuples.rs b/libafl_bolts/src/tuples.rs index f9497799a7..4c9b5c78aa 100644 --- a/libafl_bolts/src/tuples.rs +++ b/libafl_bolts/src/tuples.rs @@ -833,6 +833,81 @@ macro_rules! tuple_for_each_mut { }; } +/// Maps the types of a mapping with a [`MappingFunctor`] +/// +/// ```rust +/// use libafl_bolts::{ +/// map_tuple_list_type, +/// tuples::{MappingFunctor, Map, tuple_list, tuple_list_type} +/// }; +/// +/// struct Wrapper(T); +/// struct MyMapper; +/// +/// impl MappingFunctor for MyMapper { +/// type Output = Wrapper; +/// +/// fn apply(&mut self, from: T) -> >::Output { +/// Wrapper(from) +/// } +/// } +/// +/// struct A; +/// struct B; +/// struct C; +/// +/// type OrigType = tuple_list_type!(A, B, C); +/// type MappedType = map_tuple_list_type!(OrigType, MyMapper); +/// let orig: OrigType = tuple_list!(A, B, C); +/// let _mapped: MappedType = orig.map(MyMapper); +/// ``` +#[macro_export] +macro_rules! map_tuple_list_type { + ($Tuple:ty, $Mapper:ty) => { + <$Tuple as $crate::tuples::Map<$Mapper>>::MapResult + }; +} + +/// Merges the types of two merged [`tuple_list!`]s +/// +/// ```rust +/// use libafl_bolts::{merge_tuple_list_type, tuples::{Merge, tuple_list, tuple_list_type}}; +/// +/// struct A; +/// struct B; +/// struct C; +/// struct D; +/// struct E; +/// +/// type Lhs = tuple_list_type!(A, B, C); +/// type Rhs = tuple_list_type!(D, E); +/// type Merged = merge_tuple_list_type!(Lhs, Rhs); +/// +/// let lhs: Lhs = tuple_list!(A, B, C); +/// let rhs: Rhs = tuple_list!(D, E); +/// let _merged: Merged = lhs.merge(rhs); +/// ``` +#[macro_export] +macro_rules! merge_tuple_list_type { + // Base case: when only two types are provided, apply the Merge trait directly + ($Type1:ty) => { + $Type1 + }; + + // Base case: when only two types are provided, apply the Merge trait directly + ($Type1:ty, $Type2:ty) => { + <$Type1 as $crate::tuples::Merge<$Type2>>::MergeResult + }; + + // Recursive case: when more than two types are provided + ($Type1:ty, $Type2:ty, $( $rest:ty ),+) => { + merge_tuple_list_type!( + <$Type1 as $crate::tuples::Merge<$Type2>>::MergeResult, + $( $rest ),+ + ) + }; +} + /* // Define trait and implement it for several primitive types. @@ -864,11 +939,13 @@ impl PlusOne for (Head, Tail) where #[cfg(test)] mod test { + use core::marker::PhantomData; + use tuple_list::{tuple_list, tuple_list_type}; #[cfg(feature = "alloc")] use crate::ownedref::OwnedMutSlice; - use crate::tuples::{type_eq, Map, MappingFunctor}; + use crate::tuples::{type_eq, Map, MappingFunctor, Merge}; #[test] // for type name tests @@ -916,9 +993,11 @@ mod test { #[test] fn test_mapper() { struct W(T); - struct MyMapper; - impl MappingFunctor for MyMapper { + // PhantomData shows how to deal with mappers that have generics + struct ExampleMapper

(PhantomData

); + + impl MappingFunctor for ExampleMapper

{ type Output = W; fn apply(&mut self, from: T) -> Self::Output { @@ -930,12 +1009,40 @@ mod test { struct B; struct C; - let orig = tuple_list!(A, B, C); - let mapped = orig.map(MyMapper); + type OrigType = tuple_list_type!(A, B, C); + type MappedType = map_tuple_list_type!(OrigType, ExampleMapper); + let orig: OrigType = tuple_list!(A, B, C); + let _mapped: MappedType = orig.map(ExampleMapper(PhantomData::)); + } - // this won't compile if the mapped type is not correct - #[expect(clippy::no_effect_underscore_binding)] - let _type_assert: tuple_list_type!(W, W, W) = mapped; + #[test] + fn test_merge() { + struct A; + struct B; + struct C; + struct D; + struct E; + + type Lhs = tuple_list_type!(A, B, C); + type Rhs = tuple_list_type!(D, E); + type Merged = merge_tuple_list_type!(Lhs, Rhs); + type IndividuallyMergedPre = merge_tuple_list_type!( + tuple_list_type!(A), + tuple_list_type!(B), + tuple_list_type!(C), + Rhs + ); + type IndividuallyMergedPost = + merge_tuple_list_type!(Lhs, tuple_list_type!(D), tuple_list_type!(E)); + type MergedCloned = merge_tuple_list_type!(Merged); + + let lhs: Lhs = tuple_list!(A, B, C); + let rhs: Rhs = tuple_list!(D, E); + let merged: Merged = lhs.merge(rhs); + let merged: IndividuallyMergedPre = merged; + let merged: IndividuallyMergedPost = merged; + #[allow(clippy::no_effect_underscore_binding)] + let _merged: MergedCloned = merged; } /// Function that tests the tuple macros From 6927d61a89e70622dd52caa920bd5011409633ed Mon Sep 17 00:00:00 2001 From: s1341 Date: Tue, 24 Dec 2024 11:00:44 +0200 Subject: [PATCH 04/25] libafl_cc: Automatically find llvm_ar path (#2790) --- libafl_cc/build.rs | 18 ++++++++++++++++++ libafl_cc/src/ar.rs | 8 +++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libafl_cc/build.rs b/libafl_cc/build.rs index c602457e58..d58b8ca835 100644 --- a/libafl_cc/build.rs +++ b/libafl_cc/build.rs @@ -234,6 +234,7 @@ fn main() { println!("cargo:rerun-if-env-changed=LLVM_CONFIG"); println!("cargo:rerun-if-env-changed=LLVM_BINDIR"); + println!("cargo:rerun-if-env-changed=LLVM_AR_PATH"); println!("cargo:rerun-if-env-changed=LLVM_CXXFLAGS"); println!("cargo:rerun-if-env-changed=LLVM_LDFLAGS"); println!("cargo:rerun-if-env-changed=LLVM_VERSION"); @@ -244,6 +245,7 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let llvm_bindir = env::var("LLVM_BINDIR"); + let llvm_ar_path = env::var("LLVM_AR_PATH"); let llvm_cxxflags = env::var("LLVM_CXXFLAGS"); let llvm_ldflags = env::var("LLVM_LDFLAGS"); let llvm_version = env::var("LLVM_VERSION"); @@ -266,6 +268,8 @@ fn main() { pub const CLANG_PATH: &str = \"clang\"; /// The path to the `clang++` executable pub const CLANGXX_PATH: &str = \"clang++\"; +/// The path to the `llvm-ar` executable +pub const LLVM_AR_PATH: &str = \"llvm-ar\"; /// The llvm version used to build llvm passes pub const LIBAFL_CC_LLVM_VERSION: Option = None; " @@ -281,16 +285,24 @@ pub const LIBAFL_CC_LLVM_VERSION: Option = None; exec_llvm_config(&["--bindir"]) }; let bindir_path = Path::new(&llvm_bindir); + let llvm_ar_path = if let Ok(ar_path) = llvm_ar_path { + ar_path + } else { + exec_llvm_config(&["--bindir"]) + }; let clang; let clangcpp; + let llvm_ar; if cfg!(windows) { clang = bindir_path.join("clang.exe"); clangcpp = bindir_path.join("clang++.exe"); + llvm_ar = Path::new(&llvm_ar_path).join("llvm-ar.exe"); } else { clang = bindir_path.join("clang"); clangcpp = bindir_path.join("clang++"); + llvm_ar = Path::new(&llvm_ar_path).join("llvm-ar"); } if !clang.exists() { @@ -302,6 +314,10 @@ pub const LIBAFL_CC_LLVM_VERSION: Option = None; println!("cargo:warning=Failed to find clang++ frontend."); return; } + if !llvm_ar.exists() { + println!("cargo:warning=Failed to find llvm-ar archiver."); + return; + } let cxxflags = if let Ok(flags) = llvm_cxxflags { flags @@ -344,6 +360,8 @@ pub const LIBAFL_CC_LLVM_VERSION: Option = None; pub const CLANG_PATH: &str = {clang:?}; /// The path to the `clang++` executable pub const CLANGXX_PATH: &str = {clangcpp:?}; + /// The path to the `llvm-ar` executable + pub const LLVM_AR_PATH: &str = {llvm_ar:?}; /// The default size of the edges map the fuzzer uses pub const EDGES_MAP_DEFAULT_SIZE: usize = {edge_map_default_size}; diff --git a/libafl_cc/src/ar.rs b/libafl_cc/src/ar.rs index 373d6b4b2c..50eeb3e68b 100644 --- a/libafl_cc/src/ar.rs +++ b/libafl_cc/src/ar.rs @@ -5,6 +5,8 @@ use std::{env, path::PathBuf, str::FromStr}; use crate::{Error, ToolWrapper, LIB_EXT, LIB_PREFIX}; +include!(concat!(env!("OUT_DIR"), "/clang_constants.rs")); + /// Wrap Clang #[expect(clippy::struct_excessive_bools)] #[derive(Debug)] @@ -184,11 +186,7 @@ impl ToolWrapper for ArWrapper { }) .collect::>(); - let Ok(ar_path) = env::var("LLVM_AR_PATH") else { - panic!("Couldn't find llvm-ar. Specify the `LLVM_AR_PATH` environment variable"); - }; - - args.push(ar_path); + args.push(LLVM_AR_PATH.to_string()); args.extend_from_slice(base_args.as_slice()); From 9b4cd51c638e69204437838d381dd657b0cd2e4f Mon Sep 17 00:00:00 2001 From: s1341 Date: Tue, 24 Dec 2024 15:22:01 +0200 Subject: [PATCH 05/25] imemory_ondisk: Don't fail write under any circumstances if locking is disabled (#2791) * imemory_ondisk: Don't fail write under any circumstances if locking is disabled * fmt * inmemory_ondisk: Add a log message on failure * clippy' * micro optimization --- libafl/src/corpus/inmemory_ondisk.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index c2e0a5536b..8afccf93cb 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -442,7 +442,12 @@ impl InMemoryOnDiskCorpus { *testcase.metadata_path_mut() = Some(metafile_path); } - self.store_input_from(testcase)?; + if let Err(err) = self.store_input_from(testcase) { + if self.locking { + return Err(err); + } + log::error!("An error occurred when trying to write a testcase without locking: {err}"); + } Ok(()) } From 2a79ee5b4fe5d73c03803c10beb336925e9a920f Mon Sep 17 00:00:00 2001 From: s1341 Date: Wed, 25 Dec 2024 14:42:54 +0200 Subject: [PATCH 06/25] frida: Deduplicate with IfElseRuntime (#2792) * frida: Deduplicate with IfElseRuntime * clippy' * get rid of cfg * fmt * documentation * fix lint * fix lint * debug: add tmate * debug: add tmate * frida_windows_gdiplus: move to mimalloc on windows * remove tmate --- .../binary_only/frida_libpng/src/fuzzer.rs | 559 ++++++------------ .../frida_windows_gdiplus/Cargo.toml | 2 +- .../frida_windows_gdiplus/src/fuzzer.rs | 7 - libafl_frida/src/asan/asan_rt.rs | 4 +- libafl_frida/src/helper.rs | 72 +++ 5 files changed, 243 insertions(+), 401 deletions(-) diff --git a/fuzzers/binary_only/frida_libpng/src/fuzzer.rs b/fuzzers/binary_only/frida_libpng/src/fuzzer.rs index 6f49f06a72..9a94d2459a 100644 --- a/fuzzers/binary_only/frida_libpng/src/fuzzer.rs +++ b/fuzzers/binary_only/frida_libpng/src/fuzzer.rs @@ -21,7 +21,7 @@ use libafl::{ }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, - stages::{ShadowTracingStage, StdMutationalStage}, + stages::{IfElseStage, ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, Error, HasMetadata, }; @@ -34,16 +34,15 @@ use libafl_bolts::{ tuples::{tuple_list, Merge}, AsSlice, }; -#[cfg(unix)] -use libafl_frida::asan::{ - asan_rt::AsanRuntime, - errors::{AsanErrorsFeedback, AsanErrorsObserver}, -}; use libafl_frida::{ + asan::{ + asan_rt::AsanRuntime, + errors::{AsanErrorsFeedback, AsanErrorsObserver}, + }, cmplog_rt::CmpLogRuntime, coverage_rt::{CoverageRuntime, MAP_SIZE}, executor::FridaInProcessExecutor, - helper::FridaInstrumentationHelper, + helper::{FridaInstrumentationHelper, IfElseRuntime}, }; use libafl_targets::cmplog::CmpLogObserver; use mimalloc::MiMalloc; @@ -74,6 +73,12 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let monitor = MultiMonitor::new(|s| println!("{s}")); let shmem_provider = StdShMemProvider::new()?; + let is_asan = |options: &FuzzerOptions, client_description: &ClientDescription| { + options.asan && options.asan_cores.contains(client_description.core_id()) + }; + let is_cmplog = |options: &FuzzerOptions, client_description: &ClientDescription| { + options.cmplog && options.cmplog_cores.contains(client_description.core_id()) + }; let mut run_client = |state: Option<_>, mgr: LlmpRestartingEventManager<_, _, _>, @@ -94,390 +99,162 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { ExitKind::Ok }; - if options.asan && options.asan_cores.contains(client_description.core_id()) { - (|state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _>, - _client_description| { - let gum = Gum::obtain(); - - let coverage = CoverageRuntime::new(); - #[cfg(unix)] - let asan = AsanRuntime::new(options); - - #[cfg(unix)] - let mut frida_helper = - FridaInstrumentationHelper::new(&gum, options, tuple_list!(asan, coverage)); - #[cfg(windows)] - let mut frida_helper = - FridaInstrumentationHelper::new(&gum, &options, tuple_list!(coverage)); - - // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( - "edges", - frida_helper.map_mut_ptr().unwrap(), - MAP_SIZE, - )) - .track_indices(); - - // Create an observation channel to keep track of the execution time - let time_observer = TimeObserver::new("time"); - #[cfg(unix)] - let asan_observer = AsanErrorsObserver::from_static_asan_errors(); - - // Feedback to rate the interestingness of an input - // This one is composed by two Feedbacks in OR - let mut feedback = feedback_or!( - // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new(&edges_observer), - // Time feedback, this one does not need a feedback state - TimeFeedback::new(&time_observer) - ); - - // Feedbacks to recognize an input as solution - #[cfg(unix)] - let mut objective = feedback_or_fast!( - CrashFeedback::new(), - TimeoutFeedback::new(), - // true enables the AsanErrorFeedback - feedback_and_fast!( - ConstFeedback::from(true), - AsanErrorsFeedback::new(&asan_observer) - ) - ); - #[cfg(windows)] - let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); - - // If not restarting, create a State from scratch - let mut state = state.unwrap_or_else(|| { - StdState::new( - // RNG - StdRand::new(), - // Corpus that will be evolved, we keep it in memory for performance - CachedOnDiskCorpus::no_meta(PathBuf::from("./corpus_discovered"), 64) - .unwrap(), - // Corpus in which we store solutions (crashes in this example), - // on disk so the user can get them after stopping the fuzzer - OnDiskCorpus::new(options.output.clone()).unwrap(), - &mut feedback, - &mut objective, - ) - .unwrap() - }); - - println!("We're a client, let's fuzz :)"); - - // Create a PNG dictionary if not existing - if state.metadata_map().get::().is_none() { - state.add_metadata(Tokens::from([ - vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header - b"IHDR".to_vec(), - b"IDAT".to_vec(), - b"PLTE".to_vec(), - b"IEND".to_vec(), - ])); - } - - // Setup a basic mutator with a mutational stage - let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - - // A minimization+queue policy to get testcasess from the corpus - let scheduler = - IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); - - // A fuzzer with feedbacks and a corpus scheduler - let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - - #[cfg(unix)] - let observers = tuple_list!(edges_observer, time_observer, asan_observer); - #[cfg(windows)] - let observers = tuple_list!(edges_observer, time_observer); - - // Create the executor for an in-process function with just one observer for edge coverage - let mut executor = FridaInProcessExecutor::new( - &gum, - InProcessExecutor::new( - &mut frida_harness, - observers, - &mut fuzzer, - &mut state, - &mut mgr, - )?, - &mut frida_helper, - ); - - // In case the corpus is empty (on first run), reset - if state.must_load_initial_inputs() { - state - .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &options.input) - .unwrap_or_else(|_| { - panic!("Failed to load initial corpus at {:?}", &options.input) - }); - println!("We imported {} inputs from disk.", state.corpus().count()); - } - - let mut stages = tuple_list!(StdMutationalStage::new(mutator)); - - fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; - - Ok(()) - })(state, mgr, client_description) - } else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) { - (|state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _>, - _client_description| { - let gum = Gum::obtain(); - - let coverage = CoverageRuntime::new(); - let cmplog = CmpLogRuntime::new(); - println!("cmplog runtime created"); - - let mut frida_helper = - FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage, cmplog)); - - // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( - "edges", - frida_helper.map_mut_ptr().unwrap(), - MAP_SIZE, - )) - .track_indices(); - - // Create an observation channel to keep track of the execution time - let time_observer = TimeObserver::new("time"); - #[cfg(unix)] - let asan_observer = AsanErrorsObserver::from_static_asan_errors(); - - // Feedback to rate the interestingness of an input - // This one is composed by two Feedbacks in OR - let mut feedback = feedback_or!( - // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new(&edges_observer), - // Time feedback, this one does not need a feedback state - TimeFeedback::new(&time_observer) - ); - - #[cfg(unix)] - let mut objective = feedback_or_fast!( - CrashFeedback::new(), - TimeoutFeedback::new(), - feedback_and_fast!( - ConstFeedback::from(false), - AsanErrorsFeedback::new(&asan_observer) - ) - ); - #[cfg(windows)] - let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); - - // If not restarting, create a State from scratch - let mut state = state.unwrap_or_else(|| { - StdState::new( - // RNG - StdRand::new(), - // Corpus that will be evolved, we keep it in memory for performance - CachedOnDiskCorpus::no_meta(PathBuf::from("./corpus_discovered"), 64) - .unwrap(), - // Corpus in which we store solutions (crashes in this example), - // on disk so the user can get them after stopping the fuzzer - OnDiskCorpus::new(options.output.clone()).unwrap(), - &mut feedback, - &mut objective, - ) - .unwrap() - }); - - println!("We're a client, let's fuzz :)"); - - // Create a PNG dictionary if not existing - if state.metadata_map().get::().is_none() { - state.add_metadata(Tokens::from([ - vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header - b"IHDR".to_vec(), - b"IDAT".to_vec(), - b"PLTE".to_vec(), - b"IEND".to_vec(), - ])); - } - - // Setup a basic mutator with a mutational stage - let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - - // A minimization+queue policy to get testcasess from the corpus - let scheduler = - IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); - - // A fuzzer with feedbacks and a corpus scheduler - let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - - #[cfg(unix)] - let observers = tuple_list!(edges_observer, time_observer, asan_observer); - #[cfg(windows)] - let observers = tuple_list!(edges_observer, time_observer); - - // Create the executor for an in-process function with just one observer for edge coverage - let mut executor = FridaInProcessExecutor::new( - &gum, - InProcessExecutor::new( - &mut frida_harness, - observers, - &mut fuzzer, - &mut state, - &mut mgr, - )?, - &mut frida_helper, - ); - - // In case the corpus is empty (on first run), reset - if state.must_load_initial_inputs() { - state - .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &options.input) - .unwrap_or_else(|_| { - panic!("Failed to load initial corpus at {:?}", &options.input) - }); - println!("We imported {} inputs from disk.", state.corpus().count()); - } - - // Create an observation channel using cmplog map - let cmplog_observer = CmpLogObserver::new("cmplog", true); - - let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer)); - - let tracing = ShadowTracingStage::new(&mut executor); - - // Setup a randomic Input2State stage - let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!( - I2SRandReplace::new() - ))); - - // Setup a basic mutator - let mutational = StdMutationalStage::new(mutator); - - // The order of the stages matter! - let mut stages = tuple_list!(tracing, i2s, mutational); - - fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; - - Ok(()) - })(state, mgr, client_description) - } else { - (|state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _>, - _client_description| { - let gum = Gum::obtain(); - - let coverage = CoverageRuntime::new(); - - let mut frida_helper = - FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage)); - - // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( - "edges", - frida_helper.map_mut_ptr().unwrap(), - MAP_SIZE, - )) - .track_indices(); - - // Create an observation channel to keep track of the execution time - let time_observer = TimeObserver::new("time"); - #[cfg(unix)] - let asan_observer = AsanErrorsObserver::from_static_asan_errors(); - - // Feedback to rate the interestingness of an input - // This one is composed by two Feedbacks in OR - let mut feedback = feedback_or!( - // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new(&edges_observer), - // Time feedback, this one does not need a feedback state - TimeFeedback::new(&time_observer) - ); - - #[cfg(unix)] - let mut objective = feedback_or_fast!( - CrashFeedback::new(), - TimeoutFeedback::new(), - feedback_and_fast!( - ConstFeedback::from(false), - AsanErrorsFeedback::new(&asan_observer) - ) - ); - #[cfg(windows)] - let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); - - // If not restarting, create a State from scratch - let mut state = state.unwrap_or_else(|| { - StdState::new( - // RNG - StdRand::new(), - // Corpus that will be evolved, we keep it in memory for performance - CachedOnDiskCorpus::no_meta(PathBuf::from("./corpus_discovered"), 64) - .unwrap(), - // Corpus in which we store solutions (crashes in this example), - // on disk so the user can get them after stopping the fuzzer - OnDiskCorpus::new(options.output.clone()).unwrap(), - &mut feedback, - &mut objective, - ) - .unwrap() - }); - - println!("We're a client, let's fuzz :)"); - - // Create a PNG dictionary if not existing - if state.metadata_map().get::().is_none() { - state.add_metadata(Tokens::from([ - vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header - b"IHDR".to_vec(), - b"IDAT".to_vec(), - b"PLTE".to_vec(), - b"IEND".to_vec(), - ])); - } - - // Setup a basic mutator with a mutational stage - let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - - // A minimization+queue policy to get testcasess from the corpus - let scheduler = - IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); - - // A fuzzer with feedbacks and a corpus scheduler - let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - - #[cfg(unix)] - let observers = tuple_list!(edges_observer, time_observer, asan_observer); - #[cfg(windows)] - let observers = tuple_list!(edges_observer, time_observer); - - // Create the executor for an in-process function with just one observer for edge coverage - let mut executor = FridaInProcessExecutor::new( - &gum, - InProcessExecutor::new( - &mut frida_harness, - observers, - &mut fuzzer, - &mut state, - &mut mgr, - )?, - &mut frida_helper, - ); - - // In case the corpus is empty (on first run), reset - if state.must_load_initial_inputs() { - state - .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &options.input) - .unwrap_or_else(|_| { - panic!("Failed to load initial corpus at {:?}", &options.input) - }); - println!("We imported {} inputs from disk.", state.corpus().count()); - } - - let mut stages = tuple_list!(StdMutationalStage::new(mutator)); - - fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; - - Ok(()) - })(state, mgr, client_description) - } + // if options.asan && options.asan_cores.contains(client_description.core_id()) { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _>, _client_description| { + let gum = Gum::obtain(); + + let coverage = CoverageRuntime::new(); + let asan = AsanRuntime::new(options); + let cmplog = CmpLogRuntime::new(); + + let client_description_clone = client_description.clone(); + let options_clone = options.clone(); + let client_description_clone2 = client_description.clone(); + let options_clone2 = options.clone(); + let mut frida_helper = FridaInstrumentationHelper::new( + &gum, + options, + tuple_list!( + IfElseRuntime::new( + move || Ok(is_asan(&options_clone, &client_description_clone)), + tuple_list!(asan), + tuple_list!() + ), + IfElseRuntime::new( + move || Ok(is_cmplog(&options_clone2, &client_description_clone2)), + tuple_list!(cmplog), + tuple_list!() + ), + coverage + ), + ); + + // Create an observation channel using the coverage map + let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( + "edges", + frida_helper.map_mut_ptr().unwrap(), + MAP_SIZE, + )) + .track_indices(); + + // Create an observation channel to keep track of the execution time + let time_observer = TimeObserver::new("time"); + let asan_observer = AsanErrorsObserver::from_static_asan_errors(); + + // Feedback to rate the interestingness of an input + // This one is composed by two Feedbacks in OR + let mut feedback = feedback_or!( + // New maximization map feedback linked to the edges observer and the feedback state + MaxMapFeedback::new(&edges_observer), + // Time feedback, this one does not need a feedback state + TimeFeedback::new(&time_observer) + ); + + // Feedbacks to recognize an input as solution + #[cfg(unix)] + let mut objective = feedback_or_fast!( + CrashFeedback::new(), + TimeoutFeedback::new(), + // true enables the AsanErrorFeedback + feedback_and_fast!( + ConstFeedback::from(true), + AsanErrorsFeedback::new(&asan_observer) + ) + ); + #[cfg(windows)] + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + + // If not restarting, create a State from scratch + let mut state = state.unwrap_or_else(|| { + StdState::new( + // RNG + StdRand::new(), + // Corpus that will be evolved, we keep it in memory for performance + CachedOnDiskCorpus::no_meta(PathBuf::from("./corpus_discovered"), 64).unwrap(), + // Corpus in which we store solutions (crashes in this example), + // on disk so the user can get them after stopping the fuzzer + OnDiskCorpus::new(options.output.clone()).unwrap(), + &mut feedback, + &mut objective, + ) + .unwrap() + }); + + println!("We're a client, let's fuzz :)"); + + // Create a PNG dictionary if not existing + if state.metadata_map().get::().is_none() { + state.add_metadata(Tokens::from([ + vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header + b"IHDR".to_vec(), + b"IDAT".to_vec(), + b"PLTE".to_vec(), + b"IEND".to_vec(), + ])); + } + + // Setup a basic mutator with a mutational stage + let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); + + // A minimization+queue policy to get testcasess from the corpus + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); + + // A fuzzer with feedbacks and a corpus scheduler + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); + + #[cfg(unix)] + let observers = tuple_list!(edges_observer, time_observer, asan_observer); + #[cfg(windows)] + let observers = tuple_list!(edges_observer, time_observer); + + // Create the executor for an in-process function with just one observer for edge coverage + let mut executor = FridaInProcessExecutor::new( + &gum, + InProcessExecutor::new( + &mut frida_harness, + observers, + &mut fuzzer, + &mut state, + &mut mgr, + )?, + &mut frida_helper, + ); + // Create an observation channel using cmplog map + let cmplog_observer = CmpLogObserver::new("cmplog", true); + + let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer)); + + let tracing = ShadowTracingStage::new(&mut executor); + + // Setup a randomic Input2State stage + let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!( + I2SRandReplace::new() + ))); + + // In case the corpus is empty (on first run), reset + if state.must_load_initial_inputs() { + state + .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &options.input) + .unwrap_or_else(|_| { + panic!("Failed to load initial corpus at {:?}", &options.input) + }); + println!("We imported {} inputs from disk.", state.corpus().count()); + } + + let mut stages = tuple_list!( + IfElseStage::new( + |_, _, _, _| Ok(is_cmplog(&options, &client_description)), + tuple_list!(tracing, i2s), + tuple_list!() + ), + StdMutationalStage::new(mutator) + ); + + fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; + + Ok(()) + })(state, mgr, client_description.clone()) }; Launcher::builder() diff --git a/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml b/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml index 43b2252748..92ae48c01e 100644 --- a/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml +++ b/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml @@ -36,7 +36,7 @@ libafl_targets = { path = "../../../libafl_targets", features = [ libloading = "0.8.5" log = { version = "0.4.22", features = ["release_max_level_info"] } mimalloc = { version = "0.1.43", default-features = false } -dlmalloc = { version = "0.2.6", features = ["global"] } +#dlmalloc = { version = "0.2.6", features = ["global"] } color-backtrace = "0.6.1" env_logger = "0.11.5" iced-x86 = { version = "1.21.0", features = ["code_asm"] } diff --git a/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs b/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs index 41afe956b5..42e9d5de25 100644 --- a/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs +++ b/fuzzers/binary_only/frida_windows_gdiplus/src/fuzzer.rs @@ -6,16 +6,9 @@ //! going to make it compilable only for Windows, don't forget to modify the //! `scripts/test_fuzzer.sh` to opt-out this fuzzer from that test. -#[cfg(unix)] use mimalloc::MiMalloc; -#[cfg(unix)] #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; -#[cfg(windows)] -use dlmalloc::GlobalDlmalloc; -#[cfg(windows)] -#[global_allocator] -static GLOBAL: GlobalDlmalloc = GlobalDlmalloc; use std::path::PathBuf; diff --git a/libafl_frida/src/asan/asan_rt.rs b/libafl_frida/src/asan/asan_rt.rs index 0fd25d79d2..727b248249 100644 --- a/libafl_frida/src/asan/asan_rt.rs +++ b/libafl_frida/src/asan/asan_rt.rs @@ -509,7 +509,7 @@ impl AsanRuntime { let _ = [<$lib_ident:snake:upper _ $name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap(); - #[expect(non_snake_case)] + #[allow(non_snake_case)] unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); @@ -593,7 +593,7 @@ impl AsanRuntime { let _ = [<$lib_ident:snake:upper _ $name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap_or_else(|e| println!("{:?}", e)); - #[expect(non_snake_case)] + #[allow(non_snake_case)] unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index d7148a6a7b..278ba6f553 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -52,6 +52,78 @@ pub trait FridaRuntime: 'static + Debug { fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error>; } +/// Use the runtime if closure evaluates to true +pub struct IfElseRuntime { + closure: CB, + if_runtimes: FR1, + else_runtimes: FR2, +} + +impl Debug for IfElseRuntime +where + FR1: Debug, + FR2: Debug, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&self.if_runtimes, f)?; + Debug::fmt(&self.else_runtimes, f)?; + Ok(()) + } +} +impl IfElseRuntime { + /// Constructor for this conditionally enabled runtime + pub fn new(closure: CB, if_runtimes: FR1, else_runtimes: FR2) -> Self { + Self { + closure, + if_runtimes, + else_runtimes, + } + } +} + +impl FridaRuntime for IfElseRuntime +where + CB: FnMut() -> Result + 'static, + FR1: FridaRuntimeTuple + 'static, + FR2: FridaRuntimeTuple + 'static, +{ + fn init( + &mut self, + gum: &Gum, + ranges: &RangeMap, + module_map: &Rc, + ) { + if (self.closure)().unwrap() { + self.if_runtimes.init_all(gum, ranges, module_map); + } else { + self.else_runtimes.init_all(gum, ranges, module_map); + } + } + + fn deinit(&mut self, gum: &Gum) { + if (self.closure)().unwrap() { + self.if_runtimes.deinit_all(gum); + } else { + self.else_runtimes.deinit_all(gum); + } + } + + fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + if (self.closure)()? { + self.if_runtimes.pre_exec_all(input_bytes) + } else { + self.else_runtimes.pre_exec_all(input_bytes) + } + } + + fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + if (self.closure)()? { + self.if_runtimes.post_exec_all(input_bytes) + } else { + self.else_runtimes.post_exec_all(input_bytes) + } + } +} /// The tuple for Frida Runtime pub trait FridaRuntimeTuple: MatchFirstType + Debug { /// Initialization From d8ec991b489280ca7c1301e08a62a955d1e0fe8d Mon Sep 17 00:00:00 2001 From: Valentin Huber Date: Sat, 28 Dec 2024 15:22:31 +0100 Subject: [PATCH 07/25] Add bloom filter for duplicate execution of the same inputs (#2771) * fixing empty multipart name * fixing clippy * New rules for the contributing (#2752) * Rules * more * aa * Improve Flexibility of DumpToDiskStage (#2753) * fixing empty multipart name * fixing clippy * improve flexibility of DumpToDiskStage * adding note to MIGRATION.md * Update bindgen requirement from 0.70.1 to 0.71.1 (#2756) Updates the requirements on [bindgen](https://github.com/rust-lang/rust-bindgen) to permit the latest version. - [Release notes](https://github.com/rust-lang/rust-bindgen/releases) - [Changelog](https://github.com/rust-lang/rust-bindgen/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/rust-bindgen/compare/v0.70.1...v0.71.1) --- updated-dependencies: - dependency-name: bindgen dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * No Use* from stages (#2745) * no from stage * fixer * doc fix * how was this working???? * more fixes * delete more * rq * cargo-fuzz * m * aa * Update CONTRIBUTING.md MIGRATION.md (#2762) * No Uses* from `fuzzer` (#2761) * go * fixing stuf * hello from windows * more * lolg * lolf * fix * a --------- Co-authored-by: Your Name * Remove useless cfgs (#2764) * Link libresolv on all Apple OSs (#2767) * Somewhat ugly CI fix... (#2768) * Maybe fix CI * does this help? * Very dirty 'fix' * Add Input Types and Mutators for Numeric Types (#2760) * fixing empty multipart name * fixing clippy * New rules for the contributing (#2752) * Rules * more * aa * Improve Flexibility of DumpToDiskStage (#2753) * fixing empty multipart name * fixing clippy * improve flexibility of DumpToDiskStage * adding note to MIGRATION.md * Introduce WrappingMutator * introducing mutators for int types * fixing no_std * random fixes * Add hash derivation for WrappingInput * Revert fixes that broke things * Derive Default on WrappingInput * Add unit tests * Fixes according to code review * introduce mappable ValueInputs * remove unnecessary comments * Elide more lifetimes * remove dead code * simplify hashing * improve docs * improve randomization * rename method to align with standard library * add typedefs for int types for ValueMutRefInput * rename test * add safety notice to trait function * improve randomize performance for i128/u128 * rename macro * improve comment * actually check return values in test * make 128 bit int randomize even more efficient * shifting signed values --------- Co-authored-by: Dongjia "toka" Zhang Co-authored-by: Dominik Maier * Add HashMutator * Fix docs * Fix docs again * introducing bloom filter * fix tests * Implement evaluate_filtered * Add macros to libafl_bolts tuples for mapping and merging types (#2788) * Add macros * Use the macros for havoc_mutations * Fix docs * improve merge_tuple_list_type to accept n items * libafl_cc: Automatically find llvm_ar path (#2790) * imemory_ondisk: Don't fail write under any circumstances if locking is disabled (#2791) * imemory_ondisk: Don't fail write under any circumstances if locking is disabled * fmt * inmemory_ondisk: Add a log message on failure * clippy' * micro optimization * Revert changes to global Cargo.toml * Hide std-dependent dependency behind std feature * Fix example fuzzer * Rename constructor for filtered fuzzer * Reorder generics alphabetically * Rename HashingMutator, add note to MutationResult about filtered fuzzers * Improve StdFuzzer according to feedback * rename hashing mutator * Fix english in comment * Cleanup of old PRs that break the CI * Fix more CI bugs * Code cleanup * Remove unnecessary comments --------- Signed-off-by: dependabot[bot] Co-authored-by: Dongjia "toka" Zhang Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Sharad Khanna Co-authored-by: Dominik Maier Co-authored-by: s1341 --- .../baby_fuzzer_custom_executor/Cargo.toml | 3 +- .../baby_fuzzer_custom_executor/src/main.rs | 4 + libafl/Cargo.toml | 2 + libafl/src/executors/inprocess/mod.rs | 2 +- libafl/src/fuzzer/mod.rs | 190 ++++++++++++++++-- libafl/src/mutators/hash.rs | 80 ++++++++ libafl/src/mutators/mod.rs | 16 +- libafl/src/stages/concolic.rs | 3 +- libafl/src/stages/generation.rs | 2 +- libafl/src/stages/mutational.rs | 8 +- libafl/src/stages/power.rs | 4 +- libafl/src/stages/tuneable.rs | 3 +- libafl_bolts/src/llmp.rs | 8 +- libafl_bolts/src/rands/mod.rs | 4 +- libafl_bolts/src/shmem.rs | 7 +- libafl_qemu/src/modules/usermode/asan.rs | 3 +- libafl_qemu/src/modules/usermode/snapshot.rs | 3 +- libafl_targets/src/libfuzzer/mod.rs | 3 +- 18 files changed, 298 insertions(+), 47 deletions(-) create mode 100644 libafl/src/mutators/hash.rs diff --git a/fuzzers/baby/baby_fuzzer_custom_executor/Cargo.toml b/fuzzers/baby/baby_fuzzer_custom_executor/Cargo.toml index f7905ec4c2..969bbf0bb1 100644 --- a/fuzzers/baby/baby_fuzzer_custom_executor/Cargo.toml +++ b/fuzzers/baby/baby_fuzzer_custom_executor/Cargo.toml @@ -8,8 +8,9 @@ authors = [ edition = "2021" [features] -default = ["std"] +default = ["std", "bloom_input_filter"] tui = ["libafl/tui_monitor"] +bloom_input_filter = ["std"] std = [] [profile.dev] diff --git a/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs b/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs index 059aa6ef14..adeae32832 100644 --- a/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs @@ -134,7 +134,11 @@ pub fn main() { let scheduler = QueueScheduler::new(); // A fuzzer with feedbacks and a corpus scheduler + #[cfg(not(feature = "bloom_input_filter"))] let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); + #[cfg(feature = "bloom_input_filter")] + let mut fuzzer = + StdFuzzer::with_bloom_input_filter(scheduler, feedback, objective, 10_000_000, 0.001); // Create the executor for an in-process function with just one observer let executor = CustomExecutor::new(&state); diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 2592a2c7c1..7781fce16d 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -58,6 +58,7 @@ std = [ "serial_test", "libafl_bolts/std", "typed-builder", + "fastbloom", ] ## Tracks the Feedbacks and the Objectives that were interesting for a Testcase @@ -291,6 +292,7 @@ document-features = { workspace = true, optional = true } clap = { workspace = true, optional = true } num_enum = { workspace = true, optional = true } libipt = { workspace = true, optional = true } +fastbloom = { version = "0.8.0", optional = true } [lints] workspace = true diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index 431ab3ed0a..0efb911448 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -557,7 +557,7 @@ mod tests { let mut mgr = NopEventManager::new(); let mut state = StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap(); - let mut fuzzer = StdFuzzer::<_, _, _>::new(sche, feedback, objective); + let mut fuzzer = StdFuzzer::new(sche, feedback, objective); let mut in_process_executor = InProcessExecutor::new( &mut harness, diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 5b5728e3b0..1b8e41daa6 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -2,7 +2,11 @@ use alloc::{string::ToString, vec::Vec}; use core::{fmt::Debug, time::Duration}; +#[cfg(feature = "std")] +use std::hash::Hash; +#[cfg(feature = "std")] +use fastbloom::BloomFilter; use libafl_bolts::{current_time, tuples::MatchName}; use serde::Serialize; @@ -138,6 +142,16 @@ pub trait EvaluatorObservers { /// Evaluate an input modifying the state of the fuzzer pub trait Evaluator { + /// Runs the input if it was (likely) not previously run and triggers observers and feedback and adds the input to the previously executed list + /// returns if is interesting an (option) the index of the new [`crate::corpus::Testcase`] in the corpus + fn evaluate_filtered( + &mut self, + state: &mut S, + executor: &mut E, + manager: &mut EM, + input: I, + ) -> Result<(ExecuteInputResult, Option), Error>; + /// Runs the input and triggers observers and feedback, /// returns if is interesting an (option) the index of the new [`crate::corpus::Testcase`] in the corpus fn evaluate_input( @@ -242,13 +256,14 @@ pub enum ExecuteInputResult { /// Your default fuzzer instance, for everyday use. #[derive(Debug)] -pub struct StdFuzzer { +pub struct StdFuzzer { scheduler: CS, feedback: F, objective: OF, + input_filter: IF, } -impl HasScheduler<::Input, S> for StdFuzzer +impl HasScheduler<::Input, S> for StdFuzzer where S: HasCorpus, CS: Scheduler<::Input, S>, @@ -264,7 +279,7 @@ where } } -impl HasFeedback for StdFuzzer { +impl HasFeedback for StdFuzzer { type Feedback = F; fn feedback(&self) -> &Self::Feedback { @@ -276,7 +291,7 @@ impl HasFeedback for StdFuzzer { } } -impl HasObjective for StdFuzzer { +impl HasObjective for StdFuzzer { type Objective = OF; fn objective(&self) -> &OF { @@ -288,8 +303,8 @@ impl HasObjective for StdFuzzer { } } -impl ExecutionProcessor::Input, OT, S> - for StdFuzzer +impl ExecutionProcessor::Input, OT, S> + for StdFuzzer where CS: Scheduler<::Input, S>, EM: EventFirer, @@ -494,8 +509,8 @@ where } } -impl EvaluatorObservers::Input, S> - for StdFuzzer +impl EvaluatorObservers::Input, S> + for StdFuzzer where CS: Scheduler<::Input, S>, E: HasObservers + Executor, @@ -532,7 +547,48 @@ where } } -impl Evaluator::Input, S> for StdFuzzer +trait InputFilter { + fn should_execute(&mut self, input: &I) -> bool; +} + +/// A pseudo-filter that will execute each input. +#[derive(Debug)] +pub struct NopInputFilter; +impl InputFilter for NopInputFilter { + #[inline] + #[must_use] + fn should_execute(&mut self, _input: &I) -> bool { + true + } +} + +/// A filter that probabilistically prevents duplicate execution of the same input based on a bloom filter. +#[cfg(feature = "std")] +#[derive(Debug)] +pub struct BloomInputFilter { + bloom: BloomFilter, +} + +#[cfg(feature = "std")] +impl BloomInputFilter { + #[must_use] + fn new(items_count: usize, fp_p: f64) -> Self { + let bloom = BloomFilter::with_false_pos(fp_p).expected_items(items_count); + Self { bloom } + } +} + +#[cfg(feature = "std")] +impl InputFilter for BloomInputFilter { + #[inline] + #[must_use] + fn should_execute(&mut self, input: &I) -> bool { + !self.bloom.insert(input) + } +} + +impl Evaluator::Input, S> + for StdFuzzer where CS: Scheduler<::Input, S>, E: HasObservers + Executor, @@ -549,7 +605,22 @@ where + UsesInput::Input>, ::Input: Input, S::Solutions: Corpus::Input>, + IF: InputFilter<::Input>, { + fn evaluate_filtered( + &mut self, + state: &mut S, + executor: &mut E, + manager: &mut EM, + input: ::Input, + ) -> Result<(ExecuteInputResult, Option), Error> { + if self.input_filter.should_execute(&input) { + self.evaluate_input(state, executor, manager, input) + } else { + Ok((ExecuteInputResult::None, None)) + } + } + /// Process one input, adding to the respective corpora if needed and firing the right events #[inline] fn evaluate_input_events( @@ -562,6 +633,7 @@ where ) -> Result<(ExecuteInputResult, Option), Error> { self.evaluate_input_with_observers(state, executor, manager, input, send_events) } + fn add_disabled_input( &mut self, state: &mut S, @@ -573,6 +645,7 @@ where let id = state.corpus_mut().add_disabled(testcase)?; Ok(id) } + /// Adds an input, even if it's not considered `interesting` by any of the executors fn add_input( &mut self, @@ -672,7 +745,7 @@ where } } -impl Fuzzer for StdFuzzer +impl Fuzzer for StdFuzzer where CS: Scheduler, E: UsesState, @@ -796,17 +869,44 @@ where } } -impl StdFuzzer { - /// Create a new `StdFuzzer` with standard behavior. - pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self { +impl StdFuzzer { + /// Create a new [`StdFuzzer`] with standard behavior and the provided duplicate input execution filter. + pub fn with_input_filter(scheduler: CS, feedback: F, objective: OF, input_filter: IF) -> Self { Self { scheduler, feedback, objective, + input_filter, } } } +impl StdFuzzer { + /// Create a new [`StdFuzzer`] with standard behavior and no duplicate input execution filtering. + pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self { + Self::with_input_filter(scheduler, feedback, objective, NopInputFilter) + } +} + +#[cfg(feature = "std")] // hashing requires std +impl StdFuzzer { + /// Create a new [`StdFuzzer`], which, with a certain certainty, executes each input only once. + /// + /// This is achieved by hashing each input and using a bloom filter to differentiate inputs. + /// + /// Use this implementation if hashing each input is very fast compared to executing potential duplicate inputs. + pub fn with_bloom_input_filter( + scheduler: CS, + feedback: F, + objective: OF, + items_count: usize, + fp_p: f64, + ) -> Self { + let input_filter = BloomInputFilter::new(items_count, fp_p); + Self::with_input_filter(scheduler, feedback, objective, input_filter) + } +} + /// Structs with this trait will execute an input pub trait ExecutesInput { /// Runs the input and triggers observers and feedback @@ -819,8 +919,8 @@ pub trait ExecutesInput { ) -> Result; } -impl ExecutesInput::Input, S> - for StdFuzzer +impl ExecutesInput::Input, S> + for StdFuzzer where CS: Scheduler<::Input, S>, E: Executor + HasObservers, @@ -913,3 +1013,63 @@ where unimplemented!("NopFuzzer cannot fuzz"); } } + +#[cfg(all(test, feature = "std"))] +mod tests { + use core::cell::RefCell; + + use libafl_bolts::rands::StdRand; + + use super::{Evaluator, StdFuzzer}; + use crate::{ + corpus::InMemoryCorpus, + events::NopEventManager, + executors::{ExitKind, InProcessExecutor}, + inputs::BytesInput, + schedulers::StdScheduler, + state::StdState, + }; + + #[test] + fn filtered_execution() { + let execution_count = RefCell::new(0); + let scheduler = StdScheduler::new(); + let mut fuzzer = StdFuzzer::with_bloom_input_filter(scheduler, (), (), 100, 1e-4); + let mut state = StdState::new( + StdRand::new(), + InMemoryCorpus::new(), + InMemoryCorpus::new(), + &mut (), + &mut (), + ) + .unwrap(); + let mut manager = NopEventManager::new(); + let mut harness = |_input: &BytesInput| { + *execution_count.borrow_mut() += 1; + ExitKind::Ok + }; + let mut executor = + InProcessExecutor::new(&mut harness, (), &mut fuzzer, &mut state, &mut manager) + .unwrap(); + let input = BytesInput::new(vec![1, 2, 3]); + assert!(fuzzer + .evaluate_input(&mut state, &mut executor, &mut manager, input.clone()) + .is_ok()); + assert_eq!(1, *execution_count.borrow()); // evaluate_input does not add it to the filter + + assert!(fuzzer + .evaluate_filtered(&mut state, &mut executor, &mut manager, input.clone()) + .is_ok()); + assert_eq!(2, *execution_count.borrow()); // at to the filter + + assert!(fuzzer + .evaluate_filtered(&mut state, &mut executor, &mut manager, input.clone()) + .is_ok()); + assert_eq!(2, *execution_count.borrow()); // the harness is not called + + assert!(fuzzer + .evaluate_input(&mut state, &mut executor, &mut manager, input.clone()) + .is_ok()); + assert_eq!(3, *execution_count.borrow()); // evaluate_input ignores filters + } +} diff --git a/libafl/src/mutators/hash.rs b/libafl/src/mutators/hash.rs new file mode 100644 index 0000000000..8b231b7d75 --- /dev/null +++ b/libafl/src/mutators/hash.rs @@ -0,0 +1,80 @@ +//! A wrapper around a [`Mutator`] that ensures an input really changed [`MutationResult::Mutated`] +//! by hashing pre- and post-mutation +use std::{borrow::Cow, hash::Hash}; + +use libafl_bolts::{generic_hash_std, Error, Named}; + +use super::{MutationResult, Mutator}; + +/// A wrapper around a [`Mutator`] that ensures an input really changed [`MutationResult::Mutated`] +/// by hashing pre- and post-mutation and comparing the values +#[derive(Debug)] +pub struct MutationChecker { + inner: M, + name: Cow<'static, str>, +} + +impl MutationChecker +where + M: Named, +{ + /// Create a new [`MutationChecker`] + pub fn new(inner: M) -> Self { + let name = Cow::Owned(format!("MutationChecker<{}>", inner.name().clone())); + Self { inner, name } + } +} + +impl Mutator for MutationChecker +where + I: Hash, + M: Mutator, +{ + fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { + let before = generic_hash_std(input); + self.inner.mutate(state, input)?; + if before == generic_hash_std(input) { + Ok(MutationResult::Skipped) + } else { + Ok(MutationResult::Mutated) + } + } +} + +impl Named for MutationChecker { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +#[cfg(test)] +mod tests { + use crate::{ + inputs::BytesInput, + mutators::{BytesSetMutator, MutationChecker, MutationResult, Mutator}, + state::NopState, + }; + + #[test] + fn not_mutated() { + let mut state: NopState = NopState::new(); + let mut inner = BytesSetMutator::new(); + + let mut input = BytesInput::new(vec![0; 5]); + + // nothing changed, yet `MutationResult::Mutated` was reported + assert_eq!( + MutationResult::Mutated, + inner.mutate(&mut state, &mut input).unwrap() + ); + assert_eq!(BytesInput::new(vec![0; 5]), input); + + // now it is correctly reported as `MutationResult::Skipped` + let mut hash_mutator = MutationChecker::new(inner); + assert_eq!( + MutationResult::Skipped, + hash_mutator.mutate(&mut state, &mut input).unwrap() + ); + assert_eq!(BytesInput::new(vec![0; 5]), input); + } +} diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 22dec0d64f..5b2de83bd4 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -28,6 +28,11 @@ pub use mapping::*; pub mod tuneable; pub use tuneable::*; +#[cfg(feature = "std")] +pub mod hash; +#[cfg(feature = "std")] +pub use hash::*; + #[cfg(feature = "unicode")] pub mod unicode; #[cfg(feature = "unicode")] @@ -84,12 +89,15 @@ impl From for MutationId { } } -/// The result of a mutation. -/// If the mutation got skipped, the target -/// will not be executed with the returned input. +/// Result of the mutation. +/// +/// [`MutationResult::Skipped`] does not necessarily mean that the input changed, +/// just that the mutator did something. For slow targets, consider using +/// a filtered fuzzer (see [`crate::fuzzer::StdFuzzer::with_input_filter`]) +/// or wrapping your mutator in a [`hash::MutationChecker`]. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum MutationResult { - /// The [`Mutator`] mutated this `Input`. + /// The [`Mutator`] executed on this `Input`. It may not guarantee that the input has actually been changed. Mutated, /// The [`Mutator`] did not mutate this `Input`. It was `Skipped`. Skipped, diff --git a/libafl/src/stages/concolic.rs b/libafl/src/stages/concolic.rs index 2f2ebd0876..be5765f3c6 100644 --- a/libafl/src/stages/concolic.rs +++ b/libafl/src/stages/concolic.rs @@ -417,8 +417,7 @@ where for (index, new_byte) in mutation { input_copy.bytes_mut()[index] = new_byte; } - // Time is measured directly the `evaluate_input` function - fuzzer.evaluate_input(state, executor, manager, input_copy)?; + fuzzer.evaluate_filtered(state, executor, manager, input_copy)?; } } Ok(()) diff --git a/libafl/src/stages/generation.rs b/libafl/src/stages/generation.rs index 8fe6ff28fa..ccf1b94f9d 100644 --- a/libafl/src/stages/generation.rs +++ b/libafl/src/stages/generation.rs @@ -44,7 +44,7 @@ where manager: &mut EM, ) -> Result<(), Error> { let input = self.0.generate(state)?; - fuzzer.evaluate_input(state, executor, manager, input)?; + fuzzer.evaluate_filtered(state, executor, manager, input)?; Ok(()) } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 61ac616eee..9b3ffdbb9f 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -277,9 +277,9 @@ where continue; } - // Time is measured directly the `evaluate_input` function let (untransformed, post) = input.try_transform_into(state)?; - let (_, corpus_id) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; + let (_, corpus_id) = + fuzzer.evaluate_filtered(state, executor, manager, untransformed)?; start_timer!(state); self.mutator_mut().post_exec(state, corpus_id)?; @@ -345,9 +345,9 @@ where let generated = self.mutator.multi_mutate(state, &input, None)?; for new_input in generated { - // Time is measured directly the `evaluate_input` function let (untransformed, post) = new_input.try_transform_into(state)?; - let (_, corpus_id) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; + let (_, corpus_id) = + fuzzer.evaluate_filtered(state, executor, manager, untransformed)?; self.mutator.multi_post_exec(state, corpus_id)?; post.post_exec(state, corpus_id)?; } diff --git a/libafl/src/stages/power.rs b/libafl/src/stages/power.rs index e3d64def59..695d2c6038 100644 --- a/libafl/src/stages/power.rs +++ b/libafl/src/stages/power.rs @@ -189,9 +189,9 @@ where continue; } - // Time is measured directly the `evaluate_input` function let (untransformed, post) = input.try_transform_into(state)?; - let (_, corpus_id) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; + let (_, corpus_id) = + fuzzer.evaluate_filtered(state, executor, manager, untransformed)?; start_timer!(state); self.mutator_mut().post_exec(state, corpus_id)?; diff --git a/libafl/src/stages/tuneable.rs b/libafl/src/stages/tuneable.rs index 9c3aeab6af..2764291281 100644 --- a/libafl/src/stages/tuneable.rs +++ b/libafl/src/stages/tuneable.rs @@ -453,9 +453,8 @@ where return Ok(()); } - // Time is measured directly the `evaluate_input` function let (untransformed, post) = input.try_transform_into(state)?; - let (_, corpus_id) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; + let (_, corpus_id) = fuzzer.evaluate_filtered(state, executor, manager, untransformed)?; start_timer!(state); self.mutator_mut().post_exec(state, corpus_id)?; diff --git a/libafl_bolts/src/llmp.rs b/libafl_bolts/src/llmp.rs index 614d502557..d191e02b6c 100644 --- a/libafl_bolts/src/llmp.rs +++ b/libafl_bolts/src/llmp.rs @@ -2669,7 +2669,11 @@ where self.inner .llmp_clients .binary_search_by_key(&client_id, |x| x.id) - .expect("Fatal error, client ID {client_id} not found in llmp_clients.") + .unwrap_or_else(|_| { + panic!( + "Fatal error, client ID {client_id:?} not found in llmp_clients." + ) + }) }; let client = &mut self.inner.llmp_clients[pos]; match client.recv()? { @@ -2768,7 +2772,7 @@ where self.inner .llmp_clients .binary_search_by_key(&client_id, |x| x.id) - .expect("Fatal error, client ID {client_id} not found in llmp_clients.") + .unwrap_or_else(|_| panic!("Fatal error, client ID {client_id:?} not found in llmp_clients.")) }; let map = &mut self.inner.llmp_clients[pos].current_recv_shmem; diff --git a/libafl_bolts/src/rands/mod.rs b/libafl_bolts/src/rands/mod.rs index a6a8730c95..c55f105b2b 100644 --- a/libafl_bolts/src/rands/mod.rs +++ b/libafl_bolts/src/rands/mod.rs @@ -18,7 +18,7 @@ static SEED_COUNTER: AtomicUsize = AtomicUsize::new(0); /// Return a pseudo-random seed. For `no_std` environments, a single deterministic sequence is used. #[must_use] -#[expect(unreachable_code)] +#[allow(unreachable_code)] // cfg dependent pub fn random_seed() -> u64 { #[cfg(feature = "std")] return random_seed_from_random_state(); @@ -365,7 +365,7 @@ impl Rand for Lehmer64Rand { fn set_seed(&mut self, mut seed: u64) { let hi = splitmix64(&mut seed); let lo = splitmix64(&mut seed) | 1; - self.s = u128::from(hi) << 64 | u128::from(lo); + self.s = (u128::from(hi) << 64) | u128::from(lo); } #[inline] diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index 7df2bbe154..2144af1ab5 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -624,12 +624,9 @@ where /// Is needed on top. #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] pub mod unix_shmem { - /// Mmap [`ShMemProvider`] for Unix - #[cfg(not(target_os = "android"))] - pub use default::MmapShMemProvider; /// Mmap [`ShMem`] for Unix #[cfg(not(target_os = "android"))] - pub use default::{MmapShMem, MAX_MMAP_FILENAME_LEN}; + pub use default::{MmapShMem, MmapShMemProvider, MAX_MMAP_FILENAME_LEN}; #[cfg(doc)] use crate::shmem::{ShMem, ShMemProvider}; @@ -669,7 +666,7 @@ pub mod unix_shmem { Error, }; - /// The size of the buffer of the filename of mmap mapped memory regions + /// The max number of bytes used when generating names for [`MmapShMem`]s. pub const MAX_MMAP_FILENAME_LEN: usize = 20; /// Mmap-based The sharedmap impl for unix using [`shm_open`] and [`mmap`]. diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index 96674a899d..5ff4cd5b31 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -1532,8 +1532,7 @@ mod addr2line_legacy { /// # Safety /// Will access the global [`FullBacktraceCollector`]. /// Calling this function concurrently might be racey. -#[expect(clippy::unnecessary_cast)] -#[expect(clippy::too_many_lines)] +#[expect(clippy::too_many_lines, clippy::unnecessary_cast)] pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &AsanError) { let mut regions = HashMap::new(); for region in qemu.mappings() { diff --git a/libafl_qemu/src/modules/usermode/snapshot.rs b/libafl_qemu/src/modules/usermode/snapshot.rs index 776fc749da..e3579ed0e9 100644 --- a/libafl_qemu/src/modules/usermode/snapshot.rs +++ b/libafl_qemu/src/modules/usermode/snapshot.rs @@ -780,8 +780,7 @@ where SyscallHookResult::new(None) } -#[expect(clippy::too_many_arguments)] -#[expect(non_upper_case_globals)] +#[expect(non_upper_case_globals, clippy::too_many_arguments)] pub fn trace_mmap_snapshot( emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, diff --git a/libafl_targets/src/libfuzzer/mod.rs b/libafl_targets/src/libfuzzer/mod.rs index f5d9d41bdb..4cd967808b 100644 --- a/libafl_targets/src/libfuzzer/mod.rs +++ b/libafl_targets/src/libfuzzer/mod.rs @@ -26,8 +26,7 @@ extern "C" { /// /// # Safety /// Calls the libfuzzer-style init function which is native code. -#[expect(clippy::similar_names)] -#[expect(clippy::must_use_candidate)] // nobody uses that return code... +#[expect(clippy::must_use_candidate, clippy::similar_names)] // nobody uses that return code... pub unsafe fn libfuzzer_initialize(args: &[String]) -> i32 { let args: Vec = args.iter().map(|x| x.clone() + "\0").collect(); let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect(); From 930951827fa9b4a7db6b3c42ff7976acd3ff79c2 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 30 Dec 2024 15:02:52 +0000 Subject: [PATCH 08/25] bolts limit ashmem concept to Linux/Android only. (#2795) --- libafl_bolts/src/shmem.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index 2144af1ab5..d3b0d8b7c6 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -1134,7 +1134,7 @@ pub mod unix_shmem { } /// Module containing `ashmem` shared memory support, commonly used on Android. - #[cfg(all(unix, feature = "std"))] + #[cfg(all(any(target_os = "linux", target_os = "android"), feature = "std"))] pub mod ashmem { use alloc::string::ToString; use core::{ @@ -1154,7 +1154,6 @@ pub mod unix_shmem { }; /// An ashmem based impl for linux/android - #[cfg(unix)] #[derive(Clone, Debug)] pub struct AshmemShMem { id: ShMemId, @@ -1273,7 +1272,6 @@ pub mod unix_shmem { } } - #[cfg(unix)] impl ShMem for AshmemShMem { fn id(&self) -> ShMemId { self.id @@ -1295,7 +1293,6 @@ pub mod unix_shmem { } /// [`Drop`] implementation for [`AshmemShMem`], which cleans up the mapping. - #[cfg(unix)] impl Drop for AshmemShMem { #[expect(trivial_numeric_casts)] fn drop(&mut self) { @@ -1318,13 +1315,11 @@ pub mod unix_shmem { } /// A [`ShMemProvider`] which uses ashmem to provide shared memory mappings. - #[cfg(unix)] #[derive(Clone, Debug)] pub struct AshmemShMemProvider {} unsafe impl Send for AshmemShMemProvider {} - #[cfg(unix)] impl Default for AshmemShMemProvider { fn default() -> Self { Self::new().unwrap() @@ -1332,7 +1327,6 @@ pub mod unix_shmem { } /// Implement [`ShMemProvider`] for [`AshmemShMemProvider`], for the Android `ShMem`. - #[cfg(unix)] impl ShMemProvider for AshmemShMemProvider { type ShMem = AshmemShMem; From 8cd069cf3e583a241815df3a5120c7606e7d0974 Mon Sep 17 00:00:00 2001 From: Mehtab Zafar Date: Tue, 31 Dec 2024 01:15:48 +0530 Subject: [PATCH 09/25] Optimize event serialization with pre-allocated buffer (#2794) * Optimize event serialization with pre-allocated buffer - Added event_buffer field to LlmpEventManager - Used to_slice instead of to_allocvec - Pre-allocated buffer size is 4KB Fixes #1082 * Fallback to to_allocvec in case of event_buffer overflow Also combined the shared logic between compressed & uncompressed event firing while keeping the same behavior * Made the initial event_buffer size to a const Also removed the unnecessary event_buffer.clear(), since we are already resizing it --- libafl/src/events/llmp/mgr.rs | 69 +++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/libafl/src/events/llmp/mgr.rs b/libafl/src/events/llmp/mgr.rs index 1b76f0813c..63f0f7f5e2 100644 --- a/libafl/src/events/llmp/mgr.rs +++ b/libafl/src/events/llmp/mgr.rs @@ -45,6 +45,9 @@ use crate::{ Error, HasMetadata, }; +/// Default initial capacity of the event buffer - 4KB +const INITIAL_EVENT_BUFFER_SIZE: usize = 1024 * 4; + /// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp, /// using low-level message passing, `llmp`. pub struct LlmpEventManager @@ -75,6 +78,7 @@ where should_serialize_cnt: usize, pub(crate) time_ref: Option>, phantom: PhantomData, + event_buffer: Vec, } impl LlmpEventManager<(), NopState, NopShMemProvider> { @@ -165,6 +169,7 @@ impl LlmpEventManagerBuilder { time_ref, phantom: PhantomData, custom_buf_handlers: vec![], + event_buffer: Vec::with_capacity(INITIAL_EVENT_BUFFER_SIZE), }) } @@ -199,6 +204,7 @@ impl LlmpEventManagerBuilder { time_ref, phantom: PhantomData, custom_buf_handlers: vec![], + event_buffer: Vec::with_capacity(INITIAL_EVENT_BUFFER_SIZE), }) } @@ -233,6 +239,7 @@ impl LlmpEventManagerBuilder { time_ref, phantom: PhantomData, custom_buf_handlers: vec![], + event_buffer: Vec::with_capacity(INITIAL_EVENT_BUFFER_SIZE), }) } @@ -265,6 +272,7 @@ impl LlmpEventManagerBuilder { time_ref, phantom: PhantomData, custom_buf_handlers: vec![], + event_buffer: Vec::with_capacity(INITIAL_EVENT_BUFFER_SIZE), }) } } @@ -409,6 +417,7 @@ where + EvaluatorObservers::Input, S> + Evaluator::Input, S>, { + println!("Got event in client: {} from {:?}", event.name(), client_id); if !self.hooks.pre_exec_all(state, client_id, &event)? { return Ok(()); } @@ -512,44 +521,56 @@ where true } } - - #[cfg(feature = "llmp_compression")] fn fire( &mut self, _state: &mut Self::State, event: Event<::Input>, ) -> Result<(), Error> { - let serialized = postcard::to_allocvec(&event)?; + #[cfg(feature = "llmp_compression")] let flags = LLMP_FLAG_INITIALIZED; - match self.compressor.maybe_compress(&serialized) { - Some(comp_buf) => { - self.llmp.send_buf_with_flags( - LLMP_TAG_EVENT_TO_BOTH, - flags | LLMP_FLAG_COMPRESSED, - &comp_buf, - )?; + self.event_buffer.resize(self.event_buffer.capacity(), 0); + + // Serialize the event, reallocating event_buffer if needed + let written_len = match postcard::to_slice(&event, &mut self.event_buffer) { + Ok(written) => written.len(), + Err(postcard::Error::SerializeBufferFull) => { + let serialized = postcard::to_allocvec(&event)?; + self.event_buffer = serialized; + self.event_buffer.len() } - None => { - self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; + Err(e) => return Err(Error::from(e)), + }; + + #[cfg(feature = "llmp_compression")] + { + match self + .compressor + .maybe_compress(&self.event_buffer[..written_len]) + { + Some(comp_buf) => { + self.llmp.send_buf_with_flags( + LLMP_TAG_EVENT_TO_BOTH, + flags | LLMP_FLAG_COMPRESSED, + &comp_buf, + )?; + } + None => { + self.llmp + .send_buf(LLMP_TAG_EVENT_TO_BOTH, &self.event_buffer[..written_len])?; + } } } - self.last_sent = current_time(); - Ok(()) - } + #[cfg(not(feature = "llmp_compression"))] + { + self.llmp + .send_buf(LLMP_TAG_EVENT_TO_BOTH, &self.event_buffer[..written_len]); + } - #[cfg(not(feature = "llmp_compression"))] - fn fire( - &mut self, - _state: &mut Self::State, - event: Event<::Input>, - ) -> Result<(), Error> { - let serialized = postcard::to_allocvec(&event)?; - self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; + self.last_sent = current_time(); Ok(()) } - fn serialize_observers(&mut self, observers: &OT) -> Result>, Error> where OT: ObserversTuple + Serialize, From 92db678995423c217abdf3614e1ca92571dc151e Mon Sep 17 00:00:00 2001 From: AshrafIbrahim03 <123664304+AshrafIbrahim03@users.noreply.github.com> Date: Mon, 30 Dec 2024 14:47:04 -0500 Subject: [PATCH 10/25] Added expect error message to TimeFeedback where there used to be an unwrap (#2777) * Added expect error message to TimeFeedback where there used to be an unwrap * Changed error message handling * fixed cargo clippy --------- Co-authored-by: Dominik Maier --- libafl/src/feedbacks/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 5fbf13f64a..49e9f2e2d7 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -932,7 +932,12 @@ where observers: &OT, testcase: &mut Testcase, ) -> Result<(), Error> { - let observer = observers.get(&self.observer_handle).unwrap(); + let Some(observer) = observers.get(&self.observer_handle) else { + return Err(Error::illegal_state( + "Observer referenced by TimeFeedback is not found in observers given to the fuzzer", + )); + }; + *testcase.exec_time_mut() = *observer.last_runtime(); Ok(()) } From deb76555b75ca2ccac83b83a6db1a276c07080b5 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 1 Jan 2025 20:57:43 +0100 Subject: [PATCH 11/25] New year new clippy (#2797) * New year new clippy * More clipy * fix --- libafl/src/corpus/mod.rs | 2 +- libafl/src/events/llmp/mgr.rs | 4 ++-- libafl/src/mutators/mod.rs | 4 ++-- libafl/src/mutators/token_mutations.rs | 22 +++++++++++----------- libafl_frida/src/helper.rs | 5 +++-- libafl_qemu/src/emu/hooks.rs | 20 ++++++++++---------- libafl_qemu/src/qemu/usermode.rs | 2 +- 7 files changed, 30 insertions(+), 29 deletions(-) diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index f90d7b3802..8e4917c225 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -175,7 +175,7 @@ pub trait Corpus: Sized { fn nth(&self, nth: usize) -> CorpusId { self.ids() .nth(nth) - .expect("Failed to get the {nth} CorpusId") + .unwrap_or_else(|| panic!("Failed to get the {nth} CorpusId")) } /// Get the nth corpus id; considers both enabled and disabled testcases diff --git a/libafl/src/events/llmp/mgr.rs b/libafl/src/events/llmp/mgr.rs index 63f0f7f5e2..5fac3c07e5 100644 --- a/libafl/src/events/llmp/mgr.rs +++ b/libafl/src/events/llmp/mgr.rs @@ -417,7 +417,7 @@ where + EvaluatorObservers::Input, S> + Evaluator::Input, S>, { - println!("Got event in client: {} from {:?}", event.name(), client_id); + log::trace!("Got event in client: {} from {client_id:?}", event.name()); if !self.hooks.pre_exec_all(state, client_id, &event)? { return Ok(()); } @@ -565,7 +565,7 @@ where #[cfg(not(feature = "llmp_compression"))] { self.llmp - .send_buf(LLMP_TAG_EVENT_TO_BOTH, &self.event_buffer[..written_len]); + .send_buf(LLMP_TAG_EVENT_TO_BOTH, &self.event_buffer[..written_len])?; } self.last_sent = current_time(); diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 5b2de83bd4..93667b789d 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -353,7 +353,7 @@ impl MutatorsTuple for Vec>> { ) -> Result { let mutator = self .get_mut(index.0) - .ok_or_else(|| Error::key_not_found("Mutator with id {index:?} not found."))?; + .ok_or_else(|| Error::key_not_found(format!("Mutator with id {index:?} not found.")))?; mutator.mutate(state, input) } @@ -365,7 +365,7 @@ impl MutatorsTuple for Vec>> { ) -> Result<(), Error> { let mutator = self .get_mut(index) - .ok_or_else(|| Error::key_not_found("Mutator with id {index:?} not found."))?; + .ok_or_else(|| Error::key_not_found(format!("Mutator with id {index:?} not found.")))?; mutator.post_exec(state, new_corpus_id) } } diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 5d5d3c8e12..23664f3d53 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -1059,7 +1059,7 @@ impl AFLppRedQueen { if buf_16 == pattern as u16 && another_buf_16 == another_pattern as u16 { let mut cloned = buf.to_vec(); cloned[buf_idx + 1] = (repl & 0xff) as u8; - cloned[buf_idx] = (repl >> 8 & 0xff) as u8; + cloned[buf_idx] = ((repl >> 8) & 0xff) as u8; vec.push(cloned); return Ok(true); } @@ -1074,9 +1074,9 @@ impl AFLppRedQueen { if buf_32 == pattern as u32 && another_buf_32 == another_pattern as u32 { let mut cloned = buf.to_vec(); cloned[buf_idx + 3] = (repl & 0xff) as u8; - cloned[buf_idx + 2] = (repl >> 8 & 0xff) as u8; - cloned[buf_idx + 1] = (repl >> 16 & 0xff) as u8; - cloned[buf_idx] = (repl >> 24 & 0xff) as u8; + cloned[buf_idx + 2] = ((repl >> 8) & 0xff) as u8; + cloned[buf_idx + 1] = ((repl >> 16) & 0xff) as u8; + cloned[buf_idx] = ((repl >> 24) & 0xff) as u8; vec.push(cloned); return Ok(true); @@ -1093,13 +1093,13 @@ impl AFLppRedQueen { let mut cloned = buf.to_vec(); cloned[buf_idx + 7] = (repl & 0xff) as u8; - cloned[buf_idx + 6] = (repl >> 8 & 0xff) as u8; - cloned[buf_idx + 5] = (repl >> 16 & 0xff) as u8; - cloned[buf_idx + 4] = (repl >> 24 & 0xff) as u8; - cloned[buf_idx + 3] = (repl >> 32 & 0xff) as u8; - cloned[buf_idx + 2] = (repl >> 32 & 0xff) as u8; - cloned[buf_idx + 1] = (repl >> 40 & 0xff) as u8; - cloned[buf_idx] = (repl >> 48 & 0xff) as u8; + cloned[buf_idx + 6] = ((repl >> 8) & 0xff) as u8; + cloned[buf_idx + 5] = ((repl >> 16) & 0xff) as u8; + cloned[buf_idx + 4] = ((repl >> 24) & 0xff) as u8; + cloned[buf_idx + 3] = ((repl >> 32) & 0xff) as u8; + cloned[buf_idx + 2] = ((repl >> 32) & 0xff) as u8; + cloned[buf_idx + 1] = ((repl >> 40) & 0xff) as u8; + cloned[buf_idx] = ((repl >> 48) & 0xff) as u8; vec.push(cloned); return Ok(true); diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 278ba6f553..98d1fe3599 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -239,9 +239,10 @@ impl FridaInstrumentationHelperBuilder { let name = path .file_name() .and_then(|name| name.to_str()) - .expect("Failed to get script file name from path: {path:}"); + .unwrap_or_else(|| panic!("Failed to get script file name from path: {path:?}")); let script_prefix = include_str!("script.js"); - let file_contents = read_to_string(path).expect("Failed to read script: {path:}"); + let file_contents = read_to_string(path) + .unwrap_or_else(|err| panic!("Failed to read script {path:?}: {err:?}")); let payload = script_prefix.to_string() + &file_contents; let gum = Gum::obtain(); let backend = match backend { diff --git a/libafl_qemu/src/emu/hooks.rs b/libafl_qemu/src/emu/hooks.rs index 6f7a8b625e..53a6dc3350 100644 --- a/libafl_qemu/src/emu/hooks.rs +++ b/libafl_qemu/src/emu/hooks.rs @@ -182,13 +182,13 @@ where .push(Box::pin((InstructionHookId::invalid(), fat))); unsafe { - let hook_state = &mut self + let hook_state = &raw mut self .instruction_hooks .last_mut() .unwrap() .as_mut() .get_unchecked_mut() - .1 as *mut FatPtr; + .1; let id = self.qemu_hooks.add_instruction_hooks( &mut *hook_state, @@ -656,13 +656,13 @@ where self.backdoor_hooks .push(Box::pin((BackdoorHookId::invalid(), fat))); - let hook_state = &mut self + let hook_state = &raw mut self .backdoor_hooks .last_mut() .unwrap() .as_mut() .get_unchecked_mut() - .1 as *mut FatPtr; + .1; let id = self .qemu_hooks @@ -739,13 +739,13 @@ where self.new_thread_hooks .push(Box::pin((NewThreadHookId::invalid(), fat))); - let hook_state = &mut self + let hook_state = &raw mut self .new_thread_hooks .last_mut() .unwrap() .as_mut() .get_unchecked_mut() - .1 as *mut FatPtr; + .1; let id = self .qemu_hooks @@ -797,13 +797,13 @@ where self.pre_syscall_hooks .push(Box::pin((PreSyscallHookId::invalid(), fat))); - let hook_state = &mut self + let hook_state = &raw mut self .pre_syscall_hooks .last_mut() .unwrap() .as_mut() .get_unchecked_mut() - .1 as *mut FatPtr; + .1; let id = self .qemu_hooks @@ -848,13 +848,13 @@ where self.post_syscall_hooks .push(Box::pin((PostSyscallHookId::invalid(), fat))); - let hooks_state = &mut self + let hooks_state = &raw mut self .post_syscall_hooks .last_mut() .unwrap() .as_mut() .get_unchecked_mut() - .1 as *mut FatPtr; + .1; let id = self.qemu_hooks.add_post_syscall_hook( &mut *hooks_state, diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index e621adaf09..33b31e326c 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -286,7 +286,7 @@ pub mod pybind { a6: u64, a7: u64, ) -> SyscallHookResult { - unsafe { PY_SYSCALL_HOOK.as_ref() }.map_or_else( + unsafe { &*(&raw const PY_SYSCALL_HOOK).as_ref() }.map_or_else( || SyscallHookResult::new(None), |obj| { let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7); From 187e06cb11fdfb56809abedc9e7aad50001dc21c Mon Sep 17 00:00:00 2001 From: henri2h Date: Thu, 2 Jan 2025 15:57:57 +0100 Subject: [PATCH 12/25] Specify that InProcessForkExecutor should abort on panic (#2803) * Revert "New year new clippy (#2797)" This reverts commit deb76555b75ca2ccac83b83a6db1a276c07080b5. * Mention that program should panic when using InProcessForkExecutor * Reapply "New year new clippy (#2797)" This reverts commit 529213ef6334fc18e1898f3cfbd8bed24c312522. --- docs/src/core_concepts/executor.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/src/core_concepts/executor.md b/docs/src/core_concepts/executor.md index 85ee0fff46..ce0c800dda 100644 --- a/docs/src/core_concepts/executor.md +++ b/docs/src/core_concepts/executor.md @@ -14,14 +14,16 @@ In Rust, we bind this concept to the [`Executor`](https://docs.rs/libafl/latest/ By default, we implement some commonly used Executors such as [`InProcessExecutor`](https://docs.rs/libafl/latest/libafl/executors/inprocess/type.InProcessExecutor.html) in which the target is a harness function providing in-process crash detection. Another Executor is the [`ForkserverExecutor`](https://docs.rs/libafl/latest/libafl/executors/forkserver/struct.ForkserverExecutor.html) that implements an AFL-like mechanism to spawn child processes to fuzz. ## InProcessExecutor + Let's begin with the base case; `InProcessExecutor`. This executor executes the harness program (function) inside the fuzzer process. When you want to execute the harness as fast as possible, you will most probably want to use this `InprocessExecutor`. - One thing to note here is, when your harness is likely to have heap corruption bugs, you want to use another allocator so that corrupted heap does not affect the fuzzer itself. (For example, we adopt MiMalloc in some of our fuzzers.). Alternatively you can compile your harness with address sanitizer to make sure you can catch these heap bugs. +One thing to note here is, when your harness is likely to have heap corruption bugs, you want to use another allocator so that corrupted heap does not affect the fuzzer itself. (For example, we adopt MiMalloc in some of our fuzzers.). Alternatively you can compile your harness with address sanitizer to make sure you can catch these heap bugs. ## ForkserverExecutor + Next, we'll take a look at the `ForkserverExecutor`. In this case, it is `afl-cc` (from AFL/AFLplusplus) that compiles the harness code, and therefore, we can't use `EDGES_MAP` anymore. Fortunately we have [_a way_](https://github.com/AFLplusplus/AFLplusplus/blob/2e15661f184c77ac1fbb6f868c894e946cbb7f17/instrumentation/afl-compiler-rt.o.c#L270) to tell the forkserver which map to record the coverage in. As you can see from the forkserver example, @@ -36,7 +38,7 @@ let mut shmem_buf = shmem.as_slice_mut(); Here we make a shared memory region; `shmem`, and write this to environmental variable `__AFL_SHM_ID`. Then the instrumented binary, or the forkserver, finds this shared memory region (from the aforementioned env var) to record its coverage. On your fuzzer side, you can pass this shmem map to your `Observer` to obtain coverage feedbacks combined with any `Feedback`. -Another feature of the `ForkserverExecutor` to mention is the shared memory testcases. In normal cases, the mutated input is passed between the forkserver and the instrumented binary via `.cur_input` file. You can improve your forkserver fuzzer's performance by passing the input with shared memory. +Another feature of the `ForkserverExecutor` to mention is the shared memory testcases. In normal cases, the mutated input is passed between the forkserver and the instrumented binary via `.cur_input` file. You can improve your forkserver fuzzer's performance by passing the input with shared memory. If the target is configured to use shared memory testcases, the `ForkserverExecutor` will notice this during the handshake and will automatically set up things accordingly. See AFL++'s [_documentation_](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md#5-shared-memory-fuzzing) or the fuzzer example in `forkserver_simple/src/program.c` for reference. @@ -66,3 +68,16 @@ unsafe{ ``` Again, you can pass this shmem map to your `Observer` and `Feedback` to obtain coverage feedbacks. + +Additionaly to allow the fuzzer to know when the child has crashed, the program should abort instead of unwinding upon a panic. +Without it, no crashes are saved by the fuzzer. + +Cargo.toml: + +```toml +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +``` From 7543a54d0de1e64fbdc05e7e15381e6806546843 Mon Sep 17 00:00:00 2001 From: jejuisland87654 Date: Thu, 2 Jan 2025 16:33:47 +0100 Subject: [PATCH 13/25] Add dynamic frida runtime list called `FridaRuntimeVec` (#2799) Co-authored-by: Dominik Maier --- libafl_frida/src/helper.rs | 64 +++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 98d1fe3599..d6dca76dc5 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -1,5 +1,6 @@ use core::fmt::{self, Debug, Formatter}; use std::{ + any::TypeId, cell::{Ref, RefCell, RefMut}, ffi::CStr, fs::{self, read_to_string}, @@ -34,7 +35,7 @@ use crate::cmplog_rt::CmpLogRuntime; use crate::{asan::asan_rt::AsanRuntime, coverage_rt::CoverageRuntime, drcov_rt::DrCovRuntime}; /// The Runtime trait -pub trait FridaRuntime: 'static + Debug { +pub trait FridaRuntime: 'static + Debug + std::any::Any { /// Initialization fn init( &mut self, @@ -193,6 +194,67 @@ where } } +/// Vector of `FridaRuntime` +#[derive(Debug)] +pub struct FridaRuntimeVec(pub Vec>); + +impl MatchFirstType for FridaRuntimeVec { + fn match_first_type(&self) -> Option<&T> { + for member in &self.0 { + if TypeId::of::() == member.type_id() { + let raw = std::ptr::from_ref::(&**member) as *const T; + return unsafe { raw.as_ref() }; + } + } + + None + } + + fn match_first_type_mut(&mut self) -> Option<&mut T> { + for member in &mut self.0 { + if TypeId::of::() == member.type_id() { + let raw = std::ptr::from_mut::(&mut **member) as *mut T; + return unsafe { raw.as_mut() }; + } + } + + None + } +} + +impl FridaRuntimeTuple for FridaRuntimeVec { + fn init_all( + &mut self, + gum: &Gum, + ranges: &RangeMap, + module_map: &Rc, + ) { + for runtime in &mut self.0 { + runtime.init(gum, ranges, module_map); + } + } + + fn deinit_all(&mut self, gum: &Gum) { + for runtime in &mut self.0 { + runtime.deinit(gum); + } + } + + fn pre_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + for runtime in &mut self.0 { + runtime.pre_exec(input_bytes)?; + } + Ok(()) + } + + fn post_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + for runtime in &mut self.0 { + runtime.post_exec(input_bytes)?; + } + Ok(()) + } +} + /// Represents a range to be skipped for instrumentation #[derive(Debug, Clone, PartialEq, Eq)] pub enum SkipRange { From d39ded5b29c23deb38e8c799fea0fed73d835b9b Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 3 Jan 2025 15:17:46 +0100 Subject: [PATCH 14/25] Fix and/or mute more clippy lints, deprecation warnings in Pyo3 (#2805) --- libafl/src/common/nautilus/grammartec/context.rs | 2 ++ .../common/nautilus/grammartec/python_grammar_loader.rs | 8 +++++--- libafl/src/common/nautilus/grammartec/tree.rs | 8 ++++---- libafl_qemu/src/qemu/usermode.rs | 4 +++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libafl/src/common/nautilus/grammartec/context.rs b/libafl/src/common/nautilus/grammartec/context.rs index c29901b9fd..cd4068d014 100644 --- a/libafl/src/common/nautilus/grammartec/context.rs +++ b/libafl/src/common/nautilus/grammartec/context.rs @@ -357,6 +357,8 @@ mod tests { tree::{Tree, TreeLike}, }; + // Some (but not all) versions of clippy think the from_nt things are format strings. + #[allow(clippy::literal_string_with_formatting_args)] #[test] fn simple_context() { let mut ctx = Context::new(); diff --git a/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs b/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs index 7ed7ab5f9b..061b15238c 100644 --- a/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs +++ b/libafl/src/common/nautilus/grammartec/python_grammar_loader.rs @@ -1,4 +1,6 @@ -use std::{string::String, vec::Vec}; +#![allow(clippy::useless_conversion)] // This seems to be a false-positive(?) + +use std::{ffi::CString, string::String, vec::Vec}; use pyo3::{prelude::*, pyclass, types::IntoPyDict}; @@ -48,8 +50,8 @@ impl PyContext { fn loader(py: Python, grammar: &str) -> PyResult { let py_ctx = Bound::new(py, PyContext::new())?; - let locals = [("ctx", &py_ctx)].into_py_dict_bound(py); - py.run_bound(grammar, None, Some(&locals))?; + let locals = [("ctx", &py_ctx)].into_py_dict(py)?; + py.run(&CString::new(grammar)?, None, Some(&locals))?; Ok(py_ctx.borrow().get_context()) } diff --git a/libafl/src/common/nautilus/grammartec/tree.rs b/libafl/src/common/nautilus/grammartec/tree.rs index d330076736..b8f46061f8 100644 --- a/libafl/src/common/nautilus/grammartec/tree.rs +++ b/libafl/src/common/nautilus/grammartec/tree.rs @@ -85,13 +85,13 @@ impl<'data, 'tree: 'data, 'ctx: 'data, W: Write, T: TreeLike> Unparser<'data, 't .into_iter() .map(io::Cursor::into_inner) .collect::>(); - let byte_arrays = bufs.iter().map(|b| PyBytes::new_bound(py, b)); - let res = expr.call1(py, PyTuple::new_bound(py, byte_arrays))?; + let byte_arrays = bufs.iter().map(|b| PyBytes::new(py, b)); + let res = expr.call1(py, PyTuple::new(py, byte_arrays)?)?; let bound = res.bind(py); - if PyString::is_type_of_bound(bound) { + if PyString::is_type_of(bound) { let pystr = bound.downcast::()?; self.write(pystr.to_string_lossy().as_bytes()); - } else if PyBytes::is_type_of_bound(bound) { + } else if PyBytes::is_type_of(bound) { let pybytes = bound.downcast::()?; self.write(pybytes.as_bytes()); } else { diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index 33b31e326c..f9549ede64 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -286,7 +286,9 @@ pub mod pybind { a6: u64, a7: u64, ) -> SyscallHookResult { - unsafe { &*(&raw const PY_SYSCALL_HOOK).as_ref() }.map_or_else( + // If we don't deref_addrof we run into the "static-mut-references" lint which is worse. + #[expect(clippy::deref_addrof)] + unsafe { (*(&raw const PY_SYSCALL_HOOK)).as_ref() }.map_or_else( || SyscallHookResult::new(None), |obj| { let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7); From da55e70aa3b42fe9c757deb6ed2575d141521871 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:04:41 +0000 Subject: [PATCH 15/25] qemu_launcher: Fix command line parsing of ranges (#2804) Co-authored-by: Your Name Co-authored-by: Dominik Maier --- .../binary_only/qemu_launcher/src/options.rs | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/fuzzers/binary_only/qemu_launcher/src/options.rs b/fuzzers/binary_only/qemu_launcher/src/options.rs index ea6823ac3e..0b2fa31fa2 100644 --- a/fuzzers/binary_only/qemu_launcher/src/options.rs +++ b/fuzzers/binary_only/qemu_launcher/src/options.rs @@ -92,33 +92,23 @@ impl FuzzerOptions { Ok(Duration::from_millis(src.parse()?)) } - fn parse_ranges(src: &str) -> Result>, Error> { - src.split(',') - .map(|r| { - let parts = r.split('-').collect::>(); - if parts.len() == 2 { - let start = GuestAddr::from_str_radix(parts[0].trim_start_matches("0x"), 16) - .map_err(|e| { - Error::illegal_argument(format!( - "Invalid start address: {} ({e:})", - parts[0] - )) - })?; - let end = GuestAddr::from_str_radix(parts[1].trim_start_matches("0x"), 16) - .map_err(|e| { - Error::illegal_argument(format!( - "Invalid end address: {} ({e:})", - parts[1] - )) - })?; - Ok(Range { start, end }) - } else { - Err(Error::illegal_argument(format!( - "Invalid range provided: {r:}" - ))) - } - }) - .collect::>, Error>>() + fn parse_ranges(src: &str) -> Result, Error> { + let parts = src.split('-').collect::>(); + if parts.len() == 2 { + let start = + GuestAddr::from_str_radix(parts[0].trim_start_matches("0x"), 16).map_err(|e| { + Error::illegal_argument(format!("Invalid start address: {} ({e:})", parts[0])) + })?; + let end = + GuestAddr::from_str_radix(parts[1].trim_start_matches("0x"), 16).map_err(|e| { + Error::illegal_argument(format!("Invalid end address: {} ({e:})", parts[1])) + })?; + Ok(Range { start, end }) + } else { + Err(Error::illegal_argument(format!( + "Invalid range provided: {src:}" + ))) + } } pub fn is_asan_core(&self, core_id: CoreId) -> bool { From b3b216386ee00b7a970aacb9ecc9c05983de628e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 3 Jan 2025 16:05:02 +0100 Subject: [PATCH 16/25] Another clippy bugfix (#2806) --- libafl_targets/src/libfuzzer/mutators.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libafl_targets/src/libfuzzer/mutators.rs b/libafl_targets/src/libfuzzer/mutators.rs index a57b7fa751..7511766823 100644 --- a/libafl_targets/src/libfuzzer/mutators.rs +++ b/libafl_targets/src/libfuzzer/mutators.rs @@ -350,7 +350,7 @@ where return result.replace(Ok(MutationResult::Skipped)); } if new_len > len_max { - return Err(Error::illegal_state("LLVMFuzzerCustomMutator returned more bytes than allowed. Expected up to {max_len} but got {new_len}")); + return Err(Error::illegal_state(format!("LLVMFuzzerCustomMutator returned more bytes than allowed. Expected up to {max_len} but got {new_len}"))); } input.resize(new_len, 0); Ok(MutationResult::Mutated) @@ -448,7 +448,7 @@ where } if new_len > len_max { - return Err(Error::illegal_state("LLVMFuzzerCustomCrossOver returned more bytes than allowed. Expected up to {max_len} but got {new_len}")); + return Err(Error::illegal_state(format!("LLVMFuzzerCustomCrossOver returned more bytes than allowed. Expected up to {max_len} but got {new_len}"))); } input.resize(new_len, 0); From 6e921cf8706923adc496d63e1fcf59702d0f8d7d Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sun, 5 Jan 2025 15:56:27 +0100 Subject: [PATCH 17/25] More clippy (#2811) * More clippy * clip --- libafl_targets/src/libfuzzer/mutators.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libafl_targets/src/libfuzzer/mutators.rs b/libafl_targets/src/libfuzzer/mutators.rs index 7511766823..434fbed7ca 100644 --- a/libafl_targets/src/libfuzzer/mutators.rs +++ b/libafl_targets/src/libfuzzer/mutators.rs @@ -323,8 +323,8 @@ where ) -> Result { let seed = state.rand_mut().next(); let len_orig = input.bytes().len(); - let len_max = state.max_size(); - input.resize(len_max, 0); + let max_len = state.max_size(); + input.resize(max_len, 0); // we assume that the fuzzer did not use this mutator, but instead utilised their own let result = Rc::new(RefCell::new(Ok(MutationResult::Mutated))); @@ -337,7 +337,7 @@ where libafl_targets_libfuzzer_custom_mutator( input.bytes_mut().as_mut_ptr(), len_orig, - len_max, + max_len, seed as u32, ) }; @@ -349,7 +349,8 @@ where if result.deref().borrow().is_err() { return result.replace(Ok(MutationResult::Skipped)); } - if new_len > len_max { + + if new_len > max_len { return Err(Error::illegal_state(format!("LLVMFuzzerCustomMutator returned more bytes than allowed. Expected up to {max_len} but got {new_len}"))); } input.resize(new_len, 0); @@ -415,10 +416,10 @@ where let seed = state.rand_mut().next(); let mut out = vec![0u8; state.max_size()]; - let len_max = state.max_size(); + let max_len = state.max_size(); let len_orig = input.len(); - input.resize(len_max, 0); + input.resize(max_len, 0); // we assume that the fuzzer did not use this mutator, but instead utilised their own let result = Rc::new(RefCell::new(Ok(MutationResult::Mutated))); @@ -434,7 +435,7 @@ where data2.as_ptr(), data2.len(), out.as_mut_ptr(), - len_max, + max_len, seed as u32, ) }; @@ -447,7 +448,7 @@ where return result.replace(Ok(MutationResult::Skipped)); } - if new_len > len_max { + if new_len > max_len { return Err(Error::illegal_state(format!("LLVMFuzzerCustomCrossOver returned more bytes than allowed. Expected up to {max_len} but got {new_len}"))); } From 2a3f5a59425027028f4b94a2893a94f512bcfdd0 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 6 Jan 2025 02:03:18 +0100 Subject: [PATCH 18/25] Add Bloomfilter-based Feedback for Values (#2813) * Initial commit: ValueBloomFeedback * Add test, fix feedback * Remove unneeded feedback * fix * more commit --- Cargo.toml | 1 + libafl/Cargo.toml | 5 +- libafl/src/feedbacks/mod.rs | 5 + libafl/src/feedbacks/value_bloom.rs | 190 ++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 libafl/src/feedbacks/value_bloom.rs diff --git a/Cargo.toml b/Cargo.toml index 335e8eb66b..6a834b6bd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ clap = "4.5.18" cc = "1.1.21" cmake = "0.1.51" document-features = "0.2.10" +fastbloom = { version = "0.8.0", default-features = false } hashbrown = { version = "0.14.5", default-features = false } # A faster hashmap, nostd compatible libc = "0.2.159" # For (*nix) libc libipt = "0.2.0" diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 7781fce16d..a990e9f0c7 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -64,6 +64,9 @@ std = [ ## Tracks the Feedbacks and the Objectives that were interesting for a Testcase track_hit_feedbacks = ["std"] +## `ValueBloomFeedback` checks if an observed value has already been observed, and returns `is_interesting=true` otherwise. +value_bloom_feedback = ["fastbloom", "fastbloom/serde"] + ## Collects performance statistics of the fuzzing pipeline and displays it on `Monitor` components introspection = [] @@ -292,7 +295,7 @@ document-features = { workspace = true, optional = true } clap = { workspace = true, optional = true } num_enum = { workspace = true, optional = true } libipt = { workspace = true, optional = true } -fastbloom = { version = "0.8.0", optional = true } +fastbloom = { workspace = true, optional = true } [lints] workspace = true diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 49e9f2e2d7..c18d08ea49 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -54,6 +54,11 @@ pub use capture_feedback::CaptureTimeoutFeedback; #[cfg(feature = "introspection")] use crate::state::HasClientPerfMonitor; +#[cfg(feature = "value_bloom_feedback")] +pub mod value_bloom; +#[cfg(feature = "value_bloom_feedback")] +pub use value_bloom::ValueBloomFeedback; + /// Feedback which initializes a state. /// /// This trait is separate from the general [`Feedback`] definition as it would not be sufficiently diff --git a/libafl/src/feedbacks/value_bloom.rs b/libafl/src/feedbacks/value_bloom.rs new file mode 100644 index 0000000000..8e9bacbf07 --- /dev/null +++ b/libafl/src/feedbacks/value_bloom.rs @@ -0,0 +1,190 @@ +//! The [`ValueBloomFeedback`] checks if a value has already been observed in a [`BloomFilter`] and returns `true` if the value is new, adding it to the bloom filter. +//! + +use core::hash::Hash; +use std::borrow::Cow; + +use fastbloom::BloomFilter; +use libafl_bolts::{ + impl_serdeany, + tuples::{Handle, MatchNameRef}, + Error, Named, +}; +use serde::{Deserialize, Serialize}; + +use super::{Feedback, StateInitializer}; +use crate::{ + executors::ExitKind, + observers::{ObserversTuple, ValueObserver}, + HasNamedMetadata, +}; + +impl_serdeany!(ValueBloomFeedbackMetadata); + +#[derive(Debug, Serialize, Deserialize)] +struct ValueBloomFeedbackMetadata { + bloom: BloomFilter, +} + +/// A Feedback that returns `true` for `is_interesting` for new values it found in a [`ValueObserver`]. +/// It keeps track of the previously seen values in a [`BloomFilter`]. +#[derive(Debug)] +pub struct ValueBloomFeedback<'a, T> { + name: Cow<'static, str>, + observer_hnd: Handle>, + #[cfg(feature = "track_hit_feedbacks")] + last_result: Option, +} + +impl<'a, T> ValueBloomFeedback<'a, T> { + /// Create a new [`ValueBloomFeedback`] + #[must_use] + pub fn new(observer_hnd: &Handle>) -> Self { + Self::with_name(observer_hnd.name().clone(), observer_hnd) + } + + /// Create a new [`ValueBloomFeedback`] with a given name + #[must_use] + pub fn with_name(name: Cow<'static, str>, observer_hnd: &Handle>) -> Self { + Self { + name, + observer_hnd: observer_hnd.clone(), + #[cfg(feature = "track_hit_feedbacks")] + last_result: None, + } + } +} + +impl Named for ValueBloomFeedback<'_, T> { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl StateInitializer for ValueBloomFeedback<'_, T> { + fn init_state(&mut self, state: &mut S) -> Result<(), Error> { + let _ = + state.named_metadata_or_insert_with::(&self.name, || { + ValueBloomFeedbackMetadata { + bloom: BloomFilter::with_false_pos(0.001).expected_items(1024), + } + }); + Ok(()) + } +} + +impl, S: HasNamedMetadata, T: Hash> Feedback + for ValueBloomFeedback<'_, T> +{ + fn is_interesting( + &mut self, + state: &mut S, + _manager: &mut EM, + _input: &I, + observers: &OT, + _exit_kind: &ExitKind, + ) -> Result { + let Some(observer) = observers.get(&self.observer_hnd) else { + return Err(Error::illegal_state(format!( + "Observer {:?} not found", + self.observer_hnd + ))); + }; + let val = observer.value.as_ref(); + + let metadata = state.named_metadata_mut::(&self.name)?; + + let res = if metadata.bloom.contains(val) { + false + } else { + metadata.bloom.insert(val); + true + }; + + #[cfg(feature = "track_hit_feedbacks")] + { + self.last_result = Some(true); + } + + Ok(res) + } + + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { + self.last_result.ok_or_else(|| Error::illegal_state("No last result set in `ValueBloomFeedback`. Either `is_interesting` has never been called or the fuzzer restarted in the meantime.")) + } +} + +#[cfg(test)] +mod test { + use core::ptr::write_volatile; + + use libafl_bolts::{ownedref::OwnedRef, serdeany::NamedSerdeAnyMap, tuples::Handled}; + use tuple_list::tuple_list; + + use super::ValueBloomFeedback; + use crate::{ + events::NopEventManager, + executors::ExitKind, + feedbacks::{Feedback, StateInitializer}, + inputs::NopInput, + observers::ValueObserver, + HasNamedMetadata, + }; + + static mut VALUE: u32 = 0; + + struct NamedMetadataState { + map: NamedSerdeAnyMap, + } + + impl HasNamedMetadata for NamedMetadataState { + fn named_metadata_map(&self) -> &NamedSerdeAnyMap { + &self.map + } + + fn named_metadata_map_mut(&mut self) -> &mut NamedSerdeAnyMap { + &mut self.map + } + } + + #[test] + fn test_value_bloom_feedback() { + let value_ptr = unsafe { OwnedRef::from_ptr(&raw mut VALUE) }; + + let observer = ValueObserver::new("test_value", value_ptr); + + let mut vbf = ValueBloomFeedback::new(&observer.handle()); + + let mut state = NamedMetadataState { + map: NamedSerdeAnyMap::new(), + }; + vbf.init_state(&mut state).unwrap(); + + let observers = tuple_list!(observer); + let mut mgr = NopEventManager::::new(); + let input = NopInput {}; + let exit_ok = ExitKind::Ok; + + let first_eval = vbf + .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) + .unwrap(); + assert_eq!(first_eval, true); + + let second_eval = vbf + .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) + .unwrap(); + + assert_ne!(first_eval, second_eval); + + unsafe { + write_volatile(&raw mut VALUE, 1234_u32); + } + + let next_eval = vbf + .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) + .unwrap(); + assert_eq!(next_eval, true); + + } +} From 4b4a22bc44aec270ca7d0d59d864d94bc850540e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 6 Jan 2025 02:11:47 +0100 Subject: [PATCH 19/25] Cargo Format (#2814) * Initial commit: ValueBloomFeedback * Add test, fix feedback * Remove unneeded feedback * fix * more commit * Cargo fmt * fmt --- libafl/src/feedbacks/value_bloom.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/libafl/src/feedbacks/value_bloom.rs b/libafl/src/feedbacks/value_bloom.rs index 8e9bacbf07..eb2dbef55e 100644 --- a/libafl/src/feedbacks/value_bloom.rs +++ b/libafl/src/feedbacks/value_bloom.rs @@ -185,6 +185,5 @@ mod test { .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) .unwrap(); assert_eq!(next_eval, true); - } } From 742773bc17f8e998df15e4eef451238a368d8cab Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 6 Jan 2025 04:25:36 +0100 Subject: [PATCH 20/25] Add BoolValueFeedback (#2815) * Add BoolValueFeedback * No_std * clippy * Fix tests * More clip * fix no_std tests --- libafl/src/events/llmp/restarting.rs | 7 + libafl/src/feedbacks/bool.rs | 154 ++++++++++++++++++++++ libafl/src/feedbacks/mod.rs | 3 + libafl/src/feedbacks/new_hash_feedback.rs | 2 +- libafl/src/feedbacks/value_bloom.rs | 61 ++++----- libafl/src/inputs/mod.rs | 12 +- libafl/src/stages/mod.rs | 14 +- libafl/src/state/mod.rs | 12 ++ 8 files changed, 222 insertions(+), 43 deletions(-) create mode 100644 libafl/src/feedbacks/bool.rs diff --git a/libafl/src/events/llmp/restarting.rs b/libafl/src/events/llmp/restarting.rs index 4feeababcf..361e979ac1 100644 --- a/libafl/src/events/llmp/restarting.rs +++ b/libafl/src/events/llmp/restarting.rs @@ -737,6 +737,13 @@ mod tests { #[serial] #[cfg_attr(miri, ignore)] fn test_mgr_state_restore() { + // # Safety + // The same testcase doesn't usually run twice + #[cfg(any(not(feature = "serdeany_autoreg"), miri))] + unsafe { + crate::stages::RetryCountRestartHelper::register(); + } + let rand = StdRand::with_seed(0); let time = TimeObserver::new("time"); diff --git a/libafl/src/feedbacks/bool.rs b/libafl/src/feedbacks/bool.rs new file mode 100644 index 0000000000..74a6ba577b --- /dev/null +++ b/libafl/src/feedbacks/bool.rs @@ -0,0 +1,154 @@ +//! The [`BoolValueFeedback`] is a [`Feedback`] returning `true` or `false` as the `is_interesting` value. + +use alloc::borrow::Cow; + +use libafl_bolts::{ + tuples::{Handle, MatchNameRef}, + Error, Named, +}; + +use crate::{ + feedbacks::{Feedback, StateInitializer}, + observers::{ObserversTuple, ValueObserver}, + HasNamedMetadata, +}; + +/// This feedback returns `true` or `false` as the `is_interesting` value. +#[derive(Debug)] +pub struct BoolValueFeedback<'a> { + name: Cow<'static, str>, + observer_hnd: Handle>, + #[cfg(feature = "track_hit_feedbacks")] + last_result: Option, +} + +impl<'a> BoolValueFeedback<'a> { + /// Create a new [`BoolValueFeedback`] + #[must_use] + pub fn new(observer_hnd: &Handle>) -> Self { + Self::with_name(observer_hnd.name().clone(), observer_hnd) + } + + /// Create a new [`BoolValueFeedback`] with a given name + #[must_use] + pub fn with_name( + name: Cow<'static, str>, + observer_hnd: &Handle>, + ) -> Self { + Self { + name, + observer_hnd: observer_hnd.clone(), + #[cfg(feature = "track_hit_feedbacks")] + last_result: None, + } + } +} + +impl Named for BoolValueFeedback<'_> { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl StateInitializer for BoolValueFeedback<'_> { + fn init_state(&mut self, _state: &mut S) -> Result<(), Error> { + Ok(()) + } +} + +impl Feedback for BoolValueFeedback<'_> +where + OT: ObserversTuple, + S: HasNamedMetadata, +{ + fn is_interesting( + &mut self, + _state: &mut S, + _manager: &mut EM, + _input: &I, + observers: &OT, + _exit_kind: &crate::executors::ExitKind, + ) -> Result { + let Some(observer) = observers.get(&self.observer_hnd) else { + return Err(Error::illegal_state(format!( + "Observer {:?} not found", + self.observer_hnd + ))); + }; + + let val = observer.value.as_ref(); + + Ok(*val) + } + + fn append_metadata( + &mut self, + _state: &mut S, + _manager: &mut EM, + _observers: &OT, + _testcase: &mut crate::corpus::Testcase, + ) -> Result<(), Error> { + Ok(()) + } + + fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + Ok(()) + } + + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { + self.last_result.ok_or_else(|| Error::illegal_state("No last result set in `BoolValuefeedback`. Either `is_interesting` has never been called or the fuzzer restarted in the meantime.")) + } +} + +#[cfg(test)] +mod test { + use core::{cell::UnsafeCell, ptr::write_volatile}; + + use libafl_bolts::{ownedref::OwnedRef, tuples::Handled}; + use tuple_list::tuple_list; + + use crate::{ + executors::ExitKind, + feedbacks::{BoolValueFeedback, Feedback, StateInitializer}, + observers::ValueObserver, + state::NopState, + }; + + #[test] + fn test_bool_value_feedback() { + let value: UnsafeCell = false.into(); + + // # Safety + // The value is only read from in the feedback, not while we change the value. + let value_ptr = unsafe { OwnedRef::from_ptr(value.get()) }; + + let observer = ValueObserver::new("test_value", value_ptr); + + let mut bool_feedback = BoolValueFeedback::new(&observer.handle()); + + let mut state: NopState<()> = NopState::new(); + bool_feedback.init_state(&mut state).unwrap(); + + let observers = tuple_list!(observer); + let mut mgr = (); + let input = (); + let exit_ok = ExitKind::Ok; + + let false_eval = bool_feedback + .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) + .unwrap(); + assert!(!false_eval); + + // # Safety + // The feedback is not keeping a borrow around, only the pointer. + unsafe { + write_volatile(value.get(), true); + } + + let true_eval = bool_feedback + .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) + .unwrap(); + assert!(true_eval); + } +} diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index c18d08ea49..5fa19965ea 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -31,6 +31,9 @@ use crate::{corpus::Testcase, executors::ExitKind, observers::TimeObserver, Erro #[cfg(feature = "std")] pub mod capture_feedback; +pub mod bool; +pub use bool::BoolValueFeedback; + #[cfg(feature = "std")] pub mod concolic; #[cfg(feature = "std")] diff --git a/libafl/src/feedbacks/new_hash_feedback.rs b/libafl/src/feedbacks/new_hash_feedback.rs index 5fa7a4b825..f79be125fc 100644 --- a/libafl/src/feedbacks/new_hash_feedback.rs +++ b/libafl/src/feedbacks/new_hash_feedback.rs @@ -1,4 +1,4 @@ -//! The ``NewHashFeedback`` uses the backtrace hash and a hashset to only keep novel cases +//! The [`NewHashFeedback`] uses the backtrace hash and a hashset to only keep novel cases use alloc::{borrow::Cow, string::ToString}; use std::fmt::Debug; diff --git a/libafl/src/feedbacks/value_bloom.rs b/libafl/src/feedbacks/value_bloom.rs index eb2dbef55e..031b603dee 100644 --- a/libafl/src/feedbacks/value_bloom.rs +++ b/libafl/src/feedbacks/value_bloom.rs @@ -12,9 +12,9 @@ use libafl_bolts::{ }; use serde::{Deserialize, Serialize}; -use super::{Feedback, StateInitializer}; use crate::{ executors::ExitKind, + feedbacks::{Feedback, StateInitializer}, observers::{ObserversTuple, ValueObserver}, HasNamedMetadata, }; @@ -117,73 +117,66 @@ impl, S: HasNamedMetadata, T: Hash> Feedback = 0_u32.into(); - impl HasNamedMetadata for NamedMetadataState { - fn named_metadata_map(&self) -> &NamedSerdeAnyMap { - &self.map + // # Safety + // The same testcase doesn't usually run twice + #[cfg(any(not(feature = "serdeany_autoreg"), miri))] + unsafe { + super::ValueBloomFeedbackMetadata::register(); } - fn named_metadata_map_mut(&mut self) -> &mut NamedSerdeAnyMap { - &mut self.map - } - } - - #[test] - fn test_value_bloom_feedback() { - let value_ptr = unsafe { OwnedRef::from_ptr(&raw mut VALUE) }; + // # Safety + // The value is only read from in the feedback, not while we change the value. + let value_ptr = unsafe { OwnedRef::from_ptr(value.get()) }; let observer = ValueObserver::new("test_value", value_ptr); - let mut vbf = ValueBloomFeedback::new(&observer.handle()); - let mut state = NamedMetadataState { - map: NamedSerdeAnyMap::new(), - }; - vbf.init_state(&mut state).unwrap(); - let observers = tuple_list!(observer); - let mut mgr = NopEventManager::::new(); - let input = NopInput {}; + + let mut state: NopState<()> = NopState::new(); + let mut mgr = (); + let input = (); let exit_ok = ExitKind::Ok; + vbf.init_state(&mut state).unwrap(); + let first_eval = vbf .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) .unwrap(); - assert_eq!(first_eval, true); + assert!(first_eval); let second_eval = vbf .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) .unwrap(); - assert_ne!(first_eval, second_eval); + assert!(!second_eval); + // # Safety + // The feedback is not keeping a borrow around, only the pointer. unsafe { - write_volatile(&raw mut VALUE, 1234_u32); + write_volatile(value.get(), 1234_u32); } let next_eval = vbf .is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok) .unwrap(); - assert_eq!(next_eval, true); + assert!(next_eval); } } diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 055e2fb407..91aac35652 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -116,13 +116,23 @@ macro_rules! none_input_converter { } /// An input for tests, mainly. There is no real use much else. -#[derive(Copy, Clone, Serialize, Deserialize, Debug, Hash)] +#[derive(Copy, Clone, Serialize, Deserialize, Debug, Default, Hash)] pub struct NopInput {} + +impl NopInput { + /// Creates a new [`NopInput`] + #[must_use] + pub fn new() -> Self { + Self {} + } +} + impl Input for NopInput { fn generate_name(&self, _id: Option) -> String { "nop-input".to_string() } } + impl HasTargetBytes for NopInput { fn target_bytes(&self) -> OwnedSlice { OwnedSlice::from(vec![0]) diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index da01ae7886..d0626abe8c 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -612,13 +612,6 @@ mod test { /// Test to test retries in stages #[test] fn test_tries_progress() -> Result<(), Error> { - // # Safety - // No concurrency per testcase - #[cfg(any(not(feature = "serdeany_autoreg"), miri))] - unsafe { - RetryCountRestartHelper::register(); - } - struct StageWithOneTry; impl Named for StageWithOneTry { @@ -628,6 +621,13 @@ mod test { } } + // # Safety + // No concurrency per testcase + #[cfg(any(not(feature = "serdeany_autoreg"), miri))] + unsafe { + RetryCountRestartHelper::register(); + } + let mut state = StdState::nop()?; let stage = StageWithOneTry; diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 86477a6aa1..35ffedba68 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -1242,6 +1242,7 @@ impl HasScalabilityMonitor for StdState { #[derive(Debug, Serialize, Deserialize, Default)] pub struct NopState { metadata: SerdeAnyMap, + named_metadata: NamedSerdeAnyMap, execution: u64, stop_requested: bool, rand: StdRand, @@ -1254,6 +1255,7 @@ impl NopState { pub fn new() -> Self { NopState { metadata: SerdeAnyMap::new(), + named_metadata: NamedSerdeAnyMap::new(), execution: 0, rand: StdRand::default(), stop_requested: false, @@ -1323,6 +1325,16 @@ impl HasMetadata for NopState { } } +impl HasNamedMetadata for NopState { + fn named_metadata_map(&self) -> &NamedSerdeAnyMap { + &self.named_metadata + } + + fn named_metadata_map_mut(&mut self) -> &mut NamedSerdeAnyMap { + &mut self.named_metadata + } +} + impl HasRand for NopState { type Rand = StdRand; From 5a3cbc18a76e04144ab89d9c197d34c2cb327772 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:22:08 +0000 Subject: [PATCH 21/25] Changes to use InMemoryCorpus (#2816) Co-authored-by: Your Name --- fuzzers/binary_only/qemu_coverage/src/fuzzer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs index d5826a4fa4..7d70b2daf7 100644 --- a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs @@ -7,7 +7,7 @@ use std::{env, fmt::Write, fs::DirEntry, io, path::PathBuf, process}; use clap::{builder::Str, Parser}; use libafl::{ - corpus::{Corpus, NopCorpus}, + corpus::{Corpus, InMemoryCorpus}, events::{ launcher::Launcher, ClientDescription, EventConfig, EventRestarter, LlmpRestartingEventManager, @@ -221,8 +221,8 @@ pub fn fuzz() { let mut state = state.unwrap_or_else(|| { StdState::new( StdRand::new(), - NopCorpus::new(), - NopCorpus::new(), + InMemoryCorpus::new(), + InMemoryCorpus::new(), &mut feedback, &mut objective, ) From 7c8708d4b1fb7a81dc65ba8717eeb0cc395855f7 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 6 Jan 2025 15:04:40 +0100 Subject: [PATCH 22/25] Refactor of Qemu configuration (#2707) * Qemu config refactoring. * QEMU error refactoring. * Single QEMU init function. * Light refactor of EmulatorModules. * Qemu is now a parameter to EmulatorModule callbacks and most function hooks. * EmulatorModules is initialized before QEMU is initialized. * refactor asan and asanguest modules to avoid custom init of QEMU and use the module interface instead. * asan fixed size accesses working with generics. * use pre_syscall_* and post_syscall_* everywhere for consistency. * adapt qemu_launcher example to fully work with Emulator, since Qemu must now be initialized by Emulator. * start writing Emulator / EmulatorBuilder / QemuConfig doc. * fix broken intel pt doc. --- .../fuzzbench_fork_qemu/src/fuzzer.rs | 2 +- .../binary_only/fuzzbench_qemu/src/fuzzer.rs | 52 +- fuzzers/binary_only/qemu_cmin/src/fuzzer.rs | 51 +- .../binary_only/qemu_coverage/src/fuzzer.rs | 147 +++--- .../binary_only/qemu_launcher/src/client.rs | 70 +-- .../binary_only/qemu_launcher/src/instance.rs | 34 +- .../qemu_baremetal/src/fuzzer_breakpoint.rs | 7 +- .../qemu_baremetal/src/fuzzer_low_level.rs | 17 +- .../qemu_baremetal/src/fuzzer_sync_exit.rs | 2 +- .../qemu_linux_kernel/src/fuzzer.rs | 7 +- .../qemu_linux_process/src/fuzzer.rs | 2 +- libafl/src/executors/command.rs | 12 +- libafl/src/feedbacks/value_bloom.rs | 2 +- libafl/src/stages/tracing.rs | 2 +- libafl_qemu/Cargo.toml | 5 +- libafl_qemu/libafl_qemu_build/Cargo.toml | 5 +- libafl_qemu/libafl_qemu_sys/Cargo.toml | 5 +- libafl_qemu/src/command/mod.rs | 4 +- libafl_qemu/src/emu/builder.rs | 173 ++++--- libafl_qemu/src/emu/drivers.rs | 12 +- libafl_qemu/src/emu/hooks.rs | 204 +++----- libafl_qemu/src/emu/mod.rs | 82 ++- libafl_qemu/src/executor.rs | 6 +- libafl_qemu/src/modules/calls.rs | 35 +- libafl_qemu/src/modules/cmplog.rs | 32 +- libafl_qemu/src/modules/drcov.rs | 25 +- libafl_qemu/src/modules/edges/helpers.rs | 23 +- libafl_qemu/src/modules/edges/mod.rs | 9 +- libafl_qemu/src/modules/mod.rs | 108 ++-- libafl_qemu/src/modules/usermode/asan.rs | 489 ++++++------------ .../src/modules/usermode/asan_guest.rs | 261 +++++----- .../src/modules/usermode/injections.rs | 27 +- libafl_qemu/src/modules/usermode/mod.rs | 4 +- libafl_qemu/src/modules/usermode/snapshot.rs | 17 +- libafl_qemu/src/qemu/config.rs | 47 +- libafl_qemu/src/qemu/error.rs | 155 ++++++ libafl_qemu/src/qemu/hooks.rs | 269 +++++++--- libafl_qemu/src/qemu/mod.rs | 310 +++++------ libafl_qemu/src/qemu/systemmode.rs | 2 +- libafl_sugar/src/qemu.rs | 19 +- 40 files changed, 1428 insertions(+), 1307 deletions(-) create mode 100644 libafl_qemu/src/qemu/error.rs diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs index 19e2ca5b54..fa10f654f3 100644 --- a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs @@ -176,7 +176,7 @@ fn fuzz( ); let emulator = Emulator::empty() - .qemu_cli(args) + .qemu_parameters(args) .modules(emulator_modules) .build()?; diff --git a/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs index fe82f757ff..a1490c5a68 100644 --- a/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs @@ -55,7 +55,6 @@ use libafl_qemu::{ GuestReg, //snapshot::QemuSnapshotHelper, MmapPerms, - Qemu, QemuExecutor, QemuExitError, QemuExitReason, @@ -175,8 +174,33 @@ fn fuzz( env::remove_var("LD_LIBRARY_PATH"); let args: Vec = env::args().collect(); - let qemu = Qemu::init(&args).expect("QEMU init failed"); - // let (emu, asan) = init_with_asan(&mut args, &mut env).unwrap(); + + // Create an observation channel using the coverage map + let mut edges_observer = unsafe { + HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( + "edges", + OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE), + &raw mut MAX_EDGES_FOUND, + )) + .track_indices() + }; + + let modules = tuple_list!( + StdEdgeCoverageModule::builder() + .map_observer(edges_observer.as_mut()) + .build() + .unwrap(), + CmpLogModule::default(), + // QemuAsanHelper::default(asan), + //QemuSnapshotHelper::new() + ); + + let emulator = Emulator::empty() + .qemu_parameters(args) + .modules(modules) + .build()?; + + let qemu = emulator.qemu(); let mut elf_buffer = Vec::new(); let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?; @@ -255,16 +279,6 @@ fn fuzz( }, }; - // Create an observation channel using the coverage map - let mut edges_observer = unsafe { - HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( - "edges", - OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE), - &raw mut MAX_EDGES_FOUND, - )) - .track_indices() - }; - // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -364,18 +378,6 @@ fn fuzz( ExitKind::Ok }; - let modules = tuple_list!( - StdEdgeCoverageModule::builder() - .map_observer(edges_observer.as_mut()) - .build() - .unwrap(), - CmpLogModule::default(), - // QemuAsanHelper::default(asan), - //QemuSnapshotHelper::new() - ); - - let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?; - // Create the executor for an in-process function with one observer for edge coverage and one for the execution time let executor = QemuExecutor::new( emulator, diff --git a/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs b/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs index bb6715fd6c..483e20c3f8 100644 --- a/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs @@ -28,8 +28,8 @@ use libafl_bolts::{ }; use libafl_qemu::{ elf::EasyElf, modules::edges::StdEdgeCoverageChildModule, ArchExtras, CallingConvention, - Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, QemuExitReason, - QemuForkExecutor, QemuShutdownCause, Regs, + Emulator, GuestAddr, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor, + QemuShutdownCause, Regs, }; use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR}; @@ -113,7 +113,31 @@ pub fn fuzz() -> Result<(), Error> { log::debug!("ARGS: {:#?}", options.args); env::remove_var("LD_LIBRARY_PATH"); - let qemu = Qemu::init(&options.args).unwrap(); + + let mut shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); + + let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap(); + let edges = edges_shmem.as_slice_mut(); + unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() }; + + let mut edges_observer = unsafe { + HitcountsMapObserver::new(ConstMapObserver::from_mut_ptr( + "edges", + NonNull::new(edges.as_mut_ptr()) + .expect("The edge map pointer is null.") + .cast::<[u8; EDGES_MAP_DEFAULT_SIZE]>(), + )) + }; + + let modules = tuple_list!(StdEdgeCoverageChildModule::builder() + .const_map_observer(edges_observer.as_mut()) + .build()?); + + let emulator = Emulator::empty() + .qemu_parameters(options.args) + .modules(modules) + .build()?; + let qemu = emulator.qemu(); let mut elf_buffer = Vec::new(); let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer).unwrap(); @@ -139,8 +163,6 @@ pub fn fuzz() -> Result<(), Error> { let stack_ptr: GuestAddr = qemu.read_reg(Regs::Sp).unwrap(); - let mut shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); - let monitor = SimpleMonitor::with_user_monitor(|s| { println!("{s}"); }); @@ -157,19 +179,6 @@ pub fn fuzz() -> Result<(), Error> { }, }; - let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap(); - let edges = edges_shmem.as_slice_mut(); - unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() }; - - let mut edges_observer = unsafe { - HitcountsMapObserver::new(ConstMapObserver::from_mut_ptr( - "edges", - NonNull::new(edges.as_mut_ptr()) - .expect("The edge map pointer is null.") - .cast::<[u8; EDGES_MAP_DEFAULT_SIZE]>(), - )) - }; - let mut feedback = MaxMapFeedback::new(&edges_observer); let mut objective = (); @@ -222,12 +231,6 @@ pub fn fuzz() -> Result<(), Error> { ExitKind::Ok }; - let modules = tuple_list!(StdEdgeCoverageChildModule::builder() - .const_map_observer(edges_observer.as_mut()) - .build()?); - - let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?; - let mut executor = QemuForkExecutor::new( emulator, &mut harness, diff --git a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs index 7d70b2daf7..f57b33a887 100644 --- a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs @@ -31,7 +31,7 @@ use libafl_bolts::{ use libafl_qemu::{ elf::EasyElf, modules::{drcov::DrCovModule, StdAddressFilter}, - ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExecutor, + ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, QemuExecutor, QemuExitReason, QemuRWError, QemuShutdownCause, Regs, }; @@ -123,80 +123,93 @@ pub fn fuzz() { env::remove_var("LD_LIBRARY_PATH"); - let qemu = Qemu::init(&options.args).unwrap(); - - let mut elf_buffer = Vec::new(); - let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer).unwrap(); - - let test_one_input_ptr = elf - .resolve_symbol("LLVMFuzzerTestOneInput", qemu.load_addr()) - .expect("Symbol LLVMFuzzerTestOneInput not found"); - log::debug!("LLVMFuzzerTestOneInput @ {test_one_input_ptr:#x}"); + let mut run_client = |state: Option<_>, + mut mgr: LlmpRestartingEventManager<_, _, _>, + client_description: ClientDescription| { + let mut cov_path = options.coverage_path.clone(); - qemu.entry_break(test_one_input_ptr); + let emulator_modules = tuple_list!(DrCovModule::builder() + .filter(StdAddressFilter::default()) + .filename(cov_path.clone()) + .full_trace(false) + .build()); - for m in qemu.mappings() { - log::debug!( - "Mapping: 0x{:016x}-0x{:016x}, {}", - m.start(), - m.end(), - m.path().unwrap_or(&"".to_string()) - ); - } + let emulator = Emulator::empty() + .qemu_parameters(options.args.clone()) + .modules(emulator_modules) + .build() + .expect("QEMU initialization failed"); + let qemu = emulator.qemu(); + + let mut elf_buffer = Vec::new(); + let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer).unwrap(); + + let test_one_input_ptr = elf + .resolve_symbol("LLVMFuzzerTestOneInput", qemu.load_addr()) + .expect("Symbol LLVMFuzzerTestOneInput not found"); + log::debug!("LLVMFuzzerTestOneInput @ {test_one_input_ptr:#x}"); + + qemu.entry_break(test_one_input_ptr); + + for m in qemu.mappings() { + log::debug!( + "Mapping: 0x{:016x}-0x{:016x}, {}", + m.start(), + m.end(), + m.path().unwrap_or(&"".to_string()) + ); + } - let pc: GuestReg = qemu.read_reg(Regs::Pc).unwrap(); - log::debug!("Break at {pc:#x}"); + let pc: GuestReg = qemu.read_reg(Regs::Pc).unwrap(); + log::debug!("Break at {pc:#x}"); - let ret_addr: GuestAddr = qemu.read_return_address().unwrap(); - log::debug!("Return address = {ret_addr:#x}"); + let ret_addr: GuestAddr = qemu.read_return_address().unwrap(); + log::debug!("Return address = {ret_addr:#x}"); - qemu.set_breakpoint(ret_addr); + qemu.set_breakpoint(ret_addr); - let input_addr = qemu - .map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite) - .unwrap(); - log::debug!("Placing input at {input_addr:#x}"); + let input_addr = qemu + .map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite) + .unwrap(); + log::debug!("Placing input at {input_addr:#x}"); - let stack_ptr: GuestAddr = qemu.read_reg(Regs::Sp).unwrap(); + let stack_ptr: GuestAddr = qemu.read_reg(Regs::Sp).unwrap(); - let reset = |buf: &[u8], len: GuestReg| -> Result<(), QemuRWError> { - unsafe { - let _ = qemu.write_mem(input_addr, buf); - qemu.write_reg(Regs::Pc, test_one_input_ptr)?; - qemu.write_reg(Regs::Sp, stack_ptr)?; - qemu.write_return_address(ret_addr)?; - qemu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?; - qemu.write_function_argument(CallingConvention::Cdecl, 1, len)?; + let reset = |buf: &[u8], len: GuestReg| -> Result<(), QemuRWError> { + unsafe { + let _ = qemu.write_mem(input_addr, buf); + qemu.write_reg(Regs::Pc, test_one_input_ptr)?; + qemu.write_reg(Regs::Sp, stack_ptr)?; + qemu.write_return_address(ret_addr)?; + qemu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?; + qemu.write_function_argument(CallingConvention::Cdecl, 1, len)?; - match qemu.run() { - Ok(QemuExitReason::Breakpoint(_)) => {} - Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(Signal::SigInterrupt))) => { - process::exit(0) + match qemu.run() { + Ok(QemuExitReason::Breakpoint(_)) => {} + Ok(QemuExitReason::End(QemuShutdownCause::HostSignal( + Signal::SigInterrupt, + ))) => process::exit(0), + _ => panic!("Unexpected QEMU exit."), } - _ => panic!("Unexpected QEMU exit."), - } - - Ok(()) - } - }; - let mut harness = - |_emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| { - let target = input.target_bytes(); - let mut buf = target.as_slice(); - let mut len = buf.len(); - if len > MAX_INPUT_SIZE { - buf = &buf[0..MAX_INPUT_SIZE]; - len = MAX_INPUT_SIZE; + Ok(()) } - let len = len as GuestReg; - reset(buf, len).unwrap(); - ExitKind::Ok }; - let mut run_client = |state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _>, - client_description: ClientDescription| { + let mut harness = + |_emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| { + let target = input.target_bytes(); + let mut buf = target.as_slice(); + let mut len = buf.len(); + if len > MAX_INPUT_SIZE { + buf = &buf[0..MAX_INPUT_SIZE]; + len = MAX_INPUT_SIZE; + } + let len = len as GuestReg; + reset(buf, len).unwrap(); + ExitKind::Ok + }; + let core_id = client_description.core_id(); let core_idx = options .cores @@ -232,23 +245,11 @@ pub fn fuzz() { let scheduler = QueueScheduler::new(); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - let mut cov_path = options.coverage_path.clone(); let coverage_name = cov_path.file_stem().unwrap().to_str().unwrap(); let coverage_extension = cov_path.extension().unwrap_or_default().to_str().unwrap(); let core = core_id.0; cov_path.set_file_name(format!("{coverage_name}-{core:03}.{coverage_extension}")); - let emulator_modules = tuple_list!(DrCovModule::builder() - .filter(StdAddressFilter::default()) - .filename(cov_path) - .full_trace(false) - .build()); - - let emulator = Emulator::empty() - .qemu(qemu) - .modules(emulator_modules) - .build()?; - let mut executor = QemuExecutor::new( emulator, &mut harness, diff --git a/fuzzers/binary_only/qemu_launcher/src/client.rs b/fuzzers/binary_only/qemu_launcher/src/client.rs index 1016788ae6..3ab3fdfb97 100644 --- a/fuzzers/binary_only/qemu_launcher/src/client.rs +++ b/fuzzers/binary_only/qemu_launcher/src/client.rs @@ -11,14 +11,8 @@ use libafl::{ use libafl_bolts::{rands::StdRand, tuples::tuple_list}; #[cfg(feature = "injections")] use libafl_qemu::modules::injections::InjectionModule; -use libafl_qemu::{ - modules::{ - asan::{init_qemu_with_asan, AsanModule}, - asan_guest::{init_qemu_with_asan_guest, AsanGuestModule}, - cmplog::CmpLogModule, - DrCovModule, - }, - Qemu, +use libafl_qemu::modules::{ + asan::AsanModule, asan_guest::AsanGuestModule, cmplog::CmpLogModule, DrCovModule, }; use crate::{ @@ -80,18 +74,6 @@ impl Client<'_> { Err(Error::empty_optional("Multiple ASAN modes configured"))?; } - let (qemu, mut asan, mut asan_lib) = { - if is_asan { - let (emu, asan) = init_qemu_with_asan(&mut args, &mut env)?; - (emu, Some(asan), None) - } else if is_asan_guest { - let (emu, asan_lib) = init_qemu_with_asan_guest(&mut args, &mut env)?; - (emu, None, Some(asan_lib)) - } else { - (Qemu::init(&args)?, None, None) - } - }; - #[cfg(not(feature = "injections"))] let injection_module = None; @@ -111,8 +93,6 @@ impl Client<'_> { } }); - let harness = Harness::init(qemu).expect("Error setting up harness."); - let is_cmplog = self.options.is_cmplog_core(core_id); let extra_tokens = injection_module @@ -122,8 +102,6 @@ impl Client<'_> { let instance_builder = Instance::builder() .options(self.options) - .qemu(qemu) - .harness(harness) .mgr(mgr) .client_description(client_description) .extra_tokens(extra_tokens); @@ -136,77 +114,79 @@ impl Client<'_> { .filename(drcov.clone()) .full_trace(true) .build(); - instance_builder.build().run(tuple_list!(drcov), state) + instance_builder + .build() + .run(args, tuple_list!(drcov), state) } else if is_asan && is_cmplog { if let Some(injection_module) = injection_module { instance_builder.build().run( + args, tuple_list!( CmpLogModule::default(), - AsanModule::default(asan.take().unwrap()), + AsanModule::default(&env), injection_module, ), state, ) } else { instance_builder.build().run( - tuple_list!( - CmpLogModule::default(), - AsanModule::default(asan.take().unwrap()), - ), + args, + tuple_list!(CmpLogModule::default(), AsanModule::default(&env),), state, ) } } else if is_asan_guest && is_cmplog { if let Some(injection_module) = injection_module { instance_builder.build().run( + args, tuple_list!( CmpLogModule::default(), - AsanGuestModule::default(qemu, &asan_lib.take().unwrap()), + AsanGuestModule::default(&env), injection_module ), state, ) } else { instance_builder.build().run( - tuple_list!( - CmpLogModule::default(), - AsanGuestModule::default(qemu, &asan_lib.take().unwrap()), - ), + args, + tuple_list!(CmpLogModule::default(), AsanGuestModule::default(&env),), state, ) } } else if is_asan { if let Some(injection_module) = injection_module { instance_builder.build().run( - tuple_list!(AsanModule::default(asan.take().unwrap()), injection_module), + args, + tuple_list!(AsanModule::default(&env), injection_module), state, ) } else { - instance_builder.build().run( - tuple_list!(AsanModule::default(asan.take().unwrap()),), - state, - ) + instance_builder + .build() + .run(args, tuple_list!(AsanModule::default(&env),), state) } } else if is_asan_guest { - let modules = tuple_list!(AsanGuestModule::default(qemu, &asan_lib.take().unwrap())); - instance_builder.build().run(modules, state) + instance_builder + .build() + .run(args, tuple_list!(AsanGuestModule::default(&env)), state) } else if is_cmplog { if let Some(injection_module) = injection_module { instance_builder.build().run( + args, tuple_list!(CmpLogModule::default(), injection_module), state, ) } else { instance_builder .build() - .run(tuple_list!(CmpLogModule::default()), state) + .run(args, tuple_list!(CmpLogModule::default()), state) } } else if let Some(injection_module) = injection_module { instance_builder .build() - .run(tuple_list!(injection_module), state) + .run(args, tuple_list!(injection_module), state) } else { - instance_builder.build().run(tuple_list!(), state) + instance_builder.build().run(args, tuple_list!(), state) } } } diff --git a/fuzzers/binary_only/qemu_launcher/src/instance.rs b/fuzzers/binary_only/qemu_launcher/src/instance.rs index 0bcebdbb96..a08d73d7fa 100644 --- a/fuzzers/binary_only/qemu_launcher/src/instance.rs +++ b/fuzzers/binary_only/qemu_launcher/src/instance.rs @@ -34,12 +34,13 @@ use libafl_bolts::shmem::StdShMemProvider; use libafl_bolts::{ ownedref::OwnedMutSlice, rands::StdRand, - tuples::{tuple_list, Merge, Prepend}, + tuples::{tuple_list, MatchFirstType, Merge, Prepend}, }; use libafl_qemu::{ elf::EasyElf, modules::{ - cmplog::CmpLogObserver, EmulatorModuleTuple, StdAddressFilter, StdEdgeCoverageModule, + cmplog::CmpLogObserver, edges::EdgeCoverageFullVariant, EdgeCoverageModule, EmulatorModule, + EmulatorModuleTuple, NopPageFilter, StdAddressFilter, StdEdgeCoverageModule, }, Emulator, GuestAddr, Qemu, QemuExecutor, }; @@ -61,9 +62,6 @@ pub type ClientMgr = pub struct Instance<'a, M: Monitor> { options: &'a FuzzerOptions, /// The harness. We create it before forking, then `take()` it inside the client. - #[builder(setter(strip_option))] - harness: Option, - qemu: Qemu, mgr: ClientMgr, client_description: ClientDescription, #[builder(default)] @@ -106,7 +104,12 @@ impl Instance<'_, M> { } #[expect(clippy::too_many_lines)] - pub fn run(&mut self, modules: ET, state: Option) -> Result<(), Error> + pub fn run( + &mut self, + args: Vec, + modules: ET, + state: Option, + ) -> Result<(), Error> where ET: EmulatorModuleTuple + Debug, { @@ -122,10 +125,21 @@ impl Instance<'_, M> { let edge_coverage_module = StdEdgeCoverageModule::builder() .map_observer(edges_observer.as_mut()) - .address_filter(self.coverage_filter(self.qemu)?) .build()?; let modules = modules.prepend(edge_coverage_module); + let mut emulator = Emulator::empty() + .qemu_parameters(args) + .modules(modules) + .build()?; + let harness = Harness::init(emulator.qemu()).expect("Error setting up harness."); + let qemu = emulator.qemu(); + + // update address filter after qemu has been initialized + as EmulatorModule>::update_address_filter(emulator.modules_mut() + .modules_mut() + .match_first_type_mut::>() + .expect("Could not find back the edge module"), qemu, self.coverage_filter(qemu)?); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -198,10 +212,6 @@ impl Instance<'_, M> { state.add_metadata(tokens); - let harness = self - .harness - .take() - .expect("The harness can never be None here!"); harness.post_fork(); let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>, @@ -211,8 +221,6 @@ impl Instance<'_, M> { // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - let emulator = Emulator::empty().qemu(self.qemu).modules(modules).build()?; - if let Some(rerun_input) = &self.options.rerun_input { // TODO: We might want to support non-bytes inputs at some point? let bytes = fs::read(rerun_input) diff --git a/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs b/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs index d6a91bd267..6248078597 100644 --- a/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs +++ b/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs @@ -107,14 +107,13 @@ pub fn fuzz() { // Initialize QEMU Emulator let emu = Emulator::builder() - .qemu_cli(args) - .add_module( + .qemu_parameters(args) + .prepend_module( StdEdgeCoverageModule::builder() .map_observer(edges_observer.as_mut()) .build()?, ) - .build() - .unwrap(); + .build()?; // Set breakpoints of interest with corresponding commands. emu.add_breakpoint( diff --git a/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs b/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs index aefd60af13..72fac07d83 100644 --- a/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs +++ b/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs @@ -29,9 +29,9 @@ use libafl_bolts::{ AsSlice, }; use libafl_qemu::{ - config, elf::EasyElf, executor::QemuExecutor, modules::edges::StdEdgeCoverageModuleBuilder, - Emulator, GuestPhysAddr, Qemu, QemuExitError, QemuExitReason, QemuRWError, QemuShutdownCause, - Regs, + config, config::QemuConfig, elf::EasyElf, executor::QemuExecutor, + modules::edges::StdEdgeCoverageModuleBuilder, Emulator, GuestPhysAddr, QemuExitError, + QemuExitReason, QemuRWError, QemuShutdownCause, Regs, }; use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND}; @@ -93,8 +93,8 @@ pub fn fuzz() { .track_indices() }; - // Initialize QEMU - let qemu = Qemu::builder() + // Create QEMU configuration + let qemu_config = QemuConfig::builder() .machine("mps2-an385") .monitor(config::Monitor::Null) .kernel(format!("{target_dir}/example.elf")) @@ -107,18 +107,19 @@ pub fn fuzz() { .file(format!("{target_dir}/dummy.qcow2")) .build()]) .start_cpu(false) - .build() - .expect("Failed to initialized QEMU"); + .build(); let emulator_modules = tuple_list!(StdEdgeCoverageModuleBuilder::default() .map_observer(edges_observer.as_mut()) .build()?); let emulator = Emulator::empty() - .qemu(qemu) + .qemu_parameters(qemu_config) .modules(emulator_modules) .build()?; + let qemu = emulator.qemu(); + qemu.set_breakpoint(main_addr); unsafe { diff --git a/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs b/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs index fe6bc314f4..dd691305ec 100644 --- a/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs +++ b/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs @@ -63,7 +63,7 @@ pub fn fuzz() { .build()?); let emu = Emulator::builder() - .qemu_cli(args) + .qemu_parameters(args) .modules(modules) .build()?; diff --git a/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs b/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs index bb33be5f5f..0587202bae 100644 --- a/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs +++ b/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs @@ -67,14 +67,9 @@ pub fn fuzz() { CmpLogModule::default(), ); - // let driver = StdEmulatorDriver::builder() - // .print_commands(true) - // .build(); - let emu = Emulator::builder() - .qemu_cli(args) + .qemu_parameters(args) .modules(modules) - // .driver(driver) .build()?; let devices = emu.list_devices(); diff --git a/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs b/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs index ec8cf7beed..cd0b7defc1 100644 --- a/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs +++ b/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs @@ -70,7 +70,7 @@ pub fn fuzz() { ); let emu = Emulator::builder() - .qemu_cli(args) + .qemu_parameters(args) .modules(modules) .build()?; diff --git a/libafl/src/executors/command.rs b/libafl/src/executors/command.rs index 375af104e6..2749d6aef2 100644 --- a/libafl/src/executors/command.rs +++ b/libafl/src/executors/command.rs @@ -5,7 +5,7 @@ use core::{ marker::PhantomData, ops::IndexMut, }; -#[cfg(target_os = "linux")] +#[cfg(all(feature = "intel_pt", target_os = "linux"))] use std::{ ffi::{CStr, CString}, os::fd::AsRawFd, @@ -19,14 +19,14 @@ use std::{ time::Duration, }; -#[cfg(target_os = "linux")] +#[cfg(all(feature = "intel_pt", target_os = "linux"))] use libafl_bolts::core_affinity::CoreId; use libafl_bolts::{ fs::{get_unique_std_input_file, InputFile}, tuples::{Handle, MatchName, RefIndexable}, AsSlice, }; -#[cfg(target_os = "linux")] +#[cfg(all(feature = "intel_pt", target_os = "linux"))] use libc::STDIN_FILENO; #[cfg(target_os = "linux")] use nix::{ @@ -42,7 +42,7 @@ use nix::{ }, unistd::Pid, }; -#[cfg(target_os = "linux")] +#[cfg(all(feature = "intel_pt", target_os = "linux"))] use typed_builder::TypedBuilder; use super::HasTimeout; @@ -181,7 +181,7 @@ where /// /// This configurator was primarly developed to be used in conjunction with /// [`crate::executors::hooks::intel_pt::IntelPTHook`] -#[cfg(target_os = "linux")] +#[cfg(all(feature = "intel_pt", target_os = "linux"))] #[derive(Debug, Clone, PartialEq, Eq, TypedBuilder)] pub struct PTraceCommandConfigurator { #[builder(setter(into))] @@ -198,7 +198,7 @@ pub struct PTraceCommandConfigurator { timeout: u32, } -#[cfg(target_os = "linux")] +#[cfg(all(feature = "intel_pt", target_os = "linux"))] impl CommandConfigurator for PTraceCommandConfigurator where I: HasTargetBytes, diff --git a/libafl/src/feedbacks/value_bloom.rs b/libafl/src/feedbacks/value_bloom.rs index 031b603dee..afa7e0646e 100644 --- a/libafl/src/feedbacks/value_bloom.rs +++ b/libafl/src/feedbacks/value_bloom.rs @@ -1,8 +1,8 @@ //! The [`ValueBloomFeedback`] checks if a value has already been observed in a [`BloomFilter`] and returns `true` if the value is new, adding it to the bloom filter. //! +use alloc::borrow::Cow; use core::hash::Hash; -use std::borrow::Cow; use fastbloom::BloomFilter; use libafl_bolts::{ diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index acb81782c0..3ca29cefbc 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -42,10 +42,10 @@ where + UsesInput::Input>, EM: UsesState, //delete me { - #[expect(rustdoc::broken_intra_doc_links)] /// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your /// own stage and you need to manage [`super::NestedStageRetryCountRestartHelper`] differently /// see [`super::ConcolicTracingStage`]'s implementation as an example of usage. + #[allow(rustdoc::broken_intra_doc_links)] pub fn trace(&mut self, fuzzer: &mut Z, state: &mut S, manager: &mut EM) -> Result<(), Error> { start_timer!(state); let input = state.current_input_cloned()?; diff --git a/libafl_qemu/Cargo.toml b/libafl_qemu/Cargo.toml index d107dc4d0b..28287ea12c 100644 --- a/libafl_qemu/Cargo.toml +++ b/libafl_qemu/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "libafl_qemu" version.workspace = true -authors = ["Andrea Fioraldi "] +authors = [ + "Andrea Fioraldi ", + "Romain Malmain ", +] description = "QEMU user backend library for LibAFL" documentation = "https://docs.rs/libafl_qemu" repository = "https://github.com/AFLplusplus/LibAFL/" diff --git a/libafl_qemu/libafl_qemu_build/Cargo.toml b/libafl_qemu/libafl_qemu_build/Cargo.toml index 7dbca22934..8b6c31b074 100644 --- a/libafl_qemu/libafl_qemu_build/Cargo.toml +++ b/libafl_qemu/libafl_qemu_build/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "libafl_qemu_build" version.workspace = true -authors = ["Andrea Fioraldi "] +authors = [ + "Andrea Fioraldi ", + "Romain Malmain ", +] description = "Builder for LibAFL QEMU" documentation = "https://docs.rs/libafl_qemu_build" repository = "https://github.com/AFLplusplus/LibAFL/" diff --git a/libafl_qemu/libafl_qemu_sys/Cargo.toml b/libafl_qemu/libafl_qemu_sys/Cargo.toml index 0ad98885bd..b5730812d8 100644 --- a/libafl_qemu/libafl_qemu_sys/Cargo.toml +++ b/libafl_qemu/libafl_qemu_sys/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "libafl_qemu_sys" version.workspace = true -authors = ["Andrea Fioraldi "] +authors = [ + "Andrea Fioraldi ", + "Romain Malmain ", +] description = "C to Rust bindings for the LibAFL QEMU bridge" documentation = "https://docs.rs/libafl_qemu_sys" repository = "https://github.com/AFLplusplus/LibAFL/" diff --git a/libafl_qemu/src/command/mod.rs b/libafl_qemu/src/command/mod.rs index f107171a19..25e64f5329 100644 --- a/libafl_qemu/src/command/mod.rs +++ b/libafl_qemu/src/command/mod.rs @@ -452,8 +452,8 @@ where // Unleash hooks if locked if emu.driver_mut().unlock_hooks() { // Prepare hooks - emu.modules_mut().first_exec_all(state); - emu.modules_mut().pre_exec_all(state, input); + emu.modules_mut().first_exec_all(qemu, state); + emu.modules_mut().pre_exec_all(qemu, state, input); } // Auto page filtering if option is enabled diff --git a/libafl_qemu/src/emu/builder.rs b/libafl_qemu/src/emu/builder.rs index 6adb97c12a..c82b6013f5 100644 --- a/libafl_qemu/src/emu/builder.rs +++ b/libafl_qemu/src/emu/builder.rs @@ -1,30 +1,33 @@ -use std::{fmt::Debug, marker::PhantomData}; +use std::marker::PhantomData; use libafl::{ inputs::{HasTargetBytes, UsesInput}, state::{HasExecutions, State}, }; -use libafl_bolts::tuples::{tuple_list, Prepend}; +use libafl_bolts::tuples::{tuple_list, Append, Prepend}; #[cfg(feature = "systemmode")] use crate::FastSnapshotManager; use crate::{ command::{CommandManager, NopCommandManager, StdCommandManager}, - config::QemuConfig, + config::QemuConfigBuilder, modules::{EmulatorModule, EmulatorModuleTuple}, - Emulator, EmulatorHooks, NopEmulatorDriver, NopSnapshotManager, Qemu, QemuHooks, QemuInitError, - StdEmulatorDriver, StdSnapshotManager, + Emulator, NopEmulatorDriver, NopSnapshotManager, QemuInitError, QemuParams, StdEmulatorDriver, + StdSnapshotManager, }; +#[cfg(doc)] +use crate::{config::QemuConfig, Qemu}; -#[derive(Clone, Debug)] -enum QemuBuilder { - Qemu(Qemu), - QemuConfig(QemuConfig), - QemuString(Vec), -} - -#[derive(Clone, Debug)] -pub struct EmulatorBuilder +/// An [`Emulator`] Builder. +/// +/// It is the most common way to create a new [`Emulator`]. +/// In addition to the main components of an [`Emulator`], it expects to receive a way to initialize [`Qemu`]. +/// It must be set through [`EmulatorBuilder::qemu_parameters`]. +/// At the moment, there are two main ways to initialize QEMU: +/// - with a QEMU-compatible CLI. It will be given to QEMU as-is. The first argument should always be a path to the running binary, as expected by execve. +/// - with an instance of [`QemuConfig`]. It is a more programmatic way to configure [`Qemu`]. It should be built using [`QemuConfigBuilder`]. +#[derive(Clone)] +pub struct EmulatorBuilder where S: UsesInput, { @@ -32,11 +35,19 @@ where driver: ED, snapshot_manager: SM, command_manager: CM, - qemu_builder: Option, + qemu_parameters: Option, phantom: PhantomData, } -impl EmulatorBuilder +impl + EmulatorBuilder< + NopCommandManager, + NopEmulatorDriver, + (), + QemuConfigBuilder, + S, + NopSnapshotManager, + > where S: UsesInput, { @@ -47,14 +58,22 @@ where driver: NopEmulatorDriver, snapshot_manager: NopSnapshotManager, command_manager: NopCommandManager, - qemu_builder: None, + qemu_parameters: None, phantom: PhantomData, } } } #[cfg(feature = "usermode")] -impl EmulatorBuilder, StdEmulatorDriver, (), S, StdSnapshotManager> +impl + EmulatorBuilder< + StdCommandManager, + StdEmulatorDriver, + (), + QemuConfigBuilder, + S, + StdSnapshotManager, + > where S: State + HasExecutions + Unpin, S::Input: HasTargetBytes, @@ -67,14 +86,22 @@ where command_manager: StdCommandManager::default(), snapshot_manager: StdSnapshotManager::default(), driver: StdEmulatorDriver::builder().build(), - qemu_builder: None, + qemu_parameters: None, phantom: PhantomData, } } } #[cfg(feature = "systemmode")] -impl EmulatorBuilder, StdEmulatorDriver, (), S, StdSnapshotManager> +impl + EmulatorBuilder< + StdCommandManager, + StdEmulatorDriver, + (), + QemuConfigBuilder, + S, + StdSnapshotManager, + > where S: State + HasExecutions + Unpin, S::Input: HasTargetBytes, @@ -87,12 +114,12 @@ where command_manager: StdCommandManager::default(), snapshot_manager: FastSnapshotManager::default(), driver: StdEmulatorDriver::builder().build(), - qemu_builder: None, + qemu_parameters: None, phantom: PhantomData, } } } -impl EmulatorBuilder +impl EmulatorBuilder where S: UsesInput + Unpin, { @@ -101,114 +128,104 @@ where driver: ED, command_manager: CM, snapshot_manager: SM, - qemu_builder: Option, + qemu_parameters: Option, ) -> Self { Self { modules, command_manager, driver, snapshot_manager, - qemu_builder, + qemu_parameters, phantom: PhantomData, } } - pub fn build(self) -> Result, QemuInitError> + pub fn build(self) -> Result, QemuInitError> where CM: CommandManager, ET: EmulatorModuleTuple, + QP: TryInto, + QemuInitError: From, { - let qemu_builder = self.qemu_builder.ok_or(QemuInitError::EmptyArgs)?; - - let mut emulator_hooks = unsafe { EmulatorHooks::new(QemuHooks::get_unchecked()) }; - - self.modules.pre_qemu_init_all(&mut emulator_hooks); + let qemu_params: QemuParams = self + .qemu_parameters + .ok_or(QemuInitError::NoParametersProvided)? + .try_into()?; - let qemu: Qemu = match qemu_builder { - QemuBuilder::Qemu(qemu) => qemu, - QemuBuilder::QemuConfig(qemu_config) => { - let res: Result = qemu_config.into(); - res? - } - QemuBuilder::QemuString(qemu_string) => Qemu::init(&qemu_string)?, - }; - - unsafe { - Ok(Emulator::new_with_qemu( - qemu, - emulator_hooks, - self.modules, - self.driver, - self.snapshot_manager, - self.command_manager, - )) - } + Emulator::new( + qemu_params, + self.modules, + self.driver, + self.snapshot_manager, + self.command_manager, + ) } } -impl EmulatorBuilder +impl EmulatorBuilder where CM: CommandManager, S: UsesInput + Unpin, { #[must_use] - pub fn qemu_config(self, qemu_config: QemuConfig) -> EmulatorBuilder { - EmulatorBuilder::new( - self.modules, - self.driver, - self.command_manager, - self.snapshot_manager, - Some(QemuBuilder::QemuConfig(qemu_config)), - ) - } - - #[must_use] - pub fn qemu_cli(self, qemu_cli: Vec) -> EmulatorBuilder { + pub fn qemu_parameters( + self, + qemu_parameters: QP2, + ) -> EmulatorBuilder + where + QP2: Into, + { EmulatorBuilder::new( self.modules, self.driver, self.command_manager, self.snapshot_manager, - Some(QemuBuilder::QemuString(qemu_cli)), + Some(qemu_parameters), ) } - #[must_use] - pub fn qemu(self, qemu: Qemu) -> EmulatorBuilder { + pub fn prepend_module(self, module: EM) -> EmulatorBuilder + where + EM: EmulatorModule + Unpin, + ET: EmulatorModuleTuple, + { EmulatorBuilder::new( - self.modules, + self.modules.prepend(module), self.driver, self.command_manager, self.snapshot_manager, - Some(QemuBuilder::Qemu(qemu)), + self.qemu_parameters, ) } - pub fn add_module(self, module: EM) -> EmulatorBuilder + pub fn append_module(self, module: EM) -> EmulatorBuilder where EM: EmulatorModule + Unpin, ET: EmulatorModuleTuple, { EmulatorBuilder::new( - self.modules.prepend(module), + self.modules.append(module), self.driver, self.command_manager, self.snapshot_manager, - self.qemu_builder, + self.qemu_parameters, ) } - pub fn driver(self, driver: ED2) -> EmulatorBuilder { + pub fn driver(self, driver: ED2) -> EmulatorBuilder { EmulatorBuilder::new( self.modules, driver, self.command_manager, self.snapshot_manager, - self.qemu_builder, + self.qemu_parameters, ) } - pub fn command_manager(self, command_manager: CM2) -> EmulatorBuilder + pub fn command_manager( + self, + command_manager: CM2, + ) -> EmulatorBuilder where CM2: CommandManager, { @@ -217,30 +234,30 @@ where self.driver, command_manager, self.snapshot_manager, - self.qemu_builder, + self.qemu_parameters, ) } - pub fn modules(self, modules: ET2) -> EmulatorBuilder { + pub fn modules(self, modules: ET2) -> EmulatorBuilder { EmulatorBuilder::new( modules, self.driver, self.command_manager, self.snapshot_manager, - self.qemu_builder, + self.qemu_parameters, ) } pub fn snapshot_manager( self, snapshot_manager: SM2, - ) -> EmulatorBuilder { + ) -> EmulatorBuilder { EmulatorBuilder::new( self.modules, self.driver, self.command_manager, snapshot_manager, - self.qemu_builder, + self.qemu_parameters, ) } } diff --git a/libafl_qemu/src/emu/drivers.rs b/libafl_qemu/src/emu/drivers.rs index 41ccda5e50..2a9d0ff4be 100644 --- a/libafl_qemu/src/emu/drivers.rs +++ b/libafl_qemu/src/emu/drivers.rs @@ -54,7 +54,7 @@ where /// Just before calling user's harness for the first time. /// Called only once fn first_harness_exec(emulator: &mut Emulator, state: &mut S) { - emulator.modules.first_exec_all(state); + emulator.modules.first_exec_all(emulator.qemu, state); } /// Just before calling user's harness @@ -63,7 +63,7 @@ where state: &mut S, input: &S::Input, ) { - emulator.modules.pre_exec_all(state, input); + emulator.modules.pre_exec_all(emulator.qemu, state, input); } /// Just after returning from user's harness @@ -78,7 +78,7 @@ where { emulator .modules - .post_exec_all(state, input, observers, exit_kind); + .post_exec_all(emulator.qemu, state, input, observers, exit_kind); } /// Just before entering QEMU @@ -169,7 +169,7 @@ where { fn first_harness_exec(emulator: &mut Emulator, state: &mut S) { if !emulator.driver.hooks_locked { - emulator.modules.first_exec_all(state); + emulator.modules.first_exec_all(emulator.qemu, state); } } @@ -179,7 +179,7 @@ where input: &S::Input, ) { if !emulator.driver.hooks_locked { - emulator.modules.pre_exec_all(state, input); + emulator.modules.pre_exec_all(emulator.qemu, state, input); } let input_location = { emulator.driver.input_location.get().cloned() }; @@ -206,7 +206,7 @@ where if !emulator.driver.hooks_locked { emulator .modules - .post_exec_all(state, input, observers, exit_kind); + .post_exec_all(emulator.qemu, state, input, observers, exit_kind); } } diff --git a/libafl_qemu/src/emu/hooks.rs b/libafl_qemu/src/emu/hooks.rs index 53a6dc3350..7a2993212d 100644 --- a/libafl_qemu/src/emu/hooks.rs +++ b/libafl_qemu/src/emu/hooks.rs @@ -3,13 +3,13 @@ use std::{fmt::Debug, marker::PhantomData, mem::transmute, pin::Pin, ptr}; use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple}; -use libafl_qemu_sys::{CPUArchStatePtr, CPUStatePtr, FatPtr, GuestAddr, GuestUsize, TCGTemp}; +use libafl_qemu_sys::{CPUStatePtr, FatPtr, GuestAddr, GuestUsize, TCGTemp}; #[cfg(feature = "usermode")] use crate::qemu::{ closure_post_syscall_hook_wrapper, closure_pre_syscall_hook_wrapper, func_post_syscall_hook_wrapper, func_pre_syscall_hook_wrapper, PostSyscallHook, - PostSyscallHookId, PreSyscallHook, PreSyscallHookId, SyscallHookResult, + PostSyscallHookId, PreSyscallHook, PreSyscallHookId, }; #[cfg(feature = "usermode")] use crate::qemu::{ @@ -37,9 +37,15 @@ use crate::{ ReadExecNHook, ReadGenHook, ReadHookId, TcgHookState, WriteExecHook, WriteExecNHook, WriteGenHook, WriteHookId, }, - CpuPostRunHook, CpuPreRunHook, CpuRunHookId, HookState, MemAccessInfo, Qemu, + CpuPostRunHook, CpuPreRunHook, CpuRunHookId, HookState, MemAccessInfo, NewThreadHookFn, Qemu, }; +/// Get a C-compatible function pointer from the input hook. +/// If the hook was already a c function, nothing is done. +/// +/// h: input hook +/// replacement: C-compatible function to call when C side should call the hook +/// fntype: type used to cast h into replacement macro_rules! get_raw_hook { ($h:expr, $replacement:expr, $fntype:ty) => { match $h { @@ -74,6 +80,7 @@ where { unsafe { let emulator_modules = EmulatorModules::::emulator_modules_mut().unwrap(); + let qemu = Qemu::get_unchecked(); let crash_hooks_ptr = &raw mut emulator_modules.hooks.crash_hooks; @@ -81,12 +88,12 @@ where match crash_hook { HookRepr::Function(ptr) => { let func: CrashHookFn = transmute(*ptr); - func(emulator_modules, target_sig); + func(qemu, emulator_modules, target_sig); } HookRepr::Closure(ptr) => { let func: &mut CrashHookClosure = &mut *(ptr::from_mut::(ptr) as *mut CrashHookClosure); - func(emulator_modules, target_sig); + func(qemu, emulator_modules, target_sig); } HookRepr::Empty => (), } @@ -100,7 +107,6 @@ pub struct EmulatorModules where S: UsesInput, { - qemu: Qemu, modules: Pin>, hooks: EmulatorHooks, phantom: PhantomData, @@ -170,6 +176,11 @@ where } } + #[must_use] + pub fn qemu_hooks(&self) -> QemuHooks { + self.qemu_hooks + } + pub fn instruction_closure( &mut self, addr: GuestAddr, @@ -679,10 +690,7 @@ where } } - pub fn backdoor_function( - &self, - hook: fn(&mut EmulatorModules, Option<&mut S>, cpu: CPUArchStatePtr, pc: GuestAddr), - ) -> BackdoorHookId { + pub fn backdoor_function(&self, hook: BackdoorHookFn) -> BackdoorHookId { unsafe { self.qemu_hooks .add_backdoor_hook(transmute(hook), func_backdoor_hook_wrapper::) @@ -715,15 +723,7 @@ where } } - pub fn thread_creation_function( - &mut self, - hook: fn( - &mut EmulatorModules, - Option<&mut S>, - env: CPUArchStatePtr, - tid: u32, - ) -> bool, - ) -> NewThreadHookId { + pub fn thread_creation_function(&mut self, hook: NewThreadHookFn) -> NewThreadHookId { unsafe { self.qemu_hooks .add_new_thread_hook(transmute(hook), func_new_thread_hook_wrapper::) @@ -767,10 +767,10 @@ where ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - pub fn syscalls(&mut self, hook: PreSyscallHook) -> Option { + pub fn pre_syscalls(&mut self, hook: PreSyscallHook) -> Option { match hook { - Hook::Function(f) => Some(self.syscalls_function(f)), - Hook::Closure(c) => Some(self.syscalls_closure(c)), + Hook::Function(f) => Some(self.pre_syscalls_function(f)), + Hook::Closure(c) => Some(self.pre_syscalls_closure(c)), Hook::Raw(r) => { let z: *const () = ptr::null::<()>(); Some(self.qemu_hooks.add_pre_syscall_hook(z, r)) @@ -779,7 +779,7 @@ where } } - pub fn syscalls_function(&mut self, hook: PreSyscallHookFn) -> PreSyscallHookId { + pub fn pre_syscalls_function(&mut self, hook: PreSyscallHookFn) -> PreSyscallHookId { // # Safety // Will dereference the hook as [`FatPtr`]. unsafe { @@ -788,7 +788,7 @@ where } } - pub fn syscalls_closure(&mut self, hook: PreSyscallHookClosure) -> PreSyscallHookId { + pub fn pre_syscalls_closure(&mut self, hook: PreSyscallHookClosure) -> PreSyscallHookId { // # Safety // Will dereference the hook as [`FatPtr`]. unsafe { @@ -818,10 +818,10 @@ where } } - pub fn after_syscalls(&mut self, hook: PostSyscallHook) -> Option { + pub fn post_syscalls(&mut self, hook: PostSyscallHook) -> Option { match hook { - Hook::Function(f) => Some(self.after_syscalls_function(f)), - Hook::Closure(c) => Some(self.after_syscalls_closure(c)), + Hook::Function(f) => Some(self.post_syscalls_function(f)), + Hook::Closure(c) => Some(self.post_syscalls_closure(c)), Hook::Raw(r) => { let z: *const () = ptr::null::<()>(); Some(self.qemu_hooks.add_post_syscall_hook(z, r)) @@ -830,7 +830,7 @@ where } } - pub fn after_syscalls_function(&mut self, hook: PostSyscallHookFn) -> PostSyscallHookId { + pub fn post_syscalls_function(&mut self, hook: PostSyscallHookFn) -> PostSyscallHookId { // # Safety // Will dereference the hook as [`FatPtr`]. This should be ok. unsafe { @@ -839,7 +839,7 @@ where } } - pub fn after_syscalls_closure( + pub fn post_syscalls_closure( &mut self, hook: PostSyscallHookClosure, ) -> PostSyscallHookId { @@ -870,7 +870,7 @@ where } } - pub fn crash_function(&mut self, hook: fn(&mut EmulatorModules, target_signal: i32)) { + pub fn crash_function(&mut self, hook: CrashHookFn) { // # Safety // Will cast the valid hook to a ptr. self.qemu_hooks.set_crash_hook(crash_hook_wrapper::); @@ -959,7 +959,7 @@ where pub fn instruction_function( &mut self, addr: GuestAddr, - hook: fn(&mut EmulatorModules, Option<&mut S>, GuestAddr), + hook: InstructionHookFn, invalidate_block: bool, ) -> InstructionHookId { self.hooks @@ -1068,15 +1068,7 @@ where self.hooks.thread_creation(hook) } - pub fn thread_creation_function( - &mut self, - hook: fn( - &mut EmulatorModules, - Option<&mut S>, - env: CPUArchStatePtr, - tid: u32, - ) -> bool, - ) -> NewThreadHookId { + pub fn thread_creation_function(&mut self, hook: NewThreadHookFn) -> NewThreadHookId { self.hooks.thread_creation_function(hook) } @@ -1093,13 +1085,8 @@ where ET: EmulatorModuleTuple, S: UsesInput + Unpin, { - pub(super) fn new( - qemu: Qemu, - emulator_hooks: EmulatorHooks, - modules: ET, - ) -> Pin> { + pub(super) fn new(emulator_hooks: EmulatorHooks, modules: ET) -> Pin> { let mut modules = Box::pin(Self { - qemu, modules: Box::pin(modules), hooks: emulator_hooks, phantom: PhantomData, @@ -1122,35 +1109,40 @@ where modules } - pub fn post_qemu_init_all(&mut self) { + pub fn post_qemu_init_all(&mut self, qemu: Qemu) { // We give access to EmulatorModuleTuple during init, the compiler complains (for good reasons) // TODO: We should find a way to be able to check for a module without giving full access to the tuple. unsafe { self.modules_mut() - .post_qemu_init_all(Self::emulator_modules_mut_unchecked()); + .post_qemu_init_all(qemu, Self::emulator_modules_mut_unchecked()); } } - pub fn first_exec_all(&mut self, state: &mut S) { + pub fn first_exec_all(&mut self, qemu: Qemu, state: &mut S) { // # Safety // We assume that the emulator was initialized correctly unsafe { self.modules_mut() - .first_exec_all(Self::emulator_modules_mut_unchecked(), state); + .first_exec_all(qemu, Self::emulator_modules_mut_unchecked(), state); } } - pub fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) { + pub fn pre_exec_all(&mut self, qemu: Qemu, state: &mut S, input: &S::Input) { // # Safety // We assume that the emulator was initialized correctly unsafe { - self.modules_mut() - .pre_exec_all(Self::emulator_modules_mut_unchecked(), state, input); + self.modules_mut().pre_exec_all( + qemu, + Self::emulator_modules_mut_unchecked(), + state, + input, + ); } } pub fn post_exec_all( &mut self, + qemu: Qemu, state: &mut S, input: &S::Input, observers: &mut OT, @@ -1160,6 +1152,7 @@ where { unsafe { self.modules_mut().post_exec_all( + qemu, Self::emulator_modules_mut_unchecked(), state, input, @@ -1191,16 +1184,15 @@ impl EmulatorModules where S: UsesInput, { - #[must_use] - pub fn qemu(&self) -> Qemu { - self.qemu - } - #[must_use] pub fn modules(&self) -> &ET { self.modules.as_ref().get_ref() } + pub fn hooks(&mut self) -> &EmulatorHooks { + &self.hooks + } + pub fn hooks_mut(&mut self) -> &mut EmulatorHooks { &mut self.hooks } @@ -1213,107 +1205,53 @@ where ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - pub fn syscalls(&mut self, hook: PreSyscallHook) -> Option { - self.hooks.syscalls(hook) + pub fn pre_syscalls(&mut self, hook: PreSyscallHook) -> Option { + self.hooks.pre_syscalls(hook) } /// # Safety /// Calls through to the, potentially unsafe, `syscalls_function` - #[expect(clippy::type_complexity)] - pub unsafe fn syscalls_function( + #[allow(clippy::type_complexity)] + pub unsafe fn pre_syscalls_function( &mut self, - hook: fn( - &mut EmulatorModules, - Option<&mut S>, - sys_num: i32, - a0: GuestAddr, - a1: GuestAddr, - a2: GuestAddr, - a3: GuestAddr, - a4: GuestAddr, - a5: GuestAddr, - a6: GuestAddr, - a7: GuestAddr, - ) -> SyscallHookResult, + hook: PreSyscallHookFn, ) -> PreSyscallHookId { - self.hooks.syscalls_function(hook) + self.hooks.pre_syscalls_function(hook) } /// # Safety /// Calls through to the, potentially unsafe, `syscalls_closure` - #[expect(clippy::type_complexity)] - pub unsafe fn syscalls_closure( + #[allow(clippy::type_complexity)] + pub unsafe fn pre_syscalls_closure( &mut self, - hook: Box< - dyn for<'a> FnMut( - &'a mut EmulatorModules, - Option<&'a mut S>, - i32, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - ) -> SyscallHookResult, - >, + hook: PreSyscallHookClosure, ) -> PreSyscallHookId { - self.hooks.syscalls_closure(hook) + self.hooks.pre_syscalls_closure(hook) } - pub fn after_syscalls(&mut self, hook: PostSyscallHook) -> Option { - self.hooks.after_syscalls(hook) + pub fn post_syscalls(&mut self, hook: PostSyscallHook) -> Option { + self.hooks.post_syscalls(hook) } /// # Safety /// Calls through to the, potentially unsafe, `after_syscalls_function` - #[expect(clippy::type_complexity)] - pub unsafe fn after_syscalls_function( + #[allow(clippy::type_complexity)] + pub unsafe fn post_syscalls_function( &mut self, - hook: fn( - &mut EmulatorModules, - Option<&mut S>, - res: GuestAddr, - sys_num: i32, - a0: GuestAddr, - a1: GuestAddr, - a2: GuestAddr, - a3: GuestAddr, - a4: GuestAddr, - a5: GuestAddr, - a6: GuestAddr, - a7: GuestAddr, - ) -> GuestAddr, + hook: PostSyscallHookFn, ) -> PostSyscallHookId { - self.hooks.after_syscalls_function(hook) + self.hooks.post_syscalls_function(hook) } - #[expect(clippy::type_complexity)] - pub fn after_syscalls_closure( + #[allow(clippy::type_complexity)] + pub fn post_syscalls_closure( &mut self, - hook: Box< - dyn for<'a> FnMut( - &'a mut EmulatorModules, - Option<&mut S>, - GuestAddr, - i32, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - GuestAddr, - ) -> GuestAddr, - >, + hook: PostSyscallHookClosure, ) -> PostSyscallHookId { - self.hooks.after_syscalls_closure(hook) + self.hooks.post_syscalls_closure(hook) } - pub fn crash_function(&mut self, hook: fn(&mut EmulatorModules, target_signal: i32)) { + pub fn crash_function(&mut self, hook: CrashHookFn) { self.hooks.crash_function(hook); } diff --git a/libafl_qemu/src/emu/mod.rs b/libafl_qemu/src/emu/mod.rs index 8e05864d96..42820e4ea7 100644 --- a/libafl_qemu/src/emu/mod.rs +++ b/libafl_qemu/src/emu/mod.rs @@ -14,12 +14,14 @@ use libafl::{ }; use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestUsize, GuestVirtAddr}; +#[cfg(doc)] +use crate::modules::EmulatorModule; use crate::{ breakpoint::{Breakpoint, BreakpointId}, command::{CommandError, CommandManager, NopCommandManager, StdCommandManager}, modules::EmulatorModuleTuple, sync_exit::SyncExit, - Qemu, QemuExitError, QemuExitReason, QemuHooks, QemuInitError, QemuMemoryChunk, + Qemu, QemuExitError, QemuExitReason, QemuHooks, QemuInitError, QemuMemoryChunk, QemuParams, QemuShutdownCause, Regs, CPU, }; @@ -45,6 +47,8 @@ mod systemmode; #[cfg(feature = "systemmode")] pub use systemmode::*; +use crate::config::QemuConfigBuilder; + #[derive(Clone, Copy)] pub enum GuestAddrKind { Physical(GuestPhysAddr), @@ -118,6 +122,23 @@ pub struct InputLocation { ret_register: Option, } +/// The high-level interface to [`Qemu`]. +/// +/// It embeds multiple structures aiming at making QEMU usage easier: +/// +/// - An [`IsSnapshotManager`] implementation, implementing the QEMU snapshot method to use. +/// - An [`EmulatorDriver`] implementation, responsible for handling the high-level control flow of QEMU runtime. +/// - A [`CommandManager`] implementation, handling the commands received from the target. +/// - [`EmulatorModules`], containing the [`EmulatorModule`] implementations' state. +/// +/// Each of these fields can be set manually to finely tune how QEMU is getting handled. +/// It is highly encouraged to build [`Emulator`] using the associated [`EmulatorBuilder`]. +/// There are two main functions to access the builder: +/// +/// - [`Emulator::builder`] gives access to the standard [`EmulatorBuilder`], embedding all the standard components of an [`Emulator`]. +/// - [`Emulator::empty`] gives access to an empty [`EmulatorBuilder`]. This is mostly useful to create a more custom [`Emulator`]. +/// +/// Please check the documentation of [`EmulatorBuilder`] for more details. #[derive(Debug)] #[expect(clippy::type_complexity)] pub struct Emulator @@ -243,8 +264,14 @@ where S: UsesInput, { #[must_use] - pub fn empty( - ) -> EmulatorBuilder { + pub fn empty() -> EmulatorBuilder< + NopCommandManager, + NopEmulatorDriver, + (), + QemuConfigBuilder, + S, + NopSnapshotManager, + > { EmulatorBuilder::empty() } } @@ -255,8 +282,14 @@ where S::Input: HasTargetBytes, { #[must_use] - pub fn builder( - ) -> EmulatorBuilder, StdEmulatorDriver, (), S, StdSnapshotManager> { + pub fn builder() -> EmulatorBuilder< + StdCommandManager, + StdEmulatorDriver, + (), + QemuConfigBuilder, + S, + StdSnapshotManager, + > { EmulatorBuilder::default() } } @@ -321,24 +354,36 @@ where ET: EmulatorModuleTuple, S: UsesInput + Unpin, { - pub fn new( - qemu_args: &[String], + #[allow(clippy::must_use_candidate, clippy::similar_names)] + pub fn new( + qemu_params: T, modules: ET, driver: ED, snapshot_manager: SM, command_manager: CM, - ) -> Result { - let mut emulator_hooks = unsafe { EmulatorHooks::new(QemuHooks::get_unchecked()) }; + ) -> Result + where + T: Into, + { + let mut qemu_params = qemu_params.into(); + + let emulator_hooks = unsafe { EmulatorHooks::new(QemuHooks::get_unchecked()) }; + let mut emulator_modules = EmulatorModules::new(emulator_hooks, modules); - modules.pre_qemu_init_all(&mut emulator_hooks); + // TODO: fix things there properly. The biggest issue being that it creates 2 mut ref to the module with the callback being called + unsafe { + emulator_modules.modules_mut().pre_qemu_init_all( + EmulatorModules::::emulator_modules_mut_unchecked(), + &mut qemu_params, + ); + } - let qemu = Qemu::init(qemu_args)?; + let qemu = Qemu::init(qemu_params)?; unsafe { Ok(Self::new_with_qemu( qemu, - emulator_hooks, - modules, + emulator_modules, driver, snapshot_manager, command_manager, @@ -351,17 +396,16 @@ where /// /// # Safety /// - /// pre-init qemu hooks should be run by then. - pub(crate) unsafe fn new_with_qemu( + /// pre-init qemu hooks should be run before calling this. + unsafe fn new_with_qemu( qemu: Qemu, - emulator_hooks: EmulatorHooks, - modules: ET, + emulator_modules: Pin>>, driver: ED, snapshot_manager: SM, command_manager: CM, ) -> Self { let mut emulator = Emulator { - modules: EmulatorModules::new(qemu, emulator_hooks, modules), + modules: emulator_modules, command_manager, snapshot_manager, driver, @@ -370,7 +414,7 @@ where qemu, }; - emulator.modules.post_qemu_init_all(); + emulator.modules.post_qemu_init_all(qemu); emulator } diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 5c1978d720..349644ff4f 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -40,6 +40,8 @@ use libc::siginfo_t; #[cfg(feature = "usermode")] use crate::EmulatorModules; +#[cfg(feature = "usermode")] +use crate::Qemu; use crate::{command::CommandManager, modules::EmulatorModuleTuple, Emulator, EmulatorDriver}; pub struct QemuExecutor<'a, CM, ED, ET, H, OT, S, SM> @@ -183,12 +185,12 @@ where inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler:: as *const c_void; - let handler = |emulator_modules: &mut EmulatorModules, host_sig| { + let handler = |qemu: Qemu, _emulator_modules: &mut EmulatorModules, host_sig| { eprintln!("Crashed with signal {host_sig}"); unsafe { libafl::executors::inprocess::generic_inproc_crash_handler::(); } - if let Some(cpu) = emulator_modules.qemu().current_cpu() { + if let Some(cpu) = qemu.current_cpu() { eprint!("Context:\n{}", cpu.display_context()); } }; diff --git a/libafl_qemu/src/modules/calls.rs b/libafl_qemu/src/modules/calls.rs index 01687ef90f..3817c93243 100644 --- a/libafl_qemu/src/modules/calls.rs +++ b/libafl_qemu/src/modules/calls.rs @@ -243,6 +243,7 @@ where } fn on_ret( + qemu: Qemu, emulator_modules: &mut EmulatorModules, state: Option<&mut S>, pc: GuestAddr, @@ -250,7 +251,7 @@ where S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let ret_addr: GuestAddr = emulator_modules.qemu().read_return_address().unwrap(); + let ret_addr: GuestAddr = qemu.read_return_address().unwrap(); // log::info!("RET @ 0x{:#x}", ret_addr); @@ -271,6 +272,7 @@ where #[allow(clippy::needless_pass_by_value)] // no longer a problem in nightly fn gen_blocks_calls( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -293,8 +295,6 @@ where .unwrap(); } - let qemu = emulator_modules.qemu(); - let mut call_addrs: Vec<(GuestAddr, usize)> = Vec::new(); let mut ret_addrs: Vec = Vec::new(); @@ -363,7 +363,10 @@ where for (call_addr, call_len) in call_addrs { // TODO do not use a closure, find a more efficient way to pass call_len let call_cb = Box::new( - move |emulator_modules: &mut EmulatorModules, state: Option<&mut S>, pc| { + move |_qemu: Qemu, + emulator_modules: &mut EmulatorModules, + state: Option<&mut S>, + pc| { // eprintln!("CALL @ 0x{:#x}", pc + call_len); let mut collectors = if let Some(h) = emulator_modules.get_mut::() { h.collectors.take() @@ -400,7 +403,7 @@ where #[cfg(feature = "systemmode")] type ModulePageFilter = NopPageFilter; - fn post_qemu_init(&self, emulator_modules: &mut EmulatorModules) + fn post_qemu_init(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { @@ -413,21 +416,20 @@ where fn pre_exec( &mut self, - emulator_modules: &mut EmulatorModules, + qemu: Qemu, + _emulator_modules: &mut EmulatorModules, _state: &mut S, input: &S::Input, ) where ET: EmulatorModuleTuple, { - self.collectors - .as_mut() - .unwrap() - .pre_exec_all(emulator_modules.qemu(), input); + self.collectors.as_mut().unwrap().pre_exec_all(qemu, input); } fn post_exec( &mut self, - emulator_modules: &mut EmulatorModules, + qemu: Qemu, + _emulator_modules: &mut EmulatorModules, _state: &mut S, input: &S::Input, observers: &mut OT, @@ -436,12 +438,10 @@ where OT: ObserversTuple, ET: EmulatorModuleTuple, { - self.collectors.as_mut().unwrap().post_exec_all( - emulator_modules.qemu(), - input, - observers, - exit_kind, - ); + self.collectors + .as_mut() + .unwrap() + .post_exec_all(qemu, input, observers, exit_kind); } fn address_filter(&self) -> &Self::ModuleAddressFilter { @@ -553,6 +553,7 @@ pub struct FullBacktraceCollector {} impl FullBacktraceCollector { /// # Safety /// This accesses the global [`CALLSTACKS`] variable and may not be called concurrently. + #[expect(rustdoc::private_intra_doc_links)] pub unsafe fn new() -> Self { let callstacks_ptr = &raw mut CALLSTACKS; unsafe { (*callstacks_ptr) = Some(ThreadLocal::new()) }; diff --git a/libafl_qemu/src/modules/cmplog.rs b/libafl_qemu/src/modules/cmplog.rs index cdc4247510..e30b705f24 100644 --- a/libafl_qemu/src/modules/cmplog.rs +++ b/libafl_qemu/src/modules/cmplog.rs @@ -14,11 +14,12 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "systemmode")] use crate::modules::{NopPageFilter, NOP_PAGE_FILTER}; #[cfg(feature = "usermode")] -use crate::{capstone, qemu::ArchExtras, CallingConvention, Qemu}; +use crate::{capstone, qemu::ArchExtras, CallingConvention}; use crate::{ emu::EmulatorModules, modules::{hash_me, AddressFilter, EmulatorModule, EmulatorModuleTuple, StdAddressFilter}, qemu::Hook, + Qemu, }; #[cfg_attr( @@ -74,8 +75,12 @@ where #[cfg(feature = "systemmode")] type ModulePageFilter = NopPageFilter; - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { emulator_modules.cmps( @@ -139,8 +144,12 @@ where const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { emulator_modules.cmps( @@ -172,6 +181,7 @@ where } pub fn gen_unique_cmp_ids( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, state: Option<&mut S>, pc: GuestAddr, @@ -204,6 +214,7 @@ where #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_hashed_cmp_ids( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -298,6 +309,7 @@ impl CmpLogRoutinesModule { #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn gen_blocks_calls( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -320,8 +332,6 @@ impl CmpLogRoutinesModule { .unwrap(); } - let qemu = emulator_modules.qemu(); - if let Some(h) = emulator_modules.get::() { #[allow(unused_mut)] // cfg dependent let mut code = { @@ -393,8 +403,12 @@ where #[cfg(feature = "systemmode")] type ModulePageFilter = NopPageFilter; - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { emulator_modules.blocks( diff --git a/libafl_qemu/src/modules/drcov.rs b/libafl_qemu/src/modules/drcov.rs index 299cbffbcd..d10f9498ec 100644 --- a/libafl_qemu/src/modules/drcov.rs +++ b/libafl_qemu/src/modules/drcov.rs @@ -13,6 +13,7 @@ use crate::{ emu::EmulatorModules, modules::{AddressFilter, EmulatorModule, EmulatorModuleTuple, NopAddressFilter}, qemu::Hook, + Qemu, }; static DRCOV_IDS: Mutex>> = Mutex::new(None); @@ -264,7 +265,7 @@ where #[cfg(feature = "systemmode")] type ModulePageFilter = NopPageFilter; - fn post_qemu_init(&self, emulator_modules: &mut EmulatorModules) + fn post_qemu_init(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { @@ -276,15 +277,17 @@ where } #[cfg(feature = "usermode")] - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + qemu: Qemu, + _emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { if self.module_mapping.is_none() { log::info!("Auto-filling module mapping for DrCov module from QEMU mapping."); - let qemu = emulator_modules.qemu(); - let mut module_mapping: RangeMap = RangeMap::new(); #[expect(clippy::unnecessary_cast)] // for GuestAddr -> u64 @@ -307,8 +310,12 @@ where } #[cfg(feature = "systemmode")] - fn first_exec(&mut self, _emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + _emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { assert!( @@ -319,6 +326,7 @@ where fn post_exec( &mut self, + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, @@ -359,6 +367,7 @@ where } pub fn gen_unique_block_ids( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, state: Option<&mut S>, pc: GuestAddr, @@ -409,6 +418,7 @@ where #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_block_lengths( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -432,6 +442,7 @@ pub fn gen_block_lengths( #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn exec_trace_block( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, diff --git a/libafl_qemu/src/modules/edges/helpers.rs b/libafl_qemu/src/modules/edges/helpers.rs index c3cadf508c..5dd0712617 100644 --- a/libafl_qemu/src/modules/edges/helpers.rs +++ b/libafl_qemu/src/modules/edges/helpers.rs @@ -60,7 +60,7 @@ mod generators { }; use crate::{ modules::{hash_me, AddressFilter, EdgeCoverageModule, EmulatorModuleTuple, PageFilter}, - EmulatorModules, + EmulatorModules, Qemu, }; fn get_mask() -> usize { @@ -77,7 +77,9 @@ mod generators { } } + #[allow(unused_variables)] pub fn gen_unique_edge_ids( + qemu: Qemu, emulator_modules: &mut EmulatorModules, state: Option<&mut S>, src: GuestAddr, @@ -108,10 +110,7 @@ mod generators { #[cfg(feature = "systemmode")] { - let paging_id = emulator_modules - .qemu() - .current_cpu() - .and_then(|cpu| cpu.current_paging_id()); + let paging_id = qemu.current_cpu().and_then(|cpu| cpu.current_paging_id()); if !module.must_instrument(src, paging_id) && !module.must_instrument(dest, paging_id) @@ -155,8 +154,10 @@ mod generators { } } + #[allow(unused_variables)] #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_hashed_edge_ids( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, src: GuestAddr, @@ -179,10 +180,7 @@ mod generators { #[cfg(feature = "systemmode")] { - let paging_id = emulator_modules - .qemu() - .current_cpu() - .and_then(|cpu| cpu.current_paging_id()); + let paging_id = qemu.current_cpu().and_then(|cpu| cpu.current_paging_id()); if !module.must_instrument(src, paging_id) && !module.must_instrument(dest, paging_id) @@ -210,8 +208,10 @@ mod generators { } #[expect(clippy::unnecessary_cast)] + #[allow(unused_variables)] #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly pub fn gen_hashed_block_ids( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -235,10 +235,7 @@ mod generators { } #[cfg(feature = "systemmode")] { - let page_id = emulator_modules - .qemu() - .current_cpu() - .and_then(|cpu| cpu.current_paging_id()); + let page_id = qemu.current_cpu().and_then(|cpu| cpu.current_paging_id()); if !module.must_instrument(pc, page_id) { return None; diff --git a/libafl_qemu/src/modules/edges/mod.rs b/libafl_qemu/src/modules/edges/mod.rs index 35e4a0fcc9..7ccae4e5e8 100644 --- a/libafl_qemu/src/modules/edges/mod.rs +++ b/libafl_qemu/src/modules/edges/mod.rs @@ -9,6 +9,7 @@ use libafl_qemu_sys::GuestPhysAddr; use crate::{ emu::EmulatorModules, modules::{AddressFilter, EmulatorModule, EmulatorModuleTuple, PageFilter}, + Qemu, }; mod helpers; @@ -327,8 +328,12 @@ where type ModulePageFilter = PF; const HOOKS_DO_SIDE_EFFECTS: bool = V::DO_SIDE_EFFECTS; - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { if self.use_hitcounts { diff --git a/libafl_qemu/src/modules/mod.rs b/libafl_qemu/src/modules/mod.rs index b2fc689d79..83b32f39c2 100644 --- a/libafl_qemu/src/modules/mod.rs +++ b/libafl_qemu/src/modules/mod.rs @@ -40,7 +40,7 @@ pub mod drcov; #[cfg(not(cpu_target = "hexagon"))] pub use drcov::{DrCovMetadata, DrCovModule, DrCovModuleBuilder}; -use crate::{emu::EmulatorModules, EmulatorHooks, Qemu}; +use crate::{emu::EmulatorModules, Qemu, QemuParams}; /// A module for `libafl_qemu`. // TODO remove 'static when specialization will be stable @@ -58,8 +58,14 @@ where /// Hook run **before** QEMU is initialized. /// This is always run when Emulator gets initialized, in any case. /// Install here hooks that should be alive for the whole execution of the VM, even before QEMU gets initialized. - fn pre_qemu_init(&self, _emulator_hooks: &mut EmulatorHooks) - where + /// + /// It is also possible to edit QEMU parameters, just before QEMU gets initialized. + /// Thus, the module can modify options for QEMU just before it gets initialized. + fn pre_qemu_init( + &mut self, + _emulator_modules: &mut EmulatorModules, + _qemu_params: &mut QemuParams, + ) where ET: EmulatorModuleTuple, { } @@ -67,7 +73,7 @@ where /// Hook run **after** QEMU is initialized. /// This is always run when Emulator gets initialized, in any case. /// Install here hooks that should be alive for the whole execution of the VM, after QEMU gets initialized. - fn post_qemu_init(&self, _emulator_modules: &mut EmulatorModules) + fn post_qemu_init(&mut self, _qemu: Qemu, _emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { @@ -77,8 +83,12 @@ where /// This call can be delayed to the point at which fuzzing is supposed to start. /// It is mostly used to avoid running hooks during VM initialization, either /// because it is useless or it would produce wrong results. - fn first_exec(&mut self, _emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + _emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { } @@ -87,6 +97,7 @@ where /// On the first run, it is executed after [`Self::first_exec`]. fn pre_exec( &mut self, + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, @@ -98,6 +109,7 @@ where /// Run after a fuzzing run ends. fn post_exec( &mut self, + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, @@ -146,20 +158,28 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool; - fn pre_qemu_init_all(&self, _emulator_hooks: &mut EmulatorHooks) - where + fn pre_qemu_init_all( + &mut self, + emulator_modules: &mut EmulatorModules, + qemu_params: &mut QemuParams, + ) where ET: EmulatorModuleTuple; - fn post_qemu_init_all(&self, _emulator_modules: &mut EmulatorModules) + fn post_qemu_init_all(&mut self, qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple; - fn first_exec_all(&mut self, emulator_modules: &mut EmulatorModules, state: &mut S) - where + fn first_exec_all( + &mut self, + qemu: Qemu, + emulator_modules: &mut EmulatorModules, + state: &mut S, + ) where ET: EmulatorModuleTuple; fn pre_exec_all( &mut self, + qemu: Qemu, emulator_modules: &mut EmulatorModules, state: &mut S, input: &S::Input, @@ -168,6 +188,7 @@ where fn post_exec_all( &mut self, + qemu: Qemu, emulator_modules: &mut EmulatorModules, state: &mut S, input: &S::Input, @@ -195,30 +216,41 @@ where impl EmulatorModuleTuple for () where - S: UsesInput, + S: UsesInput + Unpin, { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn pre_qemu_init_all(&self, _emulator_hooks: &mut EmulatorHooks) - where + fn pre_qemu_init_all( + &mut self, + _emulator_modules: &mut EmulatorModules, + _qemu_params: &mut QemuParams, + ) where ET: EmulatorModuleTuple, { } - fn post_qemu_init_all(&self, _emulator_modules: &mut EmulatorModules) - where + fn post_qemu_init_all( + &mut self, + _qemu: Qemu, + _emulator_modules: &mut EmulatorModules, + ) where ET: EmulatorModuleTuple, { } - fn first_exec_all(&mut self, _emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec_all( + &mut self, + _qemu: Qemu, + _emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { } fn pre_exec_all( &mut self, + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, @@ -229,6 +261,7 @@ where fn post_exec_all( &mut self, + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, @@ -258,44 +291,53 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS; - fn pre_qemu_init_all(&self, emulator_hooks: &mut EmulatorHooks) - where + fn pre_qemu_init_all( + &mut self, + emulator_modules: &mut EmulatorModules, + qemu_params: &mut QemuParams, + ) where ET: EmulatorModuleTuple, { - self.0.pre_qemu_init(emulator_hooks); - self.1.pre_qemu_init_all(emulator_hooks); + self.0.pre_qemu_init(emulator_modules, qemu_params); + self.1.pre_qemu_init_all(emulator_modules, qemu_params); } - fn post_qemu_init_all(&self, emulator_modules: &mut EmulatorModules) + fn post_qemu_init_all(&mut self, qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { - self.0.post_qemu_init(emulator_modules); - self.1.post_qemu_init_all(emulator_modules); + self.0.post_qemu_init(qemu, emulator_modules); + self.1.post_qemu_init_all(qemu, emulator_modules); } - fn first_exec_all(&mut self, emulator_modules: &mut EmulatorModules, state: &mut S) - where + fn first_exec_all( + &mut self, + qemu: Qemu, + emulator_modules: &mut EmulatorModules, + state: &mut S, + ) where ET: EmulatorModuleTuple, { - self.0.first_exec(emulator_modules, state); - self.1.first_exec_all(emulator_modules, state); + self.0.first_exec(qemu, emulator_modules, state); + self.1.first_exec_all(qemu, emulator_modules, state); } fn pre_exec_all( &mut self, + qemu: Qemu, emulator_modules: &mut EmulatorModules, state: &mut S, input: &S::Input, ) where ET: EmulatorModuleTuple, { - self.0.pre_exec(emulator_modules, state, input); - self.1.pre_exec_all(emulator_modules, state, input); + self.0.pre_exec(qemu, emulator_modules, state, input); + self.1.pre_exec_all(qemu, emulator_modules, state, input); } fn post_exec_all( &mut self, + qemu: Qemu, emulator_modules: &mut EmulatorModules, state: &mut S, input: &S::Input, @@ -306,9 +348,9 @@ where ET: EmulatorModuleTuple, { self.0 - .post_exec(emulator_modules, state, input, observers, exit_kind); + .post_exec(qemu, emulator_modules, state, input, observers, exit_kind); self.1 - .post_exec_all(emulator_modules, state, input, observers, exit_kind); + .post_exec_all(qemu, emulator_modules, state, input, observers, exit_kind); } unsafe fn on_crash_all(&mut self) { diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index 5ff4cd5b31..8c963938bb 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -16,9 +16,9 @@ use crate::{ calls::FullBacktraceCollector, snapshot::SnapshotModule, EmulatorModule, EmulatorModuleTuple, }, - qemu::{MemAccessInfo, QemuInitError}, + qemu::MemAccessInfo, sys::TCGTemp, - Qemu, Regs, + Qemu, QemuParams, Regs, }; // TODO at some point, merge parts with libafl_frida @@ -176,8 +176,8 @@ impl core::fmt::Debug for AsanGiovese { } impl AsanGiovese { - unsafe fn map_shadow() { - assert!( + unsafe fn init(self: &mut Pin>, qemu_hooks: QemuHooks) { + assert_ne!( libc::mmap( HIGH_SHADOW_ADDR, HIGH_SHADOW_SIZE, @@ -185,9 +185,10 @@ impl AsanGiovese { MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, -1, 0 - ) != MAP_FAILED + ), + MAP_FAILED ); - assert!( + assert_ne!( libc::mmap( LOW_SHADOW_ADDR, LOW_SHADOW_SIZE, @@ -195,9 +196,10 @@ impl AsanGiovese { MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, -1, 0 - ) != MAP_FAILED + ), + MAP_FAILED ); - assert!( + assert_ne!( libc::mmap( GAP_SHADOW_ADDR, GAP_SHADOW_SIZE, @@ -205,12 +207,15 @@ impl AsanGiovese { MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, -1, 0 - ) != MAP_FAILED + ), + MAP_FAILED ); + + qemu_hooks.add_pre_syscall_hook(self.as_mut(), Self::fake_syscall); } #[must_use] - fn new(qemu_hooks: QemuHooks) -> Pin> { + fn new() -> Pin> { let res = Self { alloc_tree: Mutex::new(IntervalTree::new()), saved_tree: IntervalTree::new(), @@ -219,9 +224,7 @@ impl AsanGiovese { saved_shadow: HashMap::default(), snapshot_shadow: true, // By default, track the dirty shadow pages }; - let mut boxed = Box::pin(res); - qemu_hooks.add_pre_syscall_hook(boxed.as_mut(), Self::fake_syscall); - boxed + Box::pin(res) } extern "C" fn fake_syscall( @@ -255,7 +258,7 @@ impl AsanGiovese { Self::unpoison(qemu, a1, a2 as usize); } QasanAction::IsPoison => { - if Self::is_invalid_access(qemu, a1, a2 as usize) { + if Self::is_invalid_access_n(qemu, a1, a2 as usize) { r = 1; } } @@ -285,51 +288,25 @@ impl AsanGiovese { #[inline] #[must_use] - pub fn is_invalid_access_1(qemu: Qemu, addr: GuestAddr) -> bool { - unsafe { - let h = qemu.g2h::<*const c_void>(addr) as isize; - let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET); - let k = *shadow_addr as isize; - k != 0 && (h & 7).wrapping_add(1) > k - } - } - - #[inline] - #[must_use] - pub fn is_invalid_access_2(qemu: Qemu, addr: GuestAddr) -> bool { - unsafe { - let h = qemu.g2h::<*const c_void>(addr) as isize; - let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET); - let k = *shadow_addr as isize; - k != 0 && (h & 7).wrapping_add(2) > k - } - } - - #[inline] - #[must_use] - pub fn is_invalid_access_4(qemu: Qemu, addr: GuestAddr) -> bool { - unsafe { - let h = qemu.g2h::<*const c_void>(addr) as isize; - let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET); - let k = *shadow_addr as isize; - k != 0 && (h & 7).wrapping_add(4) > k - } - } + pub fn is_invalid_access(qemu: Qemu, addr: GuestAddr) -> bool { + const { assert!(N == 1 || N == 2 || N == 4 || N == 8) }; - #[inline] - #[must_use] - pub fn is_invalid_access_8(qemu: Qemu, addr: GuestAddr) -> bool { unsafe { let h = qemu.g2h::<*const c_void>(addr) as isize; let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET); - *shadow_addr != 0 + if N < 8 { + let k = *shadow_addr as isize; + k != 0 && (h & 7).wrapping_add(N as isize) > k + } else { + *shadow_addr != 0 + } } } #[inline] #[must_use] #[expect(clippy::cast_sign_loss)] - pub fn is_invalid_access(qemu: Qemu, addr: GuestAddr, n: usize) -> bool { + pub fn is_invalid_access_n(qemu: Qemu, addr: GuestAddr, n: usize) -> bool { unsafe { if n == 0 { return false; @@ -672,64 +649,6 @@ impl AsanGiovese { } } -static mut ASAN_INITED: bool = false; - -pub fn init_qemu_with_asan( - args: &mut Vec, - env: &mut [(String, String)], -) -> Result<(Qemu, Pin>), QemuInitError> { - let current = env::current_exe().unwrap(); - let asan_lib = fs::canonicalize(current) - .unwrap() - .parent() - .unwrap() - .join("libqasan.so"); - let asan_lib = asan_lib - .to_str() - .expect("The path to the asan lib is invalid") - .to_string(); - let add_asan = - |e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..]; - - // TODO: adapt since qemu does not take envp anymore as parameter - let mut added = false; - for (k, v) in &mut *env { - if k == "QEMU_SET_ENV" { - let mut new_v = vec![]; - for e in v.split(',') { - if e.starts_with("LD_PRELOAD=") { - added = true; - new_v.push(add_asan(e)); - } else { - new_v.push(e.to_string()); - } - } - *v = new_v.join(","); - } - } - for i in 0..args.len() { - if args[i] == "-E" && i + 1 < args.len() && args[i + 1].starts_with("LD_PRELOAD=") { - added = true; - args[i + 1] = add_asan(&args[i + 1]); - } - } - - if !added { - args.insert(1, "LD_PRELOAD=".to_string() + &asan_lib); - args.insert(1, "-E".into()); - } - - unsafe { - AsanGiovese::map_shadow(); - ASAN_INITED = true; - } - - let qemu = Qemu::init(args)?; - let rt = AsanGiovese::new(qemu.hooks()); - - Ok((qemu, rt)) -} - pub enum QemuAsanOptions { None, Snapshot, @@ -741,6 +660,7 @@ pub type AsanChildModule = AsanModule; #[derive(Debug)] pub struct AsanModule { + env: Vec<(String, String)>, enabled: bool, detect_leaks: bool, empty: bool, @@ -750,25 +670,28 @@ pub struct AsanModule { impl AsanModule { #[must_use] - pub fn default(rt: Pin>) -> Self { - Self::new(rt, StdAddressFilter::default(), &QemuAsanOptions::Snapshot) + pub fn default(env: &[(String, String)]) -> Self { + Self::new(StdAddressFilter::default(), &QemuAsanOptions::Snapshot, env) } #[must_use] pub fn new( - mut rt: Pin>, filter: StdAddressFilter, options: &QemuAsanOptions, + env: &[(String, String)], ) -> Self { - assert!(unsafe { ASAN_INITED }, "The ASan runtime is not initialized, use init_qemu_with_asan(...) instead of just Qemu::init(...)"); let (snapshot, detect_leaks) = match options { QemuAsanOptions::None => (false, false), QemuAsanOptions::Snapshot => (true, false), QemuAsanOptions::DetectLeaks => (false, true), QemuAsanOptions::SnapshotDetectLeaks => (true, true), }; + + let mut rt = AsanGiovese::new(); rt.set_snapshot_shadow(snapshot); + Self { + env: env.to_vec(), enabled: true, detect_leaks, empty: true, @@ -779,21 +702,24 @@ impl AsanModule { #[must_use] pub fn with_error_callback( - mut rt: Pin>, filter: StdAddressFilter, error_callback: AsanErrorCallback, options: &QemuAsanOptions, + env: &[(String, String)], ) -> Self { - assert!(unsafe { ASAN_INITED }, "The ASan runtime is not initialized, use init_qemu_with_asan(...) instead of just Qemu::init(...)"); let (snapshot, detect_leaks) = match options { QemuAsanOptions::None => (false, false), QemuAsanOptions::Snapshot => (true, false), QemuAsanOptions::DetectLeaks => (false, true), QemuAsanOptions::SnapshotDetectLeaks => (true, true), }; + + let mut rt = AsanGiovese::new(); rt.set_snapshot_shadow(snapshot); rt.set_error_callback(error_callback); + Self { + env: env.to_vec(), enabled: true, detect_leaks, empty: true, @@ -806,15 +732,15 @@ impl AsanModule { /// The `ASan` error report accesses [`FullBacktraceCollector`] #[must_use] pub unsafe fn with_asan_report( - rt: Pin>, filter: StdAddressFilter, options: &QemuAsanOptions, + env: &[(String, String)], ) -> Self { Self::with_error_callback( - rt, filter, Box::new(|rt, qemu, pc, err| unsafe { asan_report(rt, qemu, pc, &err) }), options, + env, ) } @@ -842,66 +768,30 @@ impl AsanModule { #[must_use] pub fn is_poisoned(&self, qemu: Qemu, addr: GuestAddr, size: usize) -> bool { - AsanGiovese::is_invalid_access(qemu, addr, size) - } - - pub fn read_1(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_1(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Read(addr, 1)); - } + AsanGiovese::is_invalid_access_n(qemu, addr, size) } - pub fn read_2(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_2(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Read(addr, 2)); - } - } - - pub fn read_4(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_4(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Read(addr, 4)); - } - } - - pub fn read_8(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_8(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Read(addr, 8)); + pub fn read(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { + if self.enabled() && AsanGiovese::is_invalid_access::(qemu, addr) { + self.rt.report_or_crash(qemu, pc, AsanError::Read(addr, N)); } } pub fn read_n(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr, size: usize) { - if self.enabled() && AsanGiovese::is_invalid_access(qemu, addr, size) { + if self.enabled() && AsanGiovese::is_invalid_access_n(qemu, addr, size) { self.rt .report_or_crash(qemu, pc, AsanError::Read(addr, size)); } } - pub fn write_1(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_1(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Write(addr, 1)); - } - } - - pub fn write_2(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_2(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Write(addr, 2)); - } - } - - pub fn write_4(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_4(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Write(addr, 4)); - } - } - - pub fn write_8(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { - if self.enabled() && AsanGiovese::is_invalid_access_8(qemu, addr) { - self.rt.report_or_crash(qemu, pc, AsanError::Write(addr, 8)); + pub fn write(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { + if self.enabled() && AsanGiovese::is_invalid_access::(qemu, addr) { + self.rt.report_or_crash(qemu, pc, AsanError::Write(addr, N)); } } pub fn write_n(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr, size: usize) { - if self.enabled() && AsanGiovese::is_invalid_access(qemu, addr, size) { + if self.enabled() && AsanGiovese::is_invalid_access_n(qemu, addr, size) { self.rt .report_or_crash(qemu, pc, AsanError::Write(addr, size)); } @@ -927,47 +817,108 @@ where type ModuleAddressFilter = StdAddressFilter; const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn post_qemu_init(&self, emulator_modules: &mut EmulatorModules) + fn pre_qemu_init( + &mut self, + emulator_modules: &mut EmulatorModules, + qemu_params: &mut QemuParams, + ) where + ET: EmulatorModuleTuple, + { + let mut args: Vec = qemu_params.to_cli(); + + let current = env::current_exe().unwrap(); + let asan_lib = fs::canonicalize(current) + .unwrap() + .parent() + .unwrap() + .join("libqasan.so"); + let asan_lib = asan_lib + .to_str() + .expect("The path to the asan lib is invalid") + .to_string(); + let add_asan = + |e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..]; + + // TODO: adapt since qemu does not take envp anymore as parameter + let mut added = false; + for (k, v) in &mut self.env { + if k == "QEMU_SET_ENV" { + let mut new_v = vec![]; + for e in v.split(',') { + if e.starts_with("LD_PRELOAD=") { + added = true; + new_v.push(add_asan(e)); + } else { + new_v.push(e.to_string()); + } + } + *v = new_v.join(","); + } + } + for i in 0..args.len() { + if args[i] == "-E" && i + 1 < args.len() && args[i + 1].starts_with("LD_PRELOAD=") { + added = true; + args[i + 1] = add_asan(&args[i + 1]); + } + } + + if !added { + args.insert(1, "LD_PRELOAD=".to_string() + &asan_lib); + args.insert(1, "-E".into()); + } + + unsafe { + AsanGiovese::init(&mut self.rt, emulator_modules.hooks().qemu_hooks()); + } + + *qemu_params = QemuParams::Cli(args); + } + + fn post_qemu_init(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { - emulator_modules.syscalls(Hook::Function(qasan_fake_syscall::)); + emulator_modules.pre_syscalls(Hook::Function(qasan_fake_syscall::)); if self.rt.error_callback.is_some() { emulator_modules.crash_function(oncrash_asan::); } } - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + _qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { emulator_modules.reads( Hook::Function(gen_readwrite_asan::), - Hook::Function(trace_read1_asan::), - Hook::Function(trace_read2_asan::), - Hook::Function(trace_read4_asan::), - Hook::Function(trace_read8_asan::), + Hook::Function(trace_read_asan::), + Hook::Function(trace_read_asan::), + Hook::Function(trace_read_asan::), + Hook::Function(trace_read_asan::), Hook::Function(trace_read_n_asan::), ); if emulator_modules.get::().is_none() { emulator_modules.writes( Hook::Function(gen_readwrite_asan::), - Hook::Function(trace_write1_asan::), - Hook::Function(trace_write2_asan::), - Hook::Function(trace_write4_asan::), - Hook::Function(trace_write8_asan::), + Hook::Function(trace_write_asan::), + Hook::Function(trace_write_asan::), + Hook::Function(trace_write_asan::), + Hook::Function(trace_write_asan::), Hook::Function(trace_write_n_asan::), ); } else { // track writes for both modules as opt emulator_modules.writes( Hook::Function(gen_write_asan_snapshot::), - Hook::Function(trace_write1_asan_snapshot::), - Hook::Function(trace_write2_asan_snapshot::), - Hook::Function(trace_write4_asan_snapshot::), - Hook::Function(trace_write8_asan_snapshot::), + Hook::Function(trace_write_asan_snapshot::), + Hook::Function(trace_write_asan_snapshot::), + Hook::Function(trace_write_asan_snapshot::), + Hook::Function(trace_write_asan_snapshot::), Hook::Function(trace_write_n_asan_snapshot::), ); } @@ -975,21 +926,23 @@ where fn pre_exec( &mut self, - emulator_modules: &mut EmulatorModules, + qemu: Qemu, + _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, ) where ET: EmulatorModuleTuple, { if self.empty { - self.rt.snapshot(emulator_modules.qemu()); + self.rt.snapshot(qemu); self.empty = false; } } fn post_exec( &mut self, - emulator_modules: &mut EmulatorModules, + qemu: Qemu, + _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, _observers: &mut OT, @@ -998,7 +951,7 @@ where OT: ObserversTuple, ET: EmulatorModuleTuple, { - if self.reset(emulator_modules.qemu()) == AsanRollback::HasLeaks { + if self.reset(qemu) == AsanRollback::HasLeaks { *exit_kind = ExitKind::Crash; } } @@ -1012,18 +965,21 @@ where } } -pub fn oncrash_asan(emulator_modules: &mut EmulatorModules, target_sig: i32) -where +pub fn oncrash_asan( + qemu: Qemu, + emulator_modules: &mut EmulatorModules, + target_sig: i32, +) where ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); let pc: GuestAddr = qemu.read_reg(Regs::Pc).unwrap(); h.rt.report(qemu, pc, AsanError::Signal(target_sig)); } pub fn gen_readwrite_asan( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -1042,7 +998,8 @@ where } } -pub fn trace_read1_asan( +pub fn trace_read_asan( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, @@ -1051,54 +1008,12 @@ pub fn trace_read1_asan( ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); - h.read_1(qemu, id as GuestAddr, addr); -} - -pub fn trace_read2_asan( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.read_2(qemu, id as GuestAddr, addr); -} - -pub fn trace_read4_asan( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.read_4(qemu, id as GuestAddr, addr); -} - -pub fn trace_read8_asan( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.read_8(qemu, id as GuestAddr, addr); + h.read::(qemu, id as GuestAddr, addr); } pub fn trace_read_n_asan( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, @@ -1108,54 +1023,12 @@ pub fn trace_read_n_asan( S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); h.read_n(qemu, id as GuestAddr, addr, size); } -pub fn trace_write1_asan( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.write_1(qemu, id as GuestAddr, addr); -} - -pub fn trace_write2_asan( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.write_2(qemu, id as GuestAddr, addr); -} - -pub fn trace_write4_asan( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.write_4(qemu, id as GuestAddr, addr); -} - -pub fn trace_write8_asan( +pub fn trace_write_asan( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, @@ -1164,12 +1037,12 @@ pub fn trace_write8_asan( S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); - h.write_8(qemu, id as GuestAddr, addr); + h.write::(qemu, id as GuestAddr, addr); } pub fn trace_write_n_asan( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, @@ -1179,12 +1052,12 @@ pub fn trace_write_n_asan( S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); h.read_n(qemu, id as GuestAddr, addr, size); } pub fn gen_write_asan_snapshot( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -1203,61 +1076,8 @@ where } } -pub fn trace_write1_asan_snapshot( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - if id != 0 { - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.write_1(qemu, id as GuestAddr, addr); - } - let h = emulator_modules.get_mut::().unwrap(); - h.access(addr, 1); -} - -pub fn trace_write2_asan_snapshot( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - if id != 0 { - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.write_2(qemu, id as GuestAddr, addr); - } - let h = emulator_modules.get_mut::().unwrap(); - h.access(addr, 2); -} - -pub fn trace_write4_asan_snapshot( - emulator_modules: &mut EmulatorModules, - _state: Option<&mut S>, - id: u64, - addr: GuestAddr, -) where - S: Unpin + UsesInput, - ET: EmulatorModuleTuple, -{ - if id != 0 { - let qemu = emulator_modules.qemu(); - let h = emulator_modules.get_mut::().unwrap(); - h.write_4(qemu, id as GuestAddr, addr); - } - let h = emulator_modules.get_mut::().unwrap(); - h.access(addr, 4); -} - -pub fn trace_write8_asan_snapshot( +pub fn trace_write_asan_snapshot( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, @@ -1267,15 +1087,15 @@ pub fn trace_write8_asan_snapshot( ET: EmulatorModuleTuple, { if id != 0 { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); - h.write_8(qemu, id as GuestAddr, addr); + h.write::(qemu, id as GuestAddr, addr); } let h = emulator_modules.get_mut::().unwrap(); - h.access(addr, 8); + h.access(addr, N); } pub fn trace_write_n_asan_snapshot( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, id: u64, @@ -1286,7 +1106,6 @@ pub fn trace_write_n_asan_snapshot( ET: EmulatorModuleTuple, { if id != 0 { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); h.read_n(qemu, id as GuestAddr, addr, size); } @@ -1296,6 +1115,7 @@ pub fn trace_write_n_asan_snapshot( #[expect(clippy::too_many_arguments)] pub fn qasan_fake_syscall( + qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, sys_num: i32, @@ -1313,7 +1133,6 @@ where ET: EmulatorModuleTuple, { if sys_num == QASAN_FAKESYS_NR { - let qemu = emulator_modules.qemu(); let h = emulator_modules.get_mut::().unwrap(); match QasanAction::try_from(a0).expect("Invalid QASan action number") { QasanAction::CheckLoad => { diff --git a/libafl_qemu/src/modules/usermode/asan_guest.rs b/libafl_qemu/src/modules/usermode/asan_guest.rs index eb03668685..bf031a800b 100644 --- a/libafl_qemu/src/modules/usermode/asan_guest.rs +++ b/libafl_qemu/src/modules/usermode/asan_guest.rs @@ -15,86 +15,11 @@ use crate::sys::libafl_tcg_gen_asan; use crate::{ emu::EmulatorModules, modules::{AddressFilter, EmulatorModule, EmulatorModuleTuple, StdAddressFilter}, - qemu::{Hook, MemAccessInfo, Qemu, QemuInitError}, + qemu::{Hook, MemAccessInfo, Qemu}, sys::TCGTemp, + QemuParams, }; -static mut ASAN_GUEST_INITED: bool = false; - -pub fn init_qemu_with_asan_guest( - args: &mut Vec, - env: &mut [(String, String)], -) -> Result<(Qemu, String), QemuInitError> { - let current = env::current_exe().unwrap(); - let asan_lib = fs::canonicalize(current) - .unwrap() - .parent() - .unwrap() - .join("libgasan.so"); - - let asan_lib = env::var_os("CUSTOM_ASAN_PATH") - .map_or(asan_lib, |x| PathBuf::from(x.to_string_lossy().to_string())); - - assert!( - asan_lib.as_path().exists(), - "The ASAN library doesn't exist: {asan_lib:#?}" - ); - - let asan_lib = asan_lib - .to_str() - .expect("The path to the asan lib is invalid") - .to_string(); - - println!("Loading ASAN: {asan_lib:}"); - - let add_asan = - |e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..]; - - let mut added = false; - for (k, v) in &mut *env { - if k == "QEMU_SET_ENV" { - let mut new_v = vec![]; - for e in v.split(',') { - if e.starts_with("LD_PRELOAD=") { - added = true; - new_v.push(add_asan(e)); - } else { - new_v.push(e.to_string()); - } - } - *v = new_v.join(","); - } - } - for i in 0..args.len() { - if args[i] == "-E" && i + 1 < args.len() && args[i + 1].starts_with("LD_PRELOAD=") { - added = true; - args[i + 1] = add_asan(&args[i + 1]); - } - } - - if !added { - args.insert(1, "LD_PRELOAD=".to_string() + &asan_lib); - args.insert(1, "-E".into()); - } - - if env::var("QASAN_DEBUG").is_ok() { - args.push("-E".into()); - args.push("QASAN_DEBUG=1".into()); - } - - if env::var("QASAN_LOG").is_ok() { - args.push("-E".into()); - args.push("QASAN_LOG=1".into()); - } - - unsafe { - ASAN_GUEST_INITED = true; - } - - let emu = Qemu::init(args)?; - Ok((emu, asan_lib)) -} - #[derive(Clone)] struct QemuAsanGuestMapping { start: GuestAddr, @@ -119,8 +44,10 @@ impl From<&MapInfo> for QemuAsanGuestMapping { #[derive(Debug)] pub struct AsanGuestModule { + env: Vec<(String, String)>, filter: F, - mappings: Vec, + mappings: Option>, + asan_lib: Option, } #[cfg(any( @@ -152,8 +79,8 @@ impl AsanGuestModule { impl AsanGuestModule { #[must_use] - pub fn default(qemu: Qemu, asan: &str) -> Self { - Self::new(qemu, asan, StdAddressFilter::default()) + pub fn default(env: &[(String, String)]) -> Self { + Self::new(env, StdAddressFilter::default()) } } @@ -162,41 +89,13 @@ where F: AddressFilter, { #[must_use] - pub fn new(qemu: Qemu, asan: &str, filter: F) -> Self { - for mapping in qemu.mappings() { - println!("mapping: {mapping:#?}"); + pub fn new(env: &[(String, String)], filter: F) -> Self { + Self { + env: env.to_vec(), + filter, + mappings: None, + asan_lib: None, } - - let mappings = qemu - .mappings() - .map(|m| QemuAsanGuestMapping::from(&m)) - .collect::>(); - - for mapping in &mappings { - println!("guest mapping: {mapping:#?}"); - } - - mappings - .iter() - .find(|m| m.start <= Self::HIGH_SHADOW_START && m.end > Self::HIGH_SHADOW_END) - .expect("HighShadow not found, confirm ASAN DSO is loaded in the guest"); - - mappings - .iter() - .find(|m| m.start <= Self::LOW_SHADOW_START && m.end > Self::LOW_SHADOW_END) - .expect("LowShadow not found, confirm ASAN DSO is loaded in the guest"); - - let mappings = mappings - .iter() - .filter(|m| m.path == asan) - .cloned() - .collect::>(); - - for mapping in &mappings { - println!("asan mapping: {mapping:#?}"); - } - - Self { filter, mappings } } #[must_use] @@ -207,6 +106,7 @@ where #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn gen_readwrite_guest_asan( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, pc: GuestAddr, @@ -224,8 +124,15 @@ where } /* Don't sanitize the sanitizer! */ - if h.mappings.iter().any(|m| m.start <= pc && pc < m.end) { - return None; + unsafe { + if h.mappings + .as_mut() + .unwrap_unchecked() + .iter() + .any(|m| m.start <= pc && pc < m.end) + { + return None; + } } let size = info.size(); @@ -246,6 +153,7 @@ unsafe fn libafl_tcg_gen_asan(addr: *mut TCGTemp, size: usize) {} #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn guest_trace_error_asan( + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, _id: u64, @@ -259,6 +167,7 @@ fn guest_trace_error_asan( #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn guest_trace_error_n_asan( + _qemu: Qemu, _emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, _id: u64, @@ -278,9 +187,127 @@ where { type ModuleAddressFilter = F; - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) + fn pre_qemu_init( + &mut self, + _emulator_modules: &mut EmulatorModules, + qemu_params: &mut QemuParams, + ) where + ET: EmulatorModuleTuple, + { + let mut args = qemu_params.to_cli(); + + let current = env::current_exe().unwrap(); + let asan_lib = fs::canonicalize(current) + .unwrap() + .parent() + .unwrap() + .join("libgasan.so"); + + let asan_lib = env::var_os("CUSTOM_ASAN_PATH") + .map_or(asan_lib, |x| PathBuf::from(x.to_string_lossy().to_string())); + + assert!( + asan_lib.as_path().exists(), + "The ASAN library doesn't exist: {asan_lib:#?}" + ); + + let asan_lib = asan_lib + .to_str() + .expect("The path to the asan lib is invalid") + .to_string(); + + println!("Loading ASAN: {asan_lib:}"); + + let add_asan = + |e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..]; + + let mut added = false; + for (k, v) in &mut self.env { + if k == "QEMU_SET_ENV" { + let mut new_v = vec![]; + for e in v.split(',') { + if e.starts_with("LD_PRELOAD=") { + added = true; + new_v.push(add_asan(e)); + } else { + new_v.push(e.to_string()); + } + } + *v = new_v.join(","); + } + } + for i in 0..args.len() { + if args[i] == "-E" && i + 1 < args.len() && args[i + 1].starts_with("LD_PRELOAD=") { + added = true; + args[i + 1] = add_asan(&args[i + 1]); + } + } + + if !added { + args.insert(1, "LD_PRELOAD=".to_string() + &asan_lib); + args.insert(1, "-E".into()); + } + + if env::var("QASAN_DEBUG").is_ok() { + args.push("-E".into()); + args.push("QASAN_DEBUG=1".into()); + } + + if env::var("QASAN_LOG").is_ok() { + args.push("-E".into()); + args.push("QASAN_LOG=1".into()); + } + + *qemu_params = QemuParams::Cli(args); + + self.asan_lib = Some(asan_lib); + } + + fn post_qemu_init(&mut self, qemu: Qemu, _emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, + { + for mapping in qemu.mappings() { + println!("mapping: {mapping:#?}"); + } + + let mappings = qemu + .mappings() + .map(|m| QemuAsanGuestMapping::from(&m)) + .collect::>(); + + for mapping in &mappings { + println!("guest mapping: {mapping:#?}"); + } + + mappings + .iter() + .find(|m| m.start <= Self::HIGH_SHADOW_START && m.end > Self::HIGH_SHADOW_END) + .expect("HighShadow not found, confirm ASAN DSO is loaded in the guest"); + + mappings + .iter() + .find(|m| m.start <= Self::LOW_SHADOW_START && m.end > Self::LOW_SHADOW_END) + .expect("LowShadow not found, confirm ASAN DSO is loaded in the guest"); + + let mappings = mappings + .iter() + .filter(|m| &m.path == self.asan_lib.as_ref().unwrap()) + .cloned() + .collect::>(); + + for mapping in &mappings { + println!("asan mapping: {mapping:#?}"); + } + } + + fn first_exec( + &mut self, + _qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where + ET: EmulatorModuleTuple, S: Unpin + UsesInput, { emulator_modules.reads( diff --git a/libafl_qemu/src/modules/usermode/injections.rs b/libafl_qemu/src/modules/usermode/injections.rs index 086e293c6f..3dc87b49c1 100644 --- a/libafl_qemu/src/modules/usermode/injections.rs +++ b/libafl_qemu/src/modules/usermode/injections.rs @@ -211,12 +211,15 @@ impl InjectionModule { }) } - fn on_call_check(emulator_modules: &mut EmulatorModules, id: usize, parameter: u8) - where + fn on_call_check( + qemu: Qemu, + emulator_modules: &mut EmulatorModules, + id: usize, + parameter: u8, + ) where ET: EmulatorModuleTuple, S: Unpin + UsesInput, { - let qemu = emulator_modules.qemu(); let reg: GuestAddr = qemu .current_cpu() .unwrap() @@ -262,18 +265,21 @@ where { type ModuleAddressFilter = NopAddressFilter; - fn post_qemu_init(&self, emulator_modules: &mut EmulatorModules) + fn post_qemu_init(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { - emulator_modules.syscalls(Hook::Function(syscall_hook::)); + emulator_modules.pre_syscalls(Hook::Function(syscall_hook::)); } - fn first_exec(&mut self, emulator_modules: &mut EmulatorModules, _state: &mut S) - where + fn first_exec( + &mut self, + qemu: Qemu, + emulator_modules: &mut EmulatorModules, + _state: &mut S, + ) where ET: EmulatorModuleTuple, { - let qemu = emulator_modules.qemu(); let mut libs: Vec = Vec::new(); for region in qemu.mappings() { @@ -324,8 +330,8 @@ where for hook_addr in hook_addrs { emulator_modules.instructions( hook_addr, - Hook::Closure(Box::new(move |hooks, _state, _guest_addr| { - Self::on_call_check(hooks, id, param); + Hook::Closure(Box::new(move |qemu, hooks, _state, _guest_addr| { + Self::on_call_check(qemu, hooks, id, param); })), true, ); @@ -347,6 +353,7 @@ where #[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly fn syscall_hook( // Our instantiated [`EmulatorModules`] + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, // Syscall number diff --git a/libafl_qemu/src/modules/usermode/mod.rs b/libafl_qemu/src/modules/usermode/mod.rs index 1d9cc503d2..93a8f5247c 100644 --- a/libafl_qemu/src/modules/usermode/mod.rs +++ b/libafl_qemu/src/modules/usermode/mod.rs @@ -11,9 +11,9 @@ pub use snapshot::{IntervalSnapshotFilter, SnapshotModule}; #[cfg(not(cpu_target = "hexagon"))] pub mod asan; #[cfg(not(cpu_target = "hexagon"))] -pub use asan::{init_qemu_with_asan, AsanModule}; +pub use asan::AsanModule; #[cfg(not(cpu_target = "hexagon"))] pub mod asan_guest; #[cfg(not(cpu_target = "hexagon"))] -pub use asan_guest::{init_qemu_with_asan_guest, AsanGuestModule}; +pub use asan_guest::AsanGuestModule; diff --git a/libafl_qemu/src/modules/usermode/snapshot.rs b/libafl_qemu/src/modules/usermode/snapshot.rs index e3579ed0e9..5e5bfaf458 100644 --- a/libafl_qemu/src/modules/usermode/snapshot.rs +++ b/libafl_qemu/src/modules/usermode/snapshot.rs @@ -680,7 +680,7 @@ where { type ModuleAddressFilter = NopAddressFilter; - fn post_qemu_init(&self, emulator_modules: &mut EmulatorModules) + fn post_qemu_init(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules) where ET: EmulatorModuleTuple, { @@ -697,23 +697,24 @@ where } if !self.accurate_unmap { - emulator_modules.syscalls(Hook::Function(filter_mmap_snapshot::)); + emulator_modules.pre_syscalls(Hook::Function(filter_mmap_snapshot::)); } - emulator_modules.after_syscalls(Hook::Function(trace_mmap_snapshot::)); + emulator_modules.post_syscalls(Hook::Function(trace_mmap_snapshot::)); } fn pre_exec( &mut self, - emulator_modules: &mut EmulatorModules, + qemu: Qemu, + _emulator_modules: &mut EmulatorModules, _state: &mut S, _input: &S::Input, ) where ET: EmulatorModuleTuple, { if self.empty { - self.snapshot(emulator_modules.qemu()); + self.snapshot(qemu); } else { - self.reset(emulator_modules.qemu()); + self.reset(qemu); } } @@ -727,6 +728,7 @@ where } pub fn trace_write_snapshot( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, _id: u64, @@ -740,6 +742,7 @@ pub fn trace_write_snapshot( } pub fn trace_write_n_snapshot( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, _id: u64, @@ -755,6 +758,7 @@ pub fn trace_write_n_snapshot( #[expect(clippy::too_many_arguments)] pub fn filter_mmap_snapshot( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, sys_num: i32, @@ -782,6 +786,7 @@ where #[expect(non_upper_case_globals, clippy::too_many_arguments)] pub fn trace_mmap_snapshot( + _qemu: Qemu, emulator_modules: &mut EmulatorModules, _state: Option<&mut S>, result: GuestAddr, diff --git a/libafl_qemu/src/qemu/config.rs b/libafl_qemu/src/qemu/config.rs index b17b3e5913..661c05d1ca 100644 --- a/libafl_qemu/src/qemu/config.rs +++ b/libafl_qemu/src/qemu/config.rs @@ -2,20 +2,13 @@ use core::{ fmt, fmt::{Display, Formatter}, }; -use std::{ - path::{Path, PathBuf}, - sync::OnceLock, -}; +use std::path::{Path, PathBuf}; use getset::Getters; use libafl_derive; use strum_macros; use typed_builder::TypedBuilder; -use crate::{Qemu, QemuInitError}; - -pub(super) static QEMU_CONFIG: OnceLock = OnceLock::new(); - #[cfg(feature = "systemmode")] #[derive(Debug, strum_macros::Display, Clone)] #[strum(prefix = "-accel ", serialize_all = "lowercase")] @@ -304,15 +297,6 @@ impl> From for Program { } #[derive(Debug, Clone, libafl_derive::Display, TypedBuilder, Getters)] -#[builder(build_method(into = Result), builder_method(vis = "pub(crate)", - doc = "Since Qemu is a zero sized struct, this is not a completely standard builder pattern. \ - The Qemu configuration is not stored in the Qemu struct after build() but in QEMU_CONFIG \ - Therefore, to use the derived builder and avoid boilerplate a builder for QemuConfig is \ - derived. \ - The QemuConfig::builder is called in Qemu::builder() which is the only place where it should \ - be called, in this way the one to one matching of Qemu and QemuConfig is enforced. Therefore \ - its visibility is pub(crate)"))] -#[getset(get = "pub")] pub struct QemuConfig { #[cfg(feature = "systemmode")] #[builder(default, setter(strip_option))] @@ -350,40 +334,17 @@ pub struct QemuConfig { program: Program, } // Adding something here? Please leave Program as the last field -impl From for Result { - /// This method is necessary to make the API resemble a typical builder pattern, i.e. - /// `Qemu::builder().foo(bar).build()`, while still leveraging `TypedBuilder` for this - /// non-standard use case where `Qemu` doesn't store the configuration. - /// Internally, `TypedBuilder` is used to generate a builder for `QemuConfig`. - /// This `QemuConfig.into()` method is used by the derived `QemuConfigBuilder.build()` - /// to go from `QemuConfigBuilder` to `QemuConfig`, and finally to `Qemu` in one fn. - /// - /// # Errors - /// returns `QemuInitError` if the Qemu initialization fails, including cases where Qemu has - /// already been initialized. - fn from(config: QemuConfig) -> Self { - let args = config - .to_string() - .split(' ') - .map(ToString::to_string) - .collect::>(); - let qemu = Qemu::init(&args)?; - QEMU_CONFIG - .set(config) - .map_err(|_| unreachable!("BUG: QEMU_CONFIG was already set but Qemu was not init!"))?; - Ok(qemu) - } -} - #[cfg(test)] mod test { use super::*; + use crate::Qemu; #[test] #[cfg(feature = "usermode")] fn usermode() { let program = "/bin/pwd"; - let qemu = Qemu::builder().program("/bin/pwd").build().unwrap(); + let qemu_config = QemuConfig::builder().program("/bin/pwd").build(); + let qemu = Qemu::init(qemu_config).unwrap(); let config = qemu.get_config().unwrap(); assert_eq!(config.to_string().trim(), program.trim()); } diff --git a/libafl_qemu/src/qemu/error.rs b/libafl_qemu/src/qemu/error.rs new file mode 100644 index 0000000000..6c4ce50ad8 --- /dev/null +++ b/libafl_qemu/src/qemu/error.rs @@ -0,0 +1,155 @@ +use core::fmt; +use std::{convert::Infallible, fmt::Display}; + +use libafl_qemu_sys::{CPUStatePtr, GuestAddr}; + +use crate::CallingConvention; + +#[derive(Debug)] +pub enum QemuError { + Init(QemuInitError), + Exit(QemuExitError), + RW(QemuRWError), +} + +#[derive(Debug)] +pub enum QemuInitError { + MultipleInstances, + NoParametersProvided, + EmptyArgs, + Infallible, + TooManyArgs(usize), +} + +#[derive(Debug, Clone)] +pub enum QemuExitError { + UnknownKind, // Exit reason was not NULL, but exit kind is unknown. Should never happen. + UnexpectedExit, // Qemu exited without going through an expected exit point. Can be caused by a crash for example. +} + +#[derive(Debug, Clone)] +pub enum QemuRWErrorKind { + Read, + Write, +} + +#[derive(Debug, Clone)] +pub enum QemuRWErrorCause { + WrongCallingConvention(CallingConvention, CallingConvention), // expected, given + WrongArgument(i32), + CurrentCpuNotFound, + Reg(i32), + WrongMemoryLocation(GuestAddr, usize), // addr, size +} + +#[derive(Debug, Clone)] +#[expect(dead_code)] +pub struct QemuRWError { + kind: QemuRWErrorKind, + cause: QemuRWErrorCause, + cpu: Option, // Only makes sense when cause != CurrentCpuNotFound +} + +impl std::error::Error for QemuInitError {} + +impl Display for QemuInitError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + QemuInitError::MultipleInstances => { + write!(f, "Only one instance of the QEMU Emulator is permitted") + } + QemuInitError::NoParametersProvided => { + write!(f, "No parameters were provided to initialize QEMU.") + } + QemuInitError::EmptyArgs => { + write!(f, "QEMU emulator args cannot be empty") + } + QemuInitError::TooManyArgs(n) => { + write!( + f, + "Too many arguments passed to QEMU emulator ({n} > i32::MAX)" + ) + } + QemuInitError::Infallible => { + panic!("Infallible error, should never be reached.") + } + } + } +} + +impl From for libafl::Error { + fn from(err: QemuInitError) -> Self { + libafl::Error::unknown(format!("{err}")) + } +} + +impl From for QemuInitError { + fn from(_: Infallible) -> Self { + QemuInitError::Infallible + } +} + +impl QemuRWError { + #[must_use] + pub fn new(kind: QemuRWErrorKind, cause: QemuRWErrorCause, cpu: Option) -> Self { + Self { kind, cause, cpu } + } + + pub fn wrong_reg(kind: QemuRWErrorKind, reg: R, cpu: Option) -> Self + where + R: Into + Clone, + { + Self::new(kind, QemuRWErrorCause::Reg(reg.into()), cpu) + } + + pub fn wrong_mem_location( + kind: QemuRWErrorKind, + cpu: CPUStatePtr, + addr: GuestAddr, + size: usize, + ) -> Self { + Self::new( + kind, + QemuRWErrorCause::WrongMemoryLocation(addr, size), + Some(cpu), + ) + } + + #[must_use] + pub fn current_cpu_not_found(kind: QemuRWErrorKind) -> Self { + Self::new(kind, QemuRWErrorCause::CurrentCpuNotFound, None) + } + + #[must_use] + pub fn new_argument_error(kind: QemuRWErrorKind, reg_id: i32) -> Self { + Self::new(kind, QemuRWErrorCause::WrongArgument(reg_id), None) + } + + pub fn check_conv( + kind: QemuRWErrorKind, + expected_conv: CallingConvention, + given_conv: CallingConvention, + ) -> Result<(), Self> { + if expected_conv != given_conv { + return Err(Self::new( + kind, + QemuRWErrorCause::WrongCallingConvention(expected_conv, given_conv), + None, + )); + } + + Ok(()) + } +} + +impl From for libafl::Error { + fn from(qemu_error: QemuError) -> Self { + libafl::Error::runtime(qemu_error) + } +} + +impl From for String { + fn from(qemu_error: QemuError) -> Self { + format!("LibAFL QEMU Error: {qemu_error:?}") + } +} diff --git a/libafl_qemu/src/qemu/hooks.rs b/libafl_qemu/src/qemu/hooks.rs index ea59e6d3e0..212e5fe948 100644 --- a/libafl_qemu/src/qemu/hooks.rs +++ b/libafl_qemu/src/qemu/hooks.rs @@ -100,16 +100,16 @@ impl Hook { } } -macro_rules! create_wrapper { +macro_rules! create_pre_init_wrapper { ($name:ident, ($($param:ident : $param_type:ty),*)) => { paste::paste! { - pub extern "C" fn [](hook: &mut c_void, $($param: $param_type),*) + pub extern "C" fn [](hook: &mut (), $($param: $param_type),*) where S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::(hook)); + let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::<()>(hook)); func(modules, inprocess_get_state::(), $($param),*); } } @@ -128,13 +128,13 @@ macro_rules! create_wrapper { }; ($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty) => { paste::paste! { - pub extern "C" fn [](hook: &mut c_void, $($param: $param_type),*) -> $ret_type + pub extern "C" fn [](hook: &mut (), $($param: $param_type),*) -> $ret_type where S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::(hook)); + let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::<()>(hook)); func(modules, inprocess_get_state::(), $($param),*) } } @@ -153,6 +153,63 @@ macro_rules! create_wrapper { }; } +macro_rules! create_wrapper { + ($name:ident, ($($param:ident : $param_type:ty),*)) => { + paste::paste! { + pub extern "C" fn [](hook: &mut (), $($param: $param_type),*) + where + S: UsesInput + Unpin, + { + unsafe { + let qemu = Qemu::get_unchecked(); + let modules = EmulatorModules::::emulator_modules_mut_unchecked(); + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::<()>(hook)); + func(qemu, modules, inprocess_get_state::(), $($param),*); + } + } + + pub extern "C" fn [](hook: &mut FatPtr, $($param: $param_type),*) + where + S: Unpin + UsesInput, + { + unsafe { + let qemu = Qemu::get_unchecked(); + let modules = EmulatorModules::::emulator_modules_mut_unchecked(); + let func: &mut Box, Option<&mut S>, $($param_type),*)> = &mut *(ptr::from_mut::(hook) as *mut Box, Option<&mut S>, $($param_type),*)>); + func(qemu, modules, inprocess_get_state::(), $($param),*); + } + } + } + }; + ($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty) => { + paste::paste! { + pub extern "C" fn [](hook: &mut (), $($param: $param_type),*) -> $ret_type + where + S: UsesInput + Unpin, + { + unsafe { + let qemu = Qemu::get_unchecked(); + let modules = EmulatorModules::::emulator_modules_mut_unchecked(); + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::<()>(hook)); + func(qemu, modules, inprocess_get_state::(), $($param),*) + } + } + + pub extern "C" fn [](hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type + where + S: UsesInput + Unpin, + { + unsafe { + let qemu = Qemu::get_unchecked(); + let modules = EmulatorModules::::emulator_modules_mut_unchecked(); + let func: &mut Box, Option<&mut S>, $($param_type),*) -> $ret_type> = &mut *(ptr::from_mut::(hook) as *mut Box, Option<&mut S>, $($param_type),*) -> $ret_type>); + func(qemu, modules, inprocess_get_state::(), $($param),*) + } + } + } + }; +} + macro_rules! create_pre_exec_wrapper { ($name:ident, ($($param:ident : $param_type:ty),*), $hook_id:ident) => { paste::paste! { @@ -161,21 +218,22 @@ macro_rules! create_pre_exec_wrapper { S: UsesInput + Unpin, { unsafe { + let qemu = Qemu::get_unchecked(); let modules = EmulatorModules::::emulator_modules_mut_unchecked(); match &mut hook.pre_run { HookRepr::Function(ptr) => { - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) = + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(*ptr); - func(modules, inprocess_get_state::(), $($param),*) + func(qemu, modules, inprocess_get_state::(), $($param),*) } HookRepr::Closure(ptr) => { let func: &mut Box< - dyn FnMut(&mut EmulatorModules, Option<&mut S>, $($param_type),*), + dyn FnMut(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*), > = &mut *(ptr::from_mut::(ptr) as *mut Box< - dyn FnMut(&mut EmulatorModules, Option<&mut S>, $($param_type),*), + dyn FnMut(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*), >); - func(modules, inprocess_get_state::(), $($param),*) + func(qemu, modules, inprocess_get_state::(), $($param),*) } _ => (), } @@ -193,21 +251,22 @@ macro_rules! create_post_exec_wrapper { S: UsesInput + Unpin, { unsafe { + let qemu = Qemu::get_unchecked(); let modules = EmulatorModules::::emulator_modules_mut_unchecked(); match &mut hook.post_run { HookRepr::Function(ptr) => { - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) = + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(*ptr); - func(modules, inprocess_get_state::(), $($param),*); + func(qemu, modules, inprocess_get_state::(), $($param),*); } HookRepr::Closure(ptr) => { let func: &mut Box< - dyn FnMut(&mut EmulatorModules, Option<&mut S>, $($param_type),*), + dyn FnMut(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*), > = &mut *(ptr::from_mut::(ptr) as *mut Box< - dyn FnMut(&mut EmulatorModules, Option<&mut S>, $($param_type),*), + dyn FnMut(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*), >); - func(modules, inprocess_get_state::(), $($param),*); + func(qemu, modules, inprocess_get_state::(), $($param),*); } _ => (), } @@ -225,19 +284,20 @@ macro_rules! create_gen_wrapper { S: UsesInput + Unpin, { unsafe { + let qemu = Qemu::get_unchecked(); let modules = EmulatorModules::::emulator_modules_mut_unchecked(); match &mut hook.gen { HookRepr::Function(ptr) => { - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) -> Option<$ret_type> = + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) -> Option<$ret_type> = transmute(*ptr); - func(modules, inprocess_get_state::(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id) + func(qemu, modules, inprocess_get_state::(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id) } HookRepr::Closure(ptr) => { let func: &mut Box< - dyn FnMut(&mut EmulatorModules, Option<&mut S>, $($param_type),*) -> Option<$ret_type>, - > = &mut *(ptr::from_mut::(ptr) as *mut Box, Option<&mut S>, $($param_type),*) -> Option<$ret_type>>); - func(modules, inprocess_get_state::(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id) + dyn FnMut(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) -> Option<$ret_type>, + > = &mut *(ptr::from_mut::(ptr) as *mut Box, Option<&mut S>, $($param_type),*) -> Option<$ret_type>>); + func(qemu, modules, inprocess_get_state::(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id) } _ => 0, } @@ -255,18 +315,20 @@ macro_rules! create_post_gen_wrapper { S: UsesInput + Unpin, { unsafe { + let qemu = Qemu::get_unchecked(); let modules = EmulatorModules::::emulator_modules_mut_unchecked(); + match &mut hook.post_gen { HookRepr::Function(ptr) => { - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) = + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(*ptr); - func(modules, inprocess_get_state::(), $($param),*); + func(qemu, modules, inprocess_get_state::(), $($param),*); } HookRepr::Closure(ptr) => { let func: &mut Box< - dyn FnMut(&mut EmulatorModules, Option<&mut S>, $($param_type),*), - > = &mut *(ptr::from_mut::(ptr) as *mut Box, Option<&mut S>, $($param_type),*)>); - func(modules, inprocess_get_state::(), $($param),*); + dyn FnMut(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*), + > = &mut *(ptr::from_mut::(ptr) as *mut Box, Option<&mut S>, $($param_type),*)>); + func(qemu, modules, inprocess_get_state::(), $($param),*); } _ => (), } @@ -284,16 +346,18 @@ macro_rules! create_exec_wrapper { S: UsesInput + Unpin, { unsafe { + let qemu = Qemu::get_unchecked(); let modules = EmulatorModules::::emulator_modules_mut_unchecked(); + match &mut hook.execs[$execidx] { HookRepr::Function(ptr) => { - let func: fn(&mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(*ptr); - func(modules, inprocess_get_state::(), $($param),*); + let func: fn(Qemu, &mut EmulatorModules, Option<&mut S>, $($param_type),*) = transmute(*ptr); + func(qemu, modules, inprocess_get_state::(), $($param),*); } HookRepr::Closure(ptr) => { - let func: &mut Box, Option<&mut S>, $($param_type),*)> = - &mut *(ptr::from_mut::(ptr) as *mut Box, Option<&mut S>, $($param_type),*)>); - func(modules, inprocess_get_state::(), $($param),*); + let func: &mut Box, Option<&mut S>, $($param_type),*)> = + &mut *(ptr::from_mut::(ptr) as *mut Box, Option<&mut S>, $($param_type),*)>); + func(qemu, modules, inprocess_get_state::(), $($param),*); } _ => (), } @@ -359,8 +423,8 @@ macro_rules! create_hook_types { // Instruction hook wrappers create_hook_types!( Instruction, - fn(&mut EmulatorModules, Option<&mut S>, GuestAddr), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, GuestAddr)>, + fn(Qemu, &mut EmulatorModules, Option<&mut S>, GuestAddr), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr)>, extern "C" fn(*const (), pc: GuestAddr) ); create_hook_id!(Instruction, libafl_qemu_remove_instruction_hook, true); @@ -369,9 +433,9 @@ create_wrapper!(instruction, (pc: GuestAddr)); // Backdoor hook wrappers create_hook_types!( Backdoor, - fn(&mut EmulatorModules, Option<&mut S>, cpu: CPUArchStatePtr, GuestAddr), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, GuestAddr)>, - extern "C" fn(*const (), cpu: CPUArchStatePtr, pc: GuestAddr) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, cpu: CPUArchStatePtr, GuestAddr), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr)>, + extern "C" fn(libafl_qemu_opaque: *const (), cpu: CPUArchStatePtr, pc: GuestAddr) ); create_hook_id!(Backdoor, libafl_qemu_remove_backdoor_hook, true); create_wrapper!(backdoor, (cpu: CPUArchStatePtr, pc: GuestAddr)); @@ -381,6 +445,7 @@ create_wrapper!(backdoor, (cpu: CPUArchStatePtr, pc: GuestAddr)); create_hook_types!( PreSyscall, fn( + Qemu, &mut EmulatorModules, Option<&mut S>, sys_num: i32, @@ -395,6 +460,7 @@ create_hook_types!( ) -> SyscallHookResult, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&'a mut S>, i32, @@ -445,6 +511,7 @@ create_wrapper!( create_hook_types!( PostSyscall, fn( + Qemu, &mut EmulatorModules, Option<&mut S>, res: GuestAddr, @@ -460,6 +527,7 @@ create_hook_types!( ) -> GuestAddr, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&mut S>, GuestAddr, @@ -520,23 +588,23 @@ create_hook_types!( u32, ) -> bool, >, - extern "C" fn(*const (), env: CPUArchStatePtr, tid: u32) -> bool + extern "C" fn(libafl_qemu_opaque: *const (), env: CPUArchStatePtr, tid: u32) -> bool ); create_hook_id!(NewThread, libafl_qemu_remove_new_thread_hook, false); -create_wrapper!(new_thread, (env: CPUArchStatePtr, tid: u32), bool); +create_pre_init_wrapper!(new_thread, (env: CPUArchStatePtr, tid: u32), bool); // CPU Run hook wrappers create_hook_types!( CpuPreRun, - fn(&mut EmulatorModules, Option<&mut S>, cpu: CPUStatePtr), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, CPUStatePtr)>, - extern "C" fn(*const (), cpu: CPUStatePtr) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, cpu: CPUStatePtr), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, CPUStatePtr)>, + extern "C" fn(libafl_qemu_opaque: *const (), cpu: CPUStatePtr) ); create_hook_types!( CpuPostRun, - fn(&mut EmulatorModules, Option<&mut S>, cpu: CPUStatePtr), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, CPUStatePtr)>, - extern "C" fn(*const (), cpu: CPUStatePtr) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, cpu: CPUStatePtr), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, CPUStatePtr)>, + extern "C" fn(libafl_qemu_opaque: *const (), cpu: CPUStatePtr) ); create_hook_id!(CpuRun, libafl_qemu_remove_cpu_run_hook, false); create_pre_exec_wrapper!(cpu_run, (cpu: CPUStatePtr), CpuRunHookId); @@ -546,22 +614,29 @@ create_wrapper!(cpu_run, (cpu: CPUStatePtr)); // Edge hook wrappers create_hook_types!( EdgeGen, - fn(&mut EmulatorModules, Option<&mut S>, src: GuestAddr, dest: GuestAddr) -> Option, + fn( + Qemu, + &mut EmulatorModules, + Option<&mut S>, + src: GuestAddr, + dest: GuestAddr, + ) -> Option, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr, GuestAddr, ) -> Option, >, - extern "C" fn(*const (), src: GuestAddr, dest: GuestAddr) -> u64 + extern "C" fn(libafl_qemu_opaque: *const (), src: GuestAddr, dest: GuestAddr) -> u64 ); create_hook_types!( EdgeExec, - fn(&mut EmulatorModules, Option<&mut S>, id: u64), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, u64)>, - unsafe extern "C" fn(*const (), id: u64) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, id: u64), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, u64)>, + unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64) ); create_hook_id!(Edge, libafl_qemu_remove_edge_hook, true); create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId); @@ -570,27 +645,36 @@ create_exec_wrapper!(edge, (id: u64), 0, 1, EdgeHookId); // Block hook wrappers create_hook_types!( BlockGen, - fn(&mut EmulatorModules, Option<&mut S>, pc: GuestAddr) -> Option, + fn(Qemu, &mut EmulatorModules, Option<&mut S>, pc: GuestAddr) -> Option, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr, ) -> Option, >, - unsafe extern "C" fn(*const (), pc: GuestAddr) -> u64 + unsafe extern "C" fn(libafl_qemu_opaque: *const (), pc: GuestAddr) -> u64 ); create_hook_types!( BlockPostGen, - fn(&mut EmulatorModules, Option<&mut S>, pc: GuestAddr, block_length: GuestUsize), - Box FnMut(&'a mut EmulatorModules, Option<&mut S>, GuestAddr, GuestUsize)>, - unsafe extern "C" fn(*const (), pc: GuestAddr, block_length: GuestUsize) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, pc: GuestAddr, block_length: GuestUsize), + Box< + dyn for<'a> FnMut( + Qemu, + &'a mut EmulatorModules, + Option<&mut S>, + GuestAddr, + GuestUsize, + ), + >, + unsafe extern "C" fn(libafl_qemu_opaque: *const (), pc: GuestAddr, block_length: GuestUsize) ); create_hook_types!( BlockExec, - fn(&mut EmulatorModules, Option<&mut S>, id: u64), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, u64)>, - unsafe extern "C" fn(*const (), id: u64) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, id: u64), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, u64)>, + unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64) ); create_hook_id!(Block, libafl_qemu_remove_block_hook, true); @@ -602,7 +686,8 @@ create_exec_wrapper!(block, (id: u64), 0, 1, BlockHookId); create_hook_types!( ReadGen, fn( - qemu_modules: &mut EmulatorModules, + Qemu, + emulator_modules: &mut EmulatorModules, Option<&mut S>, pc: GuestAddr, addr: *mut TCGTemp, @@ -610,6 +695,7 @@ create_hook_types!( ) -> Option, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr, @@ -617,21 +703,33 @@ create_hook_types!( MemAccessInfo, ) -> Option, >, - unsafe extern "C" fn(*const (), pc: GuestAddr, addr: *mut TCGTemp, info: MemAccessInfo) -> u64 + unsafe extern "C" fn( + libafl_qemu_opaque: *const (), + pc: GuestAddr, + addr: *mut TCGTemp, + info: MemAccessInfo, + ) -> u64 ); create_hook_types!( ReadExec, - fn(&mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, u64, GuestAddr)>, - unsafe extern "C" fn(*const (), id: u64, addr: GuestAddr) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, u64, GuestAddr)>, + unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64, addr: GuestAddr) ); create_hook_types!( ReadExecN, - fn(&mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), + fn(Qemu, &mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), Box< - dyn for<'a> FnMut(&'a mut EmulatorModules, Option<&'a mut S>, u64, GuestAddr, usize), + dyn for<'a> FnMut( + Qemu, + &'a mut EmulatorModules, + Option<&'a mut S>, + u64, + GuestAddr, + usize, + ), >, - unsafe extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize) + unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64, addr: GuestAddr, size: usize) ); create_hook_id!(Read, libafl_qemu_remove_read_hook, true); create_gen_wrapper!(read, (pc: GuestAddr, addr: *mut TCGTemp, info: MemAccessInfo), u64, 5, ReadHookId); @@ -651,6 +749,7 @@ create_exec_wrapper!( create_hook_types!( WriteGen, fn( + Qemu, &mut EmulatorModules, Option<&mut S>, pc: GuestAddr, @@ -659,6 +758,7 @@ create_hook_types!( ) -> Option, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr, @@ -666,21 +766,33 @@ create_hook_types!( MemAccessInfo, ) -> Option, >, - unsafe extern "C" fn(*const (), pc: GuestAddr, addr: *mut TCGTemp, info: MemAccessInfo) -> u64 + unsafe extern "C" fn( + libafl_qemu_opaque: *const (), + pc: GuestAddr, + addr: *mut TCGTemp, + info: MemAccessInfo, + ) -> u64 ); create_hook_types!( WriteExec, - fn(&mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr), - Box FnMut(&'a mut EmulatorModules, Option<&'a mut S>, u64, GuestAddr)>, - unsafe extern "C" fn(*const (), id: u64, addr: GuestAddr) + fn(Qemu, &mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(Qemu, &'a mut EmulatorModules, Option<&'a mut S>, u64, GuestAddr)>, + unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64, addr: GuestAddr) ); create_hook_types!( WriteExecN, - fn(&mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), + fn(Qemu, &mut EmulatorModules, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), Box< - dyn for<'a> FnMut(&'a mut EmulatorModules, Option<&'a mut S>, u64, GuestAddr, usize), + dyn for<'a> FnMut( + Qemu, + &'a mut EmulatorModules, + Option<&'a mut S>, + u64, + GuestAddr, + usize, + ), >, - unsafe extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize) + unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64, addr: GuestAddr, size: usize) ); create_hook_id!(Write, libafl_qemu_remove_write_hook, true); create_gen_wrapper!(write, (pc: GuestAddr, addr: *mut TCGTemp, info: MemAccessInfo), u64, 5, WriteHookId); @@ -699,16 +811,23 @@ create_exec_wrapper!( // Cmp hook wrappers create_hook_types!( CmpGen, - fn(&mut EmulatorModules, Option<&mut S>, pc: GuestAddr, size: usize) -> Option, + fn( + Qemu, + &mut EmulatorModules, + Option<&mut S>, + pc: GuestAddr, + size: usize, + ) -> Option, Box< dyn for<'a> FnMut( + Qemu, &'a mut EmulatorModules, Option<&'a mut S>, GuestAddr, usize, ) -> Option, >, - unsafe extern "C" fn(*const (), pc: GuestAddr, size: usize) -> u64 + unsafe extern "C" fn(libafl_qemu_opaque: *const (), pc: GuestAddr, size: usize) -> u64 ); pub type CmpExecHook = Hook< fn(&mut EmulatorModules, Option<&mut S>, id: u64, v0: SZ, v1: SZ), @@ -724,9 +843,9 @@ create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4, CmpHookId); // Crash hook wrappers #[cfg(feature = "usermode")] -pub type CrashHookFn = fn(&mut EmulatorModules, i32); +pub type CrashHookFn = fn(Qemu, &mut EmulatorModules, i32); #[cfg(feature = "usermode")] -pub type CrashHookClosure = Box, i32)>; +pub type CrashHookClosure = Box, i32)>; /// The thin wrapper around QEMU hooks. /// It is considered unsafe to use it directly. diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index 52916c38fb..482830dd01 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -14,6 +14,7 @@ use std::{ mem::MaybeUninit, ops::Range, pin::Pin, + sync::OnceLock, }; use libafl_bolts::os::unix_signals::Signal; @@ -31,7 +32,12 @@ use strum::IntoEnumIterator; use crate::{GuestAddrKind, GuestReg, Regs}; pub mod config; -use config::{QemuConfig, QemuConfigBuilder, QEMU_CONFIG}; +use config::QemuConfig; + +pub mod error; +pub use error::{ + QemuError, QemuExitError, QemuInitError, QemuRWError, QemuRWErrorCause, QemuRWErrorKind, +}; #[cfg(feature = "usermode")] mod usermode; @@ -48,30 +54,33 @@ pub use hooks::*; static mut QEMU_IS_INITIALIZED: bool = false; -#[derive(Debug)] -pub enum QemuError { - Init(QemuInitError), - Exit(QemuExitError), - RW(QemuRWError), -} +pub(super) static QEMU_CONFIG: OnceLock = OnceLock::new(); -impl From for libafl::Error { - fn from(qemu_error: QemuError) -> Self { - libafl::Error::runtime(qemu_error) - } -} +#[expect(clippy::vec_box)] +static mut GDB_COMMANDS: Vec> = Vec::new(); -impl From for String { - fn from(qemu_error: QemuError) -> Self { - format!("LibAFL QEMU Error: {qemu_error:?}") - } +pub trait HookId { + fn remove(&self, invalidate_block: bool) -> bool; } -#[derive(Debug)] -pub enum QemuInitError { - MultipleInstances, - EmptyArgs, - TooManyArgs(usize), +pub trait ArchExtras { + fn read_return_address(&self) -> Result; + fn write_return_address(&self, val: T) -> Result<(), QemuRWError> + where + T: Into; + fn read_function_argument( + &self, + conv: CallingConvention, + idx: u8, + ) -> Result; + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), QemuRWError> + where + T: Into; } #[derive(Debug, Clone)] @@ -89,81 +98,6 @@ pub enum QemuExitReason { Timeout, } -#[derive(Debug, Clone)] -pub enum QemuExitError { - UnknownKind, // Exit reason was not NULL, but exit kind is unknown. Should never happen. - UnexpectedExit, // Qemu exited without going through an expected exit point. Can be caused by a crash for example. -} - -#[derive(Debug, Clone)] -pub enum QemuRWErrorKind { - Read, - Write, -} - -#[derive(Debug, Clone)] -pub enum QemuRWErrorCause { - WrongCallingConvention(CallingConvention, CallingConvention), // expected, given - WrongArgument(i32), - CurrentCpuNotFound, - Reg(i32), - WrongMemoryLocation(GuestAddr, usize), // addr, size -} - -#[derive(Debug, Clone)] -#[expect(dead_code)] -pub struct QemuRWError { - kind: QemuRWErrorKind, - cause: QemuRWErrorCause, - cpu: Option, // Only makes sense when cause != CurrentCpuNotFound -} - -impl QemuRWError { - #[must_use] - pub fn new(kind: QemuRWErrorKind, cause: QemuRWErrorCause, cpu: Option) -> Self { - Self { kind, cause, cpu } - } - - pub fn wrong_mem_location( - kind: QemuRWErrorKind, - cpu: CPUStatePtr, - addr: GuestAddr, - size: usize, - ) -> Self { - Self::new( - kind, - QemuRWErrorCause::WrongMemoryLocation(addr, size), - Some(cpu), - ) - } - - #[must_use] - pub fn current_cpu_not_found(kind: QemuRWErrorKind) -> Self { - Self::new(kind, QemuRWErrorCause::CurrentCpuNotFound, None) - } - - #[must_use] - pub fn new_argument_error(kind: QemuRWErrorKind, reg_id: i32) -> Self { - Self::new(kind, QemuRWErrorCause::WrongArgument(reg_id), None) - } - - pub fn check_conv( - kind: QemuRWErrorKind, - expected_conv: CallingConvention, - given_conv: CallingConvention, - ) -> Result<(), Self> { - if expected_conv != given_conv { - return Err(Self::new( - kind, - QemuRWErrorCause::WrongCallingConvention(expected_conv, given_conv), - None, - )); - } - - Ok(()) - } -} - /// The thin wrapper around QEMU. /// It is considered unsafe to use it directly. /// Prefer using `Emulator` instead in case of doubt. @@ -172,6 +106,12 @@ pub struct Qemu { _private: (), } +#[derive(Clone, Debug)] +pub enum QemuParams { + Config(QemuConfig), + Cli(Vec), +} + #[derive(Debug, Clone)] pub struct QemuMemoryChunk { addr: GuestAddrKind, @@ -179,18 +119,6 @@ pub struct QemuMemoryChunk { cpu: Option, } -#[expect(clippy::vec_box)] -static mut GDB_COMMANDS: Vec> = Vec::new(); - -unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { - unsafe { - let closure = &mut *(data as *mut Box FnMut(Qemu, &'r str) -> bool>); - let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); - let qemu = Qemu::get_unchecked(); - closure(qemu, cmd) - } -} - #[derive(Debug, Clone)] pub enum QemuShutdownCause { None, @@ -223,37 +151,15 @@ pub enum CallingConvention { Cdecl, } -pub trait HookId { - fn remove(&self, invalidate_block: bool) -> bool; -} - #[derive(Debug)] pub struct HookData(u64); -impl std::error::Error for QemuInitError {} - -impl Display for QemuInitError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - QemuInitError::MultipleInstances => { - write!(f, "Only one instance of the QEMU Emulator is permitted") - } - QemuInitError::EmptyArgs => { - write!(f, "QEMU emulator args cannot be empty") - } - QemuInitError::TooManyArgs(n) => { - write!( - f, - "Too many arguments passed to QEMU emulator ({n} > i32::MAX)" - ) - } - } - } -} - -impl From for libafl::Error { - fn from(err: QemuInitError) -> Self { - libafl::Error::unknown(format!("{err}")) +unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { + unsafe { + let closure = &mut *(data as *mut Box FnMut(Qemu, &'r str) -> bool>); + let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); + let qemu = Qemu::get_unchecked(); + closure(qemu, cmd) } } @@ -268,6 +174,64 @@ impl Display for QemuExitReason { } } +impl From for QemuParams { + fn from(config: QemuConfig) -> Self { + QemuParams::Config(config) + } +} + +// impl TryFrom for QemuParams { +// type Error = QemuInitError; +// +// fn try_from(config_builder: QemuConfigBuilder) -> Result { +// Ok(QemuParams::Config( +// config_builder +// .build() +// .map_err(QemuInitError::ConfigurationError)?, +// )) +// } +// } + +impl From<&[T]> for QemuParams +where + T: AsRef, +{ + fn from(cli: &[T]) -> Self { + QemuParams::Cli(cli.iter().map(|x| x.as_ref().into()).collect()) + } +} + +impl From<&Vec> for QemuParams +where + T: AsRef, +{ + fn from(cli: &Vec) -> Self { + cli.as_slice().into() + } +} + +impl From> for QemuParams +where + T: AsRef, +{ + fn from(cli: Vec) -> Self { + (&cli).into() + } +} + +impl QemuParams { + pub fn to_cli(&self) -> Vec { + match self { + QemuParams::Config(cfg) => cfg + .to_string() + .split(' ') + .map(ToString::to_string) + .collect(), + QemuParams::Cli(cli) => cli.clone(), + } + } +} + impl MemAccessInfo { #[must_use] pub fn memop(&self) -> libafl_qemu_sys::MemOp { @@ -318,26 +282,6 @@ impl From for MemAccessInfo { } } -pub trait ArchExtras { - fn read_return_address(&self) -> Result; - fn write_return_address(&self, val: T) -> Result<(), QemuRWError> - where - T: Into; - fn read_function_argument( - &self, - conv: CallingConvention, - idx: u8, - ) -> Result; - fn write_function_argument( - &self, - conv: CallingConvention, - idx: i32, - val: T, - ) -> Result<(), QemuRWError> - where - T: Into; -} - impl CPU { #[must_use] #[expect(clippy::cast_sign_loss)] @@ -367,11 +311,11 @@ impl CPU { let mut val = MaybeUninit::uninit(); let success = libafl_qemu_read_reg(self.ptr, reg_id, val.as_mut_ptr() as *mut u8); if success == 0 { - Err(QemuRWError { - kind: QemuRWErrorKind::Write, - cause: QemuRWErrorCause::Reg(reg.into()), - cpu: Some(self.ptr), - }) + Err(QemuRWError::wrong_reg( + QemuRWErrorKind::Write, + reg, + Some(self.ptr), + )) } else { #[cfg(feature = "be")] return Ok(GuestReg::from_be(val.assume_init()).into()); @@ -396,11 +340,11 @@ impl CPU { let success = unsafe { libafl_qemu_write_reg(self.ptr, reg_id, &raw const val as *mut u8) }; if success == 0 { - Err(QemuRWError { - kind: QemuRWErrorKind::Write, - cause: QemuRWErrorCause::Reg(reg.into()), - cpu: Some(self.ptr), - }) + Err(QemuRWError::wrong_reg( + QemuRWErrorKind::Write, + reg, + Some(self.ptr), + )) } else { Ok(()) } @@ -571,14 +515,25 @@ impl From for HookData { } impl Qemu { - /// For more details about the parameters check - /// [the QEMU documentation](https://www.qemu.org/docs/master/about/). - pub fn builder() -> QemuConfigBuilder { - QemuConfig::builder() - } - #[expect(clippy::similar_names)] - pub fn init(args: &[String]) -> Result { + pub fn init(params: T) -> Result + where + T: Into, + { + let params: QemuParams = params.into(); + + match ¶ms { + QemuParams::Config(cfg) => { + QEMU_CONFIG + .set(cfg.clone()) + .map_err(|_| unreachable!("QEMU_CONFIG was already set but Qemu was not init!")) + .expect("Could not set QEMU Config."); + } + QemuParams::Cli(_) => {} + }; + + let args = params.to_cli(); + if args.is_empty() { return Err(QemuInitError::EmptyArgs); } @@ -592,6 +547,7 @@ impl Qemu { if QEMU_IS_INITIALIZED { return Err(QemuInitError::MultipleInstances); } + QEMU_IS_INITIALIZED = true; } @@ -600,7 +556,7 @@ impl Qemu { let args: Vec = args .iter() - .map(|x| CString::new(x.clone()).unwrap()) + .map(|x| CString::new(AsRef::::as_ref(x)).unwrap()) .collect(); let mut argv: Vec<*const u8> = args.iter().map(|x| x.as_ptr() as *const u8).collect(); argv.push(ptr::null()); // argv is always null terminated. @@ -904,11 +860,7 @@ impl Qemu { impl ArchExtras for Qemu { fn read_return_address(&self) -> Result { self.current_cpu() - .ok_or(QemuRWError { - kind: QemuRWErrorKind::Read, - cause: QemuRWErrorCause::CurrentCpuNotFound, - cpu: None, - })? + .ok_or(QemuRWError::current_cpu_not_found(QemuRWErrorKind::Read))? .read_return_address() } diff --git a/libafl_qemu/src/qemu/systemmode.rs b/libafl_qemu/src/qemu/systemmode.rs index c76898a293..cbdfd5d9a5 100644 --- a/libafl_qemu/src/qemu/systemmode.rs +++ b/libafl_qemu/src/qemu/systemmode.rs @@ -263,8 +263,8 @@ impl Qemu { libafl_qemu_sys::syx_snapshot_root_restore(snapshot); } - #[allow(clippy::missing_safety_doc)] #[must_use] + #[expect(clippy::missing_safety_doc)] pub unsafe fn check_fast_snapshot( &self, ref_snapshot: FastSnapshotPtr, diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 124342d999..097b6e9587 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -118,7 +118,7 @@ where { /// Run the fuzzer #[expect(clippy::too_many_lines)] - pub fn run(&mut self, qemu: Qemu) { + pub fn run(&mut self, qemu_cli: &[String]) { let conf = match self.configuration.as_ref() { Some(name) => EventConfig::from_name(name), None => EventConfig::AlwaysUnique, @@ -240,7 +240,11 @@ where ExitKind::Ok }; - let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?; + let emulator = Emulator::empty() + .qemu_parameters(qemu_cli.to_owned()) + .modules(modules) + .build() + .expect("Could not initialize Emulator"); let executor = QemuExecutor::new( emulator, @@ -357,7 +361,11 @@ where ExitKind::Ok }; - let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?; + let emulator = Emulator::empty() + .qemu_parameters(qemu_cli.to_owned()) + .modules(modules) + .build() + .expect("Could not initialize Emulator"); let mut executor = QemuExecutor::new( emulator, @@ -476,7 +484,6 @@ pub mod pybind { use std::path::PathBuf; use libafl_bolts::core_affinity::Cores; - use libafl_qemu::qemu::pybind::Qemu; use pyo3::{prelude::*, types::PyBytes}; use crate::qemu; @@ -533,7 +540,7 @@ pub mod pybind { /// Run the fuzzer #[expect(clippy::needless_pass_by_value)] - pub fn run(&self, qemu: &Qemu, harness: PyObject) { + pub fn run(&self, qemu_cli: Vec, harness: PyObject) { qemu::QemuBytesCoverageSugar::builder() .input_dirs(&self.input_dirs) .output_dir(self.output_dir.clone()) @@ -552,7 +559,7 @@ pub mod pybind { .tokens_file(self.tokens_file.clone()) .iterations(self.iterations) .build() - .run(qemu.qemu); + .run(&qemu_cli); } } From 17336dcf57f72e6fb0de0a56451b99d1b1ef0596 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 6 Jan 2025 16:58:57 +0100 Subject: [PATCH 23/25] Nyx hypercall API support for LibAFL QEMU (#2801) * Nyx hypercall API support * fix linux kernel fuzzer * hash_me -> hash_64_fast * fix multiple bug in kernel harness * do not check libmozjpeg's C files format. --- .../binary_only/qemu_coverage/src/fuzzer.rs | 4 +- .../binary_only/qemu_launcher/src/instance.rs | 6 +- .../full_system/qemu_linux_kernel/Cargo.toml | 14 +- .../qemu_linux_kernel/Makefile.toml | 19 +- .../qemu_linux_kernel/setup/Makefile | 6 +- .../qemu_linux_kernel/setup/harness.c | 14 +- .../qemu_linux_kernel/setup/setup.sh | 6 +- .../qemu_linux_kernel/src/fuzzer.rs | 39 +- .../full_system/qemu_linux_process/Cargo.toml | 13 +- .../qemu_linux_process/Makefile.toml | 48 +- .../qemu_linux_process/example/harness_nyx.c | 137 + .../qemu_linux_process/src/fuzzer.rs | 62 +- .../libfuzzer_libmozjpeg/hook_allocs.c | 4 +- libafl_bolts/src/lib.rs | 13 + libafl_intelpt/src/lib.rs | 19 +- libafl_qemu/Cargo.toml | 3 + libafl_qemu/build_linux.rs | 37 + libafl_qemu/libafl_qemu_build/Cargo.toml | 2 + libafl_qemu/libafl_qemu_build/src/bindings.rs | 6 +- libafl_qemu/libafl_qemu_build/src/build.rs | 136 +- libafl_qemu/libafl_qemu_sys/Cargo.toml | 4 + .../src/bindings/x86_64_stub_bindings.rs | 2764 +++++++++++++---- libafl_qemu/runtime/libafl_qemu_arch.h | 23 +- .../runtime/libafl_qemu_stub_bindings.rs | 242 +- libafl_qemu/runtime/nyx_api.h | 185 ++ libafl_qemu/runtime/nyx_stub_bindings.rs | 1255 ++++++++ libafl_qemu/src/command/mod.rs | 2 + libafl_qemu/src/command/nyx.rs | 532 ++++ .../src/command/{parser.rs => parser/mod.rs} | 3 + libafl_qemu/src/command/parser/nyx.rs | 189 ++ .../src/emu/{drivers.rs => drivers/mod.rs} | 20 +- libafl_qemu/src/emu/drivers/nyx.rs | 223 ++ libafl_qemu/src/emu/mod.rs | 28 +- libafl_qemu/src/emu/snapshot.rs | 2 + libafl_qemu/src/modules/calls.rs | 5 +- libafl_qemu/src/modules/cmplog.rs | 11 +- libafl_qemu/src/modules/drcov.rs | 6 +- libafl_qemu/src/modules/edges/child.rs | 3 +- libafl_qemu/src/modules/edges/classic.rs | 3 +- libafl_qemu/src/modules/edges/full.rs | 3 +- libafl_qemu/src/modules/edges/helpers.rs | 7 +- libafl_qemu/src/modules/mod.rs | 235 +- libafl_qemu/src/modules/usermode/asan.rs | 2 +- .../src/modules/usermode/asan_guest.rs | 4 +- .../src/modules/usermode/injections.rs | 5 +- libafl_qemu/src/modules/usermode/snapshot.rs | 5 +- libafl_qemu/src/modules/utils/filters.rs | 221 ++ libafl_qemu/src/modules/utils/mod.rs | 1 + libafl_qemu/src/qemu/error.rs | 18 +- libafl_qemu/src/qemu/mod.rs | 2 +- libafl_qemu/src/qemu/usermode.rs | 4 +- libafl_qemu/src/sync_exit.rs | 8 +- utils/libafl_fmt/src/main.rs | 1 + 53 files changed, 5352 insertions(+), 1252 deletions(-) create mode 100644 fuzzers/full_system/qemu_linux_process/example/harness_nyx.c create mode 100644 libafl_qemu/runtime/nyx_api.h create mode 100644 libafl_qemu/runtime/nyx_stub_bindings.rs create mode 100644 libafl_qemu/src/command/nyx.rs rename libafl_qemu/src/command/{parser.rs => parser/mod.rs} (99%) create mode 100644 libafl_qemu/src/command/parser/nyx.rs rename libafl_qemu/src/emu/{drivers.rs => drivers/mod.rs} (94%) create mode 100644 libafl_qemu/src/emu/drivers/nyx.rs create mode 100644 libafl_qemu/src/modules/utils/filters.rs create mode 100644 libafl_qemu/src/modules/utils/mod.rs diff --git a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs index f57b33a887..e3fed6483a 100644 --- a/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_coverage/src/fuzzer.rs @@ -30,8 +30,8 @@ use libafl_bolts::{ }; use libafl_qemu::{ elf::EasyElf, - modules::{drcov::DrCovModule, StdAddressFilter}, - ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, QemuExecutor, + modules::{drcov::DrCovModule, utils::filters::StdAddressFilter}, + ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExecutor, QemuExitReason, QemuRWError, QemuShutdownCause, Regs, }; diff --git a/fuzzers/binary_only/qemu_launcher/src/instance.rs b/fuzzers/binary_only/qemu_launcher/src/instance.rs index a08d73d7fa..6475562429 100644 --- a/fuzzers/binary_only/qemu_launcher/src/instance.rs +++ b/fuzzers/binary_only/qemu_launcher/src/instance.rs @@ -39,8 +39,10 @@ use libafl_bolts::{ use libafl_qemu::{ elf::EasyElf, modules::{ - cmplog::CmpLogObserver, edges::EdgeCoverageFullVariant, EdgeCoverageModule, EmulatorModule, - EmulatorModuleTuple, NopPageFilter, StdAddressFilter, StdEdgeCoverageModule, + cmplog::CmpLogObserver, + edges::EdgeCoverageFullVariant, + utils::filters::{NopPageFilter, StdAddressFilter}, + EdgeCoverageModule, EmulatorModule, EmulatorModuleTuple, StdEdgeCoverageModule, }, Emulator, GuestAddr, Qemu, QemuExecutor, }; diff --git a/fuzzers/full_system/qemu_linux_kernel/Cargo.toml b/fuzzers/full_system/qemu_linux_kernel/Cargo.toml index 9035d9b1e1..3b36005bdc 100644 --- a/fuzzers/full_system/qemu_linux_kernel/Cargo.toml +++ b/fuzzers/full_system/qemu_linux_kernel/Cargo.toml @@ -17,19 +17,15 @@ lto = "fat" codegen-units = 1 [dependencies] -libafl = { path = "../../../../../libafl" } -libafl_bolts = { path = "../../../../../libafl_bolts" } -libafl_qemu = { path = "../../../../../libafl_qemu", features = [ - "x86_64", - "systemmode", - #"paranoid_debug" -] } -libafl_qemu_sys = { path = "../../../../../libafl_qemu/libafl_qemu_sys", features = [ +libafl = { path = "../../../libafl" } +libafl_bolts = { path = "../../../libafl_bolts" } +libafl_qemu = { path = "../../../libafl_qemu", default-features = false, features = [ "x86_64", "systemmode", #"paranoid_debug" ] } +libafl_targets = { path = "../../../libafl_targets" } env_logger = "0.11.5" [build-dependencies] -libafl_qemu_build = { path = "../../../../../libafl_qemu/libafl_qemu_build" } +libafl_qemu_build = { path = "../../../libafl_qemu/libafl_qemu_build" } diff --git a/fuzzers/full_system/qemu_linux_kernel/Makefile.toml b/fuzzers/full_system/qemu_linux_kernel/Makefile.toml index 9fec43ecbe..8aa6673084 100644 --- a/fuzzers/full_system/qemu_linux_kernel/Makefile.toml +++ b/fuzzers/full_system/qemu_linux_kernel/Makefile.toml @@ -100,20 +100,23 @@ else LIBAFL_QEMU_BIOS_DIR=${LIBAFL_QEMU_CLONE_DIR}/build/qemu-bundle/usr/local/share/qemu fi -${TARGET_DIR}/${PROFILE_DIR}/qemu_systemmode_linux_kernel \ +cp ${LINUX_BUILDER_OUT}/OVMF_CODE.4m.fd ${LINUX_BUILDER_OUT}/OVMF_CODE.fd.clone +cp ${LINUX_BUILDER_OUT}/OVMF_VARS.4m.fd ${LINUX_BUILDER_OUT}/OVMF_VARS.fd.clone +cp ${LINUX_BUILDER_OUT}/linux.qcow2 ${LINUX_BUILDER_OUT}/linux.qcow2.clone + +${TARGET_DIR}/${PROFILE_DIR}/qemu_linux_kernel \ -accel tcg \ -m 4G \ - -drive if=pflash,format=raw,readonly=on,file="${LINUX_BUILDER_OUT}/OVMF_CODE.fd" \ - -drive if=pflash,format=raw,snapshot=off,file="${LINUX_BUILDER_OUT}/OVMF_VARS.fd" \ - -blockdev filename="${LINUX_BUILDER_OUT}/linux.qcow2",node-name=storage,driver=file \ - -blockdev driver=qcow2,file=storage,node-name=disk \ - -device virtio-scsi-pci,id=scsi0 \ + -drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_CODE.4m.fd" `# OVMF code pflash` \ + -drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_VARS.4m.fd" `# OVMF vars pflash` \ + -device virtio-scsi-pci,id=scsi0 `# SCSI bus` \ -device scsi-hd,bus=scsi0.0,drive=disk,id=virtio-disk0,bootindex=1 \ + -blockdev driver=file,filename="${LINUX_BUILDER_OUT}/linux.qcow2",node-name=storage `# Backend file of "disk"` \ + -blockdev driver=qcow2,file=storage,node-name=disk `# QCOW2 "disk"` \ -L "${LIBAFL_QEMU_BIOS_DIR}" \ -nographic \ -monitor null \ - -serial null \ - -snapshot + -serial null ''' [tasks.debug] diff --git a/fuzzers/full_system/qemu_linux_kernel/setup/Makefile b/fuzzers/full_system/qemu_linux_kernel/setup/Makefile index a46095abea..d934995017 100644 --- a/fuzzers/full_system/qemu_linux_kernel/setup/Makefile +++ b/fuzzers/full_system/qemu_linux_kernel/setup/Makefile @@ -1,9 +1,9 @@ obj-m += harness.o all: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + make -C /lib/modules/$(LINUX_MODULES)/build M=$(PWD) modules gcc -Wall -Werror -o user user.c clean: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean - rm user \ No newline at end of file + make -C /lib/modules/$(LINUX_MODULES)/build M=$(PWD) clean + rm -f user \ No newline at end of file diff --git a/fuzzers/full_system/qemu_linux_kernel/setup/harness.c b/fuzzers/full_system/qemu_linux_kernel/setup/harness.c index c7d58c78f2..b17f031564 100644 --- a/fuzzers/full_system/qemu_linux_kernel/setup/harness.c +++ b/fuzzers/full_system/qemu_linux_kernel/setup/harness.c @@ -91,6 +91,8 @@ static int harness_find_kallsyms_lookup(void) { lqprintf("kallsyms_lookup_name address = 0x%lx\n", kln_addr); + if (kln_addr == 0) { return -1; } + kln_pointer = (unsigned long (*)(const char *name))kln_addr; return ret; @@ -108,6 +110,8 @@ static int __init harness_init(void) { err = alloc_chrdev_region(&dev, 0, 1, "harness"); + if (err < 0) { return err; } + dev_major = MAJOR(dev); harness_class = class_create("harness"); @@ -120,7 +124,9 @@ static int __init harness_init(void) { device_create(harness_class, NULL, MKDEV(dev_major, 0), NULL, "harness"); - harness_find_kallsyms_lookup(); + err = harness_find_kallsyms_lookup(); + + if (err < 0) { return err; } return 0; } @@ -135,7 +141,6 @@ static void __exit harness_exit(void) { } static int harness_open(struct inode *inode, struct file *file) { - int ret; lqprintf("harness: Device open\n"); char *data = kzalloc(BUF_SIZE, GFP_KERNEL); @@ -144,6 +149,11 @@ static int harness_open(struct inode *inode, struct file *file) { unsigned long x509_fn_addr = kln_pointer("x509_cert_parse"); lqprintf("harness: x509 fn addr: 0x%lx\n", x509_fn_addr); + if (x509_fn_addr == 0) { + lqprintf("harness: Error: x509 function not found.\n"); + return -1; + } + // TODO: better filtering... libafl_qemu_trace_vaddr_size(x509_fn_addr, 0x1000); diff --git a/fuzzers/full_system/qemu_linux_kernel/setup/setup.sh b/fuzzers/full_system/qemu_linux_kernel/setup/setup.sh index 56fafcc8b6..5090430ef2 100644 --- a/fuzzers/full_system/qemu_linux_kernel/setup/setup.sh +++ b/fuzzers/full_system/qemu_linux_kernel/setup/setup.sh @@ -1,6 +1,8 @@ #!/bin/bash +LINUX_MODULES=$(pacman -Ql linux-headers | grep -m 1 -E '/usr/lib/modules/[^/]*/' | sed 's|.*/usr/lib/modules/\([^/]*\)/.*|\1|') +export LINUX_MODULES + cd /setup make clean -make -j -ls /setup \ No newline at end of file +make -j \ No newline at end of file diff --git a/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs b/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs index 0587202bae..3e3f61119a 100644 --- a/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs +++ b/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs @@ -12,10 +12,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::BytesInput, monitors::MultiMonitor, - mutators::{ - scheduled::{havoc_mutations, StdScheduledMutator}, - I2SRandReplaceBinonly, - }, + mutators::{havoc_mutations, scheduled::StdScheduledMutator, I2SRandReplaceBinonly}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, @@ -33,16 +30,10 @@ use libafl_bolts::{ use libafl_qemu::{ emu::Emulator, executor::QemuExecutor, - modules::{ - cmplog::CmpLogObserver, - edges::{ - edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_ALLOCATED_SIZE, - MAX_EDGES_FOUND, - }, - CmpLogModule, - }, + modules::{cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, CmpLogModule}, // StdEmulatorDriver }; +use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND}; pub fn fuzz() { env_logger::init(); @@ -61,9 +52,21 @@ pub fn fuzz() { // Initialize QEMU let args: Vec = env::args().collect(); + // Create an observation channel using the coverage map + let mut edges_observer = unsafe { + HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( + "edges", + OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE), + &raw mut MAX_EDGES_FOUND, + )) + .track_indices() + }; + // Choose modules to use let modules = tuple_list!( - StdEdgeCoverageClassicModule::builder().build(), + StdEdgeCoverageClassicModule::builder() + .map_observer(edges_observer.as_mut()) + .build()?, CmpLogModule::default(), ); @@ -81,16 +84,6 @@ pub fn fuzz() { emulator.run(state, input).unwrap().try_into().unwrap() }; - // Create an observation channel using the coverage map - let edges_observer = unsafe { - HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( - "edges", - OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE), - &raw mut MAX_EDGES_FOUND, - )) - .track_indices() - }; - // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); diff --git a/fuzzers/full_system/qemu_linux_process/Cargo.toml b/fuzzers/full_system/qemu_linux_process/Cargo.toml index 0f2f626f92..065fdeea25 100644 --- a/fuzzers/full_system/qemu_linux_process/Cargo.toml +++ b/fuzzers/full_system/qemu_linux_process/Cargo.toml @@ -5,6 +5,10 @@ authors = ["Romain Malmain "] edition = "2021" [features] + +## Build and run the target with the Nyx API instead of the built-in LibAFL QEMU API. +nyx = [] + shared = ["libafl_qemu/shared"] [profile.release] @@ -16,15 +20,10 @@ codegen-units = 1 [dependencies] libafl = { path = "../../../libafl" } libafl_bolts = { path = "../../../libafl_bolts" } -libafl_qemu = { path = "../../../libafl_qemu", features = [ - "x86_64", - "systemmode", - # "paranoid_debug" -] } -libafl_qemu_sys = { path = "../../../libafl_qemu/libafl_qemu_sys", features = [ +libafl_qemu = { path = "../../../libafl_qemu", default-features = false, features = [ "x86_64", "systemmode", - # "paranoid_debug" + # "paranoid_debug", ] } env_logger = "0.11.5" libafl_targets = { path = "../../../libafl_targets" } diff --git a/fuzzers/full_system/qemu_linux_process/Makefile.toml b/fuzzers/full_system/qemu_linux_process/Makefile.toml index 8317a1ff1a..fe298369da 100644 --- a/fuzzers/full_system/qemu_linux_process/Makefile.toml +++ b/fuzzers/full_system/qemu_linux_process/Makefile.toml @@ -1,12 +1,20 @@ env_scripts = [''' #!@duckscript profile = get_env PROFILE +harness_api = get_env HARNESS_API if eq ${profile} "dev" set_env PROFILE_DIR debug else set_env PROFILE_DIR ${profile} end + +if eq ${harness_api} "nyx" + set_env FEATURE nyx +else + set_env FEATURE "" +end + ''', ''' #!@duckscript runs_on_ci = get_env RUN_ON_CI @@ -25,12 +33,12 @@ TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}" LIBAFL_QEMU_CLONE_DIR = { value = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/qemu-libafl-bridge", condition = { env_not_set = [ "LIBAFL_QEMU_DIR", ] } } - LINUX_BUILDER_URL = "git@github.com:AFLplusplus/linux-qemu-image-builder.git" LINUX_BUILDER_DIR = { value = "${TARGET_DIR}/linux_builder", condition = { env_not_set = [ "LINUX_BUILDER_DIR", ] } } LINUX_BUILDER_OUT = "${LINUX_BUILDER_DIR}/output" +HARNESS_API = { value = "lqemu", condition = { env_not_set = ["HARNESS_API"] } } [tasks.target_dir] condition = { files_not_exist = [ @@ -51,7 +59,22 @@ script = ''' git clone ${LINUX_BUILDER_URL} ${LINUX_BUILDER_DIR} ''' -[tasks.compile_target] +[tasks.compile_target_nyx] +condition = { env = { "HARNESS_API" = "nyx" } } +dependencies = ["target_dir", "linux_builder_dir"] +command = "clang" +args = [ + "-O0", + "-static", + "${WORKING_DIR}/example/harness_nyx.c", + "-o", + "${TARGET_DIR}/runtime/harness", + "-I", + "${TARGET_DIR}/${PROFILE_DIR}/include", +] + +[tasks.compile_target_native] +condition = { env = { "HARNESS_API" = "lqemu" } } dependencies = ["target_dir", "linux_builder_dir"] command = "clang" args = [ @@ -64,6 +87,9 @@ args = [ "${TARGET_DIR}/${PROFILE_DIR}/include", ] +[tasks.compile_target] +dependencies = ["compile_target_native", "compile_target_nyx"] + [tasks.target] dependencies = ["build", "compile_target"] script_runner = "@shell" @@ -96,7 +122,15 @@ ${LINUX_BUILDER_DIR}/update.sh [tasks.build] dependencies = ["target_dir"] command = "cargo" -args = ["build", "--profile", "${PROFILE}", "--target-dir", "${TARGET_DIR}"] +args = [ + "build", + "--profile", + "${PROFILE}", + "--target-dir", + "${TARGET_DIR}", + "--features", + "${FEATURE}", +] [tasks.run] dependencies = ["build"] @@ -111,15 +145,15 @@ else LIBAFL_QEMU_BIOS_DIR=${LIBAFL_QEMU_CLONE_DIR}/build/qemu-bundle/usr/local/share/qemu fi -cp ${LINUX_BUILDER_OUT}/OVMF_CODE.fd ${LINUX_BUILDER_OUT}/OVMF_CODE.fd.clone -cp ${LINUX_BUILDER_OUT}/OVMF_VARS.fd ${LINUX_BUILDER_OUT}/OVMF_VARS.fd.clone +cp ${LINUX_BUILDER_OUT}/OVMF_CODE.4m.fd ${LINUX_BUILDER_OUT}/OVMF_CODE.fd.clone +cp ${LINUX_BUILDER_OUT}/OVMF_VARS.4m.fd ${LINUX_BUILDER_OUT}/OVMF_VARS.fd.clone cp ${LINUX_BUILDER_OUT}/linux.qcow2 ${LINUX_BUILDER_OUT}/linux.qcow2.clone ${TARGET_DIR}/${PROFILE_DIR}/qemu_linux_process \ -accel tcg \ -m 4G \ - -drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_CODE.fd" `# OVMF code pflash` \ - -drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_VARS.fd" `# OVMF vars pflash` \ + -drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_CODE.4m.fd" `# OVMF code pflash` \ + -drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_VARS.4m.fd" `# OVMF vars pflash` \ -device virtio-scsi-pci,id=scsi0 `# SCSI bus` \ -device scsi-hd,bus=scsi0.0,drive=disk,id=virtio-disk0,bootindex=1 \ -blockdev driver=file,filename="${LINUX_BUILDER_OUT}/linux.qcow2",node-name=storage `# Backend file of "disk"` \ diff --git a/fuzzers/full_system/qemu_linux_process/example/harness_nyx.c b/fuzzers/full_system/qemu_linux_process/example/harness_nyx.c new file mode 100644 index 0000000000..15c4eca2ae --- /dev/null +++ b/fuzzers/full_system/qemu_linux_process/example/harness_nyx.c @@ -0,0 +1,137 @@ +// Adapted from +// https://github.com/google/fuzzing/blob/master/tutorial/libFuzzer/fuzz_me.cc +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PAGE_SIZE 4096 +#define PAYLOAD_MAX_SIZE (1 * 1024 * 1024) + +bool FuzzMe(const uint8_t *Data, size_t DataSize) { + if (DataSize > 3) { + if (Data[0] == 'F') { + if (Data[1] == 'U') { + if (Data[2] == 'Z') { + if (Data[3] == 'Z') { return true; } + } + } + } + } + + return false; +} + +/** + * Allocate page-aligned memory + */ +void *malloc_resident_pages(size_t num_pages) { + size_t data_size = PAGE_SIZE * num_pages; + void *ptr = NULL; + + if ((ptr = aligned_alloc(PAGE_SIZE, data_size)) == NULL) { + fprintf(stderr, "Allocation failure: %s\n", strerror(errno)); + goto err_out; + } + + // ensure pages are aligned and resident + memset(ptr, 0x42, data_size); + if (mlock(ptr, data_size) == -1) { + fprintf(stderr, "Error locking scratch buffer: %s\n", strerror(errno)); + goto err_out; + } + + assert(((uintptr_t)ptr % PAGE_SIZE) == 0); + return ptr; +err_out: + free(ptr); + return NULL; +} + +int agent_init(int verbose) { + host_config_t host_config; + + // set ready state + kAFL_hypercall(HYPERCALL_KAFL_ACQUIRE, 0); + kAFL_hypercall(HYPERCALL_KAFL_RELEASE, 0); + + kAFL_hypercall(HYPERCALL_KAFL_GET_HOST_CONFIG, (uintptr_t)&host_config); + + if (verbose) { + fprintf(stderr, "GET_HOST_CONFIG\n"); + fprintf(stderr, "\thost magic: 0x%x, version: 0x%x\n", + host_config.host_magic, host_config.host_version); + fprintf(stderr, "\tbitmap size: 0x%x, ijon: 0x%x\n", + host_config.bitmap_size, host_config.ijon_bitmap_size); + fprintf(stderr, "\tpayload size: %u KB\n", + host_config.payload_buffer_size / 1024); + fprintf(stderr, "\tworker id: %d\n", host_config.worker_id); + } + + if (host_config.host_magic != NYX_HOST_MAGIC) { + hprintf("HOST_MAGIC mismatch: %08x != %08x\n", host_config.host_magic, + NYX_HOST_MAGIC); + habort("HOST_MAGIC mismatch!"); + return -1; + } + + if (host_config.host_version != NYX_HOST_VERSION) { + hprintf("HOST_VERSION mismatch: %08x != %08x\n", host_config.host_version, + NYX_HOST_VERSION); + habort("HOST_VERSION mismatch!"); + return -1; + } + + if (host_config.payload_buffer_size > PAYLOAD_MAX_SIZE) { + hprintf("Fuzzer payload size too large: %lu > %lu\n", + host_config.payload_buffer_size, PAYLOAD_MAX_SIZE); + habort("Host payload size too large!"); + return -1; + } + + agent_config_t agent_config = {0}; + agent_config.agent_magic = NYX_AGENT_MAGIC; + agent_config.agent_version = NYX_AGENT_VERSION; + // agent_config.agent_timeout_detection = 0; // timeout by host + // agent_config.agent_tracing = 0; // trace by host + // agent_config.agent_ijon_tracing = 0; // no IJON + agent_config.agent_non_reload_mode = 0; // no persistent mode + // agent_config.trace_buffer_vaddr = 0xdeadbeef; + // agent_config.ijon_trace_buffer_vaddr = 0xdeadbeef; + agent_config.coverage_bitmap_size = host_config.bitmap_size; + // agent_config.input_buffer_size; + // agent_config.dump_payloads; // set by hypervisor (??) + + kAFL_hypercall(HYPERCALL_KAFL_SET_AGENT_CONFIG, (uintptr_t)&agent_config); + + return 0; +} + +int main() { + kAFL_payload *pbuf = malloc_resident_pages(PAYLOAD_MAX_SIZE / PAGE_SIZE); + assert(pbuf); + + agent_init(1); + + kAFL_hypercall(HYPERCALL_KAFL_GET_PAYLOAD, (uint64_t)pbuf); + + hprintf("payload size addr: %p", &pbuf->size); + hprintf("payload addr: %p", &pbuf->data); + + kAFL_hypercall(HYPERCALL_KAFL_NEXT_PAYLOAD, 0); + kAFL_hypercall(HYPERCALL_KAFL_ACQUIRE, 0); + + // Call the target + bool ret = FuzzMe(pbuf->data, pbuf->size); + + kAFL_hypercall(HYPERCALL_KAFL_RELEASE, 0); + + habort("Error: post-release code has been triggered."); +} \ No newline at end of file diff --git a/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs b/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs index cd0b7defc1..c6b4bc6b3c 100644 --- a/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs +++ b/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs @@ -3,6 +3,8 @@ use core::time::Duration; use std::{env, path::PathBuf, process}; +#[cfg(not(feature = "nyx"))] +use libafl::state::{HasExecutions, State}; use libafl::{ corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus}, events::{launcher::Launcher, EventConfig}, @@ -10,7 +12,7 @@ use libafl::{ feedback_or, feedback_or_fast, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, - inputs::BytesInput, + inputs::{BytesInput, HasTargetBytes, UsesInput}, monitors::MultiMonitor, mutators::{havoc_mutations, I2SRandReplaceBinonly, StdScheduledMutator}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, @@ -27,13 +29,64 @@ use libafl_bolts::{ shmem::{ShMemProvider, StdShMemProvider}, tuples::tuple_list, }; +#[cfg(feature = "nyx")] +use libafl_qemu::{command::nyx::NyxCommandManager, NyxEmulatorDriver}; +#[cfg(not(feature = "nyx"))] +use libafl_qemu::{command::StdCommandManager, StdEmulatorDriver}; use libafl_qemu::{ emu::Emulator, executor::QemuExecutor, - modules::{cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, CmpLogModule}, + modules::{ + cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, CmpLogModule, + EmulatorModuleTuple, + }, + FastSnapshotManager, QemuInitError, }; use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND}; +#[cfg(feature = "nyx")] +fn get_emulator( + args: Vec, + modules: ET, +) -> Result< + Emulator, NyxEmulatorDriver, ET, S, FastSnapshotManager>, + QemuInitError, +> +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + ::Input: HasTargetBytes, +{ + Emulator::empty() + .qemu_parameters(args) + .modules(modules) + .driver( + NyxEmulatorDriver::builder() + .allow_page_on_start(true) + .process_only(true) + .build(), + ) + .command_manager(NyxCommandManager::default()) + .snapshot_manager(FastSnapshotManager::default()) + .build() +} + +#[cfg(not(feature = "nyx"))] +fn get_emulator( + args: Vec, + modules: ET, +) -> Result< + Emulator, StdEmulatorDriver, ET, S, FastSnapshotManager>, + QemuInitError, +> +where + ET: EmulatorModuleTuple, + S: State + HasExecutions + Unpin, + ::Input: HasTargetBytes, +{ + Emulator::builder().qemu_cli(args).modules(modules).build() +} + pub fn fuzz() { env_logger::init(); @@ -69,10 +122,7 @@ pub fn fuzz() { CmpLogModule::default(), ); - let emu = Emulator::builder() - .qemu_parameters(args) - .modules(modules) - .build()?; + let emu = get_emulator(args, modules)?; // The wrapped harness function, calling out to the LLVM-style harness let mut harness = diff --git a/fuzzers/inprocess/libfuzzer_libmozjpeg/hook_allocs.c b/fuzzers/inprocess/libfuzzer_libmozjpeg/hook_allocs.c index e1d7e2203e..1399261c65 100644 --- a/fuzzers/inprocess/libfuzzer_libmozjpeg/hook_allocs.c +++ b/fuzzers/inprocess/libfuzzer_libmozjpeg/hook_allocs.c @@ -7,9 +7,9 @@ #ifdef _WIN32 #define posix_memalign(p, a, s) \ (((*(p)) = _aligned_malloc((s), (a))), *(p) ? 0 : errno) - #define RETADDR (uintptr_t)_ReturnAddress() + #define RETADDR (uintptr_t) _ReturnAddress() #else - #define RETADDR (uintptr_t)__builtin_return_address(0) + #define RETADDR (uintptr_t) __builtin_return_address(0) #endif #ifdef __GNUC__ diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 2a3a68bff5..96b13dac89 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -265,6 +265,19 @@ pub fn hash_std(input: &[u8]) -> u64 { } } +/// Fast hash function for 64 bits integers minimizing collisions. +/// Adapted from +#[must_use] +pub fn hash_64_fast(mut x: u64) -> u64 { + x = (x ^ (x.overflowing_shr(30).0)) + .overflowing_mul(0xbf58476d1ce4e5b9) + .0; + x = (x ^ (x.overflowing_shr(27).0)) + .overflowing_mul(0x94d049bb133111eb) + .0; + x ^ (x.overflowing_shr(31).0) +} + /// Hashes the input with a given hash /// /// Hashes the input with a given hash, depending on features: diff --git a/libafl_intelpt/src/lib.rs b/libafl_intelpt/src/lib.rs index 0530aa33fc..43402c2e77 100644 --- a/libafl_intelpt/src/lib.rs +++ b/libafl_intelpt/src/lib.rs @@ -41,7 +41,7 @@ use bitbybit::bitfield; use caps::{CapSet, Capability}; #[cfg(target_os = "linux")] use libafl_bolts::ownedref::OwnedRefMut; -use libafl_bolts::Error; +use libafl_bolts::{hash_64_fast, Error}; use libipt::PtError; #[cfg(target_os = "linux")] use libipt::{ @@ -407,7 +407,7 @@ impl IntelPT { let offset = decoder.offset().map_err(error_from_pt_error)?; if b.ninsn() > 0 && skip < offset { - let id = hash_me(*previous_block_end_ip) ^ hash_me(b.ip()); + let id = hash_64_fast(*previous_block_end_ip) ^ hash_64_fast(b.ip()); // SAFETY: the index is < map.len() since the modulo operation is applied let map_loc = unsafe { map.get_unchecked_mut(id as usize % map.len()) }; *map_loc = (*map_loc).saturating_add(&1u8.into()); @@ -961,21 +961,6 @@ const fn next_page_aligned_addr(address: u64) -> u64 { (address + PAGE_SIZE as u64 - 1) & !(PAGE_SIZE as u64 - 1) } -// copy pasted from libafl_qemu/src/modules/edges.rs -// adapted from https://xorshift.di.unimi.it/splitmix64.c -#[cfg(target_os = "linux")] -#[inline] -#[must_use] -const fn hash_me(mut x: u64) -> u64 { - x = (x ^ (x.overflowing_shr(30).0)) - .overflowing_mul(0xbf58476d1ce4e5b9) - .0; - x = (x ^ (x.overflowing_shr(27).0)) - .overflowing_mul(0x94d049bb133111eb) - .0; - x ^ (x.overflowing_shr(31).0) -} - #[cfg(target_os = "linux")] #[inline] fn smp_rmb() { diff --git a/libafl_qemu/Cargo.toml b/libafl_qemu/Cargo.toml index 28287ea12c..064dc5e27a 100644 --- a/libafl_qemu/Cargo.toml +++ b/libafl_qemu/Cargo.toml @@ -34,6 +34,9 @@ default = [ "injections", ] document-features = ["dep:document-features"] + +qemu_sanitizers = ["libafl_qemu_sys/qemu_sanitizers"] + paranoid_debug = [ "libafl_qemu_sys/paranoid_debug", ] # Will perform as many checks as possible. The target will be greatly slowed down. diff --git a/libafl_qemu/build_linux.rs b/libafl_qemu/build_linux.rs index bbe796047e..a250554525 100644 --- a/libafl_qemu/build_linux.rs +++ b/libafl_qemu/build_linux.rs @@ -51,6 +51,8 @@ pub fn build() { let libafl_qemu_defs_hdr_name = "libafl_qemu_defs.h"; let libafl_qemu_impl_hdr_name = "libafl_qemu_impl.h"; + let nyx_hdr_name = "nyx_api.h"; + let libafl_runtime_dir = src_dir.join("runtime"); let libafl_qemu_hdr = libafl_runtime_dir.join(libafl_qemu_hdr_name); @@ -58,6 +60,8 @@ pub fn build() { let libafl_qemu_defs_hdr = libafl_runtime_dir.join(libafl_qemu_defs_hdr_name); let libafl_qemu_impl_hdr = libafl_runtime_dir.join(libafl_qemu_impl_hdr_name); + let nyx_hdr = libafl_runtime_dir.join(nyx_hdr_name); + let libafl_runtime_testfile = out_dir.join("runtime_test.c"); fs::write(&libafl_runtime_testfile, LIBAFL_QEMU_RUNTIME_TEST) .expect("Could not write runtime test file"); @@ -76,6 +80,9 @@ pub fn build() { let runtime_bindings_file = out_dir.join("libafl_qemu_bindings.rs"); let stub_runtime_bindings_file = src_dir.join("runtime/libafl_qemu_stub_bindings.rs"); + let nyx_bindings_file = out_dir.join("nyx_bindings.rs"); + let stub_nyx_bindings_file = src_dir.join("runtime/nyx_stub_bindings.rs"); + println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build_linux.rs"); println!("cargo:rerun-if-changed={}", libafl_runtime_dir.display()); @@ -121,6 +128,8 @@ pub fn build() { if env::var("DOCS_RS").is_ok() || cfg!(feature = "clippy") { fs::copy(&stub_runtime_bindings_file, &runtime_bindings_file) .expect("Could not copy stub bindings file"); + fs::copy(&stub_nyx_bindings_file, &nyx_bindings_file) + .expect("Could not copy stub bindings file"); return; // only build when we're not generating docs } @@ -150,6 +159,12 @@ pub fn build() { ) .expect("Could not copy libafl_qemu_impl.h to out directory."); + fs::copy( + nyx_hdr.clone(), + include_dir.join(nyx_hdr_name), + ) + .expect("Could not copy libafl_qemu_impl.h to out directory."); + bindgen::Builder::default() .derive_debug(true) .derive_default(true) @@ -165,6 +180,21 @@ pub fn build() { .write_to_file(&runtime_bindings_file) .expect("Could not write bindings."); + bindgen::Builder::default() + .derive_debug(true) + .derive_default(true) + .impl_debug(true) + .generate_comments(true) + .default_enum_style(bindgen::EnumVariation::NewType { + is_global: true, + is_bitfield: true, + }) + .header(nyx_hdr.display().to_string()) + .generate() + .expect("Exit bindings generation failed.") + .write_to_file(&nyx_bindings_file) + .expect("Could not write bindings."); + maybe_generate_stub_bindings( &cpu_target, emulation_mode, @@ -172,6 +202,13 @@ pub fn build() { runtime_bindings_file.as_path(), ); + maybe_generate_stub_bindings( + &cpu_target, + emulation_mode, + stub_nyx_bindings_file.as_path(), + nyx_bindings_file.as_path(), + ); + if cfg!(feature = "usermode") && (qemu_asan || qemu_asan_guest) { let qasan_dir = Path::new("libqasan"); let qasan_dir = fs::canonicalize(qasan_dir).unwrap(); diff --git a/libafl_qemu/libafl_qemu_build/Cargo.toml b/libafl_qemu/libafl_qemu_build/Cargo.toml index 8b6c31b074..6282e9f6ef 100644 --- a/libafl_qemu/libafl_qemu_build/Cargo.toml +++ b/libafl_qemu/libafl_qemu_build/Cargo.toml @@ -29,6 +29,8 @@ slirp = [] # build qemu with host libslirp (for user networking) clippy = [] # special feature for clippy, don't use in normal projects§ +qemu_sanitizers = [] # Enable QEMU sanitizers + paranoid_debug = [ ] # Will perform as many checks as possible. The target will be greatly slowed down. diff --git a/libafl_qemu/libafl_qemu_build/src/bindings.rs b/libafl_qemu/libafl_qemu_build/src/bindings.rs index 1733cff770..0fdc10d391 100644 --- a/libafl_qemu/libafl_qemu_build/src/bindings.rs +++ b/libafl_qemu/libafl_qemu_build/src/bindings.rs @@ -149,10 +149,8 @@ pub fn generate( .allowlist_type("MemOp") .allowlist_type("DeviceSnapshotKind") .allowlist_type("ShutdownCause") - .allowlist_type("libafl_exit_reason") - .allowlist_type("libafl_exit_reason_kind") - .allowlist_type("libafl_exit_reason_sync_backdoor") - .allowlist_type("libafl_exit_reason_breakpoint") + .allowlist_type("libafl.*") + .allowlist_type("LIBAFL.*") .allowlist_type("Syx.*") .allowlist_type("libafl_mapinfo") .allowlist_type("IntervalTreeRoot") diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index 70c17de121..00432e424e 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -11,7 +11,7 @@ use crate::cargo_add_rpath; pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -pub const QEMU_REVISION: &str = "06bf8facec33548840413fba1b20858f58e38e2d"; +pub const QEMU_REVISION: &str = "ace364678aef879514e150e626695c4793db41e9"; pub struct BuildResult { pub qemu_path: PathBuf, @@ -96,9 +96,11 @@ fn configure_qemu( .arg("--disable-tools"); if cfg!(feature = "paranoid_debug") { - cmd.arg("--enable-debug") - .arg("--enable-debug-tcg") - .arg("--enable-sanitizers"); + cmd.arg("--enable-debug").arg("--enable-debug-tcg"); + } + + if cfg!(feature = "qemu_sanitizers") { + cmd.arg("--enable-sanitizers"); } if is_usermode { @@ -433,29 +435,6 @@ pub fn build( assert!(output_lib.is_file()); // Make sure this isn't very very wrong - /* - let mut objects = vec![]; - for dir in [ - build_dir.join("libcommon.fa.p"), - build_dir.join(format!("libqemu-{cpu_target}-{target_suffix}.fa.p")), - ] { - for path in fs::read_dir(dir).unwrap() { - let path = path.unwrap().path(); - if path.is_file() { - if let Some(name) = path.file_name() { - if name.to_string_lossy().starts_with("stubs") { - continue; - } else if let Some(ext) = path.extension() { - if ext == "o" { - objects.push(path); - } - } - } - } - } - } - */ - let compile_commands_string = &fs::read_to_string(libafl_qemu_build_dir.join("linkinfo.json")) .expect("Failed to read linkinfo.json"); @@ -515,90 +494,6 @@ pub fn build( panic!("Linking failed."); } - /* // Old manual linking, kept here for reference and debugging - if is_usermode { - Command::new("ld") - .current_dir(out_dir_path) - .arg("-o") - .arg("libqemu-partially-linked.o") - .arg("-r") - .args(objects) - .arg("--start-group") - .arg("--whole-archive") - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/libevent-loop-base.a", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display())) - .arg("--no-whole-archive") - .arg(format!("{}/libqemuutil.a", build_dir.display())) - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display())) - .arg(format!( - "--dynamic-list={}/plugins/qemu-plugins.symbols", - qemu_path.display() - )) - .arg("--end-group") - .status() - .expect("Partial linked failure"); - } else { - Command::new("ld") - .current_dir(out_dir_path) - .arg("-o") - .arg("libqemu-partially-linked.o") - .arg("-r") - .args(objects) - .arg("--start-group") - .arg("--whole-archive") - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/libevent-loop-base.a", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display())) - .arg(format!("{}/libio.fa", build_dir.display())) - .arg(format!("{}/libcrypto.fa", build_dir.display())) - .arg(format!("{}/libauthz.fa", build_dir.display())) - .arg(format!("{}/libblockdev.fa", build_dir.display())) - .arg(format!("{}/libblock.fa", build_dir.display())) - .arg(format!("{}/libchardev.fa", build_dir.display())) - .arg(format!("{}/libqmp.fa", build_dir.display())) - .arg("--no-whole-archive") - .arg(format!("{}/libqemuutil.a", build_dir.display())) - .arg(format!( - "{}/subprojects/dtc/libfdt/libfdt.a", - build_dir.display() - )) - .arg(format!( - "{}/subprojects/libvhost-user/libvhost-user-glib.a", - build_dir.display() - )) - .arg(format!( - "{}/subprojects/libvhost-user/libvhost-user.a", - build_dir.display() - )) - .arg(format!( - "{}/subprojects/libvduse/libvduse.a", - build_dir.display() - )) - .arg(format!("{}/libmigration.fa", build_dir.display())) - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display())) - .arg(format!("{}/libio.fa", build_dir.display())) - .arg(format!("{}/libcrypto.fa", build_dir.display())) - .arg(format!("{}/libauthz.fa", build_dir.display())) - .arg(format!("{}/libblockdev.fa", build_dir.display())) - .arg(format!("{}/libblock.fa", build_dir.display())) - .arg(format!("{}/libchardev.fa", build_dir.display())) - .arg(format!("{}/libqmp.fa", build_dir.display())) - .arg(format!( - "--dynamic-list={}/plugins/qemu-plugins.symbols", - qemu_path.display() - )) - .arg("--end-group") - .status() - .expect("Partial linked failure"); - }*/ - Command::new("ar") .current_dir(out_dir_path) .arg("crs") @@ -640,29 +535,12 @@ pub fn build( } } - if cfg!(feature = "paranoid_debug") { + if cfg!(feature = "qemu_sanitizers") { println!("cargo:rustc-link-lib=ubsan"); println!("cargo:rustc-link-lib=asan"); } - /* - println!("cargo:rustc-link-lib=rt"); - println!("cargo:rustc-link-lib=gmodule-2.0"); - println!("cargo:rustc-link-lib=glib-2.0"); - println!("cargo:rustc-link-lib=stdc++"); - println!("cargo:rustc-link-lib=z"); - // if keyutils is available, qemu meson script will compile code with keyutils. - // therefore, we need to link with keyutils if our system have libkeyutils. - let _: Result = - pkg_config::Config::new().probe("libkeyutils"); - */ - if !is_usermode { - //println!("cargo:rustc-link-lib=pixman-1"); - //if env::var("LINK_SLIRP").is_ok() || cfg!(feature = "slirp") { - // println!("cargo:rustc-link-lib=slirp"); - //} - fs::create_dir_all(target_dir.join("pc-bios")).unwrap(); for path in fs::read_dir(libafl_qemu_build_dir.join("pc-bios")).unwrap() { let path = path.unwrap().path(); diff --git a/libafl_qemu/libafl_qemu_sys/Cargo.toml b/libafl_qemu/libafl_qemu_sys/Cargo.toml index b5730812d8..aad3048ff3 100644 --- a/libafl_qemu/libafl_qemu_sys/Cargo.toml +++ b/libafl_qemu/libafl_qemu_sys/Cargo.toml @@ -56,6 +56,10 @@ clippy = [ "libafl_qemu_build/clippy", ] # special feature for clippy, don't use in normal projects +qemu_sanitizers = [ + "libafl_qemu_build/qemu_sanitizers", +] # Compile QEMU with sanitizers enabled + paranoid_debug = [ "libafl_qemu_build/paranoid_debug", ] # Will perform as many checks as possible. The target will be greatly slowed down. diff --git a/libafl_qemu/libafl_qemu_sys/src/bindings/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/bindings/x86_64_stub_bindings.rs index edae125224..b9664a601c 100644 --- a/libafl_qemu/libafl_qemu_sys/src/bindings/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/bindings/x86_64_stub_bindings.rs @@ -1,6 +1,6 @@ -/* 1.84.0-nightly */ -/* qemu git hash: 805b14ffc44999952562e8f219d81c21a4fa50b9 */ -/* automatically generated by rust-bindgen 0.70.1 */ +/* 1.85.0-nightly */ +/* qemu git hash: 81e52dc60f83c3ae191c1a07b39bb255e633c234 */ +/* automatically generated by rust-bindgen 0.71.1 */ use libc::siginfo_t; @@ -20,10 +20,7 @@ where Storage: AsRef<[u8]> + AsMut<[u8]>, { #[inline] - pub fn get_bit(&self, index: usize) -> bool { - debug_assert!(index / 8 < self.storage.as_ref().len()); - let byte_index = index / 8; - let byte = self.storage.as_ref()[byte_index]; + fn extract_bit(byte: u8, index: usize) -> bool { let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { @@ -33,10 +30,21 @@ where byte & mask == mask } #[inline] - pub fn set_bit(&mut self, index: usize, val: bool) { + pub fn get_bit(&self, index: usize) -> bool { debug_assert!(index / 8 < self.storage.as_ref().len()); let byte_index = index / 8; - let byte = &mut self.storage.as_mut()[byte_index]; + let byte = self.storage.as_ref()[byte_index]; + Self::extract_bit(byte, index) + } + #[inline] + pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = *(core::ptr::addr_of!((*this).storage) as *const u8).offset(byte_index as isize); + Self::extract_bit(byte, index) + } + #[inline] + fn change_bit(byte: u8, index: usize, val: bool) -> u8 { let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { @@ -44,12 +52,27 @@ where }; let mask = 1 << bit_index; if val { - *byte |= mask; + byte | mask } else { - *byte &= !mask; + byte & !mask } } #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + *byte = Self::change_bit(*byte, index, val); + } + #[inline] + pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = + (core::ptr::addr_of_mut!((*this).storage) as *mut u8).offset(byte_index as isize); + *byte = Self::change_bit(*byte, index, val); + } + #[inline] pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); @@ -68,6 +91,24 @@ where val } #[inline] + pub unsafe fn raw_get(this: *const Self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if Self::raw_get_bit(this, i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); @@ -83,6 +124,22 @@ where self.set_bit(index + bit_offset, val_bit_is_set); } } + #[inline] + pub unsafe fn raw_set(this: *mut Self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + Self::raw_set_bit(this, index + bit_offset, val_bit_is_set); + } + } } #[repr(C)] #[derive(Default)] @@ -916,21 +973,6 @@ pub struct Clock { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct CPUAddressSpace { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CpuInfoFast { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CPUJumpCache { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct Error { _unused: [u8; 0], } @@ -1005,7 +1047,7 @@ impl Default for QEnumLookup { } } } -extern "C" { +unsafe extern "C" { pub fn qemu_target_page_size() -> usize; } #[repr(C)] @@ -1130,6 +1172,28 @@ impl MemTxAttrs { } } #[inline] + pub unsafe fn unspecified_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 3usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 0usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_unspecified_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 3usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn secure(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u32) } } @@ -1141,6 +1205,28 @@ impl MemTxAttrs { } } #[inline] + pub unsafe fn secure_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 3usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 1usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_secure_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 3usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 1usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn space(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(2usize, 2u8) as u32) } } @@ -1152,6 +1238,28 @@ impl MemTxAttrs { } } #[inline] + pub unsafe fn space_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 3usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 2usize, + 2u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_space_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 3usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 2usize, + 2u8, + val as u64, + ) + } + } + #[inline] pub fn user(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 1u8) as u32) } } @@ -1163,6 +1271,28 @@ impl MemTxAttrs { } } #[inline] + pub unsafe fn user_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 3usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 4usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_user_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 3usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 4usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn memory(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(5usize, 1u8) as u32) } } @@ -1174,6 +1304,28 @@ impl MemTxAttrs { } } #[inline] + pub unsafe fn memory_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 3usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 5usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_memory_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 3usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 5usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn requester_id(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(6usize, 16u8) as u32) } } @@ -1185,6 +1337,28 @@ impl MemTxAttrs { } } #[inline] + pub unsafe fn requester_id_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 3usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 6usize, + 16u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_requester_id_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 3usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 6usize, + 16u8, + val as u64, + ) + } + } + #[inline] pub fn new_bitfield_1( unspecified: ::std::os::raw::c_uint, secure: ::std::os::raw::c_uint, @@ -2124,10 +2298,9 @@ pub const bfd_architecture_bfd_arch_cris: bfd_architecture = bfd_architecture(36 pub const bfd_architecture_bfd_arch_microblaze: bfd_architecture = bfd_architecture(37); pub const bfd_architecture_bfd_arch_moxie: bfd_architecture = bfd_architecture(38); pub const bfd_architecture_bfd_arch_ia64: bfd_architecture = bfd_architecture(39); -pub const bfd_architecture_bfd_arch_nios2: bfd_architecture = bfd_architecture(40); -pub const bfd_architecture_bfd_arch_rx: bfd_architecture = bfd_architecture(41); -pub const bfd_architecture_bfd_arch_loongarch: bfd_architecture = bfd_architecture(42); -pub const bfd_architecture_bfd_arch_last: bfd_architecture = bfd_architecture(43); +pub const bfd_architecture_bfd_arch_rx: bfd_architecture = bfd_architecture(40); +pub const bfd_architecture_bfd_arch_loongarch: bfd_architecture = bfd_architecture(41); +pub const bfd_architecture_bfd_arch_last: bfd_architecture = bfd_architecture(42); impl ::std::ops::BitOr for bfd_architecture { type Output = Self; #[inline] @@ -2407,46 +2580,57 @@ impl Default for disassemble_info { } } } -pub type hwaddr = u64; #[doc = " vaddr:\n Type wide enough to contain any #target_ulong virtual address."] pub type vaddr = u64; #[repr(C)] #[derive(Copy, Clone)] -pub union CPUTLBEntry { - pub __bindgen_anon_1: CPUTLBEntry__bindgen_ty_1, - pub addr_idx: [u64; 4usize], +pub struct CPUBreakpoint { + pub pc: vaddr, + pub flags: ::std::os::raw::c_int, + pub entry: CPUBreakpoint__bindgen_ty_1, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct CPUTLBEntry__bindgen_ty_1 { - pub addr_read: u64, - pub addr_write: u64, - pub addr_code: u64, - pub addend: usize, +#[derive(Copy, Clone)] +pub union CPUBreakpoint__bindgen_ty_1 { + pub tqe_next: *mut CPUBreakpoint, + pub tqe_circ: QTailQLink, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUTLBEntry__bindgen_ty_1"] - [::std::mem::size_of::() - 32usize]; - ["Alignment of CPUTLBEntry__bindgen_ty_1"] - [::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUTLBEntry__bindgen_ty_1::addr_read"] - [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addr_read) - 0usize]; - ["Offset of field: CPUTLBEntry__bindgen_ty_1::addr_write"] - [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addr_write) - 8usize]; - ["Offset of field: CPUTLBEntry__bindgen_ty_1::addr_code"] - [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addr_code) - 16usize]; - ["Offset of field: CPUTLBEntry__bindgen_ty_1::addend"] - [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addend) - 24usize]; + ["Size of CPUBreakpoint__bindgen_ty_1"] + [::std::mem::size_of::() - 16usize]; + ["Alignment of CPUBreakpoint__bindgen_ty_1"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUBreakpoint__bindgen_ty_1::tqe_next"] + [::std::mem::offset_of!(CPUBreakpoint__bindgen_ty_1, tqe_next) - 0usize]; + ["Offset of field: CPUBreakpoint__bindgen_ty_1::tqe_circ"] + [::std::mem::offset_of!(CPUBreakpoint__bindgen_ty_1, tqe_circ) - 0usize]; }; +impl Default for CPUBreakpoint__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUBreakpoint__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "CPUBreakpoint__bindgen_ty_1 {{ union }}") + } +} #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUTLBEntry"][::std::mem::size_of::() - 32usize]; - ["Alignment of CPUTLBEntry"][::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUTLBEntry::addr_idx"] - [::std::mem::offset_of!(CPUTLBEntry, addr_idx) - 0usize]; + ["Size of CPUBreakpoint"][::std::mem::size_of::() - 32usize]; + ["Alignment of CPUBreakpoint"][::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUBreakpoint::pc"][::std::mem::offset_of!(CPUBreakpoint, pc) - 0usize]; + ["Offset of field: CPUBreakpoint::flags"] + [::std::mem::offset_of!(CPUBreakpoint, flags) - 8usize]; + ["Offset of field: CPUBreakpoint::entry"] + [::std::mem::offset_of!(CPUBreakpoint, entry) - 16usize]; }; -impl Default for CPUTLBEntry { +impl Default for CPUBreakpoint { fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -2455,27 +2639,43 @@ impl Default for CPUTLBEntry { } } } -impl ::std::fmt::Debug for CPUTLBEntry { +impl ::std::fmt::Debug for CPUBreakpoint { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "CPUTLBEntry {{ union }}") + write!( + f, + "CPUBreakpoint {{ flags: {:?}, entry: {:?} }}", + self.flags, self.entry + ) } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CPUTLBDescFast { - pub mask: usize, - pub table: *mut CPUTLBEntry, +#[derive(Copy, Clone)] +pub struct CPUWatchpoint { + pub vaddr: vaddr, + pub len: vaddr, + pub hitaddr: vaddr, + pub hitattrs: MemTxAttrs, + pub flags: ::std::os::raw::c_int, + pub entry: CPUWatchpoint__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union CPUWatchpoint__bindgen_ty_1 { + pub tqe_next: *mut CPUWatchpoint, + pub tqe_circ: QTailQLink, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUTLBDescFast"][::std::mem::size_of::() - 16usize]; - ["Alignment of CPUTLBDescFast"][::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUTLBDescFast::mask"] - [::std::mem::offset_of!(CPUTLBDescFast, mask) - 0usize]; - ["Offset of field: CPUTLBDescFast::table"] - [::std::mem::offset_of!(CPUTLBDescFast, table) - 8usize]; + ["Size of CPUWatchpoint__bindgen_ty_1"] + [::std::mem::size_of::() - 16usize]; + ["Alignment of CPUWatchpoint__bindgen_ty_1"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUWatchpoint__bindgen_ty_1::tqe_next"] + [::std::mem::offset_of!(CPUWatchpoint__bindgen_ty_1, tqe_next) - 0usize]; + ["Offset of field: CPUWatchpoint__bindgen_ty_1::tqe_circ"] + [::std::mem::offset_of!(CPUWatchpoint__bindgen_ty_1, tqe_circ) - 0usize]; }; -impl Default for CPUTLBDescFast { +impl Default for CPUWatchpoint__bindgen_ty_1 { fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -2484,37 +2684,481 @@ impl Default for CPUTLBDescFast { } } } -pub const ShutdownCause_SHUTDOWN_CAUSE_NONE: ShutdownCause = ShutdownCause(0); -pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_ERROR: ShutdownCause = ShutdownCause(1); -pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_QMP_QUIT: ShutdownCause = ShutdownCause(2); -pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET: ShutdownCause = ShutdownCause(3); -pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_SIGNAL: ShutdownCause = ShutdownCause(4); -pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_UI: ShutdownCause = ShutdownCause(5); -pub const ShutdownCause_SHUTDOWN_CAUSE_GUEST_SHUTDOWN: ShutdownCause = ShutdownCause(6); -pub const ShutdownCause_SHUTDOWN_CAUSE_GUEST_RESET: ShutdownCause = ShutdownCause(7); -pub const ShutdownCause_SHUTDOWN_CAUSE_GUEST_PANIC: ShutdownCause = ShutdownCause(8); -pub const ShutdownCause_SHUTDOWN_CAUSE_SUBSYSTEM_RESET: ShutdownCause = ShutdownCause(9); -pub const ShutdownCause_SHUTDOWN_CAUSE_SNAPSHOT_LOAD: ShutdownCause = ShutdownCause(10); -pub const ShutdownCause_SHUTDOWN_CAUSE__MAX: ShutdownCause = ShutdownCause(11); -impl ::std::ops::BitOr for ShutdownCause { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - ShutdownCause(self.0 | other.0) - } -} -impl ::std::ops::BitOrAssign for ShutdownCause { - #[inline] - fn bitor_assign(&mut self, rhs: ShutdownCause) { - self.0 |= rhs.0; +impl ::std::fmt::Debug for CPUWatchpoint__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "CPUWatchpoint__bindgen_ty_1 {{ union }}") } } -impl ::std::ops::BitAnd for ShutdownCause { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - ShutdownCause(self.0 & other.0) - } +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CPUWatchpoint"][::std::mem::size_of::() - 48usize]; + ["Alignment of CPUWatchpoint"][::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUWatchpoint::vaddr"] + [::std::mem::offset_of!(CPUWatchpoint, vaddr) - 0usize]; + ["Offset of field: CPUWatchpoint::len"][::std::mem::offset_of!(CPUWatchpoint, len) - 8usize]; + ["Offset of field: CPUWatchpoint::hitaddr"] + [::std::mem::offset_of!(CPUWatchpoint, hitaddr) - 16usize]; + ["Offset of field: CPUWatchpoint::hitattrs"] + [::std::mem::offset_of!(CPUWatchpoint, hitattrs) - 24usize]; + ["Offset of field: CPUWatchpoint::flags"] + [::std::mem::offset_of!(CPUWatchpoint, flags) - 28usize]; + ["Offset of field: CPUWatchpoint::entry"] + [::std::mem::offset_of!(CPUWatchpoint, entry) - 32usize]; +}; +impl Default for CPUWatchpoint { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUWatchpoint { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "CPUWatchpoint {{ hitattrs: {:?}, flags: {:?}, entry: {:?} }}", + self.hitattrs, self.flags, self.entry + ) + } +} +pub type hwaddr = u64; +#[repr(C)] +#[derive(Copy, Clone)] +pub union CPUTLBEntry { + pub __bindgen_anon_1: CPUTLBEntry__bindgen_ty_1, + pub addr_idx: [u64; 4usize], +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct CPUTLBEntry__bindgen_ty_1 { + pub addr_read: u64, + pub addr_write: u64, + pub addr_code: u64, + pub addend: usize, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CPUTLBEntry__bindgen_ty_1"] + [::std::mem::size_of::() - 32usize]; + ["Alignment of CPUTLBEntry__bindgen_ty_1"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUTLBEntry__bindgen_ty_1::addr_read"] + [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addr_read) - 0usize]; + ["Offset of field: CPUTLBEntry__bindgen_ty_1::addr_write"] + [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addr_write) - 8usize]; + ["Offset of field: CPUTLBEntry__bindgen_ty_1::addr_code"] + [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addr_code) - 16usize]; + ["Offset of field: CPUTLBEntry__bindgen_ty_1::addend"] + [::std::mem::offset_of!(CPUTLBEntry__bindgen_ty_1, addend) - 24usize]; +}; +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CPUTLBEntry"][::std::mem::size_of::() - 32usize]; + ["Alignment of CPUTLBEntry"][::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUTLBEntry::addr_idx"] + [::std::mem::offset_of!(CPUTLBEntry, addr_idx) - 0usize]; +}; +impl Default for CPUTLBEntry { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUTLBEntry { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "CPUTLBEntry {{ union }}") + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CPUTLBDescFast { + pub mask: usize, + pub table: *mut CPUTLBEntry, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CPUTLBDescFast"][::std::mem::size_of::() - 16usize]; + ["Alignment of CPUTLBDescFast"][::std::mem::align_of::() - 8usize]; + ["Offset of field: CPUTLBDescFast::mask"] + [::std::mem::offset_of!(CPUTLBDescFast, mask) - 0usize]; + ["Offset of field: CPUTLBDescFast::table"] + [::std::mem::offset_of!(CPUTLBDescFast, table) - 8usize]; +}; +impl Default for CPUTLBDescFast { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +pub const OnOffAuto_ON_OFF_AUTO_AUTO: OnOffAuto = OnOffAuto(0); +pub const OnOffAuto_ON_OFF_AUTO_ON: OnOffAuto = OnOffAuto(1); +pub const OnOffAuto_ON_OFF_AUTO_OFF: OnOffAuto = OnOffAuto(2); +pub const OnOffAuto_ON_OFF_AUTO__MAX: OnOffAuto = OnOffAuto(3); +impl ::std::ops::BitOr for OnOffAuto { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + OnOffAuto(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for OnOffAuto { + #[inline] + fn bitor_assign(&mut self, rhs: OnOffAuto) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for OnOffAuto { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + OnOffAuto(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for OnOffAuto { + #[inline] + fn bitand_assign(&mut self, rhs: OnOffAuto) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct OnOffAuto(pub ::std::os::raw::c_uint); +pub const CpuS390Entitlement_S390_CPU_ENTITLEMENT_AUTO: CpuS390Entitlement = CpuS390Entitlement(0); +pub const CpuS390Entitlement_S390_CPU_ENTITLEMENT_LOW: CpuS390Entitlement = CpuS390Entitlement(1); +pub const CpuS390Entitlement_S390_CPU_ENTITLEMENT_MEDIUM: CpuS390Entitlement = + CpuS390Entitlement(2); +pub const CpuS390Entitlement_S390_CPU_ENTITLEMENT_HIGH: CpuS390Entitlement = CpuS390Entitlement(3); +pub const CpuS390Entitlement_S390_CPU_ENTITLEMENT__MAX: CpuS390Entitlement = CpuS390Entitlement(4); +impl ::std::ops::BitOr for CpuS390Entitlement { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + CpuS390Entitlement(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for CpuS390Entitlement { + #[inline] + fn bitor_assign(&mut self, rhs: CpuS390Entitlement) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for CpuS390Entitlement { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + CpuS390Entitlement(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for CpuS390Entitlement { + #[inline] + fn bitand_assign(&mut self, rhs: CpuS390Entitlement) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct CpuS390Entitlement(pub ::std::os::raw::c_uint); +pub const SysEmuTarget_SYS_EMU_TARGET_AARCH64: SysEmuTarget = SysEmuTarget(0); +pub const SysEmuTarget_SYS_EMU_TARGET_ALPHA: SysEmuTarget = SysEmuTarget(1); +pub const SysEmuTarget_SYS_EMU_TARGET_ARM: SysEmuTarget = SysEmuTarget(2); +pub const SysEmuTarget_SYS_EMU_TARGET_AVR: SysEmuTarget = SysEmuTarget(3); +pub const SysEmuTarget_SYS_EMU_TARGET_CRIS: SysEmuTarget = SysEmuTarget(4); +pub const SysEmuTarget_SYS_EMU_TARGET_HPPA: SysEmuTarget = SysEmuTarget(5); +pub const SysEmuTarget_SYS_EMU_TARGET_I386: SysEmuTarget = SysEmuTarget(6); +pub const SysEmuTarget_SYS_EMU_TARGET_LOONGARCH64: SysEmuTarget = SysEmuTarget(7); +pub const SysEmuTarget_SYS_EMU_TARGET_M68K: SysEmuTarget = SysEmuTarget(8); +pub const SysEmuTarget_SYS_EMU_TARGET_MICROBLAZE: SysEmuTarget = SysEmuTarget(9); +pub const SysEmuTarget_SYS_EMU_TARGET_MICROBLAZEEL: SysEmuTarget = SysEmuTarget(10); +pub const SysEmuTarget_SYS_EMU_TARGET_MIPS: SysEmuTarget = SysEmuTarget(11); +pub const SysEmuTarget_SYS_EMU_TARGET_MIPS64: SysEmuTarget = SysEmuTarget(12); +pub const SysEmuTarget_SYS_EMU_TARGET_MIPS64EL: SysEmuTarget = SysEmuTarget(13); +pub const SysEmuTarget_SYS_EMU_TARGET_MIPSEL: SysEmuTarget = SysEmuTarget(14); +pub const SysEmuTarget_SYS_EMU_TARGET_OR1K: SysEmuTarget = SysEmuTarget(15); +pub const SysEmuTarget_SYS_EMU_TARGET_PPC: SysEmuTarget = SysEmuTarget(16); +pub const SysEmuTarget_SYS_EMU_TARGET_PPC64: SysEmuTarget = SysEmuTarget(17); +pub const SysEmuTarget_SYS_EMU_TARGET_RISCV32: SysEmuTarget = SysEmuTarget(18); +pub const SysEmuTarget_SYS_EMU_TARGET_RISCV64: SysEmuTarget = SysEmuTarget(19); +pub const SysEmuTarget_SYS_EMU_TARGET_RX: SysEmuTarget = SysEmuTarget(20); +pub const SysEmuTarget_SYS_EMU_TARGET_S390X: SysEmuTarget = SysEmuTarget(21); +pub const SysEmuTarget_SYS_EMU_TARGET_SH4: SysEmuTarget = SysEmuTarget(22); +pub const SysEmuTarget_SYS_EMU_TARGET_SH4EB: SysEmuTarget = SysEmuTarget(23); +pub const SysEmuTarget_SYS_EMU_TARGET_SPARC: SysEmuTarget = SysEmuTarget(24); +pub const SysEmuTarget_SYS_EMU_TARGET_SPARC64: SysEmuTarget = SysEmuTarget(25); +pub const SysEmuTarget_SYS_EMU_TARGET_TRICORE: SysEmuTarget = SysEmuTarget(26); +pub const SysEmuTarget_SYS_EMU_TARGET_X86_64: SysEmuTarget = SysEmuTarget(27); +pub const SysEmuTarget_SYS_EMU_TARGET_XTENSA: SysEmuTarget = SysEmuTarget(28); +pub const SysEmuTarget_SYS_EMU_TARGET_XTENSAEB: SysEmuTarget = SysEmuTarget(29); +pub const SysEmuTarget_SYS_EMU_TARGET__MAX: SysEmuTarget = SysEmuTarget(30); +impl ::std::ops::BitOr for SysEmuTarget { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + SysEmuTarget(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for SysEmuTarget { + #[inline] + fn bitor_assign(&mut self, rhs: SysEmuTarget) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for SysEmuTarget { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + SysEmuTarget(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for SysEmuTarget { + #[inline] + fn bitand_assign(&mut self, rhs: SysEmuTarget) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct SysEmuTarget(pub ::std::os::raw::c_uint); +pub const CpuS390State_S390_CPU_STATE_UNINITIALIZED: CpuS390State = CpuS390State(0); +pub const CpuS390State_S390_CPU_STATE_STOPPED: CpuS390State = CpuS390State(1); +pub const CpuS390State_S390_CPU_STATE_CHECK_STOP: CpuS390State = CpuS390State(2); +pub const CpuS390State_S390_CPU_STATE_OPERATING: CpuS390State = CpuS390State(3); +pub const CpuS390State_S390_CPU_STATE_LOAD: CpuS390State = CpuS390State(4); +pub const CpuS390State_S390_CPU_STATE__MAX: CpuS390State = CpuS390State(5); +impl ::std::ops::BitOr for CpuS390State { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + CpuS390State(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for CpuS390State { + #[inline] + fn bitor_assign(&mut self, rhs: CpuS390State) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for CpuS390State { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + CpuS390State(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for CpuS390State { + #[inline] + fn bitand_assign(&mut self, rhs: CpuS390State) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct CpuS390State(pub ::std::os::raw::c_uint); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CpuInfoS390 { + pub cpu_state: CpuS390State, + pub has_dedicated: bool, + pub dedicated: bool, + pub has_entitlement: bool, + pub entitlement: CpuS390Entitlement, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CpuInfoS390"][::std::mem::size_of::() - 12usize]; + ["Alignment of CpuInfoS390"][::std::mem::align_of::() - 4usize]; + ["Offset of field: CpuInfoS390::cpu_state"] + [::std::mem::offset_of!(CpuInfoS390, cpu_state) - 0usize]; + ["Offset of field: CpuInfoS390::has_dedicated"] + [::std::mem::offset_of!(CpuInfoS390, has_dedicated) - 4usize]; + ["Offset of field: CpuInfoS390::dedicated"] + [::std::mem::offset_of!(CpuInfoS390, dedicated) - 5usize]; + ["Offset of field: CpuInfoS390::has_entitlement"] + [::std::mem::offset_of!(CpuInfoS390, has_entitlement) - 6usize]; + ["Offset of field: CpuInfoS390::entitlement"] + [::std::mem::offset_of!(CpuInfoS390, entitlement) - 8usize]; +}; +impl Default for CpuInfoS390 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CpuInfoFast { + pub cpu_index: i64, + pub qom_path: *mut ::std::os::raw::c_char, + pub thread_id: i64, + pub props: *mut CpuInstanceProperties, + pub target: SysEmuTarget, + pub u: CpuInfoFast__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union CpuInfoFast__bindgen_ty_1 { + pub s390x: CpuInfoS390, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CpuInfoFast__bindgen_ty_1"] + [::std::mem::size_of::() - 12usize]; + ["Alignment of CpuInfoFast__bindgen_ty_1"] + [::std::mem::align_of::() - 4usize]; + ["Offset of field: CpuInfoFast__bindgen_ty_1::s390x"] + [::std::mem::offset_of!(CpuInfoFast__bindgen_ty_1, s390x) - 0usize]; +}; +impl Default for CpuInfoFast__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CpuInfoFast__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "CpuInfoFast__bindgen_ty_1 {{ union }}") + } +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CpuInfoFast"][::std::mem::size_of::() - 48usize]; + ["Alignment of CpuInfoFast"][::std::mem::align_of::() - 8usize]; + ["Offset of field: CpuInfoFast::cpu_index"] + [::std::mem::offset_of!(CpuInfoFast, cpu_index) - 0usize]; + ["Offset of field: CpuInfoFast::qom_path"] + [::std::mem::offset_of!(CpuInfoFast, qom_path) - 8usize]; + ["Offset of field: CpuInfoFast::thread_id"] + [::std::mem::offset_of!(CpuInfoFast, thread_id) - 16usize]; + ["Offset of field: CpuInfoFast::props"][::std::mem::offset_of!(CpuInfoFast, props) - 24usize]; + ["Offset of field: CpuInfoFast::target"][::std::mem::offset_of!(CpuInfoFast, target) - 32usize]; + ["Offset of field: CpuInfoFast::u"][::std::mem::offset_of!(CpuInfoFast, u) - 36usize]; +}; +impl Default for CpuInfoFast { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CpuInfoFast { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "CpuInfoFast {{ qom_path: {:?}, props: {:?}, target: {:?}, u: {:?} }}", + self.qom_path, self.props, self.target, self.u + ) + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct CpuInstanceProperties { + pub has_node_id: bool, + pub node_id: i64, + pub has_drawer_id: bool, + pub drawer_id: i64, + pub has_book_id: bool, + pub book_id: i64, + pub has_socket_id: bool, + pub socket_id: i64, + pub has_die_id: bool, + pub die_id: i64, + pub has_cluster_id: bool, + pub cluster_id: i64, + pub has_module_id: bool, + pub module_id: i64, + pub has_core_id: bool, + pub core_id: i64, + pub has_thread_id: bool, + pub thread_id: i64, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of CpuInstanceProperties"][::std::mem::size_of::() - 144usize]; + ["Alignment of CpuInstanceProperties"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: CpuInstanceProperties::has_node_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_node_id) - 0usize]; + ["Offset of field: CpuInstanceProperties::node_id"] + [::std::mem::offset_of!(CpuInstanceProperties, node_id) - 8usize]; + ["Offset of field: CpuInstanceProperties::has_drawer_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_drawer_id) - 16usize]; + ["Offset of field: CpuInstanceProperties::drawer_id"] + [::std::mem::offset_of!(CpuInstanceProperties, drawer_id) - 24usize]; + ["Offset of field: CpuInstanceProperties::has_book_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_book_id) - 32usize]; + ["Offset of field: CpuInstanceProperties::book_id"] + [::std::mem::offset_of!(CpuInstanceProperties, book_id) - 40usize]; + ["Offset of field: CpuInstanceProperties::has_socket_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_socket_id) - 48usize]; + ["Offset of field: CpuInstanceProperties::socket_id"] + [::std::mem::offset_of!(CpuInstanceProperties, socket_id) - 56usize]; + ["Offset of field: CpuInstanceProperties::has_die_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_die_id) - 64usize]; + ["Offset of field: CpuInstanceProperties::die_id"] + [::std::mem::offset_of!(CpuInstanceProperties, die_id) - 72usize]; + ["Offset of field: CpuInstanceProperties::has_cluster_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_cluster_id) - 80usize]; + ["Offset of field: CpuInstanceProperties::cluster_id"] + [::std::mem::offset_of!(CpuInstanceProperties, cluster_id) - 88usize]; + ["Offset of field: CpuInstanceProperties::has_module_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_module_id) - 96usize]; + ["Offset of field: CpuInstanceProperties::module_id"] + [::std::mem::offset_of!(CpuInstanceProperties, module_id) - 104usize]; + ["Offset of field: CpuInstanceProperties::has_core_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_core_id) - 112usize]; + ["Offset of field: CpuInstanceProperties::core_id"] + [::std::mem::offset_of!(CpuInstanceProperties, core_id) - 120usize]; + ["Offset of field: CpuInstanceProperties::has_thread_id"] + [::std::mem::offset_of!(CpuInstanceProperties, has_thread_id) - 128usize]; + ["Offset of field: CpuInstanceProperties::thread_id"] + [::std::mem::offset_of!(CpuInstanceProperties, thread_id) - 136usize]; +}; +pub const ShutdownCause_SHUTDOWN_CAUSE_NONE: ShutdownCause = ShutdownCause(0); +pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_ERROR: ShutdownCause = ShutdownCause(1); +pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_QMP_QUIT: ShutdownCause = ShutdownCause(2); +pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET: ShutdownCause = ShutdownCause(3); +pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_SIGNAL: ShutdownCause = ShutdownCause(4); +pub const ShutdownCause_SHUTDOWN_CAUSE_HOST_UI: ShutdownCause = ShutdownCause(5); +pub const ShutdownCause_SHUTDOWN_CAUSE_GUEST_SHUTDOWN: ShutdownCause = ShutdownCause(6); +pub const ShutdownCause_SHUTDOWN_CAUSE_GUEST_RESET: ShutdownCause = ShutdownCause(7); +pub const ShutdownCause_SHUTDOWN_CAUSE_GUEST_PANIC: ShutdownCause = ShutdownCause(8); +pub const ShutdownCause_SHUTDOWN_CAUSE_SUBSYSTEM_RESET: ShutdownCause = ShutdownCause(9); +pub const ShutdownCause_SHUTDOWN_CAUSE_SNAPSHOT_LOAD: ShutdownCause = ShutdownCause(10); +pub const ShutdownCause_SHUTDOWN_CAUSE__MAX: ShutdownCause = ShutdownCause(11); +impl ::std::ops::BitOr for ShutdownCause { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + ShutdownCause(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for ShutdownCause { + #[inline] + fn bitor_assign(&mut self, rhs: ShutdownCause) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for ShutdownCause { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + ShutdownCause(self.0 & other.0) + } } impl ::std::ops::BitAndAssign for ShutdownCause { #[inline] @@ -2527,6 +3171,16 @@ impl ::std::ops::BitAndAssign for ShutdownCause { pub struct ShutdownCause(pub ::std::os::raw::c_uint); #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct CPUAddressSpace { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CPUJumpCache { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct SysemuCPUOps { _unused: [u8; 0], } @@ -2887,163 +3541,18 @@ const _: () = { ["Alignment of IcountDecr__bindgen_ty_1"] [::std::mem::align_of::() - 2usize]; ["Offset of field: IcountDecr__bindgen_ty_1::low"] - [::std::mem::offset_of!(IcountDecr__bindgen_ty_1, low) - 0usize]; - ["Offset of field: IcountDecr__bindgen_ty_1::high"] - [::std::mem::offset_of!(IcountDecr__bindgen_ty_1, high) - 2usize]; -}; -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of IcountDecr"][::std::mem::size_of::() - 4usize]; - ["Alignment of IcountDecr"][::std::mem::align_of::() - 4usize]; - ["Offset of field: IcountDecr::u32_"][::std::mem::offset_of!(IcountDecr, u32_) - 0usize]; - ["Offset of field: IcountDecr::u16_"][::std::mem::offset_of!(IcountDecr, u16_) - 0usize]; -}; -impl Default for IcountDecr { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for IcountDecr { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "IcountDecr {{ union }}") - } -} -#[repr(C)] -#[repr(align(16))] -#[derive(Copy, Clone)] -pub struct CPUNegativeOffsetState { - pub tlb: CPUTLB, - pub icount_decr: IcountDecr, - pub can_do_io: bool, -} -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of CPUNegativeOffsetState"][::std::mem::size_of::() - 9392usize]; - ["Alignment of CPUNegativeOffsetState"] - [::std::mem::align_of::() - 16usize]; - ["Offset of field: CPUNegativeOffsetState::tlb"] - [::std::mem::offset_of!(CPUNegativeOffsetState, tlb) - 0usize]; - ["Offset of field: CPUNegativeOffsetState::icount_decr"] - [::std::mem::offset_of!(CPUNegativeOffsetState, icount_decr) - 9376usize]; - ["Offset of field: CPUNegativeOffsetState::can_do_io"] - [::std::mem::offset_of!(CPUNegativeOffsetState, can_do_io) - 9380usize]; -}; -impl Default for CPUNegativeOffsetState { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for CPUNegativeOffsetState { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "CPUNegativeOffsetState {{ tlb: {:?}, icount_decr: {:?}, can_do_io: {:?} }}", - self.tlb, self.icount_decr, self.can_do_io - ) - } -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct CPUBreakpoint { - pub pc: vaddr, - pub flags: ::std::os::raw::c_int, - pub entry: CPUBreakpoint__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union CPUBreakpoint__bindgen_ty_1 { - pub tqe_next: *mut CPUBreakpoint, - pub tqe_circ: QTailQLink, -} -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of CPUBreakpoint__bindgen_ty_1"] - [::std::mem::size_of::() - 16usize]; - ["Alignment of CPUBreakpoint__bindgen_ty_1"] - [::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUBreakpoint__bindgen_ty_1::tqe_next"] - [::std::mem::offset_of!(CPUBreakpoint__bindgen_ty_1, tqe_next) - 0usize]; - ["Offset of field: CPUBreakpoint__bindgen_ty_1::tqe_circ"] - [::std::mem::offset_of!(CPUBreakpoint__bindgen_ty_1, tqe_circ) - 0usize]; -}; -impl Default for CPUBreakpoint__bindgen_ty_1 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for CPUBreakpoint__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "CPUBreakpoint__bindgen_ty_1 {{ union }}") - } -} -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of CPUBreakpoint"][::std::mem::size_of::() - 32usize]; - ["Alignment of CPUBreakpoint"][::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUBreakpoint::pc"][::std::mem::offset_of!(CPUBreakpoint, pc) - 0usize]; - ["Offset of field: CPUBreakpoint::flags"] - [::std::mem::offset_of!(CPUBreakpoint, flags) - 8usize]; - ["Offset of field: CPUBreakpoint::entry"] - [::std::mem::offset_of!(CPUBreakpoint, entry) - 16usize]; -}; -impl Default for CPUBreakpoint { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for CPUBreakpoint { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "CPUBreakpoint {{ flags: {:?}, entry: {:?} }}", - self.flags, self.entry - ) - } -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct CPUWatchpoint { - pub vaddr: vaddr, - pub len: vaddr, - pub hitaddr: vaddr, - pub hitattrs: MemTxAttrs, - pub flags: ::std::os::raw::c_int, - pub entry: CPUWatchpoint__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union CPUWatchpoint__bindgen_ty_1 { - pub tqe_next: *mut CPUWatchpoint, - pub tqe_circ: QTailQLink, -} + [::std::mem::offset_of!(IcountDecr__bindgen_ty_1, low) - 0usize]; + ["Offset of field: IcountDecr__bindgen_ty_1::high"] + [::std::mem::offset_of!(IcountDecr__bindgen_ty_1, high) - 2usize]; +}; #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUWatchpoint__bindgen_ty_1"] - [::std::mem::size_of::() - 16usize]; - ["Alignment of CPUWatchpoint__bindgen_ty_1"] - [::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUWatchpoint__bindgen_ty_1::tqe_next"] - [::std::mem::offset_of!(CPUWatchpoint__bindgen_ty_1, tqe_next) - 0usize]; - ["Offset of field: CPUWatchpoint__bindgen_ty_1::tqe_circ"] - [::std::mem::offset_of!(CPUWatchpoint__bindgen_ty_1, tqe_circ) - 0usize]; + ["Size of IcountDecr"][::std::mem::size_of::() - 4usize]; + ["Alignment of IcountDecr"][::std::mem::align_of::() - 4usize]; + ["Offset of field: IcountDecr::u32_"][::std::mem::offset_of!(IcountDecr, u32_) - 0usize]; + ["Offset of field: IcountDecr::u16_"][::std::mem::offset_of!(IcountDecr, u16_) - 0usize]; }; -impl Default for CPUWatchpoint__bindgen_ty_1 { +impl Default for IcountDecr { fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -3052,28 +3561,36 @@ impl Default for CPUWatchpoint__bindgen_ty_1 { } } } -impl ::std::fmt::Debug for CPUWatchpoint__bindgen_ty_1 { +impl ::std::fmt::Debug for IcountDecr { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "CPUWatchpoint__bindgen_ty_1 {{ union }}") + write!(f, "IcountDecr {{ union }}") } } +#[doc = " CPUNegativeOffsetState: Elements of CPUState most efficiently accessed\n from CPUArchState, via small negative offsets.\n @can_do_io: True if memory-mapped IO is allowed.\n @plugin_mem_cbs: active plugin memory callbacks"] +#[repr(C)] +#[repr(align(16))] +#[derive(Copy, Clone)] +pub struct CPUNegativeOffsetState { + pub tlb: CPUTLB, + pub plugin_mem_cbs: *mut GArray, + pub icount_decr: IcountDecr, + pub can_do_io: bool, +} #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUWatchpoint"][::std::mem::size_of::() - 48usize]; - ["Alignment of CPUWatchpoint"][::std::mem::align_of::() - 8usize]; - ["Offset of field: CPUWatchpoint::vaddr"] - [::std::mem::offset_of!(CPUWatchpoint, vaddr) - 0usize]; - ["Offset of field: CPUWatchpoint::len"][::std::mem::offset_of!(CPUWatchpoint, len) - 8usize]; - ["Offset of field: CPUWatchpoint::hitaddr"] - [::std::mem::offset_of!(CPUWatchpoint, hitaddr) - 16usize]; - ["Offset of field: CPUWatchpoint::hitattrs"] - [::std::mem::offset_of!(CPUWatchpoint, hitattrs) - 24usize]; - ["Offset of field: CPUWatchpoint::flags"] - [::std::mem::offset_of!(CPUWatchpoint, flags) - 28usize]; - ["Offset of field: CPUWatchpoint::entry"] - [::std::mem::offset_of!(CPUWatchpoint, entry) - 32usize]; + ["Size of CPUNegativeOffsetState"][::std::mem::size_of::() - 9392usize]; + ["Alignment of CPUNegativeOffsetState"] + [::std::mem::align_of::() - 16usize]; + ["Offset of field: CPUNegativeOffsetState::tlb"] + [::std::mem::offset_of!(CPUNegativeOffsetState, tlb) - 0usize]; + ["Offset of field: CPUNegativeOffsetState::plugin_mem_cbs"] + [::std::mem::offset_of!(CPUNegativeOffsetState, plugin_mem_cbs) - 9376usize]; + ["Offset of field: CPUNegativeOffsetState::icount_decr"] + [::std::mem::offset_of!(CPUNegativeOffsetState, icount_decr) - 9384usize]; + ["Offset of field: CPUNegativeOffsetState::can_do_io"] + [::std::mem::offset_of!(CPUNegativeOffsetState, can_do_io) - 9388usize]; }; -impl Default for CPUWatchpoint { +impl Default for CPUNegativeOffsetState { fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -3082,13 +3599,9 @@ impl Default for CPUWatchpoint { } } } -impl ::std::fmt::Debug for CPUWatchpoint { +impl ::std::fmt::Debug for CPUNegativeOffsetState { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "CPUWatchpoint {{ hitattrs: {:?}, flags: {:?}, entry: {:?} }}", - self.hitattrs, self.flags, self.entry - ) + write ! (f , "CPUNegativeOffsetState {{ tlb: {:?}, plugin_mem_cbs: {:?}, icount_decr: {:?}, can_do_io: {:?} }}" , self . tlb , self . plugin_mem_cbs , self . icount_decr , self . can_do_io) } } #[repr(C)] @@ -3106,7 +3619,7 @@ pub struct kvm_run { pub struct qemu_work_item { _unused: [u8; 0], } -#[doc = " CPUState:\n @cpu_index: CPU index (informative).\n @cluster_index: Identifies which cluster this CPU is in.\n For boards which don't define clusters or for \"loose\" CPUs not assigned\n to a cluster this will be UNASSIGNED_CLUSTER_INDEX; otherwise it will\n be the same as the cluster-id property of the CPU object's TYPE_CPU_CLUSTER\n QOM parent.\n Under TCG this value is propagated to @tcg_cflags.\n See TranslationBlock::TCG CF_CLUSTER_MASK.\n @tcg_cflags: Pre-computed cflags for this cpu.\n @nr_cores: Number of cores within this CPU package.\n @nr_threads: Number of threads within this CPU core.\n @running: #true if CPU is currently running (lockless).\n @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;\n valid under cpu_list_lock.\n @created: Indicates whether the CPU thread has been successfully created.\n @interrupt_request: Indicates a pending interrupt request.\n @halted: Nonzero if the CPU is in suspended state.\n @stop: Indicates a pending stop request.\n @stopped: Indicates the CPU has been artificially stopped.\n @unplug: Indicates a pending CPU unplug request.\n @crash_occurred: Indicates the OS reported a crash (panic) for this CPU\n @singlestep_enabled: Flags for single-stepping.\n @icount_extra: Instructions until next timer event.\n @neg.can_do_io: True if memory-mapped IO is allowed.\n @cpu_ases: Pointer to array of CPUAddressSpaces (which define the\n AddressSpaces this CPU has)\n @num_ases: number of CPUAddressSpaces in @cpu_ases\n @as: Pointer to the first AddressSpace, for the convenience of targets which\n only have a single AddressSpace\n @gdb_regs: Additional GDB registers.\n @gdb_num_regs: Number of total registers accessible to GDB.\n @gdb_num_g_regs: Number of registers in GDB 'g' packets.\n @node: QTAILQ of CPUs sharing TB cache.\n @opaque: User data.\n @mem_io_pc: Host Program Counter at which the memory was accessed.\n @accel: Pointer to accelerator specific state.\n @kvm_fd: vCPU file descriptor for KVM.\n @work_mutex: Lock to prevent multiple access to @work_list.\n @work_list: List of pending asynchronous work.\n @plugin_mem_cbs: active plugin memory callbacks\n @plugin_state: per-CPU plugin state\n @ignore_memory_transaction_failures: Cached copy of the MachineState\n flag of the same name: allows the board to suppress calling of the\n CPU do_transaction_failed hook function.\n @kvm_dirty_gfns: Points to the KVM dirty ring for this CPU when KVM dirty\n ring is enabled.\n @kvm_fetch_index: Keeps the index that we last fetched from the per-vCPU\n dirty ring structure.\n\n State of one CPU core or thread.\n\n Align, in order to match possible alignment required by CPUArchState,\n and eliminate a hole between CPUState and CPUArchState within ArchCPU."] +#[doc = " struct CPUState - common state of one CPU core or thread.\n\n @cpu_index: CPU index (informative).\n @cluster_index: Identifies which cluster this CPU is in.\n For boards which don't define clusters or for \"loose\" CPUs not assigned\n to a cluster this will be UNASSIGNED_CLUSTER_INDEX; otherwise it will\n be the same as the cluster-id property of the CPU object's TYPE_CPU_CLUSTER\n QOM parent.\n Under TCG this value is propagated to @tcg_cflags.\n See TranslationBlock::TCG CF_CLUSTER_MASK.\n @tcg_cflags: Pre-computed cflags for this cpu.\n @nr_cores: Number of cores within this CPU package.\n @nr_threads: Number of threads within this CPU core.\n @thread: Host thread details, only live once @created is #true\n @sem: WIN32 only semaphore used only for qtest\n @thread_id: native thread id of vCPU, only live once @created is #true\n @running: #true if CPU is currently running (lockless).\n @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;\n valid under cpu_list_lock.\n @created: Indicates whether the CPU thread has been successfully created.\n @halt_cond: condition variable sleeping threads can wait on.\n @interrupt_request: Indicates a pending interrupt request.\n @halted: Nonzero if the CPU is in suspended state.\n @stop: Indicates a pending stop request.\n @stopped: Indicates the CPU has been artificially stopped.\n @unplug: Indicates a pending CPU unplug request.\n @crash_occurred: Indicates the OS reported a crash (panic) for this CPU\n @singlestep_enabled: Flags for single-stepping.\n @icount_extra: Instructions until next timer event.\n @cpu_ases: Pointer to array of CPUAddressSpaces (which define the\n AddressSpaces this CPU has)\n @num_ases: number of CPUAddressSpaces in @cpu_ases\n @as: Pointer to the first AddressSpace, for the convenience of targets which\n only have a single AddressSpace\n @gdb_regs: Additional GDB registers.\n @gdb_num_regs: Number of total registers accessible to GDB.\n @gdb_num_g_regs: Number of registers in GDB 'g' packets.\n @node: QTAILQ of CPUs sharing TB cache.\n @opaque: User data.\n @mem_io_pc: Host Program Counter at which the memory was accessed.\n @accel: Pointer to accelerator specific state.\n @kvm_fd: vCPU file descriptor for KVM.\n @work_mutex: Lock to prevent multiple access to @work_list.\n @work_list: List of pending asynchronous work.\n @plugin_state: per-CPU plugin state\n @ignore_memory_transaction_failures: Cached copy of the MachineState\n flag of the same name: allows the board to suppress calling of the\n CPU do_transaction_failed hook function.\n @kvm_dirty_gfns: Points to the KVM dirty ring for this CPU when KVM dirty\n ring is enabled.\n @kvm_fetch_index: Keeps the index that we last fetched from the per-vCPU\n dirty ring structure.\n\n @neg_align: The CPUState is the common part of a concrete ArchCPU\n which is allocated when an individual CPU instance is created. As\n such care is taken is ensure there is no gap between between\n CPUState and CPUArchState within ArchCPU.\n\n @neg: The architectural register state (\"cpu_env\") immediately follows\n CPUState in ArchCPU and is passed to TCG code. The @neg structure holds\n some common TCG CPU variables which are accessed with a negative offset\n from cpu_env."] #[repr(C)] #[repr(align(16))] pub struct CPUState { @@ -3138,6 +3651,7 @@ pub struct CPUState { pub work_mutex: QemuMutex, pub work_list: CPUState__bindgen_ty_1, pub cpu_ases: *mut CPUAddressSpace, + pub cpu_ases_count: ::std::os::raw::c_int, pub num_ases: ::std::os::raw::c_int, pub as_: *mut AddressSpace, pub memory: *mut MemoryRegion, @@ -3158,8 +3672,8 @@ pub struct CPUState { pub kvm_fetch_index: u32, pub dirty_pages: u64, pub kvm_vcpu_stats_fd: ::std::os::raw::c_int, + pub vcpu_dirty: bool, pub in_ioctl_lock: QemuLockCnt, - pub plugin_mem_cbs: *mut GArray, pub plugin_state: *mut CPUPluginState, pub cpu_index: ::std::os::raw::c_int, pub cluster_index: ::std::os::raw::c_int, @@ -3167,7 +3681,6 @@ pub struct CPUState { pub halted: u32, pub exception_index: i32, pub accel: *mut AccelCPUState, - pub vcpu_dirty: bool, pub throttle_thread_scheduled: bool, pub throttle_us_per_full: i64, pub ignore_memory_transaction_failures: bool, @@ -3342,7 +3855,9 @@ const _: () = { ["Offset of field: CPUState::work_list"] [::std::mem::offset_of!(CPUState, work_list) - 496usize]; ["Offset of field: CPUState::cpu_ases"][::std::mem::offset_of!(CPUState, cpu_ases) - 512usize]; - ["Offset of field: CPUState::num_ases"][::std::mem::offset_of!(CPUState, num_ases) - 520usize]; + ["Offset of field: CPUState::cpu_ases_count"] + [::std::mem::offset_of!(CPUState, cpu_ases_count) - 520usize]; + ["Offset of field: CPUState::num_ases"][::std::mem::offset_of!(CPUState, num_ases) - 524usize]; ["Offset of field: CPUState::as_"][::std::mem::offset_of!(CPUState, as_) - 528usize]; ["Offset of field: CPUState::memory"][::std::mem::offset_of!(CPUState, memory) - 536usize]; ["Offset of field: CPUState::tb_jmp_cache"] @@ -3374,10 +3889,10 @@ const _: () = { [::std::mem::offset_of!(CPUState, dirty_pages) - 680usize]; ["Offset of field: CPUState::kvm_vcpu_stats_fd"] [::std::mem::offset_of!(CPUState, kvm_vcpu_stats_fd) - 688usize]; + ["Offset of field: CPUState::vcpu_dirty"] + [::std::mem::offset_of!(CPUState, vcpu_dirty) - 692usize]; ["Offset of field: CPUState::in_ioctl_lock"] - [::std::mem::offset_of!(CPUState, in_ioctl_lock) - 692usize]; - ["Offset of field: CPUState::plugin_mem_cbs"] - [::std::mem::offset_of!(CPUState, plugin_mem_cbs) - 696usize]; + [::std::mem::offset_of!(CPUState, in_ioctl_lock) - 696usize]; ["Offset of field: CPUState::plugin_state"] [::std::mem::offset_of!(CPUState, plugin_state) - 704usize]; ["Offset of field: CPUState::cpu_index"] @@ -3390,10 +3905,8 @@ const _: () = { ["Offset of field: CPUState::exception_index"] [::std::mem::offset_of!(CPUState, exception_index) - 728usize]; ["Offset of field: CPUState::accel"][::std::mem::offset_of!(CPUState, accel) - 736usize]; - ["Offset of field: CPUState::vcpu_dirty"] - [::std::mem::offset_of!(CPUState, vcpu_dirty) - 744usize]; ["Offset of field: CPUState::throttle_thread_scheduled"] - [::std::mem::offset_of!(CPUState, throttle_thread_scheduled) - 745usize]; + [::std::mem::offset_of!(CPUState, throttle_thread_scheduled) - 744usize]; ["Offset of field: CPUState::throttle_us_per_full"] [::std::mem::offset_of!(CPUState, throttle_us_per_full) - 752usize]; ["Offset of field: CPUState::ignore_memory_transaction_failures"] @@ -3417,10 +3930,10 @@ impl Default for CPUState { } impl ::std::fmt::Debug for CPUState { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write ! (f , "CPUState {{ parent_obj: {:?}, cc: {:?}, nr_cores: {:?}, nr_threads: {:?}, thread: {:?}, thread_id: {:?}, running: {:?}, has_waiter: {:?}, halt_cond: {:?}, thread_kicked: {:?}, created: {:?}, stop: {:?}, stopped: {:?}, start_powered_off: {:?}, unplug: {:?}, crash_occurred: {:?}, exit_request: {:?}, exclusive_context_count: {:?}, singlestep_enabled: {:?}, jmp_env: {:?}, work_mutex: {:?}, work_list: {:?}, cpu_ases: {:?}, num_ases: {:?}, as: {:?}, memory: {:?}, tb_jmp_cache: {:?}, gdb_regs: {:?}, gdb_num_regs: {:?}, gdb_num_g_regs: {:?}, node: {:?}, breakpoints: {:?}, watchpoints: {:?}, watchpoint_hit: {:?}, opaque: {:?}, kvm_fd: {:?}, kvm_state: {:?}, kvm_run: {:?}, kvm_dirty_gfns: {:?}, kvm_vcpu_stats_fd: {:?}, in_ioctl_lock: {:?}, plugin_mem_cbs: {:?}, plugin_state: {:?}, cpu_index: {:?}, cluster_index: {:?}, accel: {:?}, vcpu_dirty: {:?}, throttle_thread_scheduled: {:?}, ignore_memory_transaction_failures: {:?}, prctl_unalign_sigbus: {:?}, iommu_notifiers: {:?}, neg_align: {:?}, neg: {:?} }}" , self . parent_obj , self . cc , self . nr_cores , self . nr_threads , self . thread , self . thread_id , self . running , self . has_waiter , self . halt_cond , self . thread_kicked , self . created , self . stop , self . stopped , self . start_powered_off , self . unplug , self . crash_occurred , self . exit_request , self . exclusive_context_count , self . singlestep_enabled , self . jmp_env , self . work_mutex , self . work_list , self . cpu_ases , self . num_ases , self . as_ , self . memory , self . tb_jmp_cache , self . gdb_regs , self . gdb_num_regs , self . gdb_num_g_regs , self . node , self . breakpoints , self . watchpoints , self . watchpoint_hit , self . opaque , self . kvm_fd , self . kvm_state , self . kvm_run , self . kvm_dirty_gfns , self . kvm_vcpu_stats_fd , self . in_ioctl_lock , self . plugin_mem_cbs , self . plugin_state , self . cpu_index , self . cluster_index , self . accel , self . vcpu_dirty , self . throttle_thread_scheduled , self . ignore_memory_transaction_failures , self . prctl_unalign_sigbus , self . iommu_notifiers , self . neg_align , self . neg) + write ! (f , "CPUState {{ parent_obj: {:?}, cc: {:?}, nr_cores: {:?}, nr_threads: {:?}, thread: {:?}, thread_id: {:?}, running: {:?}, has_waiter: {:?}, halt_cond: {:?}, thread_kicked: {:?}, created: {:?}, stop: {:?}, stopped: {:?}, start_powered_off: {:?}, unplug: {:?}, crash_occurred: {:?}, exit_request: {:?}, exclusive_context_count: {:?}, singlestep_enabled: {:?}, jmp_env: {:?}, work_mutex: {:?}, work_list: {:?}, cpu_ases: {:?}, cpu_ases_count: {:?}, num_ases: {:?}, as: {:?}, memory: {:?}, tb_jmp_cache: {:?}, gdb_regs: {:?}, gdb_num_regs: {:?}, gdb_num_g_regs: {:?}, node: {:?}, breakpoints: {:?}, watchpoints: {:?}, watchpoint_hit: {:?}, opaque: {:?}, kvm_fd: {:?}, kvm_state: {:?}, kvm_run: {:?}, kvm_dirty_gfns: {:?}, kvm_vcpu_stats_fd: {:?}, vcpu_dirty: {:?}, in_ioctl_lock: {:?}, plugin_state: {:?}, cpu_index: {:?}, cluster_index: {:?}, accel: {:?}, throttle_thread_scheduled: {:?}, ignore_memory_transaction_failures: {:?}, prctl_unalign_sigbus: {:?}, iommu_notifiers: {:?}, neg_align: {:?}, neg: {:?} }}" , self . parent_obj , self . cc , self . nr_cores , self . nr_threads , self . thread , self . thread_id , self . running , self . has_waiter , self . halt_cond , self . thread_kicked , self . created , self . stop , self . stopped , self . start_powered_off , self . unplug , self . crash_occurred , self . exit_request , self . exclusive_context_count , self . singlestep_enabled , self . jmp_env , self . work_mutex , self . work_list , self . cpu_ases , self . cpu_ases_count , self . num_ases , self . as_ , self . memory , self . tb_jmp_cache , self . gdb_regs , self . gdb_num_regs , self . gdb_num_g_regs , self . node , self . breakpoints , self . watchpoints , self . watchpoint_hit , self . opaque , self . kvm_fd , self . kvm_state , self . kvm_run , self . kvm_dirty_gfns , self . kvm_vcpu_stats_fd , self . vcpu_dirty , self . in_ioctl_lock , self . plugin_state , self . cpu_index , self . cluster_index , self . accel , self . throttle_thread_scheduled , self . ignore_memory_transaction_failures , self . prctl_unalign_sigbus , self . iommu_notifiers , self . neg_align , self . neg) } } -extern "C" { +unsafe extern "C" { #[doc = " cpu_reset:\n @cpu: The CPU whose state is to be reset."] pub fn cpu_reset(cpu: *mut CPUState); } @@ -3565,39 +4078,42 @@ impl Default for PropertyInfo { } #[doc = " X86CPU:\n @env: #CPUX86State\n @migratable: If set, only migratable flags will be accepted when \"enforce\"\n mode is used, and only migratable flags will be included in the \"host\"\n CPU model.\n\n An x86 CPU."] pub type X86CPU = ArchCPU; -pub const OnOffAuto_ON_OFF_AUTO_AUTO: OnOffAuto = OnOffAuto(0); -pub const OnOffAuto_ON_OFF_AUTO_ON: OnOffAuto = OnOffAuto(1); -pub const OnOffAuto_ON_OFF_AUTO_OFF: OnOffAuto = OnOffAuto(2); -pub const OnOffAuto_ON_OFF_AUTO__MAX: OnOffAuto = OnOffAuto(3); -impl ::std::ops::BitOr for OnOffAuto { +pub const CPUTopoLevel_CPU_TOPO_LEVEL_INVALID: CPUTopoLevel = CPUTopoLevel(0); +pub const CPUTopoLevel_CPU_TOPO_LEVEL_SMT: CPUTopoLevel = CPUTopoLevel(1); +pub const CPUTopoLevel_CPU_TOPO_LEVEL_CORE: CPUTopoLevel = CPUTopoLevel(2); +pub const CPUTopoLevel_CPU_TOPO_LEVEL_MODULE: CPUTopoLevel = CPUTopoLevel(3); +pub const CPUTopoLevel_CPU_TOPO_LEVEL_DIE: CPUTopoLevel = CPUTopoLevel(4); +pub const CPUTopoLevel_CPU_TOPO_LEVEL_PACKAGE: CPUTopoLevel = CPUTopoLevel(5); +pub const CPUTopoLevel_CPU_TOPO_LEVEL_MAX: CPUTopoLevel = CPUTopoLevel(6); +impl ::std::ops::BitOr for CPUTopoLevel { type Output = Self; #[inline] fn bitor(self, other: Self) -> Self { - OnOffAuto(self.0 | other.0) + CPUTopoLevel(self.0 | other.0) } } -impl ::std::ops::BitOrAssign for OnOffAuto { +impl ::std::ops::BitOrAssign for CPUTopoLevel { #[inline] - fn bitor_assign(&mut self, rhs: OnOffAuto) { + fn bitor_assign(&mut self, rhs: CPUTopoLevel) { self.0 |= rhs.0; } } -impl ::std::ops::BitAnd for OnOffAuto { +impl ::std::ops::BitAnd for CPUTopoLevel { type Output = Self; #[inline] fn bitand(self, other: Self) -> Self { - OnOffAuto(self.0 & other.0) + CPUTopoLevel(self.0 & other.0) } } -impl ::std::ops::BitAndAssign for OnOffAuto { +impl ::std::ops::BitAndAssign for CPUTopoLevel { #[inline] - fn bitand_assign(&mut self, rhs: OnOffAuto) { + fn bitand_assign(&mut self, rhs: CPUTopoLevel) { self.0 &= rhs.0; } } #[repr(transparent)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct OnOffAuto(pub ::std::os::raw::c_uint); +pub struct CPUTopoLevel(pub ::std::os::raw::c_uint); pub type float16 = u16; pub type float32 = u32; pub type float64 = u64; @@ -3736,7 +4252,7 @@ impl Default for float_status { } } } -pub type FeatureWordArray = [u64; 39usize]; +pub type FeatureWordArray = [u64; 40usize]; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct SegmentCache { @@ -4043,10 +4559,11 @@ pub struct CPUCacheInfo { pub no_invd_sharing: bool, pub inclusive: bool, pub complex_indexing: bool, + pub share_level: CPUTopoLevel, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUCacheInfo"][::std::mem::size_of::() - 28usize]; + ["Size of CPUCacheInfo"][::std::mem::size_of::() - 32usize]; ["Alignment of CPUCacheInfo"][::std::mem::align_of::() - 4usize]; ["Offset of field: CPUCacheInfo::type_"][::std::mem::offset_of!(CPUCacheInfo, type_) - 0usize]; ["Offset of field: CPUCacheInfo::level"][::std::mem::offset_of!(CPUCacheInfo, level) - 4usize]; @@ -4068,6 +4585,8 @@ const _: () = { [::std::mem::offset_of!(CPUCacheInfo, inclusive) - 23usize]; ["Offset of field: CPUCacheInfo::complex_indexing"] [::std::mem::offset_of!(CPUCacheInfo, complex_indexing) - 24usize]; + ["Offset of field: CPUCacheInfo::share_level"] + [::std::mem::offset_of!(CPUCacheInfo, share_level) - 28usize]; }; impl Default for CPUCacheInfo { fn default() -> Self { @@ -4165,6 +4684,15 @@ pub struct CPUArchState { pub cstar: target_ulong, pub fmask: target_ulong, pub kernelgsbase: target_ulong, + pub fred_rsp0: u64, + pub fred_rsp1: u64, + pub fred_rsp2: u64, + pub fred_rsp3: u64, + pub fred_stklvls: u64, + pub fred_ssp1: u64, + pub fred_ssp2: u64, + pub fred_ssp3: u64, + pub fred_config: u64, pub tsc_adjust: u64, pub tsc_deadline: u64, pub tsc_aux: u64, @@ -4250,6 +4778,8 @@ pub struct CPUArchState { pub nmi_injected: u8, pub nmi_pending: u8, pub retaddr: usize, + pub msr_rapl_power_unit: u64, + pub msr_pkg_energy_status: u64, pub end_reset_fields: CPUArchState__bindgen_ty_4, pub cpuid_level_func7: u32, pub cpuid_min_level_func7: u32, @@ -4304,6 +4834,8 @@ pub struct CPUArchState { pub umwait: u32, pub tpr_access_type: TPRAccess, pub nr_dies: ::std::os::raw::c_uint, + pub nr_modules: ::std::os::raw::c_uint, + pub avail_cpu_topo: [::std::os::raw::c_ulong; 1usize], } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] @@ -4368,7 +4900,7 @@ const _: () = { }; #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of CPUArchState"][::std::mem::size_of::() - 14896usize]; + ["Size of CPUArchState"][::std::mem::size_of::() - 15008usize]; ["Alignment of CPUArchState"][::std::mem::align_of::() - 16usize]; ["Offset of field: CPUArchState::regs"][::std::mem::offset_of!(CPUArchState, regs) - 0usize]; ["Offset of field: CPUArchState::eip"][::std::mem::offset_of!(CPUArchState, eip) - 128usize]; @@ -4460,278 +4992,304 @@ const _: () = { [::std::mem::offset_of!(CPUArchState, fmask) - 11344usize]; ["Offset of field: CPUArchState::kernelgsbase"] [::std::mem::offset_of!(CPUArchState, kernelgsbase) - 11352usize]; + ["Offset of field: CPUArchState::fred_rsp0"] + [::std::mem::offset_of!(CPUArchState, fred_rsp0) - 11360usize]; + ["Offset of field: CPUArchState::fred_rsp1"] + [::std::mem::offset_of!(CPUArchState, fred_rsp1) - 11368usize]; + ["Offset of field: CPUArchState::fred_rsp2"] + [::std::mem::offset_of!(CPUArchState, fred_rsp2) - 11376usize]; + ["Offset of field: CPUArchState::fred_rsp3"] + [::std::mem::offset_of!(CPUArchState, fred_rsp3) - 11384usize]; + ["Offset of field: CPUArchState::fred_stklvls"] + [::std::mem::offset_of!(CPUArchState, fred_stklvls) - 11392usize]; + ["Offset of field: CPUArchState::fred_ssp1"] + [::std::mem::offset_of!(CPUArchState, fred_ssp1) - 11400usize]; + ["Offset of field: CPUArchState::fred_ssp2"] + [::std::mem::offset_of!(CPUArchState, fred_ssp2) - 11408usize]; + ["Offset of field: CPUArchState::fred_ssp3"] + [::std::mem::offset_of!(CPUArchState, fred_ssp3) - 11416usize]; + ["Offset of field: CPUArchState::fred_config"] + [::std::mem::offset_of!(CPUArchState, fred_config) - 11424usize]; ["Offset of field: CPUArchState::tsc_adjust"] - [::std::mem::offset_of!(CPUArchState, tsc_adjust) - 11360usize]; + [::std::mem::offset_of!(CPUArchState, tsc_adjust) - 11432usize]; ["Offset of field: CPUArchState::tsc_deadline"] - [::std::mem::offset_of!(CPUArchState, tsc_deadline) - 11368usize]; + [::std::mem::offset_of!(CPUArchState, tsc_deadline) - 11440usize]; ["Offset of field: CPUArchState::tsc_aux"] - [::std::mem::offset_of!(CPUArchState, tsc_aux) - 11376usize]; + [::std::mem::offset_of!(CPUArchState, tsc_aux) - 11448usize]; ["Offset of field: CPUArchState::xcr0"] - [::std::mem::offset_of!(CPUArchState, xcr0) - 11384usize]; + [::std::mem::offset_of!(CPUArchState, xcr0) - 11456usize]; ["Offset of field: CPUArchState::mcg_status"] - [::std::mem::offset_of!(CPUArchState, mcg_status) - 11392usize]; + [::std::mem::offset_of!(CPUArchState, mcg_status) - 11464usize]; ["Offset of field: CPUArchState::msr_ia32_misc_enable"] - [::std::mem::offset_of!(CPUArchState, msr_ia32_misc_enable) - 11400usize]; + [::std::mem::offset_of!(CPUArchState, msr_ia32_misc_enable) - 11472usize]; ["Offset of field: CPUArchState::msr_ia32_feature_control"] - [::std::mem::offset_of!(CPUArchState, msr_ia32_feature_control) - 11408usize]; + [::std::mem::offset_of!(CPUArchState, msr_ia32_feature_control) - 11480usize]; ["Offset of field: CPUArchState::msr_ia32_sgxlepubkeyhash"] - [::std::mem::offset_of!(CPUArchState, msr_ia32_sgxlepubkeyhash) - 11416usize]; + [::std::mem::offset_of!(CPUArchState, msr_ia32_sgxlepubkeyhash) - 11488usize]; ["Offset of field: CPUArchState::msr_fixed_ctr_ctrl"] - [::std::mem::offset_of!(CPUArchState, msr_fixed_ctr_ctrl) - 11448usize]; + [::std::mem::offset_of!(CPUArchState, msr_fixed_ctr_ctrl) - 11520usize]; ["Offset of field: CPUArchState::msr_global_ctrl"] - [::std::mem::offset_of!(CPUArchState, msr_global_ctrl) - 11456usize]; + [::std::mem::offset_of!(CPUArchState, msr_global_ctrl) - 11528usize]; ["Offset of field: CPUArchState::msr_global_status"] - [::std::mem::offset_of!(CPUArchState, msr_global_status) - 11464usize]; + [::std::mem::offset_of!(CPUArchState, msr_global_status) - 11536usize]; ["Offset of field: CPUArchState::msr_global_ovf_ctrl"] - [::std::mem::offset_of!(CPUArchState, msr_global_ovf_ctrl) - 11472usize]; + [::std::mem::offset_of!(CPUArchState, msr_global_ovf_ctrl) - 11544usize]; ["Offset of field: CPUArchState::msr_fixed_counters"] - [::std::mem::offset_of!(CPUArchState, msr_fixed_counters) - 11480usize]; + [::std::mem::offset_of!(CPUArchState, msr_fixed_counters) - 11552usize]; ["Offset of field: CPUArchState::msr_gp_counters"] - [::std::mem::offset_of!(CPUArchState, msr_gp_counters) - 11504usize]; + [::std::mem::offset_of!(CPUArchState, msr_gp_counters) - 11576usize]; ["Offset of field: CPUArchState::msr_gp_evtsel"] - [::std::mem::offset_of!(CPUArchState, msr_gp_evtsel) - 11648usize]; - ["Offset of field: CPUArchState::pat"][::std::mem::offset_of!(CPUArchState, pat) - 11792usize]; + [::std::mem::offset_of!(CPUArchState, msr_gp_evtsel) - 11720usize]; + ["Offset of field: CPUArchState::pat"][::std::mem::offset_of!(CPUArchState, pat) - 11864usize]; ["Offset of field: CPUArchState::smbase"] - [::std::mem::offset_of!(CPUArchState, smbase) - 11800usize]; + [::std::mem::offset_of!(CPUArchState, smbase) - 11872usize]; ["Offset of field: CPUArchState::msr_smi_count"] - [::std::mem::offset_of!(CPUArchState, msr_smi_count) - 11808usize]; + [::std::mem::offset_of!(CPUArchState, msr_smi_count) - 11880usize]; ["Offset of field: CPUArchState::pkru"] - [::std::mem::offset_of!(CPUArchState, pkru) - 11816usize]; + [::std::mem::offset_of!(CPUArchState, pkru) - 11888usize]; ["Offset of field: CPUArchState::pkrs"] - [::std::mem::offset_of!(CPUArchState, pkrs) - 11820usize]; + [::std::mem::offset_of!(CPUArchState, pkrs) - 11892usize]; ["Offset of field: CPUArchState::tsx_ctrl"] - [::std::mem::offset_of!(CPUArchState, tsx_ctrl) - 11824usize]; + [::std::mem::offset_of!(CPUArchState, tsx_ctrl) - 11896usize]; ["Offset of field: CPUArchState::spec_ctrl"] - [::std::mem::offset_of!(CPUArchState, spec_ctrl) - 11832usize]; + [::std::mem::offset_of!(CPUArchState, spec_ctrl) - 11904usize]; ["Offset of field: CPUArchState::amd_tsc_scale_msr"] - [::std::mem::offset_of!(CPUArchState, amd_tsc_scale_msr) - 11840usize]; + [::std::mem::offset_of!(CPUArchState, amd_tsc_scale_msr) - 11912usize]; ["Offset of field: CPUArchState::virt_ssbd"] - [::std::mem::offset_of!(CPUArchState, virt_ssbd) - 11848usize]; + [::std::mem::offset_of!(CPUArchState, virt_ssbd) - 11920usize]; ["Offset of field: CPUArchState::end_init_save"] - [::std::mem::offset_of!(CPUArchState, end_init_save) - 11856usize]; + [::std::mem::offset_of!(CPUArchState, end_init_save) - 11928usize]; ["Offset of field: CPUArchState::system_time_msr"] - [::std::mem::offset_of!(CPUArchState, system_time_msr) - 11856usize]; + [::std::mem::offset_of!(CPUArchState, system_time_msr) - 11928usize]; ["Offset of field: CPUArchState::wall_clock_msr"] - [::std::mem::offset_of!(CPUArchState, wall_clock_msr) - 11864usize]; + [::std::mem::offset_of!(CPUArchState, wall_clock_msr) - 11936usize]; ["Offset of field: CPUArchState::steal_time_msr"] - [::std::mem::offset_of!(CPUArchState, steal_time_msr) - 11872usize]; + [::std::mem::offset_of!(CPUArchState, steal_time_msr) - 11944usize]; ["Offset of field: CPUArchState::async_pf_en_msr"] - [::std::mem::offset_of!(CPUArchState, async_pf_en_msr) - 11880usize]; + [::std::mem::offset_of!(CPUArchState, async_pf_en_msr) - 11952usize]; ["Offset of field: CPUArchState::async_pf_int_msr"] - [::std::mem::offset_of!(CPUArchState, async_pf_int_msr) - 11888usize]; + [::std::mem::offset_of!(CPUArchState, async_pf_int_msr) - 11960usize]; ["Offset of field: CPUArchState::pv_eoi_en_msr"] - [::std::mem::offset_of!(CPUArchState, pv_eoi_en_msr) - 11896usize]; + [::std::mem::offset_of!(CPUArchState, pv_eoi_en_msr) - 11968usize]; ["Offset of field: CPUArchState::poll_control_msr"] - [::std::mem::offset_of!(CPUArchState, poll_control_msr) - 11904usize]; + [::std::mem::offset_of!(CPUArchState, poll_control_msr) - 11976usize]; ["Offset of field: CPUArchState::msr_hv_hypercall"] - [::std::mem::offset_of!(CPUArchState, msr_hv_hypercall) - 11912usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_hypercall) - 11984usize]; ["Offset of field: CPUArchState::msr_hv_guest_os_id"] - [::std::mem::offset_of!(CPUArchState, msr_hv_guest_os_id) - 11920usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_guest_os_id) - 11992usize]; ["Offset of field: CPUArchState::msr_hv_tsc"] - [::std::mem::offset_of!(CPUArchState, msr_hv_tsc) - 11928usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_tsc) - 12000usize]; ["Offset of field: CPUArchState::msr_hv_syndbg_control"] - [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_control) - 11936usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_control) - 12008usize]; ["Offset of field: CPUArchState::msr_hv_syndbg_status"] - [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_status) - 11944usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_status) - 12016usize]; ["Offset of field: CPUArchState::msr_hv_syndbg_send_page"] - [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_send_page) - 11952usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_send_page) - 12024usize]; ["Offset of field: CPUArchState::msr_hv_syndbg_recv_page"] - [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_recv_page) - 11960usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_recv_page) - 12032usize]; ["Offset of field: CPUArchState::msr_hv_syndbg_pending_page"] - [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_pending_page) - 11968usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_pending_page) - 12040usize]; ["Offset of field: CPUArchState::msr_hv_syndbg_options"] - [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_options) - 11976usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_syndbg_options) - 12048usize]; ["Offset of field: CPUArchState::msr_hv_vapic"] - [::std::mem::offset_of!(CPUArchState, msr_hv_vapic) - 11984usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_vapic) - 12056usize]; ["Offset of field: CPUArchState::msr_hv_crash_params"] - [::std::mem::offset_of!(CPUArchState, msr_hv_crash_params) - 11992usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_crash_params) - 12064usize]; ["Offset of field: CPUArchState::msr_hv_runtime"] - [::std::mem::offset_of!(CPUArchState, msr_hv_runtime) - 12032usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_runtime) - 12104usize]; ["Offset of field: CPUArchState::msr_hv_synic_control"] - [::std::mem::offset_of!(CPUArchState, msr_hv_synic_control) - 12040usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_synic_control) - 12112usize]; ["Offset of field: CPUArchState::msr_hv_synic_evt_page"] - [::std::mem::offset_of!(CPUArchState, msr_hv_synic_evt_page) - 12048usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_synic_evt_page) - 12120usize]; ["Offset of field: CPUArchState::msr_hv_synic_msg_page"] - [::std::mem::offset_of!(CPUArchState, msr_hv_synic_msg_page) - 12056usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_synic_msg_page) - 12128usize]; ["Offset of field: CPUArchState::msr_hv_synic_sint"] - [::std::mem::offset_of!(CPUArchState, msr_hv_synic_sint) - 12064usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_synic_sint) - 12136usize]; ["Offset of field: CPUArchState::msr_hv_stimer_config"] - [::std::mem::offset_of!(CPUArchState, msr_hv_stimer_config) - 12192usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_stimer_config) - 12264usize]; ["Offset of field: CPUArchState::msr_hv_stimer_count"] - [::std::mem::offset_of!(CPUArchState, msr_hv_stimer_count) - 12224usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_stimer_count) - 12296usize]; ["Offset of field: CPUArchState::msr_hv_reenlightenment_control"] - [::std::mem::offset_of!(CPUArchState, msr_hv_reenlightenment_control) - 12256usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_reenlightenment_control) - 12328usize]; ["Offset of field: CPUArchState::msr_hv_tsc_emulation_control"] - [::std::mem::offset_of!(CPUArchState, msr_hv_tsc_emulation_control) - 12264usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_tsc_emulation_control) - 12336usize]; ["Offset of field: CPUArchState::msr_hv_tsc_emulation_status"] - [::std::mem::offset_of!(CPUArchState, msr_hv_tsc_emulation_status) - 12272usize]; + [::std::mem::offset_of!(CPUArchState, msr_hv_tsc_emulation_status) - 12344usize]; ["Offset of field: CPUArchState::msr_rtit_ctrl"] - [::std::mem::offset_of!(CPUArchState, msr_rtit_ctrl) - 12280usize]; + [::std::mem::offset_of!(CPUArchState, msr_rtit_ctrl) - 12352usize]; ["Offset of field: CPUArchState::msr_rtit_status"] - [::std::mem::offset_of!(CPUArchState, msr_rtit_status) - 12288usize]; + [::std::mem::offset_of!(CPUArchState, msr_rtit_status) - 12360usize]; ["Offset of field: CPUArchState::msr_rtit_output_base"] - [::std::mem::offset_of!(CPUArchState, msr_rtit_output_base) - 12296usize]; + [::std::mem::offset_of!(CPUArchState, msr_rtit_output_base) - 12368usize]; ["Offset of field: CPUArchState::msr_rtit_output_mask"] - [::std::mem::offset_of!(CPUArchState, msr_rtit_output_mask) - 12304usize]; + [::std::mem::offset_of!(CPUArchState, msr_rtit_output_mask) - 12376usize]; ["Offset of field: CPUArchState::msr_rtit_cr3_match"] - [::std::mem::offset_of!(CPUArchState, msr_rtit_cr3_match) - 12312usize]; + [::std::mem::offset_of!(CPUArchState, msr_rtit_cr3_match) - 12384usize]; ["Offset of field: CPUArchState::msr_rtit_addrs"] - [::std::mem::offset_of!(CPUArchState, msr_rtit_addrs) - 12320usize]; + [::std::mem::offset_of!(CPUArchState, msr_rtit_addrs) - 12392usize]; ["Offset of field: CPUArchState::msr_xfd"] - [::std::mem::offset_of!(CPUArchState, msr_xfd) - 12384usize]; + [::std::mem::offset_of!(CPUArchState, msr_xfd) - 12456usize]; ["Offset of field: CPUArchState::msr_xfd_err"] - [::std::mem::offset_of!(CPUArchState, msr_xfd_err) - 12392usize]; + [::std::mem::offset_of!(CPUArchState, msr_xfd_err) - 12464usize]; ["Offset of field: CPUArchState::msr_lbr_ctl"] - [::std::mem::offset_of!(CPUArchState, msr_lbr_ctl) - 12400usize]; + [::std::mem::offset_of!(CPUArchState, msr_lbr_ctl) - 12472usize]; ["Offset of field: CPUArchState::msr_lbr_depth"] - [::std::mem::offset_of!(CPUArchState, msr_lbr_depth) - 12408usize]; + [::std::mem::offset_of!(CPUArchState, msr_lbr_depth) - 12480usize]; ["Offset of field: CPUArchState::lbr_records"] - [::std::mem::offset_of!(CPUArchState, lbr_records) - 12416usize]; + [::std::mem::offset_of!(CPUArchState, lbr_records) - 12488usize]; ["Offset of field: CPUArchState::error_code"] - [::std::mem::offset_of!(CPUArchState, error_code) - 13184usize]; + [::std::mem::offset_of!(CPUArchState, error_code) - 13256usize]; ["Offset of field: CPUArchState::exception_is_int"] - [::std::mem::offset_of!(CPUArchState, exception_is_int) - 13188usize]; + [::std::mem::offset_of!(CPUArchState, exception_is_int) - 13260usize]; ["Offset of field: CPUArchState::exception_next_eip"] - [::std::mem::offset_of!(CPUArchState, exception_next_eip) - 13192usize]; - ["Offset of field: CPUArchState::dr"][::std::mem::offset_of!(CPUArchState, dr) - 13200usize]; + [::std::mem::offset_of!(CPUArchState, exception_next_eip) - 13264usize]; + ["Offset of field: CPUArchState::dr"][::std::mem::offset_of!(CPUArchState, dr) - 13272usize]; ["Offset of field: CPUArchState::old_exception"] - [::std::mem::offset_of!(CPUArchState, old_exception) - 13296usize]; + [::std::mem::offset_of!(CPUArchState, old_exception) - 13368usize]; ["Offset of field: CPUArchState::vm_vmcb"] - [::std::mem::offset_of!(CPUArchState, vm_vmcb) - 13304usize]; + [::std::mem::offset_of!(CPUArchState, vm_vmcb) - 13376usize]; ["Offset of field: CPUArchState::tsc_offset"] - [::std::mem::offset_of!(CPUArchState, tsc_offset) - 13312usize]; + [::std::mem::offset_of!(CPUArchState, tsc_offset) - 13384usize]; ["Offset of field: CPUArchState::intercept"] - [::std::mem::offset_of!(CPUArchState, intercept) - 13320usize]; + [::std::mem::offset_of!(CPUArchState, intercept) - 13392usize]; ["Offset of field: CPUArchState::intercept_cr_read"] - [::std::mem::offset_of!(CPUArchState, intercept_cr_read) - 13328usize]; + [::std::mem::offset_of!(CPUArchState, intercept_cr_read) - 13400usize]; ["Offset of field: CPUArchState::intercept_cr_write"] - [::std::mem::offset_of!(CPUArchState, intercept_cr_write) - 13330usize]; + [::std::mem::offset_of!(CPUArchState, intercept_cr_write) - 13402usize]; ["Offset of field: CPUArchState::intercept_dr_read"] - [::std::mem::offset_of!(CPUArchState, intercept_dr_read) - 13332usize]; + [::std::mem::offset_of!(CPUArchState, intercept_dr_read) - 13404usize]; ["Offset of field: CPUArchState::intercept_dr_write"] - [::std::mem::offset_of!(CPUArchState, intercept_dr_write) - 13334usize]; + [::std::mem::offset_of!(CPUArchState, intercept_dr_write) - 13406usize]; ["Offset of field: CPUArchState::intercept_exceptions"] - [::std::mem::offset_of!(CPUArchState, intercept_exceptions) - 13336usize]; + [::std::mem::offset_of!(CPUArchState, intercept_exceptions) - 13408usize]; ["Offset of field: CPUArchState::nested_cr3"] - [::std::mem::offset_of!(CPUArchState, nested_cr3) - 13344usize]; + [::std::mem::offset_of!(CPUArchState, nested_cr3) - 13416usize]; ["Offset of field: CPUArchState::nested_pg_mode"] - [::std::mem::offset_of!(CPUArchState, nested_pg_mode) - 13352usize]; + [::std::mem::offset_of!(CPUArchState, nested_pg_mode) - 13424usize]; ["Offset of field: CPUArchState::v_tpr"] - [::std::mem::offset_of!(CPUArchState, v_tpr) - 13356usize]; + [::std::mem::offset_of!(CPUArchState, v_tpr) - 13428usize]; ["Offset of field: CPUArchState::int_ctl"] - [::std::mem::offset_of!(CPUArchState, int_ctl) - 13360usize]; + [::std::mem::offset_of!(CPUArchState, int_ctl) - 13432usize]; ["Offset of field: CPUArchState::nmi_injected"] - [::std::mem::offset_of!(CPUArchState, nmi_injected) - 13364usize]; + [::std::mem::offset_of!(CPUArchState, nmi_injected) - 13436usize]; ["Offset of field: CPUArchState::nmi_pending"] - [::std::mem::offset_of!(CPUArchState, nmi_pending) - 13365usize]; + [::std::mem::offset_of!(CPUArchState, nmi_pending) - 13437usize]; ["Offset of field: CPUArchState::retaddr"] - [::std::mem::offset_of!(CPUArchState, retaddr) - 13368usize]; + [::std::mem::offset_of!(CPUArchState, retaddr) - 13440usize]; + ["Offset of field: CPUArchState::msr_rapl_power_unit"] + [::std::mem::offset_of!(CPUArchState, msr_rapl_power_unit) - 13448usize]; + ["Offset of field: CPUArchState::msr_pkg_energy_status"] + [::std::mem::offset_of!(CPUArchState, msr_pkg_energy_status) - 13456usize]; ["Offset of field: CPUArchState::end_reset_fields"] - [::std::mem::offset_of!(CPUArchState, end_reset_fields) - 13376usize]; + [::std::mem::offset_of!(CPUArchState, end_reset_fields) - 13464usize]; ["Offset of field: CPUArchState::cpuid_level_func7"] - [::std::mem::offset_of!(CPUArchState, cpuid_level_func7) - 13376usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_level_func7) - 13464usize]; ["Offset of field: CPUArchState::cpuid_min_level_func7"] - [::std::mem::offset_of!(CPUArchState, cpuid_min_level_func7) - 13380usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_min_level_func7) - 13468usize]; ["Offset of field: CPUArchState::cpuid_min_level"] - [::std::mem::offset_of!(CPUArchState, cpuid_min_level) - 13384usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_min_level) - 13472usize]; ["Offset of field: CPUArchState::cpuid_min_xlevel"] - [::std::mem::offset_of!(CPUArchState, cpuid_min_xlevel) - 13388usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_min_xlevel) - 13476usize]; ["Offset of field: CPUArchState::cpuid_min_xlevel2"] - [::std::mem::offset_of!(CPUArchState, cpuid_min_xlevel2) - 13392usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_min_xlevel2) - 13480usize]; ["Offset of field: CPUArchState::cpuid_max_level"] - [::std::mem::offset_of!(CPUArchState, cpuid_max_level) - 13396usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_max_level) - 13484usize]; ["Offset of field: CPUArchState::cpuid_max_xlevel"] - [::std::mem::offset_of!(CPUArchState, cpuid_max_xlevel) - 13400usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_max_xlevel) - 13488usize]; ["Offset of field: CPUArchState::cpuid_max_xlevel2"] - [::std::mem::offset_of!(CPUArchState, cpuid_max_xlevel2) - 13404usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_max_xlevel2) - 13492usize]; ["Offset of field: CPUArchState::cpuid_level"] - [::std::mem::offset_of!(CPUArchState, cpuid_level) - 13408usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_level) - 13496usize]; ["Offset of field: CPUArchState::cpuid_xlevel"] - [::std::mem::offset_of!(CPUArchState, cpuid_xlevel) - 13412usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_xlevel) - 13500usize]; ["Offset of field: CPUArchState::cpuid_xlevel2"] - [::std::mem::offset_of!(CPUArchState, cpuid_xlevel2) - 13416usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_xlevel2) - 13504usize]; ["Offset of field: CPUArchState::cpuid_vendor1"] - [::std::mem::offset_of!(CPUArchState, cpuid_vendor1) - 13420usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_vendor1) - 13508usize]; ["Offset of field: CPUArchState::cpuid_vendor2"] - [::std::mem::offset_of!(CPUArchState, cpuid_vendor2) - 13424usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_vendor2) - 13512usize]; ["Offset of field: CPUArchState::cpuid_vendor3"] - [::std::mem::offset_of!(CPUArchState, cpuid_vendor3) - 13428usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_vendor3) - 13516usize]; ["Offset of field: CPUArchState::cpuid_version"] - [::std::mem::offset_of!(CPUArchState, cpuid_version) - 13432usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_version) - 13520usize]; ["Offset of field: CPUArchState::features"] - [::std::mem::offset_of!(CPUArchState, features) - 13440usize]; + [::std::mem::offset_of!(CPUArchState, features) - 13528usize]; ["Offset of field: CPUArchState::user_features"] - [::std::mem::offset_of!(CPUArchState, user_features) - 13752usize]; + [::std::mem::offset_of!(CPUArchState, user_features) - 13848usize]; ["Offset of field: CPUArchState::cpuid_model"] - [::std::mem::offset_of!(CPUArchState, cpuid_model) - 14064usize]; + [::std::mem::offset_of!(CPUArchState, cpuid_model) - 14168usize]; ["Offset of field: CPUArchState::cache_info_cpuid2"] - [::std::mem::offset_of!(CPUArchState, cache_info_cpuid2) - 14112usize]; + [::std::mem::offset_of!(CPUArchState, cache_info_cpuid2) - 14216usize]; ["Offset of field: CPUArchState::cache_info_cpuid4"] - [::std::mem::offset_of!(CPUArchState, cache_info_cpuid4) - 14144usize]; + [::std::mem::offset_of!(CPUArchState, cache_info_cpuid4) - 14248usize]; ["Offset of field: CPUArchState::cache_info_amd"] - [::std::mem::offset_of!(CPUArchState, cache_info_amd) - 14176usize]; + [::std::mem::offset_of!(CPUArchState, cache_info_amd) - 14280usize]; ["Offset of field: CPUArchState::mtrr_fixed"] - [::std::mem::offset_of!(CPUArchState, mtrr_fixed) - 14208usize]; + [::std::mem::offset_of!(CPUArchState, mtrr_fixed) - 14312usize]; ["Offset of field: CPUArchState::mtrr_deftype"] - [::std::mem::offset_of!(CPUArchState, mtrr_deftype) - 14296usize]; + [::std::mem::offset_of!(CPUArchState, mtrr_deftype) - 14400usize]; ["Offset of field: CPUArchState::mtrr_var"] - [::std::mem::offset_of!(CPUArchState, mtrr_var) - 14304usize]; + [::std::mem::offset_of!(CPUArchState, mtrr_var) - 14408usize]; ["Offset of field: CPUArchState::mp_state"] - [::std::mem::offset_of!(CPUArchState, mp_state) - 14432usize]; + [::std::mem::offset_of!(CPUArchState, mp_state) - 14536usize]; ["Offset of field: CPUArchState::exception_nr"] - [::std::mem::offset_of!(CPUArchState, exception_nr) - 14436usize]; + [::std::mem::offset_of!(CPUArchState, exception_nr) - 14540usize]; ["Offset of field: CPUArchState::interrupt_injected"] - [::std::mem::offset_of!(CPUArchState, interrupt_injected) - 14440usize]; + [::std::mem::offset_of!(CPUArchState, interrupt_injected) - 14544usize]; ["Offset of field: CPUArchState::soft_interrupt"] - [::std::mem::offset_of!(CPUArchState, soft_interrupt) - 14444usize]; + [::std::mem::offset_of!(CPUArchState, soft_interrupt) - 14548usize]; ["Offset of field: CPUArchState::exception_pending"] - [::std::mem::offset_of!(CPUArchState, exception_pending) - 14445usize]; + [::std::mem::offset_of!(CPUArchState, exception_pending) - 14549usize]; ["Offset of field: CPUArchState::exception_injected"] - [::std::mem::offset_of!(CPUArchState, exception_injected) - 14446usize]; + [::std::mem::offset_of!(CPUArchState, exception_injected) - 14550usize]; ["Offset of field: CPUArchState::has_error_code"] - [::std::mem::offset_of!(CPUArchState, has_error_code) - 14447usize]; + [::std::mem::offset_of!(CPUArchState, has_error_code) - 14551usize]; ["Offset of field: CPUArchState::exception_has_payload"] - [::std::mem::offset_of!(CPUArchState, exception_has_payload) - 14448usize]; + [::std::mem::offset_of!(CPUArchState, exception_has_payload) - 14552usize]; ["Offset of field: CPUArchState::exception_payload"] - [::std::mem::offset_of!(CPUArchState, exception_payload) - 14456usize]; + [::std::mem::offset_of!(CPUArchState, exception_payload) - 14560usize]; ["Offset of field: CPUArchState::triple_fault_pending"] - [::std::mem::offset_of!(CPUArchState, triple_fault_pending) - 14464usize]; + [::std::mem::offset_of!(CPUArchState, triple_fault_pending) - 14568usize]; ["Offset of field: CPUArchState::ins_len"] - [::std::mem::offset_of!(CPUArchState, ins_len) - 14468usize]; + [::std::mem::offset_of!(CPUArchState, ins_len) - 14572usize]; ["Offset of field: CPUArchState::sipi_vector"] - [::std::mem::offset_of!(CPUArchState, sipi_vector) - 14472usize]; + [::std::mem::offset_of!(CPUArchState, sipi_vector) - 14576usize]; ["Offset of field: CPUArchState::tsc_valid"] - [::std::mem::offset_of!(CPUArchState, tsc_valid) - 14476usize]; + [::std::mem::offset_of!(CPUArchState, tsc_valid) - 14580usize]; ["Offset of field: CPUArchState::tsc_khz"] - [::std::mem::offset_of!(CPUArchState, tsc_khz) - 14480usize]; + [::std::mem::offset_of!(CPUArchState, tsc_khz) - 14584usize]; ["Offset of field: CPUArchState::user_tsc_khz"] - [::std::mem::offset_of!(CPUArchState, user_tsc_khz) - 14488usize]; + [::std::mem::offset_of!(CPUArchState, user_tsc_khz) - 14592usize]; ["Offset of field: CPUArchState::apic_bus_freq"] - [::std::mem::offset_of!(CPUArchState, apic_bus_freq) - 14496usize]; - ["Offset of field: CPUArchState::tsc"][::std::mem::offset_of!(CPUArchState, tsc) - 14504usize]; + [::std::mem::offset_of!(CPUArchState, apic_bus_freq) - 14600usize]; + ["Offset of field: CPUArchState::tsc"][::std::mem::offset_of!(CPUArchState, tsc) - 14608usize]; ["Offset of field: CPUArchState::mcg_cap"] - [::std::mem::offset_of!(CPUArchState, mcg_cap) - 14512usize]; + [::std::mem::offset_of!(CPUArchState, mcg_cap) - 14616usize]; ["Offset of field: CPUArchState::mcg_ctl"] - [::std::mem::offset_of!(CPUArchState, mcg_ctl) - 14520usize]; + [::std::mem::offset_of!(CPUArchState, mcg_ctl) - 14624usize]; ["Offset of field: CPUArchState::mcg_ext_ctl"] - [::std::mem::offset_of!(CPUArchState, mcg_ext_ctl) - 14528usize]; + [::std::mem::offset_of!(CPUArchState, mcg_ext_ctl) - 14632usize]; ["Offset of field: CPUArchState::mce_banks"] - [::std::mem::offset_of!(CPUArchState, mce_banks) - 14536usize]; + [::std::mem::offset_of!(CPUArchState, mce_banks) - 14640usize]; ["Offset of field: CPUArchState::xstate_bv"] - [::std::mem::offset_of!(CPUArchState, xstate_bv) - 14856usize]; + [::std::mem::offset_of!(CPUArchState, xstate_bv) - 14960usize]; ["Offset of field: CPUArchState::fpus_vmstate"] - [::std::mem::offset_of!(CPUArchState, fpus_vmstate) - 14864usize]; + [::std::mem::offset_of!(CPUArchState, fpus_vmstate) - 14968usize]; ["Offset of field: CPUArchState::fptag_vmstate"] - [::std::mem::offset_of!(CPUArchState, fptag_vmstate) - 14866usize]; + [::std::mem::offset_of!(CPUArchState, fptag_vmstate) - 14970usize]; ["Offset of field: CPUArchState::fpregs_format_vmstate"] - [::std::mem::offset_of!(CPUArchState, fpregs_format_vmstate) - 14868usize]; - ["Offset of field: CPUArchState::xss"][::std::mem::offset_of!(CPUArchState, xss) - 14872usize]; + [::std::mem::offset_of!(CPUArchState, fpregs_format_vmstate) - 14972usize]; + ["Offset of field: CPUArchState::xss"][::std::mem::offset_of!(CPUArchState, xss) - 14976usize]; ["Offset of field: CPUArchState::umwait"] - [::std::mem::offset_of!(CPUArchState, umwait) - 14880usize]; + [::std::mem::offset_of!(CPUArchState, umwait) - 14984usize]; ["Offset of field: CPUArchState::tpr_access_type"] - [::std::mem::offset_of!(CPUArchState, tpr_access_type) - 14884usize]; + [::std::mem::offset_of!(CPUArchState, tpr_access_type) - 14988usize]; ["Offset of field: CPUArchState::nr_dies"] - [::std::mem::offset_of!(CPUArchState, nr_dies) - 14888usize]; + [::std::mem::offset_of!(CPUArchState, nr_dies) - 14992usize]; + ["Offset of field: CPUArchState::nr_modules"] + [::std::mem::offset_of!(CPUArchState, nr_modules) - 14996usize]; + ["Offset of field: CPUArchState::avail_cpu_topo"] + [::std::mem::offset_of!(CPUArchState, avail_cpu_topo) - 15000usize]; }; impl Default for CPUArchState { fn default() -> Self { @@ -4744,7 +5302,7 @@ impl Default for CPUArchState { } impl ::std::fmt::Debug for CPUArchState { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write ! (f , "CPUArchState {{ regs: {:?}, segs: {:?}, ldt: {:?}, tr: {:?}, gdt: {:?}, idt: {:?}, cr: {:?}, pdptrs_valid: {:?}, pdptrs: {:?}, bnd_regs: {:?}, bndcs_regs: {:?}, start_init_save: {:?}, fpstt: {:?}, fptags: {:?}, fpregs: {:?}, fp_status: {:?}, ft0: {:?}, mmx_status: {:?}, sse_status: {:?}, xmm_regs: {:?}, xmm_t0: {:?}, mmx_t0: {:?}, opmask_regs: {:?}, xtilecfg: {:?}, xtiledata: {:?}, msr_ia32_sgxlepubkeyhash: {:?}, msr_fixed_counters: {:?}, msr_gp_counters: {:?}, msr_gp_evtsel: {:?}, end_init_save: {:?}, msr_hv_crash_params: {:?}, msr_hv_synic_sint: {:?}, msr_hv_stimer_config: {:?}, msr_hv_stimer_count: {:?}, msr_rtit_addrs: {:?}, lbr_records: {:?}, error_code: {:?}, exception_is_int: {:?}, dr: {:?}, __bindgen_anon_1: {:?}, old_exception: {:?}, end_reset_fields: {:?}, features: {:?}, user_features: {:?}, cpuid_model: {:?}, cache_info_cpuid2: {:?}, cache_info_cpuid4: {:?}, cache_info_amd: {:?}, mtrr_fixed: {:?}, mtrr_var: {:?}, tsc_valid: {:?}, mce_banks: {:?}, tpr_access_type: {:?}, nr_dies: {:?} }}" , self . regs , self . segs , self . ldt , self . tr , self . gdt , self . idt , self . cr , self . pdptrs_valid , self . pdptrs , self . bnd_regs , self . bndcs_regs , self . start_init_save , self . fpstt , self . fptags , self . fpregs , self . fp_status , self . ft0 , self . mmx_status , self . sse_status , self . xmm_regs , self . xmm_t0 , self . mmx_t0 , self . opmask_regs , self . xtilecfg , self . xtiledata , self . msr_ia32_sgxlepubkeyhash , self . msr_fixed_counters , self . msr_gp_counters , self . msr_gp_evtsel , self . end_init_save , self . msr_hv_crash_params , self . msr_hv_synic_sint , self . msr_hv_stimer_config , self . msr_hv_stimer_count , self . msr_rtit_addrs , self . lbr_records , self . error_code , self . exception_is_int , self . dr , self . __bindgen_anon_1 , self . old_exception , self . end_reset_fields , self . features , self . user_features , self . cpuid_model , self . cache_info_cpuid2 , self . cache_info_cpuid4 , self . cache_info_amd , self . mtrr_fixed , self . mtrr_var , self . tsc_valid , self . mce_banks , self . tpr_access_type , self . nr_dies) + write ! (f , "CPUArchState {{ regs: {:?}, segs: {:?}, ldt: {:?}, tr: {:?}, gdt: {:?}, idt: {:?}, cr: {:?}, pdptrs_valid: {:?}, pdptrs: {:?}, bnd_regs: {:?}, bndcs_regs: {:?}, start_init_save: {:?}, fpstt: {:?}, fptags: {:?}, fpregs: {:?}, fp_status: {:?}, ft0: {:?}, mmx_status: {:?}, sse_status: {:?}, xmm_regs: {:?}, xmm_t0: {:?}, mmx_t0: {:?}, opmask_regs: {:?}, xtilecfg: {:?}, xtiledata: {:?}, msr_ia32_sgxlepubkeyhash: {:?}, msr_fixed_counters: {:?}, msr_gp_counters: {:?}, msr_gp_evtsel: {:?}, end_init_save: {:?}, msr_hv_crash_params: {:?}, msr_hv_synic_sint: {:?}, msr_hv_stimer_config: {:?}, msr_hv_stimer_count: {:?}, msr_rtit_addrs: {:?}, lbr_records: {:?}, error_code: {:?}, exception_is_int: {:?}, dr: {:?}, __bindgen_anon_1: {:?}, old_exception: {:?}, end_reset_fields: {:?}, features: {:?}, user_features: {:?}, cpuid_model: {:?}, cache_info_cpuid2: {:?}, cache_info_cpuid4: {:?}, cache_info_amd: {:?}, mtrr_fixed: {:?}, mtrr_var: {:?}, tsc_valid: {:?}, mce_banks: {:?}, tpr_access_type: {:?}, nr_dies: {:?}, nr_modules: {:?}, avail_cpu_topo: {:?} }}" , self . regs , self . segs , self . ldt , self . tr , self . gdt , self . idt , self . cr , self . pdptrs_valid , self . pdptrs , self . bnd_regs , self . bndcs_regs , self . start_init_save , self . fpstt , self . fptags , self . fpregs , self . fp_status , self . ft0 , self . mmx_status , self . sse_status , self . xmm_regs , self . xmm_t0 , self . mmx_t0 , self . opmask_regs , self . xtilecfg , self . xtiledata , self . msr_ia32_sgxlepubkeyhash , self . msr_fixed_counters , self . msr_gp_counters , self . msr_gp_evtsel , self . end_init_save , self . msr_hv_crash_params , self . msr_hv_synic_sint , self . msr_hv_stimer_config , self . msr_hv_stimer_count , self . msr_rtit_addrs , self . lbr_records , self . error_code , self . exception_is_int , self . dr , self . __bindgen_anon_1 , self . old_exception , self . end_reset_fields , self . features , self . user_features , self . cpuid_model , self . cache_info_cpuid2 , self . cache_info_cpuid4 , self . cache_info_amd , self . mtrr_fixed , self . mtrr_var , self . tsc_valid , self . mce_banks , self . tpr_access_type , self . nr_dies , self . nr_modules , self . avail_cpu_topo) } } pub type CPUX86State = CPUArchState; @@ -4794,17 +5352,20 @@ pub struct ArchCPU { pub lbr_fmt: u64, pub enable_lmce: bool, pub enable_l3_cache: bool, + pub l1_cache_per_core: bool, pub legacy_cache: bool, + pub legacy_multi_node: bool, pub enable_cpuid_0xb: bool, pub full_cpuid_auto_level: bool, pub vendor_cpuid_only: bool, + pub amd_topoext_features_only: bool, pub intel_pt_auto_level: bool, pub fill_mtrr_mask: bool, pub host_phys_bits: bool, pub host_phys_bits_limit: u8, - pub kvm_no_smi_migration: bool, pub kvm_pv_enforce_cpuid: bool, pub phys_bits: u32, + pub guest_phys_bits: u32, pub apic_state: *mut DeviceState, pub cpu_as_root: *mut MemoryRegion, pub cpu_as_mem: *mut MemoryRegion, @@ -4814,6 +5375,7 @@ pub struct ArchCPU { pub node_id: i32, pub socket_id: i32, pub die_id: i32, + pub module_id: i32, pub core_id: i32, pub thread_id: i32, pub hv_max_vps: i32, @@ -4843,120 +5405,128 @@ const _: () = { }; #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of ArchCPU"][::std::mem::size_of::() - 25664usize]; + ["Size of ArchCPU"][::std::mem::size_of::() - 25792usize]; ["Alignment of ArchCPU"][::std::mem::align_of::() - 16usize]; ["Offset of field: ArchCPU::parent_obj"][::std::mem::offset_of!(ArchCPU, parent_obj) - 0usize]; ["Offset of field: ArchCPU::env"][::std::mem::offset_of!(ArchCPU, env) - 10176usize]; - ["Offset of field: ArchCPU::vmsentry"][::std::mem::offset_of!(ArchCPU, vmsentry) - 25072usize]; + ["Offset of field: ArchCPU::vmsentry"][::std::mem::offset_of!(ArchCPU, vmsentry) - 25184usize]; ["Offset of field: ArchCPU::ucode_rev"] - [::std::mem::offset_of!(ArchCPU, ucode_rev) - 25080usize]; + [::std::mem::offset_of!(ArchCPU, ucode_rev) - 25192usize]; ["Offset of field: ArchCPU::hyperv_spinlock_attempts"] - [::std::mem::offset_of!(ArchCPU, hyperv_spinlock_attempts) - 25088usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_spinlock_attempts) - 25200usize]; ["Offset of field: ArchCPU::hyperv_vendor"] - [::std::mem::offset_of!(ArchCPU, hyperv_vendor) - 25096usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_vendor) - 25208usize]; ["Offset of field: ArchCPU::hyperv_synic_kvm_only"] - [::std::mem::offset_of!(ArchCPU, hyperv_synic_kvm_only) - 25104usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_synic_kvm_only) - 25216usize]; ["Offset of field: ArchCPU::hyperv_features"] - [::std::mem::offset_of!(ArchCPU, hyperv_features) - 25112usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_features) - 25224usize]; ["Offset of field: ArchCPU::hyperv_passthrough"] - [::std::mem::offset_of!(ArchCPU, hyperv_passthrough) - 25120usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_passthrough) - 25232usize]; ["Offset of field: ArchCPU::hyperv_no_nonarch_cs"] - [::std::mem::offset_of!(ArchCPU, hyperv_no_nonarch_cs) - 25124usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_no_nonarch_cs) - 25236usize]; ["Offset of field: ArchCPU::hyperv_vendor_id"] - [::std::mem::offset_of!(ArchCPU, hyperv_vendor_id) - 25128usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_vendor_id) - 25240usize]; ["Offset of field: ArchCPU::hyperv_interface_id"] - [::std::mem::offset_of!(ArchCPU, hyperv_interface_id) - 25140usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_interface_id) - 25252usize]; ["Offset of field: ArchCPU::hyperv_limits"] - [::std::mem::offset_of!(ArchCPU, hyperv_limits) - 25156usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_limits) - 25268usize]; ["Offset of field: ArchCPU::hyperv_enforce_cpuid"] - [::std::mem::offset_of!(ArchCPU, hyperv_enforce_cpuid) - 25168usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_enforce_cpuid) - 25280usize]; ["Offset of field: ArchCPU::hyperv_ver_id_build"] - [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_build) - 25172usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_build) - 25284usize]; ["Offset of field: ArchCPU::hyperv_ver_id_major"] - [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_major) - 25176usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_major) - 25288usize]; ["Offset of field: ArchCPU::hyperv_ver_id_minor"] - [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_minor) - 25178usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_minor) - 25290usize]; ["Offset of field: ArchCPU::hyperv_ver_id_sp"] - [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_sp) - 25180usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_sp) - 25292usize]; ["Offset of field: ArchCPU::hyperv_ver_id_sb"] - [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_sb) - 25184usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_sb) - 25296usize]; ["Offset of field: ArchCPU::hyperv_ver_id_sn"] - [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_sn) - 25188usize]; + [::std::mem::offset_of!(ArchCPU, hyperv_ver_id_sn) - 25300usize]; ["Offset of field: ArchCPU::check_cpuid"] - [::std::mem::offset_of!(ArchCPU, check_cpuid) - 25192usize]; + [::std::mem::offset_of!(ArchCPU, check_cpuid) - 25304usize]; ["Offset of field: ArchCPU::enforce_cpuid"] - [::std::mem::offset_of!(ArchCPU, enforce_cpuid) - 25193usize]; + [::std::mem::offset_of!(ArchCPU, enforce_cpuid) - 25305usize]; ["Offset of field: ArchCPU::force_features"] - [::std::mem::offset_of!(ArchCPU, force_features) - 25194usize]; + [::std::mem::offset_of!(ArchCPU, force_features) - 25306usize]; ["Offset of field: ArchCPU::expose_kvm"] - [::std::mem::offset_of!(ArchCPU, expose_kvm) - 25195usize]; + [::std::mem::offset_of!(ArchCPU, expose_kvm) - 25307usize]; ["Offset of field: ArchCPU::expose_tcg"] - [::std::mem::offset_of!(ArchCPU, expose_tcg) - 25196usize]; + [::std::mem::offset_of!(ArchCPU, expose_tcg) - 25308usize]; ["Offset of field: ArchCPU::migratable"] - [::std::mem::offset_of!(ArchCPU, migratable) - 25197usize]; + [::std::mem::offset_of!(ArchCPU, migratable) - 25309usize]; ["Offset of field: ArchCPU::migrate_smi_count"] - [::std::mem::offset_of!(ArchCPU, migrate_smi_count) - 25198usize]; + [::std::mem::offset_of!(ArchCPU, migrate_smi_count) - 25310usize]; ["Offset of field: ArchCPU::max_features"] - [::std::mem::offset_of!(ArchCPU, max_features) - 25199usize]; - ["Offset of field: ArchCPU::apic_id"][::std::mem::offset_of!(ArchCPU, apic_id) - 25200usize]; + [::std::mem::offset_of!(ArchCPU, max_features) - 25311usize]; + ["Offset of field: ArchCPU::apic_id"][::std::mem::offset_of!(ArchCPU, apic_id) - 25312usize]; ["Offset of field: ArchCPU::vmware_cpuid_freq"] - [::std::mem::offset_of!(ArchCPU, vmware_cpuid_freq) - 25204usize]; + [::std::mem::offset_of!(ArchCPU, vmware_cpuid_freq) - 25316usize]; ["Offset of field: ArchCPU::cache_info_passthrough"] - [::std::mem::offset_of!(ArchCPU, cache_info_passthrough) - 25205usize]; - ["Offset of field: ArchCPU::mwait"][::std::mem::offset_of!(ArchCPU, mwait) - 25208usize]; + [::std::mem::offset_of!(ArchCPU, cache_info_passthrough) - 25317usize]; + ["Offset of field: ArchCPU::mwait"][::std::mem::offset_of!(ArchCPU, mwait) - 25320usize]; ["Offset of field: ArchCPU::filtered_features"] - [::std::mem::offset_of!(ArchCPU, filtered_features) - 25224usize]; + [::std::mem::offset_of!(ArchCPU, filtered_features) - 25336usize]; ["Offset of field: ArchCPU::enable_pmu"] - [::std::mem::offset_of!(ArchCPU, enable_pmu) - 25536usize]; - ["Offset of field: ArchCPU::lbr_fmt"][::std::mem::offset_of!(ArchCPU, lbr_fmt) - 25544usize]; + [::std::mem::offset_of!(ArchCPU, enable_pmu) - 25656usize]; + ["Offset of field: ArchCPU::lbr_fmt"][::std::mem::offset_of!(ArchCPU, lbr_fmt) - 25664usize]; ["Offset of field: ArchCPU::enable_lmce"] - [::std::mem::offset_of!(ArchCPU, enable_lmce) - 25552usize]; + [::std::mem::offset_of!(ArchCPU, enable_lmce) - 25672usize]; ["Offset of field: ArchCPU::enable_l3_cache"] - [::std::mem::offset_of!(ArchCPU, enable_l3_cache) - 25553usize]; + [::std::mem::offset_of!(ArchCPU, enable_l3_cache) - 25673usize]; + ["Offset of field: ArchCPU::l1_cache_per_core"] + [::std::mem::offset_of!(ArchCPU, l1_cache_per_core) - 25674usize]; ["Offset of field: ArchCPU::legacy_cache"] - [::std::mem::offset_of!(ArchCPU, legacy_cache) - 25554usize]; + [::std::mem::offset_of!(ArchCPU, legacy_cache) - 25675usize]; + ["Offset of field: ArchCPU::legacy_multi_node"] + [::std::mem::offset_of!(ArchCPU, legacy_multi_node) - 25676usize]; ["Offset of field: ArchCPU::enable_cpuid_0xb"] - [::std::mem::offset_of!(ArchCPU, enable_cpuid_0xb) - 25555usize]; + [::std::mem::offset_of!(ArchCPU, enable_cpuid_0xb) - 25677usize]; ["Offset of field: ArchCPU::full_cpuid_auto_level"] - [::std::mem::offset_of!(ArchCPU, full_cpuid_auto_level) - 25556usize]; + [::std::mem::offset_of!(ArchCPU, full_cpuid_auto_level) - 25678usize]; ["Offset of field: ArchCPU::vendor_cpuid_only"] - [::std::mem::offset_of!(ArchCPU, vendor_cpuid_only) - 25557usize]; + [::std::mem::offset_of!(ArchCPU, vendor_cpuid_only) - 25679usize]; + ["Offset of field: ArchCPU::amd_topoext_features_only"] + [::std::mem::offset_of!(ArchCPU, amd_topoext_features_only) - 25680usize]; ["Offset of field: ArchCPU::intel_pt_auto_level"] - [::std::mem::offset_of!(ArchCPU, intel_pt_auto_level) - 25558usize]; + [::std::mem::offset_of!(ArchCPU, intel_pt_auto_level) - 25681usize]; ["Offset of field: ArchCPU::fill_mtrr_mask"] - [::std::mem::offset_of!(ArchCPU, fill_mtrr_mask) - 25559usize]; + [::std::mem::offset_of!(ArchCPU, fill_mtrr_mask) - 25682usize]; ["Offset of field: ArchCPU::host_phys_bits"] - [::std::mem::offset_of!(ArchCPU, host_phys_bits) - 25560usize]; + [::std::mem::offset_of!(ArchCPU, host_phys_bits) - 25683usize]; ["Offset of field: ArchCPU::host_phys_bits_limit"] - [::std::mem::offset_of!(ArchCPU, host_phys_bits_limit) - 25561usize]; - ["Offset of field: ArchCPU::kvm_no_smi_migration"] - [::std::mem::offset_of!(ArchCPU, kvm_no_smi_migration) - 25562usize]; + [::std::mem::offset_of!(ArchCPU, host_phys_bits_limit) - 25684usize]; ["Offset of field: ArchCPU::kvm_pv_enforce_cpuid"] - [::std::mem::offset_of!(ArchCPU, kvm_pv_enforce_cpuid) - 25563usize]; + [::std::mem::offset_of!(ArchCPU, kvm_pv_enforce_cpuid) - 25685usize]; ["Offset of field: ArchCPU::phys_bits"] - [::std::mem::offset_of!(ArchCPU, phys_bits) - 25564usize]; + [::std::mem::offset_of!(ArchCPU, phys_bits) - 25688usize]; + ["Offset of field: ArchCPU::guest_phys_bits"] + [::std::mem::offset_of!(ArchCPU, guest_phys_bits) - 25692usize]; ["Offset of field: ArchCPU::apic_state"] - [::std::mem::offset_of!(ArchCPU, apic_state) - 25568usize]; + [::std::mem::offset_of!(ArchCPU, apic_state) - 25696usize]; ["Offset of field: ArchCPU::cpu_as_root"] - [::std::mem::offset_of!(ArchCPU, cpu_as_root) - 25576usize]; + [::std::mem::offset_of!(ArchCPU, cpu_as_root) - 25704usize]; ["Offset of field: ArchCPU::cpu_as_mem"] - [::std::mem::offset_of!(ArchCPU, cpu_as_mem) - 25584usize]; - ["Offset of field: ArchCPU::smram"][::std::mem::offset_of!(ArchCPU, smram) - 25592usize]; + [::std::mem::offset_of!(ArchCPU, cpu_as_mem) - 25712usize]; + ["Offset of field: ArchCPU::smram"][::std::mem::offset_of!(ArchCPU, smram) - 25720usize]; ["Offset of field: ArchCPU::machine_done"] - [::std::mem::offset_of!(ArchCPU, machine_done) - 25600usize]; + [::std::mem::offset_of!(ArchCPU, machine_done) - 25728usize]; ["Offset of field: ArchCPU::kvm_msr_buf"] - [::std::mem::offset_of!(ArchCPU, kvm_msr_buf) - 25624usize]; - ["Offset of field: ArchCPU::node_id"][::std::mem::offset_of!(ArchCPU, node_id) - 25632usize]; + [::std::mem::offset_of!(ArchCPU, kvm_msr_buf) - 25752usize]; + ["Offset of field: ArchCPU::node_id"][::std::mem::offset_of!(ArchCPU, node_id) - 25760usize]; ["Offset of field: ArchCPU::socket_id"] - [::std::mem::offset_of!(ArchCPU, socket_id) - 25636usize]; - ["Offset of field: ArchCPU::die_id"][::std::mem::offset_of!(ArchCPU, die_id) - 25640usize]; - ["Offset of field: ArchCPU::core_id"][::std::mem::offset_of!(ArchCPU, core_id) - 25644usize]; + [::std::mem::offset_of!(ArchCPU, socket_id) - 25764usize]; + ["Offset of field: ArchCPU::die_id"][::std::mem::offset_of!(ArchCPU, die_id) - 25768usize]; + ["Offset of field: ArchCPU::module_id"] + [::std::mem::offset_of!(ArchCPU, module_id) - 25772usize]; + ["Offset of field: ArchCPU::core_id"][::std::mem::offset_of!(ArchCPU, core_id) - 25776usize]; ["Offset of field: ArchCPU::thread_id"] - [::std::mem::offset_of!(ArchCPU, thread_id) - 25648usize]; + [::std::mem::offset_of!(ArchCPU, thread_id) - 25780usize]; ["Offset of field: ArchCPU::hv_max_vps"] - [::std::mem::offset_of!(ArchCPU, hv_max_vps) - 25652usize]; + [::std::mem::offset_of!(ArchCPU, hv_max_vps) - 25784usize]; ["Offset of field: ArchCPU::xen_vapic"] - [::std::mem::offset_of!(ArchCPU, xen_vapic) - 25656usize]; + [::std::mem::offset_of!(ArchCPU, xen_vapic) - 25788usize]; }; impl Default for ArchCPU { fn default() -> Self { @@ -4969,10 +5539,10 @@ impl Default for ArchCPU { } impl ::std::fmt::Debug for ArchCPU { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write ! (f , "ArchCPU {{ parent_obj: {:?}, env: {:?}, vmsentry: {:?}, hyperv_vendor: {:?}, hyperv_synic_kvm_only: {:?}, hyperv_passthrough: {:?}, hyperv_no_nonarch_cs: {:?}, hyperv_vendor_id: {:?}, hyperv_interface_id: {:?}, hyperv_limits: {:?}, hyperv_enforce_cpuid: {:?}, check_cpuid: {:?}, enforce_cpuid: {:?}, force_features: {:?}, expose_kvm: {:?}, expose_tcg: {:?}, migratable: {:?}, migrate_smi_count: {:?}, max_features: {:?}, vmware_cpuid_freq: {:?}, cache_info_passthrough: {:?}, mwait: {:?}, filtered_features: {:?}, enable_pmu: {:?}, enable_lmce: {:?}, enable_l3_cache: {:?}, legacy_cache: {:?}, enable_cpuid_0xb: {:?}, full_cpuid_auto_level: {:?}, vendor_cpuid_only: {:?}, intel_pt_auto_level: {:?}, fill_mtrr_mask: {:?}, host_phys_bits: {:?}, kvm_no_smi_migration: {:?}, kvm_pv_enforce_cpuid: {:?}, apic_state: {:?}, cpu_as_root: {:?}, cpu_as_mem: {:?}, smram: {:?}, machine_done: {:?}, kvm_msr_buf: {:?}, xen_vapic: {:?} }}" , self . parent_obj , self . env , self . vmsentry , self . hyperv_vendor , self . hyperv_synic_kvm_only , self . hyperv_passthrough , self . hyperv_no_nonarch_cs , self . hyperv_vendor_id , self . hyperv_interface_id , self . hyperv_limits , self . hyperv_enforce_cpuid , self . check_cpuid , self . enforce_cpuid , self . force_features , self . expose_kvm , self . expose_tcg , self . migratable , self . migrate_smi_count , self . max_features , self . vmware_cpuid_freq , self . cache_info_passthrough , self . mwait , self . filtered_features , self . enable_pmu , self . enable_lmce , self . enable_l3_cache , self . legacy_cache , self . enable_cpuid_0xb , self . full_cpuid_auto_level , self . vendor_cpuid_only , self . intel_pt_auto_level , self . fill_mtrr_mask , self . host_phys_bits , self . kvm_no_smi_migration , self . kvm_pv_enforce_cpuid , self . apic_state , self . cpu_as_root , self . cpu_as_mem , self . smram , self . machine_done , self . kvm_msr_buf , self . xen_vapic) + write ! (f , "ArchCPU {{ parent_obj: {:?}, env: {:?}, vmsentry: {:?}, hyperv_vendor: {:?}, hyperv_synic_kvm_only: {:?}, hyperv_passthrough: {:?}, hyperv_no_nonarch_cs: {:?}, hyperv_vendor_id: {:?}, hyperv_interface_id: {:?}, hyperv_limits: {:?}, hyperv_enforce_cpuid: {:?}, check_cpuid: {:?}, enforce_cpuid: {:?}, force_features: {:?}, expose_kvm: {:?}, expose_tcg: {:?}, migratable: {:?}, migrate_smi_count: {:?}, max_features: {:?}, vmware_cpuid_freq: {:?}, cache_info_passthrough: {:?}, mwait: {:?}, filtered_features: {:?}, enable_pmu: {:?}, enable_lmce: {:?}, enable_l3_cache: {:?}, l1_cache_per_core: {:?}, legacy_cache: {:?}, legacy_multi_node: {:?}, enable_cpuid_0xb: {:?}, full_cpuid_auto_level: {:?}, vendor_cpuid_only: {:?}, amd_topoext_features_only: {:?}, intel_pt_auto_level: {:?}, fill_mtrr_mask: {:?}, host_phys_bits: {:?}, kvm_pv_enforce_cpuid: {:?}, apic_state: {:?}, cpu_as_root: {:?}, cpu_as_mem: {:?}, smram: {:?}, machine_done: {:?}, kvm_msr_buf: {:?}, xen_vapic: {:?} }}" , self . parent_obj , self . env , self . vmsentry , self . hyperv_vendor , self . hyperv_synic_kvm_only , self . hyperv_passthrough , self . hyperv_no_nonarch_cs , self . hyperv_vendor_id , self . hyperv_interface_id , self . hyperv_limits , self . hyperv_enforce_cpuid , self . check_cpuid , self . enforce_cpuid , self . force_features , self . expose_kvm , self . expose_tcg , self . migratable , self . migrate_smi_count , self . max_features , self . vmware_cpuid_freq , self . cache_info_passthrough , self . mwait , self . filtered_features , self . enable_pmu , self . enable_lmce , self . enable_l3_cache , self . l1_cache_per_core , self . legacy_cache , self . legacy_multi_node , self . enable_cpuid_0xb , self . full_cpuid_auto_level , self . vendor_cpuid_only , self . amd_topoext_features_only , self . intel_pt_auto_level , self . fill_mtrr_mask , self . host_phys_bits , self . kvm_pv_enforce_cpuid , self . apic_state , self . cpu_as_root , self . cpu_as_mem , self . smram , self . machine_done , self . kvm_msr_buf , self . xen_vapic) } } -extern "C" { +unsafe extern "C" { pub fn cpu_memory_rw_debug( cpu: *mut CPUState, addr: vaddr, @@ -5083,14 +5653,11 @@ impl Default for IntervalTreeNode { pub type IntervalTreeRoot = RBRootLeftCached; pub type abi_ulong = target_ulong; pub type abi_long = target_long; -extern "C" { - pub static mut guest_base: usize; -} -extern "C" { +unsafe extern "C" { #[doc = " --- Begin LibAFL code ---"] pub fn pageflags_get_root() -> *mut IntervalTreeRoot; } -extern "C" { +unsafe extern "C" { #[doc = " page_check_range\n @start: first byte of range\n @len: length of range\n @flags: flags required for each page\n\n Return true if every page in [@start, @start+@len) has @flags set.\n Return false if any page is unmapped. Thus testing flags == 0 is\n equivalent to testing for flags == PAGE_VALID."] pub fn page_check_range( start: target_ulong, @@ -5190,6 +5757,9 @@ impl ::std::ops::BitAndAssign for MemOp { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct MemOp(pub ::std::os::raw::c_uint); pub type MemOpIdx = u32; +unsafe extern "C" { + pub static mut guest_base: usize; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct image_info { @@ -5387,20 +5957,20 @@ impl Default for TranslationBlock { } } } -extern "C" { +unsafe extern "C" { pub static mut exec_path: *mut ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub static mut mmap_next_start: abi_ulong; } -extern "C" { +unsafe extern "C" { pub fn target_mprotect( start: abi_ulong, len: abi_ulong, prot: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn target_mmap( start: abi_ulong, len: abi_ulong, @@ -5410,32 +5980,44 @@ extern "C" { offset: off_t, ) -> abi_long; } -extern "C" { +unsafe extern "C" { pub fn target_munmap(start: abi_ulong, len: abi_ulong) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { #[doc = " read_self_maps:\n\n Read /proc/self/maps and return a tree of MapInfo structures."] pub fn read_self_maps() -> *mut IntervalTreeRoot; } -extern "C" { +unsafe extern "C" { #[doc = " free_self_maps:\n @info: an interval tree\n\n Free a tree of MapInfo structures."] pub fn free_self_maps(root: *mut IntervalTreeRoot); } -extern "C" { - pub fn libafl_qemu_set_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libafl_qemu_remove_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libafl_qemu_trigger_breakpoint(cpu: *mut CPUState); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_breakpoint { + pub addr: target_ulong, + pub next: *mut libafl_breakpoint, } -extern "C" { - pub fn libafl_qemu_breakpoint_run(pc_next: vaddr); +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_breakpoint"][::std::mem::size_of::() - 16usize]; + ["Alignment of libafl_breakpoint"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_breakpoint::addr"] + [::std::mem::offset_of!(libafl_breakpoint, addr) - 0usize]; + ["Offset of field: libafl_breakpoint::next"] + [::std::mem::offset_of!(libafl_breakpoint, next) - 8usize]; +}; +impl Default for libafl_breakpoint { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } } pub const libafl_exit_reason_kind_INTERNAL: libafl_exit_reason_kind = libafl_exit_reason_kind(0); pub const libafl_exit_reason_kind_BREAKPOINT: libafl_exit_reason_kind = libafl_exit_reason_kind(1); -pub const libafl_exit_reason_kind_SYNC_EXIT: libafl_exit_reason_kind = libafl_exit_reason_kind(2); +pub const libafl_exit_reason_kind_CUSTOM_INSN: libafl_exit_reason_kind = libafl_exit_reason_kind(2); pub const libafl_exit_reason_kind_TIMEOUT: libafl_exit_reason_kind = libafl_exit_reason_kind(3); impl ::std::ops::BitOr for libafl_exit_reason_kind { type Output = Self; @@ -5466,6 +6048,41 @@ impl ::std::ops::BitAndAssign for libafl_exit_reason_kind { #[repr(transparent)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct libafl_exit_reason_kind(pub ::std::os::raw::c_uint); +pub const libafl_custom_insn_kind_LIBAFL_CUSTOM_INSN_UNDEFINED: libafl_custom_insn_kind = + libafl_custom_insn_kind(0); +pub const libafl_custom_insn_kind_LIBAFL_CUSTOM_INSN_LIBAFL: libafl_custom_insn_kind = + libafl_custom_insn_kind(1); +pub const libafl_custom_insn_kind_LIBAFL_CUSTOM_INSN_NYX: libafl_custom_insn_kind = + libafl_custom_insn_kind(2); +impl ::std::ops::BitOr for libafl_custom_insn_kind { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + libafl_custom_insn_kind(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for libafl_custom_insn_kind { + #[inline] + fn bitor_assign(&mut self, rhs: libafl_custom_insn_kind) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for libafl_custom_insn_kind { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + libafl_custom_insn_kind(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for libafl_custom_insn_kind { + #[inline] + fn bitand_assign(&mut self, rhs: libafl_custom_insn_kind) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct libafl_custom_insn_kind(pub ::std::os::raw::c_uint); #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct libafl_exit_reason_internal { @@ -5507,15 +6124,28 @@ const _: () = { [::std::mem::offset_of!(libafl_exit_reason_breakpoint, addr) - 0usize]; }; #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct libafl_exit_reason_sync_exit {} +#[derive(Debug, Copy, Clone)] +pub struct libafl_exit_reason_custom_insn { + pub kind: libafl_custom_insn_kind, +} #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { - ["Size of libafl_exit_reason_sync_exit"] - [::std::mem::size_of::() - 0usize]; - ["Alignment of libafl_exit_reason_sync_exit"] - [::std::mem::align_of::() - 1usize]; + ["Size of libafl_exit_reason_custom_insn"] + [::std::mem::size_of::() - 4usize]; + ["Alignment of libafl_exit_reason_custom_insn"] + [::std::mem::align_of::() - 4usize]; + ["Offset of field: libafl_exit_reason_custom_insn::kind"] + [::std::mem::offset_of!(libafl_exit_reason_custom_insn, kind) - 0usize]; }; +impl Default for libafl_exit_reason_custom_insn { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct libafl_exit_reason_timeout {} @@ -5539,7 +6169,7 @@ pub struct libafl_exit_reason { pub union libafl_exit_reason__bindgen_ty_1 { pub internal: libafl_exit_reason_internal, pub breakpoint: libafl_exit_reason_breakpoint, - pub sync_exit: libafl_exit_reason_sync_exit, + pub custom_insn: libafl_exit_reason_custom_insn, pub timeout: libafl_exit_reason_timeout, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -5552,8 +6182,8 @@ const _: () = { [::std::mem::offset_of!(libafl_exit_reason__bindgen_ty_1, internal) - 0usize]; ["Offset of field: libafl_exit_reason__bindgen_ty_1::breakpoint"] [::std::mem::offset_of!(libafl_exit_reason__bindgen_ty_1, breakpoint) - 0usize]; - ["Offset of field: libafl_exit_reason__bindgen_ty_1::sync_exit"] - [::std::mem::offset_of!(libafl_exit_reason__bindgen_ty_1, sync_exit) - 0usize]; + ["Offset of field: libafl_exit_reason__bindgen_ty_1::custom_insn"] + [::std::mem::offset_of!(libafl_exit_reason__bindgen_ty_1, custom_insn) - 0usize]; ["Offset of field: libafl_exit_reason__bindgen_ty_1::timeout"] [::std::mem::offset_of!(libafl_exit_reason__bindgen_ty_1, timeout) - 0usize]; }; @@ -5602,19 +6232,31 @@ impl ::std::fmt::Debug for libafl_exit_reason { ) } } -extern "C" { +unsafe extern "C" { + pub fn libafl_qemu_set_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn libafl_qemu_remove_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn libafl_qemu_trigger_breakpoint(cpu: *mut CPUState); +} +unsafe extern "C" { + pub fn libafl_qemu_breakpoint_run(pc_next: vaddr); +} +unsafe extern "C" { pub fn libafl_last_exit_cpu() -> *mut CPUState; } -extern "C" { +unsafe extern "C" { pub fn libafl_exit_signal_vm_start(); } -extern "C" { +unsafe extern "C" { pub fn libafl_exit_asap() -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_sync_exit_cpu(); } -extern "C" { +unsafe extern "C" { pub fn libafl_exit_request_internal( cpu: *mut CPUState, pc: u64, @@ -5622,13 +6264,17 @@ extern "C" { signal: ::std::os::raw::c_int, ); } -extern "C" { +unsafe extern "C" { pub fn libafl_exit_request_breakpoint(cpu: *mut CPUState, pc: target_ulong); } -extern "C" { - pub fn libafl_exit_request_sync_backdoor(cpu: *mut CPUState, pc: target_ulong); +unsafe extern "C" { + pub fn libafl_exit_request_custom_insn( + cpu: *mut CPUState, + pc: target_ulong, + kind: libafl_custom_insn_kind, + ); } -extern "C" { +unsafe extern "C" { pub fn libafl_get_exit_reason() -> *mut libafl_exit_reason; } #[repr(C)] @@ -5669,49 +6315,49 @@ impl Default for libafl_mapinfo { } } } -extern "C" { +unsafe extern "C" { pub static mut libafl_dump_core_hook: ::std::option::Option; } -extern "C" { +unsafe extern "C" { pub static mut libafl_force_dfl: ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_handle_crash( host_sig: ::std::os::raw::c_int, info: *mut siginfo_t, puc: *mut ::std::os::raw::c_void, ); } -extern "C" { +unsafe extern "C" { pub fn libafl_maps_first(map_info: *mut IntervalTreeRoot) -> *mut IntervalTreeNode; } -extern "C" { +unsafe extern "C" { pub fn libafl_maps_next( pageflags_maps_node: *mut IntervalTreeNode, proc_maps_node: *mut IntervalTreeRoot, ret: *mut libafl_mapinfo, ) -> *mut IntervalTreeNode; } -extern "C" { +unsafe extern "C" { pub fn libafl_load_addr() -> u64; } -extern "C" { +unsafe extern "C" { pub fn libafl_get_image_info() -> *mut image_info; } -extern "C" { - pub fn libafl_get_brk() -> u64; -} -extern "C" { +unsafe extern "C" { pub fn libafl_get_initial_brk() -> u64; } -extern "C" { +unsafe extern "C" { + pub fn libafl_get_brk() -> u64; +} +unsafe extern "C" { pub fn libafl_set_brk(new_brk: u64) -> u64; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_init(argc: ::std::os::raw::c_int, argv: *mut *mut ::std::os::raw::c_char); } #[repr(C)] @@ -5780,14 +6426,14 @@ impl ::std::ops::BitAndAssign for qemu_plugin_mem_rw { pub struct qemu_plugin_mem_rw(pub ::std::os::raw::c_uint); #[doc = " typedef qemu_plugin_meminfo_t - opaque memory transaction handle\n\n This can be further queried using the qemu_plugin_mem_* query\n functions."] pub type qemu_plugin_meminfo_t = u32; -extern "C" { +unsafe extern "C" { #[doc = " qemu_plugin_get_hwaddr() - return handle for memory operation\n @info: opaque memory info structure\n @vaddr: the virtual address of the memory operation\n\n For system emulation returns a qemu_plugin_hwaddr handle to query\n details about the actual physical address backing the virtual\n address. For linux-user guests it just returns NULL.\n\n This handle is *only* valid for the duration of the callback. Any\n information about the handle should be recovered before the\n callback returns."] pub fn qemu_plugin_get_hwaddr( info: qemu_plugin_meminfo_t, vaddr: u64, ) -> *mut qemu_plugin_hwaddr; } -extern "C" { +unsafe extern "C" { #[doc = " qemu_plugin_hwaddr_phys_addr() - query physical address for memory operation\n @haddr: address handle from qemu_plugin_get_hwaddr()\n\n Returns the physical address associated with the memory operation\n\n Note that the returned physical address may not be unique if you are dealing\n with multiple address spaces."] pub fn qemu_plugin_hwaddr_phys_addr(haddr: *const qemu_plugin_hwaddr) -> u64; } @@ -6030,6 +6676,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn reg_raw(this: *const Self) -> TCGReg { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 0usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_reg_raw(this: *mut Self, val: TCGReg) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn val_type(&self) -> TCGTempVal { unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 8u8) as u32) } } @@ -6041,6 +6709,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn val_type_raw(this: *const Self) -> TCGTempVal { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 8usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_val_type_raw(this: *mut Self, val: TCGTempVal) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 8usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn base_type(&self) -> TCGType { unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 8u8) as u32) } } @@ -6052,6 +6742,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn base_type_raw(this: *const Self) -> TCGType { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 16usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_base_type_raw(this: *mut Self, val: TCGType) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 16usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn type_(&self) -> TCGType { unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 8u8) as u32) } } @@ -6063,6 +6775,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn type__raw(this: *const Self) -> TCGType { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 24usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_type_raw(this: *mut Self, val: TCGType) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 24usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn kind(&self) -> TCGTempKind { unsafe { ::std::mem::transmute(self._bitfield_1.get(32usize, 3u8) as u32) } } @@ -6074,6 +6808,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn kind_raw(this: *const Self) -> TCGTempKind { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 32usize, + 3u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_kind_raw(this: *mut Self, val: TCGTempKind) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 32usize, + 3u8, + val as u64, + ) + } + } + #[inline] pub fn indirect_reg(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(35usize, 1u8) as u32) } } @@ -6085,6 +6841,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn indirect_reg_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 35usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_indirect_reg_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 35usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn indirect_base(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(36usize, 1u8) as u32) } } @@ -6096,6 +6874,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn indirect_base_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 36usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_indirect_base_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 36usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn mem_coherent(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(37usize, 1u8) as u32) } } @@ -6107,6 +6907,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn mem_coherent_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 37usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_mem_coherent_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 37usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn mem_allocated(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(38usize, 1u8) as u32) } } @@ -6118,6 +6940,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn mem_allocated_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 38usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_mem_allocated_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 38usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn temp_allocated(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(39usize, 1u8) as u32) } } @@ -6129,6 +6973,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn temp_allocated_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 39usize, + 1u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_temp_allocated_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 39usize, + 1u8, + val as u64, + ) + } + } + #[inline] pub fn temp_subindex(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(40usize, 2u8) as u32) } } @@ -6140,6 +7006,28 @@ impl TCGTemp { } } #[inline] + pub unsafe fn temp_subindex_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 6usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 40usize, + 2u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_temp_subindex_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 6usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 40usize, + 2u8, + val as u64, + ) + } + } + #[inline] pub fn new_bitfield_1( reg: TCGReg, val_type: TCGTempVal, @@ -6296,10 +7184,32 @@ impl TCGCallArgumentLoc { unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 8u8) as u32) } } #[inline] - pub fn set_kind(&mut self, val: TCGCallArgumentKind) { + pub fn set_kind(&mut self, val: TCGCallArgumentKind) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 8u8, val as u64) + } + } + #[inline] + pub unsafe fn kind_raw(this: *const Self) -> TCGCallArgumentKind { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 4usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 0usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_kind_raw(this: *mut Self, val: TCGCallArgumentKind) { unsafe { let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(0usize, 8u8, val as u64) + <__BindgenBitfieldUnit<[u8; 4usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 8u8, + val as u64, + ) } } #[inline] @@ -6314,6 +7224,28 @@ impl TCGCallArgumentLoc { } } #[inline] + pub unsafe fn arg_slot_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 4usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 8usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_arg_slot_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 4usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 8usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn ref_slot(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 8u8) as u32) } } @@ -6325,6 +7257,28 @@ impl TCGCallArgumentLoc { } } #[inline] + pub unsafe fn ref_slot_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 4usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 16usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_ref_slot_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 4usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 16usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn arg_idx(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 4u8) as u32) } } @@ -6336,6 +7290,28 @@ impl TCGCallArgumentLoc { } } #[inline] + pub unsafe fn arg_idx_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 4usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 24usize, + 4u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_arg_idx_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 4usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 24usize, + 4u8, + val as u64, + ) + } + } + #[inline] pub fn tmp_subindex(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(28usize, 2u8) as u32) } } @@ -6347,6 +7323,28 @@ impl TCGCallArgumentLoc { } } #[inline] + pub unsafe fn tmp_subindex_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 4usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 28usize, + 2u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_tmp_subindex_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 4usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 28usize, + 2u8, + val as u64, + ) + } + } + #[inline] pub fn new_bitfield_1( kind: TCGCallArgumentKind, arg_slot: ::std::os::raw::c_uint, @@ -6419,6 +7417,28 @@ impl TCGHelperInfo { } } #[inline] + pub unsafe fn typemask_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 8usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 0usize, + 32u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_typemask_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 8usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 32u8, + val as u64, + ) + } + } + #[inline] pub fn flags(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(32usize, 8u8) as u32) } } @@ -6430,6 +7450,28 @@ impl TCGHelperInfo { } } #[inline] + pub unsafe fn flags_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 8usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 32usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_flags_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 8usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 32usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn nr_in(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(40usize, 8u8) as u32) } } @@ -6441,6 +7483,28 @@ impl TCGHelperInfo { } } #[inline] + pub unsafe fn nr_in_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 8usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 40usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_nr_in_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 8usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 40usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn nr_out(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(48usize, 8u8) as u32) } } @@ -6452,6 +7516,28 @@ impl TCGHelperInfo { } } #[inline] + pub unsafe fn nr_out_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 8usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 48usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_nr_out_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 8usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 48usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn out_kind(&self) -> TCGCallReturnKind { unsafe { ::std::mem::transmute(self._bitfield_1.get(56usize, 8u8) as u32) } } @@ -6463,6 +7549,28 @@ impl TCGHelperInfo { } } #[inline] + pub unsafe fn out_kind_raw(this: *const Self) -> TCGCallReturnKind { + unsafe { + ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 8usize]>>::raw_get( + ::std::ptr::addr_of!((*this)._bitfield_1), + 56usize, + 8u8, + ) as u32) + } + } + #[inline] + pub unsafe fn set_out_kind_raw(this: *mut Self, val: TCGCallReturnKind) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit<[u8; 8usize]>>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 56usize, + 8u8, + val as u64, + ) + } + } + #[inline] pub fn new_bitfield_1( typemask: ::std::os::raw::c_uint, flags: ::std::os::raw::c_uint, @@ -6526,7 +7634,7 @@ impl Default for qemu_plugin_hwaddr { } } } -extern "C" { +unsafe extern "C" { #[doc = " tlb_plugin_lookup: query last TLB lookup\n @cpu: cpu environment\n\n This function can be used directly after a memory operation to\n query information about the access. It is used by the plugin\n infrastructure to expose more information about the address.\n\n It would only fail if not called from an instrumented memory access\n which would be an abuse of the API."] pub fn tlb_plugin_lookup( cpu: *mut CPUState, @@ -6536,54 +7644,84 @@ extern "C" { data: *mut qemu_plugin_hwaddr, ) -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_page_from_addr(addr: target_ulong) -> target_ulong; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_get_cpu(cpu_index: ::std::os::raw::c_int) -> *mut CPUState; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_num_cpus() -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_current_cpu() -> *mut CPUState; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_cpu_index(arg1: *mut CPUState) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_write_reg( cpu: *mut CPUState, reg: ::std::os::raw::c_int, val: *mut u8, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_read_reg( cpu: *mut CPUState, reg: ::std::os::raw::c_int, val: *mut u8, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_num_regs(cpu: *mut CPUState) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_flush_jit(); } -extern "C" { +unsafe extern "C" { pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_main() -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_run() -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_set_qemu_env(env: *mut CPUArchState); } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_custom_gdb_cmd { + pub callback: ::std::option::Option< + unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void, arg2: *mut u8, arg3: usize) -> bool, + >, + pub data: *mut ::std::os::raw::c_void, + pub next: *mut libafl_custom_gdb_cmd, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_custom_gdb_cmd"][::std::mem::size_of::() - 24usize]; + ["Alignment of libafl_custom_gdb_cmd"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_custom_gdb_cmd::callback"] + [::std::mem::offset_of!(libafl_custom_gdb_cmd, callback) - 0usize]; + ["Offset of field: libafl_custom_gdb_cmd::data"] + [::std::mem::offset_of!(libafl_custom_gdb_cmd, data) - 8usize]; + ["Offset of field: libafl_custom_gdb_cmd::next"] + [::std::mem::offset_of!(libafl_custom_gdb_cmd, next) - 16usize]; +}; +impl Default for libafl_custom_gdb_cmd { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_qemu_add_gdb_cmd( callback: ::std::option::Option< unsafe extern "C" fn( @@ -6595,34 +7733,69 @@ extern "C" { data: *mut ::std::os::raw::c_void, ); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_gdb_reply(buf: *const u8, len: usize); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_gdb_exec() -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_jit_trace_edge_hitcount(data: u64, id: u64) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_jit_trace_edge_single(data: u64, id: u64) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_jit_trace_block_hitcount(data: u64, id: u64) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_jit_trace_block_single(data: u64, id: u64) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_host_page_size() -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_tcg_gen_asan(addr: *mut TCGTemp, size: usize); } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_backdoor_hook { + pub gen: ::std::option::Option< + unsafe extern "C" fn(data: u64, cpu: *mut CPUArchState, pc: target_ulong), + >, + pub data: u64, + pub num: usize, + pub helper_info: TCGHelperInfo, + pub next: *mut libafl_backdoor_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_backdoor_hook"][::std::mem::size_of::() - 120usize]; + ["Alignment of libafl_backdoor_hook"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_backdoor_hook::gen"] + [::std::mem::offset_of!(libafl_backdoor_hook, gen) - 0usize]; + ["Offset of field: libafl_backdoor_hook::data"] + [::std::mem::offset_of!(libafl_backdoor_hook, data) - 8usize]; + ["Offset of field: libafl_backdoor_hook::num"] + [::std::mem::offset_of!(libafl_backdoor_hook, num) - 16usize]; + ["Offset of field: libafl_backdoor_hook::helper_info"] + [::std::mem::offset_of!(libafl_backdoor_hook, helper_info) - 24usize]; + ["Offset of field: libafl_backdoor_hook::next"] + [::std::mem::offset_of!(libafl_backdoor_hook, next) - 112usize]; +}; +impl Default for libafl_backdoor_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_gen_backdoor(pc: target_ulong); } -extern "C" { +unsafe extern "C" { pub fn libafl_add_backdoor_hook( exec: ::std::option::Option< unsafe extern "C" fn(data: u64, cpu: *mut CPUArchState, pc: target_ulong), @@ -6630,34 +7803,75 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_backdoor_hook( num: usize, invalidate: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_hook_backdoor_run(pc_next: vaddr); } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_block_hook { + pub gen: ::std::option::Option u64>, + pub post_gen: ::std::option::Option< + unsafe extern "C" fn(data: u64, pc: target_ulong, block_length: target_ulong), + >, + pub jit: ::std::option::Option usize>, + pub data: u64, + pub num: usize, + pub helper_info: TCGHelperInfo, + pub next: *mut libafl_block_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_block_hook"][::std::mem::size_of::() - 136usize]; + ["Alignment of libafl_block_hook"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_block_hook::gen"] + [::std::mem::offset_of!(libafl_block_hook, gen) - 0usize]; + ["Offset of field: libafl_block_hook::post_gen"] + [::std::mem::offset_of!(libafl_block_hook, post_gen) - 8usize]; + ["Offset of field: libafl_block_hook::jit"] + [::std::mem::offset_of!(libafl_block_hook, jit) - 16usize]; + ["Offset of field: libafl_block_hook::data"] + [::std::mem::offset_of!(libafl_block_hook, data) - 24usize]; + ["Offset of field: libafl_block_hook::num"] + [::std::mem::offset_of!(libafl_block_hook, num) - 32usize]; + ["Offset of field: libafl_block_hook::helper_info"] + [::std::mem::offset_of!(libafl_block_hook, helper_info) - 40usize]; + ["Offset of field: libafl_block_hook::next"] + [::std::mem::offset_of!(libafl_block_hook, next) - 128usize]; +}; +impl Default for libafl_block_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_qemu_hook_block_post_gen(tb: *mut TranslationBlock, pc: vaddr); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_hook_block_run(pc: target_ulong); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_block_hook_set_jit( num: usize, jit: ::std::option::Option usize>, ) -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_block_hook( num: usize, invalidate: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_add_block_hook( gen: ::std::option::Option u64>, post_gen: ::std::option::Option< @@ -6667,10 +7881,54 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_cmp_hook { + pub gen: ::std::option::Option< + unsafe extern "C" fn(data: u64, pc: target_ulong, size: usize) -> u64, + >, + pub data: u64, + pub num: usize, + pub helper_info1: TCGHelperInfo, + pub helper_info2: TCGHelperInfo, + pub helper_info4: TCGHelperInfo, + pub helper_info8: TCGHelperInfo, + pub next: *mut libafl_cmp_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_cmp_hook"][::std::mem::size_of::() - 384usize]; + ["Alignment of libafl_cmp_hook"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_cmp_hook::gen"] + [::std::mem::offset_of!(libafl_cmp_hook, gen) - 0usize]; + ["Offset of field: libafl_cmp_hook::data"] + [::std::mem::offset_of!(libafl_cmp_hook, data) - 8usize]; + ["Offset of field: libafl_cmp_hook::num"] + [::std::mem::offset_of!(libafl_cmp_hook, num) - 16usize]; + ["Offset of field: libafl_cmp_hook::helper_info1"] + [::std::mem::offset_of!(libafl_cmp_hook, helper_info1) - 24usize]; + ["Offset of field: libafl_cmp_hook::helper_info2"] + [::std::mem::offset_of!(libafl_cmp_hook, helper_info2) - 112usize]; + ["Offset of field: libafl_cmp_hook::helper_info4"] + [::std::mem::offset_of!(libafl_cmp_hook, helper_info4) - 200usize]; + ["Offset of field: libafl_cmp_hook::helper_info8"] + [::std::mem::offset_of!(libafl_cmp_hook, helper_info8) - 288usize]; + ["Offset of field: libafl_cmp_hook::next"] + [::std::mem::offset_of!(libafl_cmp_hook, next) - 376usize]; +}; +impl Default for libafl_cmp_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_gen_cmp(pc: target_ulong, op0: TCGv, op1: TCGv, ot: MemOp); } -extern "C" { +unsafe extern "C" { pub fn libafl_add_cmp_hook( gen: ::std::option::Option< unsafe extern "C" fn(data: u64, pc: target_ulong, size: usize) -> u64, @@ -6682,13 +7940,54 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_cmp_hook( num: usize, invalidate: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_edge_hook { + pub gen: ::std::option::Option< + unsafe extern "C" fn(data: u64, src: target_ulong, dst: target_ulong) -> u64, + >, + pub jit: ::std::option::Option usize>, + pub data: u64, + pub num: usize, + pub cur_id: u64, + pub helper_info: TCGHelperInfo, + pub next: *mut libafl_edge_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_edge_hook"][::std::mem::size_of::() - 136usize]; + ["Alignment of libafl_edge_hook"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_edge_hook::gen"] + [::std::mem::offset_of!(libafl_edge_hook, gen) - 0usize]; + ["Offset of field: libafl_edge_hook::jit"] + [::std::mem::offset_of!(libafl_edge_hook, jit) - 8usize]; + ["Offset of field: libafl_edge_hook::data"] + [::std::mem::offset_of!(libafl_edge_hook, data) - 16usize]; + ["Offset of field: libafl_edge_hook::num"] + [::std::mem::offset_of!(libafl_edge_hook, num) - 24usize]; + ["Offset of field: libafl_edge_hook::cur_id"] + [::std::mem::offset_of!(libafl_edge_hook, cur_id) - 32usize]; + ["Offset of field: libafl_edge_hook::helper_info"] + [::std::mem::offset_of!(libafl_edge_hook, helper_info) - 40usize]; + ["Offset of field: libafl_edge_hook::next"] + [::std::mem::offset_of!(libafl_edge_hook, next) - 128usize]; +}; +impl Default for libafl_edge_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_gen_edge( cpu: *mut CPUState, src_block: target_ulong, @@ -6699,7 +7998,7 @@ extern "C" { cflags: ::std::os::raw::c_int, ) -> *mut TranslationBlock; } -extern "C" { +unsafe extern "C" { pub fn libafl_add_edge_hook( gen: ::std::option::Option< unsafe extern "C" fn(data: u64, src: target_ulong, dst: target_ulong) -> u64, @@ -6708,22 +8007,22 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_edge_hook_set_jit( num: usize, jit: ::std::option::Option usize>, ) -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_edge_hook( num: usize, invalidate: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_hook_edge_gen(src_block: target_ulong, dst_block: target_ulong) -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_hook_edge_run(); } #[repr(C)] @@ -6761,7 +8060,7 @@ impl Default for libafl_instruction_hook { } } } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_add_instruction_hooks( pc: target_ulong, callback: ::std::option::Option, @@ -6769,31 +8068,76 @@ extern "C" { invalidate: ::std::os::raw::c_int, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_instruction_hook( num: usize, invalidate: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_instruction_hooks_at( addr: target_ulong, invalidate: ::std::os::raw::c_int, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_search_instruction_hook(addr: target_ulong) -> *mut libafl_instruction_hook; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_hook_instruction_run(pc_next: vaddr); } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_rw_hook { + pub gen: ::std::option::Option< + unsafe extern "C" fn(data: u64, pc: target_ulong, addr: *mut TCGTemp, oi: MemOpIdx) -> u64, + >, + pub data: u64, + pub num: usize, + pub helper_info1: TCGHelperInfo, + pub helper_info2: TCGHelperInfo, + pub helper_info4: TCGHelperInfo, + pub helper_info8: TCGHelperInfo, + pub helper_infoN: TCGHelperInfo, + pub next: *mut libafl_rw_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_rw_hook"][::std::mem::size_of::() - 472usize]; + ["Alignment of libafl_rw_hook"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_rw_hook::gen"][::std::mem::offset_of!(libafl_rw_hook, gen) - 0usize]; + ["Offset of field: libafl_rw_hook::data"] + [::std::mem::offset_of!(libafl_rw_hook, data) - 8usize]; + ["Offset of field: libafl_rw_hook::num"][::std::mem::offset_of!(libafl_rw_hook, num) - 16usize]; + ["Offset of field: libafl_rw_hook::helper_info1"] + [::std::mem::offset_of!(libafl_rw_hook, helper_info1) - 24usize]; + ["Offset of field: libafl_rw_hook::helper_info2"] + [::std::mem::offset_of!(libafl_rw_hook, helper_info2) - 112usize]; + ["Offset of field: libafl_rw_hook::helper_info4"] + [::std::mem::offset_of!(libafl_rw_hook, helper_info4) - 200usize]; + ["Offset of field: libafl_rw_hook::helper_info8"] + [::std::mem::offset_of!(libafl_rw_hook, helper_info8) - 288usize]; + ["Offset of field: libafl_rw_hook::helper_infoN"] + [::std::mem::offset_of!(libafl_rw_hook, helper_infoN) - 376usize]; + ["Offset of field: libafl_rw_hook::next"] + [::std::mem::offset_of!(libafl_rw_hook, next) - 464usize]; +}; +impl Default for libafl_rw_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_gen_read(addr: *mut TCGTemp, oi: MemOpIdx); } -extern "C" { +unsafe extern "C" { pub fn libafl_gen_write(addr: *mut TCGTemp, oi: MemOpIdx); } -extern "C" { +unsafe extern "C" { pub fn libafl_add_read_hook( gen: ::std::option::Option< unsafe extern "C" fn( @@ -6813,7 +8157,7 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_add_write_hook( gen: ::std::option::Option< unsafe extern "C" fn( @@ -6833,13 +8177,13 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_read_hook( num: usize, invalidate: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_write_hook( num: usize, invalidate: ::std::os::raw::c_int, @@ -6847,26 +8191,92 @@ extern "C" { } pub type libafl_cpu_run_fn = ::std::option::Option; -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_cpu_run_hook { + pub pre_cpu_run: libafl_cpu_run_fn, + pub post_cpu_run: libafl_cpu_run_fn, + pub data: u64, + pub num: usize, + pub next: *mut libafl_cpu_run_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_cpu_run_hook"][::std::mem::size_of::() - 40usize]; + ["Alignment of libafl_cpu_run_hook"][::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_cpu_run_hook::pre_cpu_run"] + [::std::mem::offset_of!(libafl_cpu_run_hook, pre_cpu_run) - 0usize]; + ["Offset of field: libafl_cpu_run_hook::post_cpu_run"] + [::std::mem::offset_of!(libafl_cpu_run_hook, post_cpu_run) - 8usize]; + ["Offset of field: libafl_cpu_run_hook::data"] + [::std::mem::offset_of!(libafl_cpu_run_hook, data) - 16usize]; + ["Offset of field: libafl_cpu_run_hook::num"] + [::std::mem::offset_of!(libafl_cpu_run_hook, num) - 24usize]; + ["Offset of field: libafl_cpu_run_hook::next"] + [::std::mem::offset_of!(libafl_cpu_run_hook, next) - 32usize]; +}; +impl Default for libafl_cpu_run_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_hook_cpu_run_add( pre_cpu_run: libafl_cpu_run_fn, post_cpu_run: libafl_cpu_run_fn, data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_hook_cpu_run_remove(num: usize) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_cpu_run_hook(num: usize) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_hook_cpu_run_pre_exec(cpu: *mut CPUState); } -extern "C" { +unsafe extern "C" { pub fn libafl_hook_cpu_run_post_exec(cpu: *mut CPUState); } -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_new_thread_hook { + pub callback: ::std::option::Option< + unsafe extern "C" fn(data: u64, cpu: *mut CPUArchState, tid: u32) -> bool, + >, + pub data: u64, + pub num: usize, + pub next: *mut libafl_new_thread_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_new_thread_hook"][::std::mem::size_of::() - 32usize]; + ["Alignment of libafl_new_thread_hook"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_new_thread_hook::callback"] + [::std::mem::offset_of!(libafl_new_thread_hook, callback) - 0usize]; + ["Offset of field: libafl_new_thread_hook::data"] + [::std::mem::offset_of!(libafl_new_thread_hook, data) - 8usize]; + ["Offset of field: libafl_new_thread_hook::num"] + [::std::mem::offset_of!(libafl_new_thread_hook, num) - 16usize]; + ["Offset of field: libafl_new_thread_hook::next"] + [::std::mem::offset_of!(libafl_new_thread_hook, next) - 24usize]; +}; +impl Default for libafl_new_thread_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_add_new_thread_hook( callback: ::std::option::Option< unsafe extern "C" fn(data: u64, env: *mut CPUArchState, tid: u32) -> bool, @@ -6874,10 +8284,10 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_new_thread_hook(num: usize) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_hook_new_thread_run(env: *mut CPUArchState, tid: u32) -> bool; } #[repr(C)] @@ -6894,7 +8304,97 @@ const _: () = { ["Offset of field: syshook_ret::skip_syscall"] [::std::mem::offset_of!(syshook_ret, skip_syscall) - 8usize]; }; -extern "C" { +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_pre_syscall_hook { + pub callback: ::std::option::Option< + unsafe extern "C" fn( + data: u64, + sys_num: ::std::os::raw::c_int, + arg0: target_ulong, + arg1: target_ulong, + arg2: target_ulong, + arg3: target_ulong, + arg4: target_ulong, + arg5: target_ulong, + arg6: target_ulong, + arg7: target_ulong, + ) -> syshook_ret, + >, + pub data: u64, + pub num: usize, + pub next: *mut libafl_pre_syscall_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_pre_syscall_hook"][::std::mem::size_of::() - 32usize]; + ["Alignment of libafl_pre_syscall_hook"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_pre_syscall_hook::callback"] + [::std::mem::offset_of!(libafl_pre_syscall_hook, callback) - 0usize]; + ["Offset of field: libafl_pre_syscall_hook::data"] + [::std::mem::offset_of!(libafl_pre_syscall_hook, data) - 8usize]; + ["Offset of field: libafl_pre_syscall_hook::num"] + [::std::mem::offset_of!(libafl_pre_syscall_hook, num) - 16usize]; + ["Offset of field: libafl_pre_syscall_hook::next"] + [::std::mem::offset_of!(libafl_pre_syscall_hook, next) - 24usize]; +}; +impl Default for libafl_pre_syscall_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_post_syscall_hook { + pub callback: ::std::option::Option< + unsafe extern "C" fn( + data: u64, + ret: target_ulong, + sys_num: ::std::os::raw::c_int, + arg0: target_ulong, + arg1: target_ulong, + arg2: target_ulong, + arg3: target_ulong, + arg4: target_ulong, + arg5: target_ulong, + arg6: target_ulong, + arg7: target_ulong, + ) -> target_ulong, + >, + pub data: u64, + pub num: usize, + pub next: *mut libafl_post_syscall_hook, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of libafl_post_syscall_hook"] + [::std::mem::size_of::() - 32usize]; + ["Alignment of libafl_post_syscall_hook"] + [::std::mem::align_of::() - 8usize]; + ["Offset of field: libafl_post_syscall_hook::callback"] + [::std::mem::offset_of!(libafl_post_syscall_hook, callback) - 0usize]; + ["Offset of field: libafl_post_syscall_hook::data"] + [::std::mem::offset_of!(libafl_post_syscall_hook, data) - 8usize]; + ["Offset of field: libafl_post_syscall_hook::num"] + [::std::mem::offset_of!(libafl_post_syscall_hook, num) - 16usize]; + ["Offset of field: libafl_post_syscall_hook::next"] + [::std::mem::offset_of!(libafl_post_syscall_hook, next) - 24usize]; +}; +impl Default for libafl_post_syscall_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { pub fn libafl_add_pre_syscall_hook( callback: ::std::option::Option< unsafe extern "C" fn( @@ -6913,7 +8413,7 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_add_post_syscall_hook( callback: ::std::option::Option< unsafe extern "C" fn( @@ -6933,13 +8433,13 @@ extern "C" { data: u64, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_pre_syscall_hook(num: usize) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_remove_post_syscall_hook(num: usize) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn libafl_hook_syscall_pre_run( env: *mut CPUArchState, num: ::std::os::raw::c_int, @@ -6954,7 +8454,7 @@ extern "C" { ret: *mut abi_long, ) -> bool; } -extern "C" { +unsafe extern "C" { pub fn libafl_hook_syscall_post_run( num: ::std::os::raw::c_int, arg1: abi_long, diff --git a/libafl_qemu/runtime/libafl_qemu_arch.h b/libafl_qemu/runtime/libafl_qemu_arch.h index 739d2c95da..74bebc20ba 100644 --- a/libafl_qemu/runtime/libafl_qemu_arch.h +++ b/libafl_qemu/runtime/libafl_qemu_arch.h @@ -78,23 +78,28 @@ #endif #endif +#define LIBAFL_DECLARE(name) \ + libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call0(libafl_word action); \ + libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call1(libafl_word action, \ + libafl_word arg1); \ + libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call2(libafl_word action, \ + libafl_word arg1, \ + libafl_word arg2); + #ifdef _WIN32 #define LIBAFL_DEFINE_FUNCTIONS(name, _opcode) \ #ifdef __cplusplus \ extern "C" { \ #endif \ - libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call0(libafl_word action); \ - libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call1(libafl_word action, \ - ##name## libafl_word arg1); \ - libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call2(libafl_word action, \ - libafl_word arg1, \ - libafl_word arg2); \ + LIBAFL_DECLARE(name) \ #ifdef __cplusplus \ } \ #endif #else #if defined(__x86_64__) #define LIBAFL_DEFINE_FUNCTIONS(name, opcode) \ + LIBAFL_DECLARE(name) \ + \ libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call0( \ libafl_word action) { \ libafl_word ret; \ @@ -142,6 +147,8 @@ #elif defined(__arm__) #define LIBAFL_DEFINE_FUNCTIONS(name, opcode) \ + LIBAFL_DECLARE(name) \ + \ libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call0( \ libafl_word action) { \ libafl_word ret; \ @@ -189,6 +196,8 @@ #elif defined(__aarch64__) #define LIBAFL_DEFINE_FUNCTIONS(name, opcode) \ + LIBAFL_DECLARE(name) \ + \ libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call0( \ libafl_word action) { \ libafl_word ret; \ @@ -235,6 +244,8 @@ } #elif defined(__riscv) #define LIBAFL_DEFINE_FUNCTIONS(name, opcode) \ + LIBAFL_DECLARE(name) \ + \ libafl_word LIBAFL_CALLING_CONVENTION _libafl_##name##_call0( \ libafl_word action) { \ libafl_word ret; \ diff --git a/libafl_qemu/runtime/libafl_qemu_stub_bindings.rs b/libafl_qemu/runtime/libafl_qemu_stub_bindings.rs index 706cddb088..7752e9c2bc 100644 --- a/libafl_qemu/runtime/libafl_qemu_stub_bindings.rs +++ b/libafl_qemu/runtime/libafl_qemu_stub_bindings.rs @@ -1,6 +1,6 @@ -/* 1.84.0-nightly */ -/* qemu git hash: 805b14ffc44999952562e8f219d81c21a4fa50b9 */ -/* automatically generated by rust-bindgen 0.70.1 */ +/* 1.85.0-nightly */ +/* qemu git hash: 81e52dc60f83c3ae191c1a07b39bb255e633c234 */ +/* automatically generated by rust-bindgen 0.71.1 */ pub const LIBAFL_SYNC_EXIT_OPCODE: u32 = 1727150607; pub const LIBAFL_BACKDOOR_OPCODE: u32 = 1156725263; @@ -562,25 +562,25 @@ pub type cookie_io_functions_t = _IO_cookie_io_functions_t; pub type va_list = __gnuc_va_list; pub type off_t = __off_t; pub type fpos_t = __fpos_t; -extern "C" { +unsafe extern "C" { pub static mut stdin: *mut FILE; } -extern "C" { +unsafe extern "C" { pub static mut stdout: *mut FILE; } -extern "C" { +unsafe extern "C" { pub static mut stderr: *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn remove(__filename: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn rename( __old: *const ::std::os::raw::c_char, __new: *const ::std::os::raw::c_char, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn renameat( __oldfd: ::std::os::raw::c_int, __old: *const ::std::os::raw::c_char, @@ -588,71 +588,71 @@ extern "C" { __new: *const ::std::os::raw::c_char, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fclose(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn tmpfile() -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn tmpnam(arg1: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub fn tmpnam_r(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub fn tempnam( __dir: *const ::std::os::raw::c_char, __pfx: *const ::std::os::raw::c_char, ) -> *mut ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub fn fflush(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fflush_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fopen( __filename: *const ::std::os::raw::c_char, __modes: *const ::std::os::raw::c_char, ) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn freopen( __filename: *const ::std::os::raw::c_char, __modes: *const ::std::os::raw::c_char, __stream: *mut FILE, ) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn fdopen(__fd: ::std::os::raw::c_int, __modes: *const ::std::os::raw::c_char) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn fopencookie( __magic_cookie: *mut ::std::os::raw::c_void, __modes: *const ::std::os::raw::c_char, __io_funcs: cookie_io_functions_t, ) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn fmemopen( __s: *mut ::std::os::raw::c_void, __len: usize, __modes: *const ::std::os::raw::c_char, ) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn open_memstream( __bufloc: *mut *mut ::std::os::raw::c_char, __sizeloc: *mut usize, ) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn setbuf(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char); } -extern "C" { +unsafe extern "C" { pub fn setvbuf( __stream: *mut FILE, __buf: *mut ::std::os::raw::c_char, @@ -660,50 +660,50 @@ extern "C" { __n: usize, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn setbuffer(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char, __size: usize); } -extern "C" { +unsafe extern "C" { pub fn setlinebuf(__stream: *mut FILE); } -extern "C" { +unsafe extern "C" { pub fn fprintf( __stream: *mut FILE, __format: *const ::std::os::raw::c_char, ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn printf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn sprintf( __s: *mut ::std::os::raw::c_char, __format: *const ::std::os::raw::c_char, ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vfprintf( __s: *mut FILE, __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vprintf( __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vsprintf( __s: *mut ::std::os::raw::c_char, __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn snprintf( __s: *mut ::std::os::raw::c_char, __maxlen: ::std::os::raw::c_ulong, @@ -711,7 +711,7 @@ extern "C" { ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vsnprintf( __s: *mut ::std::os::raw::c_char, __maxlen: ::std::os::raw::c_ulong, @@ -719,52 +719,52 @@ extern "C" { __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vasprintf( __ptr: *mut *mut ::std::os::raw::c_char, __f: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn __asprintf( __ptr: *mut *mut ::std::os::raw::c_char, __fmt: *const ::std::os::raw::c_char, ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn asprintf( __ptr: *mut *mut ::std::os::raw::c_char, __fmt: *const ::std::os::raw::c_char, ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vdprintf( __fd: ::std::os::raw::c_int, __fmt: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn dprintf( __fd: ::std::os::raw::c_int, __fmt: *const ::std::os::raw::c_char, ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fscanf( __stream: *mut FILE, __format: *const ::std::os::raw::c_char, ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn scanf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn sscanf( __s: *const ::std::os::raw::c_char, __format: *const ::std::os::raw::c_char, @@ -775,7 +775,7 @@ pub type _Float32 = f32; pub type _Float64 = f64; pub type _Float32x = f64; pub type _Float64x = u128; -extern "C" { +unsafe extern "C" { #[link_name = "\u{1}__isoc99_fscanf"] pub fn fscanf1( __stream: *mut FILE, @@ -783,11 +783,11 @@ extern "C" { ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { #[link_name = "\u{1}__isoc99_scanf"] pub fn scanf1(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { #[link_name = "\u{1}__isoc99_sscanf"] pub fn sscanf1( __s: *const ::std::os::raw::c_char, @@ -795,27 +795,27 @@ extern "C" { ... ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vfscanf( __s: *mut FILE, __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vscanf( __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn vsscanf( __s: *const ::std::os::raw::c_char, __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { #[link_name = "\u{1}__isoc99_vfscanf"] pub fn vfscanf1( __s: *mut FILE, @@ -823,14 +823,14 @@ extern "C" { __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { #[link_name = "\u{1}__isoc99_vscanf"] pub fn vscanf1( __format: *const ::std::os::raw::c_char, __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { #[link_name = "\u{1}__isoc99_vsscanf"] pub fn vsscanf1( __s: *const ::std::os::raw::c_char, @@ -838,57 +838,57 @@ extern "C" { __arg: *mut __va_list_tag, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fgetc(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn getc(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn getchar() -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn getc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn getchar_unlocked() -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fgetc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fputc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn putc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn putchar(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fputc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn putc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn putchar_unlocked(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn getw(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn putw(__w: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fgets( __s: *mut ::std::os::raw::c_char, __n: ::std::os::raw::c_int, __stream: *mut FILE, ) -> *mut ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub fn __getdelim( __lineptr: *mut *mut ::std::os::raw::c_char, __n: *mut usize, @@ -896,7 +896,7 @@ extern "C" { __stream: *mut FILE, ) -> __ssize_t; } -extern "C" { +unsafe extern "C" { pub fn getdelim( __lineptr: *mut *mut ::std::os::raw::c_char, __n: *mut usize, @@ -904,23 +904,23 @@ extern "C" { __stream: *mut FILE, ) -> __ssize_t; } -extern "C" { +unsafe extern "C" { pub fn getline( __lineptr: *mut *mut ::std::os::raw::c_char, __n: *mut usize, __stream: *mut FILE, ) -> __ssize_t; } -extern "C" { +unsafe extern "C" { pub fn fputs(__s: *const ::std::os::raw::c_char, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn puts(__s: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn ungetc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fread( __ptr: *mut ::std::os::raw::c_void, __size: ::std::os::raw::c_ulong, @@ -928,7 +928,7 @@ extern "C" { __stream: *mut FILE, ) -> ::std::os::raw::c_ulong; } -extern "C" { +unsafe extern "C" { pub fn fwrite( __ptr: *const ::std::os::raw::c_void, __size: ::std::os::raw::c_ulong, @@ -936,7 +936,7 @@ extern "C" { __s: *mut FILE, ) -> ::std::os::raw::c_ulong; } -extern "C" { +unsafe extern "C" { pub fn fread_unlocked( __ptr: *mut ::std::os::raw::c_void, __size: usize, @@ -944,7 +944,7 @@ extern "C" { __stream: *mut FILE, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn fwrite_unlocked( __ptr: *const ::std::os::raw::c_void, __size: usize, @@ -952,87 +952,87 @@ extern "C" { __stream: *mut FILE, ) -> usize; } -extern "C" { +unsafe extern "C" { pub fn fseek( __stream: *mut FILE, __off: ::std::os::raw::c_long, __whence: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn ftell(__stream: *mut FILE) -> ::std::os::raw::c_long; } -extern "C" { +unsafe extern "C" { pub fn rewind(__stream: *mut FILE); } -extern "C" { +unsafe extern "C" { pub fn fseeko( __stream: *mut FILE, __off: __off_t, __whence: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn ftello(__stream: *mut FILE) -> __off_t; } -extern "C" { +unsafe extern "C" { pub fn fgetpos(__stream: *mut FILE, __pos: *mut fpos_t) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fsetpos(__stream: *mut FILE, __pos: *const fpos_t) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn clearerr(__stream: *mut FILE); } -extern "C" { +unsafe extern "C" { pub fn feof(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn ferror(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn clearerr_unlocked(__stream: *mut FILE); } -extern "C" { +unsafe extern "C" { pub fn feof_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn ferror_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn perror(__s: *const ::std::os::raw::c_char); } -extern "C" { +unsafe extern "C" { pub fn fileno(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn fileno_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn pclose(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn popen( __command: *const ::std::os::raw::c_char, __modes: *const ::std::os::raw::c_char, ) -> *mut FILE; } -extern "C" { +unsafe extern "C" { pub fn ctermid(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub fn flockfile(__stream: *mut FILE); } -extern "C" { +unsafe extern "C" { pub fn ftrylockfile(__stream: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn funlockfile(__stream: *mut FILE); } -extern "C" { +unsafe extern "C" { pub fn __uflow(arg1: *mut FILE) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub fn __overflow(arg1: *mut FILE, arg2: ::std::os::raw::c_int) -> ::std::os::raw::c_int; } pub type int_least8_t = __int_least8_t; @@ -1054,26 +1054,26 @@ pub type uint_fast64_t = ::std::os::raw::c_ulong; pub type intmax_t = __intmax_t; pub type uintmax_t = __uintmax_t; pub type libafl_word = u64; -extern "C" { +unsafe extern "C" { pub fn _libafl_sync_exit_call0(action: libafl_word) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn _libafl_sync_exit_call1(action: libafl_word, arg1: libafl_word) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn _libafl_sync_exit_call2( action: libafl_word, arg1: libafl_word, arg2: libafl_word, ) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn _libafl_backdoor_call0(action: libafl_word) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn _libafl_backdoor_call1(action: libafl_word, arg1: libafl_word) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn _libafl_backdoor_call2( action: libafl_word, arg1: libafl_word, @@ -1113,61 +1113,61 @@ impl ::std::ops::BitAndAssign for LibaflQemuEndStatus { #[doc = " LibAFL QEMU header file.\n\n This file is a portable header file used to build target harnesses more\n conveniently. Its main purpose is to generate ready-to-use calls to\n communicate with the fuzzer. The list of commands is available at the bottom\n of this file. The rest mostly consists of macros generating the code used by\n the commands."] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct LibaflQemuEndStatus(pub ::std::os::raw::c_uint); -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_start_virt( buf_vaddr: *mut ::std::os::raw::c_void, max_len: libafl_word, ) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_start_phys( buf_paddr: *mut ::std::os::raw::c_void, max_len: libafl_word, ) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_input_virt( buf_vaddr: *mut ::std::os::raw::c_void, max_len: libafl_word, ) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_input_phys( buf_paddr: *mut ::std::os::raw::c_void, max_len: libafl_word, ) -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_end(status: LibaflQemuEndStatus); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_save(); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_load(); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_version() -> libafl_word; } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_page_current_allow(); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_internal_error(); } -extern "C" { +unsafe extern "C" { pub fn lqprintf(fmt: *const ::std::os::raw::c_char, ...); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_test(); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_trace_vaddr_range(start: libafl_word, end: libafl_word); } -extern "C" { +unsafe extern "C" { pub fn libafl_qemu_trace_vaddr_size(start: libafl_word, size: libafl_word); } -extern "C" { +unsafe extern "C" { pub static mut _lqprintf_buffer: [::std::os::raw::c_char; 4096usize]; } pub type __builtin_va_list = [__va_list_tag; 1usize]; diff --git a/libafl_qemu/runtime/nyx_api.h b/libafl_qemu/runtime/nyx_api.h new file mode 100644 index 0000000000..708b8fc915 --- /dev/null +++ b/libafl_qemu/runtime/nyx_api.h @@ -0,0 +1,185 @@ +/* + * kAFl/Nyx low-level interface definitions + * + * Copyright 2022 Sergej Schumilo, Cornelius Aschermann + * Copyright 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + */ + +#ifndef NYX_API_H +#define NYX_API_H + +#ifndef __KERNEL__ + // userspace + #include + #include + + #ifdef __MINGW64__ + #ifndef uint64_t + #define uint64_t UINT64 + #endif + #ifndef int32_t + #define int32_t INT32 + #endif + #ifndef uint32_t + #define uint32_t UINT32 + #endif + #ifndef u_long + #define u_long UINT64 + #endif + #ifndef uint8_t + #define uint8_t UINT8 + #endif + #else + #include + #endif +#else + // Linux kernel + #include + #include +#endif + +#define HYPERCALL_KAFL_RAX_ID 0x01f +#define HYPERCALL_KAFL_ACQUIRE 0 +#define HYPERCALL_KAFL_GET_PAYLOAD 1 +#define HYPERCALL_KAFL_GET_PROGRAM 2 /* deprecated */ +#define HYPERCALL_KAFL_GET_ARGV 3 /* deprecated */ +#define HYPERCALL_KAFL_RELEASE 4 +#define HYPERCALL_KAFL_SUBMIT_CR3 5 +#define HYPERCALL_KAFL_SUBMIT_PANIC 6 +#define HYPERCALL_KAFL_SUBMIT_KASAN 7 +#define HYPERCALL_KAFL_PANIC 8 +#define HYPERCALL_KAFL_KASAN 9 +#define HYPERCALL_KAFL_LOCK 10 +#define HYPERCALL_KAFL_INFO 11 /* deprecated */ +#define HYPERCALL_KAFL_NEXT_PAYLOAD 12 +#define HYPERCALL_KAFL_PRINTF 13 +#define HYPERCALL_KAFL_PRINTK_ADDR 14 /* deprecated */ +#define HYPERCALL_KAFL_PRINTK 15 /* deprecated */ + +/* user space only hypercalls */ +#define HYPERCALL_KAFL_USER_RANGE_ADVISE 16 +#define HYPERCALL_KAFL_USER_SUBMIT_MODE 17 +#define HYPERCALL_KAFL_USER_FAST_ACQUIRE 18 +/* 19 is already used for exit reason KVM_EXIT_KAFL_TOPA_MAIN_FULL */ +#define HYPERCALL_KAFL_USER_ABORT 20 +#define HYPERCALL_KAFL_TIMEOUT 21 /* deprecated */ +#define HYPERCALL_KAFL_RANGE_SUBMIT 29 +#define HYPERCALL_KAFL_REQ_STREAM_DATA 30 +#define HYPERCALL_KAFL_PANIC_EXTENDED 32 + +#define HYPERCALL_KAFL_CREATE_TMP_SNAPSHOT 33 +#define HYPERCALL_KAFL_DEBUG_TMP_SNAPSHOT \ + 34 /* hypercall for debugging / development purposes */ + +#define HYPERCALL_KAFL_GET_HOST_CONFIG 35 +#define HYPERCALL_KAFL_SET_AGENT_CONFIG 36 + +#define HYPERCALL_KAFL_DUMP_FILE 37 + +#define HYPERCALL_KAFL_REQ_STREAM_DATA_BULK 38 +#define HYPERCALL_KAFL_PERSIST_PAGE_PAST_SNAPSHOT 39 + +/* hypertrash only hypercalls */ +#define HYPERTRASH_HYPERCALL_MASK 0xAA000000 + +#define HYPERCALL_KAFL_NESTED_PREPARE (0 | HYPERTRASH_HYPERCALL_MASK) +#define HYPERCALL_KAFL_NESTED_CONFIG (1 | HYPERTRASH_HYPERCALL_MASK) +#define HYPERCALL_KAFL_NESTED_ACQUIRE (2 | HYPERTRASH_HYPERCALL_MASK) +#define HYPERCALL_KAFL_NESTED_RELEASE (3 | HYPERTRASH_HYPERCALL_MASK) +#define HYPERCALL_KAFL_NESTED_HPRINTF (4 | HYPERTRASH_HYPERCALL_MASK) + +#define HPRINTF_MAX_SIZE 0x1000 /* up to 4KB hprintf strings */ + +#define KAFL_MODE_64 0 +#define KAFL_MODE_32 1 +#define KAFL_MODE_16 2 + +typedef struct { + int32_t size; + uint8_t data[]; +} kAFL_payload; + +typedef struct { + uint64_t ip[4]; + uint64_t size[4]; + uint8_t enabled[4]; +} kAFL_ranges; + +#if defined(__i386__) +static inline uint32_t kAFL_hypercall(uint32_t p1, uint32_t p2) { + uint32_t nr = HYPERCALL_KAFL_RAX_ID; + asm volatile("vmcall" : "=a"(nr) : "a"(nr), "b"(p1), "c"(p2)); + return nr; +} +#elif defined(__x86_64__) +static inline uint64_t kAFL_hypercall(uint64_t p1, uint64_t p2) { + uint64_t nr = HYPERCALL_KAFL_RAX_ID; + asm volatile("vmcall" : "=a"(nr) : "a"(nr), "b"(p1), "c"(p2)); + return nr; +} +#endif + +static void habort(char *msg) __attribute__((unused)); +static void habort(char *msg) { + kAFL_hypercall(HYPERCALL_KAFL_USER_ABORT, (uintptr_t)msg); +} + +static void hprintf(const char *format, ...) __attribute__((unused)); +static void hprintf(const char *format, ...) { + static char hprintf_buffer[HPRINTF_MAX_SIZE] __attribute__((aligned(4096))); + + va_list args; + va_start(args, format); + vsnprintf((char *)hprintf_buffer, HPRINTF_MAX_SIZE, format, args); + // printf("%s", hprintf_buffer); + kAFL_hypercall(HYPERCALL_KAFL_PRINTF, (uintptr_t)hprintf_buffer); + va_end(args); +} + +#define NYX_HOST_MAGIC 0x4878794e +#define NYX_AGENT_MAGIC 0x4178794e + +#define NYX_HOST_VERSION 2 +#define NYX_AGENT_VERSION 1 + +typedef struct { + uint32_t host_magic; + uint32_t host_version; + uint32_t bitmap_size; + uint32_t ijon_bitmap_size; + uint32_t payload_buffer_size; + uint32_t worker_id; + /* more to come */ +} __attribute__((packed)) host_config_t; + +typedef struct { + uint32_t agent_magic; + uint32_t agent_version; + uint8_t agent_timeout_detection; + uint8_t agent_tracing; + uint8_t agent_ijon_tracing; + uint8_t agent_non_reload_mode; + uint64_t trace_buffer_vaddr; + uint64_t ijon_trace_buffer_vaddr; + uint32_t coverage_bitmap_size; + uint32_t input_buffer_size; + uint8_t dump_payloads; /* set by hypervisor */ + /* more to come */ +} __attribute__((packed)) agent_config_t; + +typedef struct { + uint64_t file_name_str_ptr; + uint64_t data_ptr; + uint64_t bytes; + uint8_t append; +} __attribute__((packed)) kafl_dump_file_t; + +typedef struct { + char file_name[256]; + uint64_t num_addresses; + uint64_t addresses[479]; +} __attribute__((packed)) req_data_bulk_t; + +#endif /* NYX_API_H */ \ No newline at end of file diff --git a/libafl_qemu/runtime/nyx_stub_bindings.rs b/libafl_qemu/runtime/nyx_stub_bindings.rs new file mode 100644 index 0000000000..34700e8f41 --- /dev/null +++ b/libafl_qemu/runtime/nyx_stub_bindings.rs @@ -0,0 +1,1255 @@ +/* 1.85.0-nightly */ +/* qemu git hash: 81e52dc60f83c3ae191c1a07b39bb255e633c234 */ +/* automatically generated by rust-bindgen 0.71.1 */ + +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); +impl __IncompleteArrayField { + #[inline] + pub const fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData, []) + } + #[inline] + pub fn as_ptr(&self) -> *const T { + self as *const _ as *const T + } + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self as *mut _ as *mut T + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} +pub const _STDIO_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const __GLIBC_USE_ISOC23: u32 = 0; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_POSIX_IMPLICITLY: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __TIMESIZE: u32 = 64; +pub const __USE_TIME_BITS64: u32 = 1; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; +pub const __GLIBC_USE_C23_STRTOL: u32 = 0; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_60559_BFP__: u32 = 201404; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 40; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; +pub const __HAVE_GENERIC_SELECTION: u32 = 1; +pub const __GLIBC_USE_LIB_EXT2: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT_C23: u32 = 0; +pub const __GLIBC_USE_IEC_60559_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C23: u32 = 0; +pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0; +pub const _BITS_TYPES_H: u32 = 1; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __STATFS_MATCHES_STATFS64: u32 = 1; +pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const _BITS_TIME64_H: u32 = 1; +pub const _____fpos_t_defined: u32 = 1; +pub const ____mbstate_t_defined: u32 = 1; +pub const _____fpos64_t_defined: u32 = 1; +pub const ____FILE_defined: u32 = 1; +pub const __FILE_defined: u32 = 1; +pub const __struct_FILE_defined: u32 = 1; +pub const _IO_EOF_SEEN: u32 = 16; +pub const _IO_ERR_SEEN: u32 = 32; +pub const _IO_USER_LOCK: u32 = 32768; +pub const __cookie_io_functions_t_defined: u32 = 1; +pub const _IOFBF: u32 = 0; +pub const _IOLBF: u32 = 1; +pub const _IONBF: u32 = 2; +pub const BUFSIZ: u32 = 8192; +pub const EOF: i32 = -1; +pub const SEEK_SET: u32 = 0; +pub const SEEK_CUR: u32 = 1; +pub const SEEK_END: u32 = 2; +pub const P_tmpdir: &[u8; 5] = b"/tmp\0"; +pub const L_tmpnam: u32 = 20; +pub const TMP_MAX: u32 = 238328; +pub const _BITS_STDIO_LIM_H: u32 = 1; +pub const FILENAME_MAX: u32 = 4096; +pub const L_ctermid: u32 = 9; +pub const FOPEN_MAX: u32 = 16; +pub const __HAVE_FLOAT128: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT128: u32 = 0; +pub const __HAVE_FLOAT64X: u32 = 1; +pub const __HAVE_FLOAT64X_LONG_DOUBLE: u32 = 1; +pub const __HAVE_FLOAT16: u32 = 0; +pub const __HAVE_FLOAT32: u32 = 1; +pub const __HAVE_FLOAT64: u32 = 1; +pub const __HAVE_FLOAT32X: u32 = 1; +pub const __HAVE_FLOAT128X: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT16: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT32: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT64: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT32X: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT64X: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT128X: u32 = 0; +pub const __HAVE_FLOATN_NOT_TYPEDEF: u32 = 0; +pub const _STDINT_H: u32 = 1; +pub const _BITS_WCHAR_H: u32 = 1; +pub const _BITS_STDINT_INTN_H: u32 = 1; +pub const _BITS_STDINT_UINTN_H: u32 = 1; +pub const _BITS_STDINT_LEAST_H: u32 = 1; +pub const INT8_MIN: i32 = -128; +pub const INT16_MIN: i32 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; +pub const UINT8_MAX: u32 = 255; +pub const UINT16_MAX: u32 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: i32 = -128; +pub const INT_LEAST16_MIN: i32 = -32768; +pub const INT_LEAST32_MIN: i32 = -2147483648; +pub const INT_LEAST8_MAX: u32 = 127; +pub const INT_LEAST16_MAX: u32 = 32767; +pub const INT_LEAST32_MAX: u32 = 2147483647; +pub const UINT_LEAST8_MAX: u32 = 255; +pub const UINT_LEAST16_MAX: u32 = 65535; +pub const UINT_LEAST32_MAX: u32 = 4294967295; +pub const INT_FAST8_MIN: i32 = -128; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; +pub const INT_FAST8_MAX: u32 = 127; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; +pub const UINT_FAST8_MAX: u32 = 255; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; +pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINTPTR_MAX: i32 = -1; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; +pub const SIG_ATOMIC_MIN: i32 = -2147483648; +pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; +pub const HYPERCALL_KAFL_RAX_ID: u32 = 31; +pub const HYPERCALL_KAFL_ACQUIRE: u32 = 0; +pub const HYPERCALL_KAFL_GET_PAYLOAD: u32 = 1; +pub const HYPERCALL_KAFL_GET_PROGRAM: u32 = 2; +pub const HYPERCALL_KAFL_GET_ARGV: u32 = 3; +pub const HYPERCALL_KAFL_RELEASE: u32 = 4; +pub const HYPERCALL_KAFL_SUBMIT_CR3: u32 = 5; +pub const HYPERCALL_KAFL_SUBMIT_PANIC: u32 = 6; +pub const HYPERCALL_KAFL_SUBMIT_KASAN: u32 = 7; +pub const HYPERCALL_KAFL_PANIC: u32 = 8; +pub const HYPERCALL_KAFL_KASAN: u32 = 9; +pub const HYPERCALL_KAFL_LOCK: u32 = 10; +pub const HYPERCALL_KAFL_INFO: u32 = 11; +pub const HYPERCALL_KAFL_NEXT_PAYLOAD: u32 = 12; +pub const HYPERCALL_KAFL_PRINTF: u32 = 13; +pub const HYPERCALL_KAFL_PRINTK_ADDR: u32 = 14; +pub const HYPERCALL_KAFL_PRINTK: u32 = 15; +pub const HYPERCALL_KAFL_USER_RANGE_ADVISE: u32 = 16; +pub const HYPERCALL_KAFL_USER_SUBMIT_MODE: u32 = 17; +pub const HYPERCALL_KAFL_USER_FAST_ACQUIRE: u32 = 18; +pub const HYPERCALL_KAFL_USER_ABORT: u32 = 20; +pub const HYPERCALL_KAFL_TIMEOUT: u32 = 21; +pub const HYPERCALL_KAFL_RANGE_SUBMIT: u32 = 29; +pub const HYPERCALL_KAFL_REQ_STREAM_DATA: u32 = 30; +pub const HYPERCALL_KAFL_PANIC_EXTENDED: u32 = 32; +pub const HYPERCALL_KAFL_CREATE_TMP_SNAPSHOT: u32 = 33; +pub const HYPERCALL_KAFL_DEBUG_TMP_SNAPSHOT: u32 = 34; +pub const HYPERCALL_KAFL_GET_HOST_CONFIG: u32 = 35; +pub const HYPERCALL_KAFL_SET_AGENT_CONFIG: u32 = 36; +pub const HYPERCALL_KAFL_DUMP_FILE: u32 = 37; +pub const HYPERCALL_KAFL_REQ_STREAM_DATA_BULK: u32 = 38; +pub const HYPERCALL_KAFL_PERSIST_PAGE_PAST_SNAPSHOT: u32 = 39; +pub const HYPERTRASH_HYPERCALL_MASK: u32 = 2852126720; +pub const HYPERCALL_KAFL_NESTED_PREPARE: u32 = 2852126720; +pub const HYPERCALL_KAFL_NESTED_CONFIG: u32 = 2852126721; +pub const HYPERCALL_KAFL_NESTED_ACQUIRE: u32 = 2852126722; +pub const HYPERCALL_KAFL_NESTED_RELEASE: u32 = 2852126723; +pub const HYPERCALL_KAFL_NESTED_HPRINTF: u32 = 2852126724; +pub const HPRINTF_MAX_SIZE: u32 = 4096; +pub const KAFL_MODE_64: u32 = 0; +pub const KAFL_MODE_32: u32 = 1; +pub const KAFL_MODE_16: u32 = 2; +pub const NYX_HOST_MAGIC: u32 = 1215854926; +pub const NYX_AGENT_MAGIC: u32 = 1098414414; +pub const NYX_HOST_VERSION: u32 = 2; +pub const NYX_AGENT_VERSION: u32 = 1; +pub type __gnuc_va_list = __builtin_va_list; +pub type va_list = __builtin_va_list; +pub type __u_char = ::std::os::raw::c_uchar; +pub type __u_short = ::std::os::raw::c_ushort; +pub type __u_int = ::std::os::raw::c_uint; +pub type __u_long = ::std::os::raw::c_ulong; +pub type __int8_t = ::std::os::raw::c_schar; +pub type __uint8_t = ::std::os::raw::c_uchar; +pub type __int16_t = ::std::os::raw::c_short; +pub type __uint16_t = ::std::os::raw::c_ushort; +pub type __int32_t = ::std::os::raw::c_int; +pub type __uint32_t = ::std::os::raw::c_uint; +pub type __int64_t = ::std::os::raw::c_long; +pub type __uint64_t = ::std::os::raw::c_ulong; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; +pub type __quad_t = ::std::os::raw::c_long; +pub type __u_quad_t = ::std::os::raw::c_ulong; +pub type __intmax_t = ::std::os::raw::c_long; +pub type __uintmax_t = ::std::os::raw::c_ulong; +pub type __dev_t = ::std::os::raw::c_ulong; +pub type __uid_t = ::std::os::raw::c_uint; +pub type __gid_t = ::std::os::raw::c_uint; +pub type __ino_t = ::std::os::raw::c_ulong; +pub type __ino64_t = ::std::os::raw::c_ulong; +pub type __mode_t = ::std::os::raw::c_uint; +pub type __nlink_t = ::std::os::raw::c_ulong; +pub type __off_t = ::std::os::raw::c_long; +pub type __off64_t = ::std::os::raw::c_long; +pub type __pid_t = ::std::os::raw::c_int; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct __fsid_t { + pub __val: [::std::os::raw::c_int; 2usize], +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of __fsid_t"][::std::mem::size_of::<__fsid_t>() - 8usize]; + ["Alignment of __fsid_t"][::std::mem::align_of::<__fsid_t>() - 4usize]; + ["Offset of field: __fsid_t::__val"][::std::mem::offset_of!(__fsid_t, __val) - 0usize]; +}; +pub type __clock_t = ::std::os::raw::c_long; +pub type __rlim_t = ::std::os::raw::c_ulong; +pub type __rlim64_t = ::std::os::raw::c_ulong; +pub type __id_t = ::std::os::raw::c_uint; +pub type __time_t = ::std::os::raw::c_long; +pub type __useconds_t = ::std::os::raw::c_uint; +pub type __suseconds_t = ::std::os::raw::c_long; +pub type __suseconds64_t = ::std::os::raw::c_long; +pub type __daddr_t = ::std::os::raw::c_int; +pub type __key_t = ::std::os::raw::c_int; +pub type __clockid_t = ::std::os::raw::c_int; +pub type __timer_t = *mut ::std::os::raw::c_void; +pub type __blksize_t = ::std::os::raw::c_long; +pub type __blkcnt_t = ::std::os::raw::c_long; +pub type __blkcnt64_t = ::std::os::raw::c_long; +pub type __fsblkcnt_t = ::std::os::raw::c_ulong; +pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; +pub type __fsword_t = ::std::os::raw::c_long; +pub type __ssize_t = ::std::os::raw::c_long; +pub type __syscall_slong_t = ::std::os::raw::c_long; +pub type __syscall_ulong_t = ::std::os::raw::c_ulong; +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut ::std::os::raw::c_char; +pub type __intptr_t = ::std::os::raw::c_long; +pub type __socklen_t = ::std::os::raw::c_uint; +pub type __sig_atomic_t = ::std::os::raw::c_int; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __mbstate_t { + pub __count: ::std::os::raw::c_int, + pub __value: __mbstate_t__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __mbstate_t__bindgen_ty_1 { + pub __wch: ::std::os::raw::c_uint, + pub __wchb: [::std::os::raw::c_char; 4usize], +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of __mbstate_t__bindgen_ty_1"] + [::std::mem::size_of::<__mbstate_t__bindgen_ty_1>() - 4usize]; + ["Alignment of __mbstate_t__bindgen_ty_1"] + [::std::mem::align_of::<__mbstate_t__bindgen_ty_1>() - 4usize]; + ["Offset of field: __mbstate_t__bindgen_ty_1::__wch"] + [::std::mem::offset_of!(__mbstate_t__bindgen_ty_1, __wch) - 0usize]; + ["Offset of field: __mbstate_t__bindgen_ty_1::__wchb"] + [::std::mem::offset_of!(__mbstate_t__bindgen_ty_1, __wchb) - 0usize]; +}; +impl Default for __mbstate_t__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for __mbstate_t__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "__mbstate_t__bindgen_ty_1 {{ union }}") + } +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of __mbstate_t"][::std::mem::size_of::<__mbstate_t>() - 8usize]; + ["Alignment of __mbstate_t"][::std::mem::align_of::<__mbstate_t>() - 4usize]; + ["Offset of field: __mbstate_t::__count"] + [::std::mem::offset_of!(__mbstate_t, __count) - 0usize]; + ["Offset of field: __mbstate_t::__value"] + [::std::mem::offset_of!(__mbstate_t, __value) - 4usize]; +}; +impl Default for __mbstate_t { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for __mbstate_t { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "__mbstate_t {{ __count: {:?}, __value: {:?} }}", + self.__count, self.__value + ) + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _G_fpos_t { + pub __pos: __off_t, + pub __state: __mbstate_t, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of _G_fpos_t"][::std::mem::size_of::<_G_fpos_t>() - 16usize]; + ["Alignment of _G_fpos_t"][::std::mem::align_of::<_G_fpos_t>() - 8usize]; + ["Offset of field: _G_fpos_t::__pos"][::std::mem::offset_of!(_G_fpos_t, __pos) - 0usize]; + ["Offset of field: _G_fpos_t::__state"][::std::mem::offset_of!(_G_fpos_t, __state) - 8usize]; +}; +impl Default for _G_fpos_t { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for _G_fpos_t { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "_G_fpos_t {{ __pos: {:?}, __state: {:?} }}", + self.__pos, self.__state + ) + } +} +pub type __fpos_t = _G_fpos_t; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _G_fpos64_t { + pub __pos: __off64_t, + pub __state: __mbstate_t, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of _G_fpos64_t"][::std::mem::size_of::<_G_fpos64_t>() - 16usize]; + ["Alignment of _G_fpos64_t"][::std::mem::align_of::<_G_fpos64_t>() - 8usize]; + ["Offset of field: _G_fpos64_t::__pos"][::std::mem::offset_of!(_G_fpos64_t, __pos) - 0usize]; + ["Offset of field: _G_fpos64_t::__state"] + [::std::mem::offset_of!(_G_fpos64_t, __state) - 8usize]; +}; +impl Default for _G_fpos64_t { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for _G_fpos64_t { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "_G_fpos64_t {{ __pos: {:?}, __state: {:?} }}", + self.__pos, self.__state + ) + } +} +pub type __fpos64_t = _G_fpos64_t; +pub type __FILE = _IO_FILE; +pub type FILE = _IO_FILE; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _IO_marker { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _IO_codecvt { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _IO_wide_data { + _unused: [u8; 0], +} +pub type _IO_lock_t = ::std::os::raw::c_void; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _IO_FILE { + pub _flags: ::std::os::raw::c_int, + pub _IO_read_ptr: *mut ::std::os::raw::c_char, + pub _IO_read_end: *mut ::std::os::raw::c_char, + pub _IO_read_base: *mut ::std::os::raw::c_char, + pub _IO_write_base: *mut ::std::os::raw::c_char, + pub _IO_write_ptr: *mut ::std::os::raw::c_char, + pub _IO_write_end: *mut ::std::os::raw::c_char, + pub _IO_buf_base: *mut ::std::os::raw::c_char, + pub _IO_buf_end: *mut ::std::os::raw::c_char, + pub _IO_save_base: *mut ::std::os::raw::c_char, + pub _IO_backup_base: *mut ::std::os::raw::c_char, + pub _IO_save_end: *mut ::std::os::raw::c_char, + pub _markers: *mut _IO_marker, + pub _chain: *mut _IO_FILE, + pub _fileno: ::std::os::raw::c_int, + pub _flags2: ::std::os::raw::c_int, + pub _old_offset: __off_t, + pub _cur_column: ::std::os::raw::c_ushort, + pub _vtable_offset: ::std::os::raw::c_schar, + pub _shortbuf: [::std::os::raw::c_char; 1usize], + pub _lock: *mut _IO_lock_t, + pub _offset: __off64_t, + pub _codecvt: *mut _IO_codecvt, + pub _wide_data: *mut _IO_wide_data, + pub _freeres_list: *mut _IO_FILE, + pub _freeres_buf: *mut ::std::os::raw::c_void, + pub _prevchain: *mut *mut _IO_FILE, + pub _mode: ::std::os::raw::c_int, + pub _unused2: [::std::os::raw::c_char; 20usize], +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of _IO_FILE"][::std::mem::size_of::<_IO_FILE>() - 216usize]; + ["Alignment of _IO_FILE"][::std::mem::align_of::<_IO_FILE>() - 8usize]; + ["Offset of field: _IO_FILE::_flags"][::std::mem::offset_of!(_IO_FILE, _flags) - 0usize]; + ["Offset of field: _IO_FILE::_IO_read_ptr"] + [::std::mem::offset_of!(_IO_FILE, _IO_read_ptr) - 8usize]; + ["Offset of field: _IO_FILE::_IO_read_end"] + [::std::mem::offset_of!(_IO_FILE, _IO_read_end) - 16usize]; + ["Offset of field: _IO_FILE::_IO_read_base"] + [::std::mem::offset_of!(_IO_FILE, _IO_read_base) - 24usize]; + ["Offset of field: _IO_FILE::_IO_write_base"] + [::std::mem::offset_of!(_IO_FILE, _IO_write_base) - 32usize]; + ["Offset of field: _IO_FILE::_IO_write_ptr"] + [::std::mem::offset_of!(_IO_FILE, _IO_write_ptr) - 40usize]; + ["Offset of field: _IO_FILE::_IO_write_end"] + [::std::mem::offset_of!(_IO_FILE, _IO_write_end) - 48usize]; + ["Offset of field: _IO_FILE::_IO_buf_base"] + [::std::mem::offset_of!(_IO_FILE, _IO_buf_base) - 56usize]; + ["Offset of field: _IO_FILE::_IO_buf_end"] + [::std::mem::offset_of!(_IO_FILE, _IO_buf_end) - 64usize]; + ["Offset of field: _IO_FILE::_IO_save_base"] + [::std::mem::offset_of!(_IO_FILE, _IO_save_base) - 72usize]; + ["Offset of field: _IO_FILE::_IO_backup_base"] + [::std::mem::offset_of!(_IO_FILE, _IO_backup_base) - 80usize]; + ["Offset of field: _IO_FILE::_IO_save_end"] + [::std::mem::offset_of!(_IO_FILE, _IO_save_end) - 88usize]; + ["Offset of field: _IO_FILE::_markers"][::std::mem::offset_of!(_IO_FILE, _markers) - 96usize]; + ["Offset of field: _IO_FILE::_chain"][::std::mem::offset_of!(_IO_FILE, _chain) - 104usize]; + ["Offset of field: _IO_FILE::_fileno"][::std::mem::offset_of!(_IO_FILE, _fileno) - 112usize]; + ["Offset of field: _IO_FILE::_flags2"][::std::mem::offset_of!(_IO_FILE, _flags2) - 116usize]; + ["Offset of field: _IO_FILE::_old_offset"] + [::std::mem::offset_of!(_IO_FILE, _old_offset) - 120usize]; + ["Offset of field: _IO_FILE::_cur_column"] + [::std::mem::offset_of!(_IO_FILE, _cur_column) - 128usize]; + ["Offset of field: _IO_FILE::_vtable_offset"] + [::std::mem::offset_of!(_IO_FILE, _vtable_offset) - 130usize]; + ["Offset of field: _IO_FILE::_shortbuf"] + [::std::mem::offset_of!(_IO_FILE, _shortbuf) - 131usize]; + ["Offset of field: _IO_FILE::_lock"][::std::mem::offset_of!(_IO_FILE, _lock) - 136usize]; + ["Offset of field: _IO_FILE::_offset"][::std::mem::offset_of!(_IO_FILE, _offset) - 144usize]; + ["Offset of field: _IO_FILE::_codecvt"][::std::mem::offset_of!(_IO_FILE, _codecvt) - 152usize]; + ["Offset of field: _IO_FILE::_wide_data"] + [::std::mem::offset_of!(_IO_FILE, _wide_data) - 160usize]; + ["Offset of field: _IO_FILE::_freeres_list"] + [::std::mem::offset_of!(_IO_FILE, _freeres_list) - 168usize]; + ["Offset of field: _IO_FILE::_freeres_buf"] + [::std::mem::offset_of!(_IO_FILE, _freeres_buf) - 176usize]; + ["Offset of field: _IO_FILE::_prevchain"] + [::std::mem::offset_of!(_IO_FILE, _prevchain) - 184usize]; + ["Offset of field: _IO_FILE::_mode"][::std::mem::offset_of!(_IO_FILE, _mode) - 192usize]; + ["Offset of field: _IO_FILE::_unused2"][::std::mem::offset_of!(_IO_FILE, _unused2) - 196usize]; +}; +impl Default for _IO_FILE { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +pub type cookie_read_function_t = ::std::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::std::os::raw::c_void, + __buf: *mut ::std::os::raw::c_char, + __nbytes: usize, + ) -> __ssize_t, +>; +pub type cookie_write_function_t = ::std::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::std::os::raw::c_void, + __buf: *const ::std::os::raw::c_char, + __nbytes: usize, + ) -> __ssize_t, +>; +pub type cookie_seek_function_t = ::std::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::std::os::raw::c_void, + __pos: *mut __off64_t, + __w: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, +>; +pub type cookie_close_function_t = ::std::option::Option< + unsafe extern "C" fn(__cookie: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, +>; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct _IO_cookie_io_functions_t { + pub read: cookie_read_function_t, + pub write: cookie_write_function_t, + pub seek: cookie_seek_function_t, + pub close: cookie_close_function_t, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of _IO_cookie_io_functions_t"] + [::std::mem::size_of::<_IO_cookie_io_functions_t>() - 32usize]; + ["Alignment of _IO_cookie_io_functions_t"] + [::std::mem::align_of::<_IO_cookie_io_functions_t>() - 8usize]; + ["Offset of field: _IO_cookie_io_functions_t::read"] + [::std::mem::offset_of!(_IO_cookie_io_functions_t, read) - 0usize]; + ["Offset of field: _IO_cookie_io_functions_t::write"] + [::std::mem::offset_of!(_IO_cookie_io_functions_t, write) - 8usize]; + ["Offset of field: _IO_cookie_io_functions_t::seek"] + [::std::mem::offset_of!(_IO_cookie_io_functions_t, seek) - 16usize]; + ["Offset of field: _IO_cookie_io_functions_t::close"] + [::std::mem::offset_of!(_IO_cookie_io_functions_t, close) - 24usize]; +}; +pub type cookie_io_functions_t = _IO_cookie_io_functions_t; +pub type off_t = __off_t; +pub type fpos_t = __fpos_t; +unsafe extern "C" { + pub static mut stdin: *mut FILE; +} +unsafe extern "C" { + pub static mut stdout: *mut FILE; +} +unsafe extern "C" { + pub static mut stderr: *mut FILE; +} +unsafe extern "C" { + pub fn remove(__filename: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn rename( + __old: *const ::std::os::raw::c_char, + __new: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn renameat( + __oldfd: ::std::os::raw::c_int, + __old: *const ::std::os::raw::c_char, + __newfd: ::std::os::raw::c_int, + __new: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fclose(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn tmpfile() -> *mut FILE; +} +unsafe extern "C" { + pub fn tmpnam(arg1: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; +} +unsafe extern "C" { + pub fn tmpnam_r(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; +} +unsafe extern "C" { + pub fn tempnam( + __dir: *const ::std::os::raw::c_char, + __pfx: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_char; +} +unsafe extern "C" { + pub fn fflush(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fflush_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fopen( + __filename: *const ::std::os::raw::c_char, + __modes: *const ::std::os::raw::c_char, + ) -> *mut FILE; +} +unsafe extern "C" { + pub fn freopen( + __filename: *const ::std::os::raw::c_char, + __modes: *const ::std::os::raw::c_char, + __stream: *mut FILE, + ) -> *mut FILE; +} +unsafe extern "C" { + pub fn fdopen(__fd: ::std::os::raw::c_int, __modes: *const ::std::os::raw::c_char) + -> *mut FILE; +} +unsafe extern "C" { + pub fn fopencookie( + __magic_cookie: *mut ::std::os::raw::c_void, + __modes: *const ::std::os::raw::c_char, + __io_funcs: cookie_io_functions_t, + ) -> *mut FILE; +} +unsafe extern "C" { + pub fn fmemopen( + __s: *mut ::std::os::raw::c_void, + __len: usize, + __modes: *const ::std::os::raw::c_char, + ) -> *mut FILE; +} +unsafe extern "C" { + pub fn open_memstream( + __bufloc: *mut *mut ::std::os::raw::c_char, + __sizeloc: *mut usize, + ) -> *mut FILE; +} +unsafe extern "C" { + pub fn setbuf(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char); +} +unsafe extern "C" { + pub fn setvbuf( + __stream: *mut FILE, + __buf: *mut ::std::os::raw::c_char, + __modes: ::std::os::raw::c_int, + __n: usize, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn setbuffer(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char, __size: usize); +} +unsafe extern "C" { + pub fn setlinebuf(__stream: *mut FILE); +} +unsafe extern "C" { + pub fn fprintf( + __stream: *mut FILE, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn printf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn sprintf( + __s: *mut ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vfprintf( + __s: *mut FILE, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vprintf( + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vsprintf( + __s: *mut ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn snprintf( + __s: *mut ::std::os::raw::c_char, + __maxlen: ::std::os::raw::c_ulong, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vsnprintf( + __s: *mut ::std::os::raw::c_char, + __maxlen: ::std::os::raw::c_ulong, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vasprintf( + __ptr: *mut *mut ::std::os::raw::c_char, + __f: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn __asprintf( + __ptr: *mut *mut ::std::os::raw::c_char, + __fmt: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn asprintf( + __ptr: *mut *mut ::std::os::raw::c_char, + __fmt: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vdprintf( + __fd: ::std::os::raw::c_int, + __fmt: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn dprintf( + __fd: ::std::os::raw::c_int, + __fmt: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fscanf( + __stream: *mut FILE, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn scanf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn sscanf( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +pub type _Float32 = f32; +pub type _Float64 = f64; +pub type _Float32x = f64; +pub type _Float64x = u128; +unsafe extern "C" { + #[link_name = "\u{1}__isoc99_fscanf"] + pub fn fscanf1( + __stream: *mut FILE, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}__isoc99_scanf"] + pub fn scanf1(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}__isoc99_sscanf"] + pub fn sscanf1( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + ... + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vfscanf( + __s: *mut FILE, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vscanf( + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn vsscanf( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}__isoc99_vfscanf"] + pub fn vfscanf1( + __s: *mut FILE, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}__isoc99_vscanf"] + pub fn vscanf1( + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}__isoc99_vsscanf"] + pub fn vsscanf1( + __s: *const ::std::os::raw::c_char, + __format: *const ::std::os::raw::c_char, + __arg: *mut __va_list_tag, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fgetc(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn getc(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn getchar() -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn getc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn getchar_unlocked() -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fgetc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fputc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn putc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn putchar(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fputc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) + -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn putc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn putchar_unlocked(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn getw(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn putw(__w: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fgets( + __s: *mut ::std::os::raw::c_char, + __n: ::std::os::raw::c_int, + __stream: *mut FILE, + ) -> *mut ::std::os::raw::c_char; +} +unsafe extern "C" { + pub fn __getdelim( + __lineptr: *mut *mut ::std::os::raw::c_char, + __n: *mut usize, + __delimiter: ::std::os::raw::c_int, + __stream: *mut FILE, + ) -> __ssize_t; +} +unsafe extern "C" { + pub fn getdelim( + __lineptr: *mut *mut ::std::os::raw::c_char, + __n: *mut usize, + __delimiter: ::std::os::raw::c_int, + __stream: *mut FILE, + ) -> __ssize_t; +} +unsafe extern "C" { + pub fn getline( + __lineptr: *mut *mut ::std::os::raw::c_char, + __n: *mut usize, + __stream: *mut FILE, + ) -> __ssize_t; +} +unsafe extern "C" { + pub fn fputs(__s: *const ::std::os::raw::c_char, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn puts(__s: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn ungetc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fread( + __ptr: *mut ::std::os::raw::c_void, + __size: ::std::os::raw::c_ulong, + __n: ::std::os::raw::c_ulong, + __stream: *mut FILE, + ) -> ::std::os::raw::c_ulong; +} +unsafe extern "C" { + pub fn fwrite( + __ptr: *const ::std::os::raw::c_void, + __size: ::std::os::raw::c_ulong, + __n: ::std::os::raw::c_ulong, + __s: *mut FILE, + ) -> ::std::os::raw::c_ulong; +} +unsafe extern "C" { + pub fn fread_unlocked( + __ptr: *mut ::std::os::raw::c_void, + __size: usize, + __n: usize, + __stream: *mut FILE, + ) -> usize; +} +unsafe extern "C" { + pub fn fwrite_unlocked( + __ptr: *const ::std::os::raw::c_void, + __size: usize, + __n: usize, + __stream: *mut FILE, + ) -> usize; +} +unsafe extern "C" { + pub fn fseek( + __stream: *mut FILE, + __off: ::std::os::raw::c_long, + __whence: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn ftell(__stream: *mut FILE) -> ::std::os::raw::c_long; +} +unsafe extern "C" { + pub fn rewind(__stream: *mut FILE); +} +unsafe extern "C" { + pub fn fseeko( + __stream: *mut FILE, + __off: __off_t, + __whence: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn ftello(__stream: *mut FILE) -> __off_t; +} +unsafe extern "C" { + pub fn fgetpos(__stream: *mut FILE, __pos: *mut fpos_t) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fsetpos(__stream: *mut FILE, __pos: *const fpos_t) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn clearerr(__stream: *mut FILE); +} +unsafe extern "C" { + pub fn feof(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn ferror(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn clearerr_unlocked(__stream: *mut FILE); +} +unsafe extern "C" { + pub fn feof_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn ferror_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn perror(__s: *const ::std::os::raw::c_char); +} +unsafe extern "C" { + pub fn fileno(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn fileno_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn pclose(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn popen( + __command: *const ::std::os::raw::c_char, + __modes: *const ::std::os::raw::c_char, + ) -> *mut FILE; +} +unsafe extern "C" { + pub fn ctermid(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; +} +unsafe extern "C" { + pub fn flockfile(__stream: *mut FILE); +} +unsafe extern "C" { + pub fn ftrylockfile(__stream: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn funlockfile(__stream: *mut FILE); +} +unsafe extern "C" { + pub fn __uflow(arg1: *mut FILE) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + pub fn __overflow(arg1: *mut FILE, arg2: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +pub type int_least8_t = __int_least8_t; +pub type int_least16_t = __int_least16_t; +pub type int_least32_t = __int_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least8_t = __uint_least8_t; +pub type uint_least16_t = __uint_least16_t; +pub type uint_least32_t = __uint_least32_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = ::std::os::raw::c_schar; +pub type int_fast16_t = ::std::os::raw::c_long; +pub type int_fast32_t = ::std::os::raw::c_long; +pub type int_fast64_t = ::std::os::raw::c_long; +pub type uint_fast8_t = ::std::os::raw::c_uchar; +pub type uint_fast16_t = ::std::os::raw::c_ulong; +pub type uint_fast32_t = ::std::os::raw::c_ulong; +pub type uint_fast64_t = ::std::os::raw::c_ulong; +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; +#[repr(C)] +#[derive(Debug, Default)] +pub struct kAFL_payload { + pub size: i32, + pub data: __IncompleteArrayField, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of kAFL_payload"][::std::mem::size_of::() - 4usize]; + ["Alignment of kAFL_payload"][::std::mem::align_of::() - 4usize]; + ["Offset of field: kAFL_payload::size"][::std::mem::offset_of!(kAFL_payload, size) - 0usize]; + ["Offset of field: kAFL_payload::data"][::std::mem::offset_of!(kAFL_payload, data) - 4usize]; +}; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct kAFL_ranges { + pub ip: [u64; 4usize], + pub size: [u64; 4usize], + pub enabled: [u8; 4usize], +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of kAFL_ranges"][::std::mem::size_of::() - 72usize]; + ["Alignment of kAFL_ranges"][::std::mem::align_of::() - 8usize]; + ["Offset of field: kAFL_ranges::ip"][::std::mem::offset_of!(kAFL_ranges, ip) - 0usize]; + ["Offset of field: kAFL_ranges::size"][::std::mem::offset_of!(kAFL_ranges, size) - 32usize]; + ["Offset of field: kAFL_ranges::enabled"] + [::std::mem::offset_of!(kAFL_ranges, enabled) - 64usize]; +}; +#[repr(C, packed)] +#[derive(Debug, Default, Copy, Clone)] +pub struct host_config_t { + pub host_magic: u32, + pub host_version: u32, + pub bitmap_size: u32, + pub ijon_bitmap_size: u32, + pub payload_buffer_size: u32, + pub worker_id: u32, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of host_config_t"][::std::mem::size_of::() - 24usize]; + ["Alignment of host_config_t"][::std::mem::align_of::() - 1usize]; + ["Offset of field: host_config_t::host_magic"] + [::std::mem::offset_of!(host_config_t, host_magic) - 0usize]; + ["Offset of field: host_config_t::host_version"] + [::std::mem::offset_of!(host_config_t, host_version) - 4usize]; + ["Offset of field: host_config_t::bitmap_size"] + [::std::mem::offset_of!(host_config_t, bitmap_size) - 8usize]; + ["Offset of field: host_config_t::ijon_bitmap_size"] + [::std::mem::offset_of!(host_config_t, ijon_bitmap_size) - 12usize]; + ["Offset of field: host_config_t::payload_buffer_size"] + [::std::mem::offset_of!(host_config_t, payload_buffer_size) - 16usize]; + ["Offset of field: host_config_t::worker_id"] + [::std::mem::offset_of!(host_config_t, worker_id) - 20usize]; +}; +#[repr(C, packed)] +#[derive(Debug, Default, Copy, Clone)] +pub struct agent_config_t { + pub agent_magic: u32, + pub agent_version: u32, + pub agent_timeout_detection: u8, + pub agent_tracing: u8, + pub agent_ijon_tracing: u8, + pub agent_non_reload_mode: u8, + pub trace_buffer_vaddr: u64, + pub ijon_trace_buffer_vaddr: u64, + pub coverage_bitmap_size: u32, + pub input_buffer_size: u32, + pub dump_payloads: u8, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of agent_config_t"][::std::mem::size_of::() - 37usize]; + ["Alignment of agent_config_t"][::std::mem::align_of::() - 1usize]; + ["Offset of field: agent_config_t::agent_magic"] + [::std::mem::offset_of!(agent_config_t, agent_magic) - 0usize]; + ["Offset of field: agent_config_t::agent_version"] + [::std::mem::offset_of!(agent_config_t, agent_version) - 4usize]; + ["Offset of field: agent_config_t::agent_timeout_detection"] + [::std::mem::offset_of!(agent_config_t, agent_timeout_detection) - 8usize]; + ["Offset of field: agent_config_t::agent_tracing"] + [::std::mem::offset_of!(agent_config_t, agent_tracing) - 9usize]; + ["Offset of field: agent_config_t::agent_ijon_tracing"] + [::std::mem::offset_of!(agent_config_t, agent_ijon_tracing) - 10usize]; + ["Offset of field: agent_config_t::agent_non_reload_mode"] + [::std::mem::offset_of!(agent_config_t, agent_non_reload_mode) - 11usize]; + ["Offset of field: agent_config_t::trace_buffer_vaddr"] + [::std::mem::offset_of!(agent_config_t, trace_buffer_vaddr) - 12usize]; + ["Offset of field: agent_config_t::ijon_trace_buffer_vaddr"] + [::std::mem::offset_of!(agent_config_t, ijon_trace_buffer_vaddr) - 20usize]; + ["Offset of field: agent_config_t::coverage_bitmap_size"] + [::std::mem::offset_of!(agent_config_t, coverage_bitmap_size) - 28usize]; + ["Offset of field: agent_config_t::input_buffer_size"] + [::std::mem::offset_of!(agent_config_t, input_buffer_size) - 32usize]; + ["Offset of field: agent_config_t::dump_payloads"] + [::std::mem::offset_of!(agent_config_t, dump_payloads) - 36usize]; +}; +#[repr(C, packed)] +#[derive(Debug, Default, Copy, Clone)] +pub struct kafl_dump_file_t { + pub file_name_str_ptr: u64, + pub data_ptr: u64, + pub bytes: u64, + pub append: u8, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of kafl_dump_file_t"][::std::mem::size_of::() - 25usize]; + ["Alignment of kafl_dump_file_t"][::std::mem::align_of::() - 1usize]; + ["Offset of field: kafl_dump_file_t::file_name_str_ptr"] + [::std::mem::offset_of!(kafl_dump_file_t, file_name_str_ptr) - 0usize]; + ["Offset of field: kafl_dump_file_t::data_ptr"] + [::std::mem::offset_of!(kafl_dump_file_t, data_ptr) - 8usize]; + ["Offset of field: kafl_dump_file_t::bytes"] + [::std::mem::offset_of!(kafl_dump_file_t, bytes) - 16usize]; + ["Offset of field: kafl_dump_file_t::append"] + [::std::mem::offset_of!(kafl_dump_file_t, append) - 24usize]; +}; +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct req_data_bulk_t { + pub file_name: [::std::os::raw::c_char; 256usize], + pub num_addresses: u64, + pub addresses: [u64; 479usize], +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of req_data_bulk_t"][::std::mem::size_of::() - 4096usize]; + ["Alignment of req_data_bulk_t"][::std::mem::align_of::() - 1usize]; + ["Offset of field: req_data_bulk_t::file_name"] + [::std::mem::offset_of!(req_data_bulk_t, file_name) - 0usize]; + ["Offset of field: req_data_bulk_t::num_addresses"] + [::std::mem::offset_of!(req_data_bulk_t, num_addresses) - 256usize]; + ["Offset of field: req_data_bulk_t::addresses"] + [::std::mem::offset_of!(req_data_bulk_t, addresses) - 264usize]; +}; +impl Default for req_data_bulk_t { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +pub type __builtin_va_list = [__va_list_tag; 1usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __va_list_tag { + pub gp_offset: ::std::os::raw::c_uint, + pub fp_offset: ::std::os::raw::c_uint, + pub overflow_arg_area: *mut ::std::os::raw::c_void, + pub reg_save_area: *mut ::std::os::raw::c_void, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of __va_list_tag"][::std::mem::size_of::<__va_list_tag>() - 24usize]; + ["Alignment of __va_list_tag"][::std::mem::align_of::<__va_list_tag>() - 8usize]; + ["Offset of field: __va_list_tag::gp_offset"] + [::std::mem::offset_of!(__va_list_tag, gp_offset) - 0usize]; + ["Offset of field: __va_list_tag::fp_offset"] + [::std::mem::offset_of!(__va_list_tag, fp_offset) - 4usize]; + ["Offset of field: __va_list_tag::overflow_arg_area"] + [::std::mem::offset_of!(__va_list_tag, overflow_arg_area) - 8usize]; + ["Offset of field: __va_list_tag::reg_save_area"] + [::std::mem::offset_of!(__va_list_tag, reg_save_area) - 16usize]; +}; +impl Default for __va_list_tag { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/libafl_qemu/src/command/mod.rs b/libafl_qemu/src/command/mod.rs index 25e64f5329..602cef26e9 100644 --- a/libafl_qemu/src/command/mod.rs +++ b/libafl_qemu/src/command/mod.rs @@ -32,6 +32,8 @@ use crate::{ IsSnapshotManager, Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorDriver, CPU, }; +#[cfg(any(cpu_target = "i386", cpu_target = "x86_64"))] +pub mod nyx; pub mod parser; mod bindings { diff --git a/libafl_qemu/src/command/nyx.rs b/libafl_qemu/src/command/nyx.rs new file mode 100644 index 0000000000..06b0d9fc41 --- /dev/null +++ b/libafl_qemu/src/command/nyx.rs @@ -0,0 +1,532 @@ +//! # Nyx API Command handlers +//! +//! Nyx command handlers. +//! Makes it possible to run Nyx targets in `LibAFL` QEMU. +//! The [Nyx API](https://github.com/IntelLabs/kafl.targets/blob/master/nyx_api.h) refers to the hypercalls used in Nyx to communicate with the fuzzer, not to the fuzzer itself. +//! This is mostly a convenient way to run Nyx-compatible targets in `LibAFL` QEMU directly, without having to change a single bit of the target files. + +use std::{ + fmt, + fmt::{Debug, Formatter}, + marker::PhantomData, + mem::offset_of, + ptr, + slice::from_raw_parts, +}; + +use enum_map::EnumMap; +use libafl::{ + executors::ExitKind, + inputs::{HasTargetBytes, UsesInput}, +}; +use libafl_qemu_sys::GuestVirtAddr; +use libc::c_uint; +use paste::paste; + +use crate::{ + command::{ + parser::nyx::{ + AcquireCommandParser, GetHostConfigCommandParser, GetPayloadCommandParser, + NextPayloadCommandParser, PrintfCommandParser, ReleaseCommandParser, + SetAgentConfigCommandParser, + }, + CommandError, CommandManager, IsCommand, NativeCommandParser, + }, + get_exit_arch_regs, + modules::EmulatorModuleTuple, + sync_exit::ExitArgs, + Emulator, EmulatorDriverError, EmulatorDriverResult, GuestReg, InputLocation, + IsSnapshotManager, NyxEmulatorDriver, Qemu, QemuMemoryChunk, Regs, +}; + +pub(crate) mod bindings { + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + #![allow(improper_ctypes)] + #![allow(unused_mut)] + #![allow(unused)] + #![allow(unused_variables)] + #![allow(clippy::all)] + #![allow(clippy::pedantic)] + + include!(concat!(env!("OUT_DIR"), "/nyx_bindings.rs")); +} + +macro_rules! define_nyx_command_manager { + ($name:ident, [$($command:ty),+], [$($native_command_parser:ty),+]) => { + paste! { + pub struct $name { + has_started: bool, + phantom: PhantomData, + } + + impl Clone for $name { + fn clone(&self) -> Self { + Self { + has_started: self.has_started, + phantom: PhantomData, + } + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{} (has started? {:?})", stringify!($name), self.has_started) + } + } + + impl Default for $name { + fn default() -> Self { + Self { + has_started: false, + phantom: PhantomData, + } + } + } + + impl $name { + fn start(&mut self) -> bool { + let tmp = self.has_started; + self.has_started = true; + tmp + } + + fn has_started(&self) -> bool { + self.has_started + } + } + + impl CommandManager for $name + where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, + { + type Commands = [<$name Commands>]; + + #[deny(unreachable_patterns)] + fn parse(&self, qemu: Qemu) -> Result { + let arch_regs_map: &'static EnumMap = get_exit_arch_regs(); + let nyx_backdoor = qemu.read_reg(arch_regs_map[ExitArgs::Cmd])? as c_uint; + + // Check nyx backdoor correctness + debug_assert_eq!(nyx_backdoor, 0x1f); + + let cmd_id = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])? as c_uint; + + match cmd_id { + // >::COMMAND_ID => Ok(StdCommandManagerCommands::StartPhysCommandParserCmd(>::parse(qemu, arch_regs_map)?)), + $(<$native_command_parser as NativeCommandParser>::COMMAND_ID => Ok(<$native_command_parser as NativeCommandParser>::parse(qemu, arch_regs_map)?.into())),+, + _ => Err(CommandError::UnknownCommand(cmd_id.into())), + } + } + } + + #[derive(Clone, Debug)] + pub enum [<$name Commands>] + { + // StartPhysCommand(StartPhysCommand) + $($command($command)),+, + } + + impl IsCommand<$name, NyxEmulatorDriver, ET, S, SM> for [<$name Commands>] + where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, + { + fn usable_at_runtime(&self) -> bool { + match self { + $([<$name Commands>]::$command(cmd) => <$command as IsCommand<$name, NyxEmulatorDriver, ET, S, SM>>::usable_at_runtime(cmd)),+ + } + } + + fn run(&self, + emu: &mut Emulator<$name, NyxEmulatorDriver, ET, S, SM>, + state: &mut S, + input: &S::Input, + ret_reg: Option + ) -> Result, NyxEmulatorDriver, ET, S, SM>>, EmulatorDriverError> { + match self { + $([<$name Commands>]::$command(cmd) => cmd.run(emu, state, input, ret_reg)),+ + } + } + } + + $( + impl From<$command> for [<$name Commands>] { + fn from(cmd: $command) -> [<$name Commands>] { + [<$name Commands>]::$command(cmd) + } + } + )+ + } + }; +} + +define_nyx_command_manager!( + NyxCommandManager, + [ + AcquireCommand, + ReleaseCommand, + GetHostConfigCommand, + SetAgentConfigCommand, + PrintfCommand, + GetPayloadCommand, + NextPayloadCommand + ], + [ + AcquireCommandParser, + ReleaseCommandParser, + GetHostConfigCommandParser, + SetAgentConfigCommandParser, + PrintfCommandParser, + GetPayloadCommandParser, + NextPayloadCommandParser + ] +); + +#[derive(Debug, Clone)] +pub struct AcquireCommand; +impl IsCommand for AcquireCommand +where + CM: CommandManager, + S: UsesInput, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + _emu: &mut Emulator, + _state: &mut S, + _input: &S::Input, + _ret_reg: Option, + ) -> Result>, EmulatorDriverError> { + Ok(None) + } +} + +#[derive(Debug, Clone)] +pub struct GetPayloadCommand { + input_struct_location: GuestVirtAddr, +} + +impl GetPayloadCommand { + #[must_use] + pub fn new(input_struct_location: GuestVirtAddr) -> Self { + Self { + input_struct_location, + } + } +} + +impl IsCommand, NyxEmulatorDriver, ET, S, SM> for GetPayloadCommand +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + emu: &mut Emulator, NyxEmulatorDriver, ET, S, SM>, + _state: &mut S, + _input: &S::Input, + _ret_reg: Option, + ) -> Result< + Option, NyxEmulatorDriver, ET, S, SM>>, + EmulatorDriverError, + > { + let qemu = emu.qemu(); + + let struct_addr = self.input_struct_location; + let input_addr = + self.input_struct_location + offset_of!(bindings::kAFL_payload, data) as GuestVirtAddr; + + let payload_struct_mem_chunk = QemuMemoryChunk::virt( + struct_addr, + size_of::() as GuestReg, + qemu.current_cpu().unwrap(), + ); + let payload_mem_chunk = QemuMemoryChunk::virt( + input_addr, + emu.driver().max_input_size() as GuestReg, + qemu.current_cpu().unwrap(), + ); + + // Save input struct location for next runs + emu.driver_mut() + .set_input_struct_location(InputLocation::new( + payload_struct_mem_chunk, + qemu.current_cpu().unwrap(), + None, + )) + .unwrap(); + + // Save input location for next runs + emu.driver_mut() + .set_input_location(InputLocation::new( + payload_mem_chunk, + qemu.current_cpu().unwrap(), + None, + )) + .unwrap(); + + Ok(None) + } +} + +#[derive(Debug, Clone)] +pub struct NextPayloadCommand; + +impl IsCommand, NyxEmulatorDriver, ET, S, SM> for NextPayloadCommand +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + emu: &mut Emulator, NyxEmulatorDriver, ET, S, SM>, + state: &mut S, + input: &S::Input, + _ret_reg: Option, + ) -> Result< + Option, NyxEmulatorDriver, ET, S, SM>>, + EmulatorDriverError, + > { + if emu.command_manager_mut().start() { + return Err(EmulatorDriverError::CommandError( + CommandError::StartedTwice, + )); + } + + let qemu = emu.qemu(); + + // Snapshot VM + let snapshot_id = emu.snapshot_manager_mut().save(qemu); + + // Set snapshot ID to restore to after fuzzing ends + emu.driver_mut() + .set_snapshot_id(snapshot_id) + .map_err(|_| EmulatorDriverError::MultipleSnapshotDefinition)?; + + // write nyx input to vm + emu.driver().write_input(qemu, input)?; + + // Unleash hooks if locked + if emu.driver_mut().unlock_hooks() { + // Prepare hooks + emu.modules_mut().first_exec_all(qemu, state); + emu.modules_mut().pre_exec_all(qemu, state, input); + } + + // Auto page filtering if option is enabled + #[cfg(feature = "systemmode")] + if emu.driver_mut().allow_page_on_start() { + if let Some(page_id) = qemu.current_cpu().unwrap().current_paging_id() { + emu.modules_mut().modules_mut().allow_page_id_all(page_id); + } + } + + #[cfg(feature = "x86_64")] + if emu.driver_mut().is_process_only() { + emu.modules_mut() + .modules_mut() + .allow_address_range_all(crate::PROCESS_ADDRESS_RANGE); + } + + // Make sure JIT cache is empty just before starting + qemu.flush_jit(); + + log::info!("Fuzzing starts"); + Ok(None) + } +} + +#[derive(Debug, Clone)] +pub struct ReleaseCommand; +impl IsCommand, NyxEmulatorDriver, ET, S, SM> for ReleaseCommand +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + emu: &mut Emulator, NyxEmulatorDriver, ET, S, SM>, + _state: &mut S, + _input: &S::Input, + _ret_reg: Option, + ) -> Result< + Option, NyxEmulatorDriver, ET, S, SM>>, + EmulatorDriverError, + > { + let qemu = emu.qemu(); + + if emu.command_manager().has_started() { + let snapshot_id = emu + .driver_mut() + .snapshot_id() + .ok_or(EmulatorDriverError::SnapshotNotFound)?; + + emu.snapshot_manager_mut().restore(qemu, &snapshot_id)?; + + #[cfg(feature = "paranoid_debug")] + emu.snapshot_manager_mut().check(qemu, &snapshot_id)?; + + Ok(Some(EmulatorDriverResult::EndOfRun(ExitKind::Ok))) + } else { + Ok(None) + } + } +} + +#[derive(Debug, Clone)] +pub struct GetHostConfigCommand { + host_config_location: QemuMemoryChunk, +} + +impl GetHostConfigCommand { + #[must_use] + pub fn new(host_config_location: QemuMemoryChunk) -> Self { + Self { + host_config_location, + } + } +} + +impl IsCommand for GetHostConfigCommand +where + CM: CommandManager, + S: UsesInput, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + emu: &mut Emulator, + _state: &mut S, + _input: &S::Input, + _ret_reg: Option, + ) -> Result>, EmulatorDriverError> { + // TODO: check this against fuzzer code + let host_config = bindings::host_config_t { + bitmap_size: 0, + ijon_bitmap_size: 0, + payload_buffer_size: 0, + worker_id: 0, + host_magic: bindings::NYX_HOST_MAGIC, + host_version: bindings::NYX_HOST_VERSION, + }; + + let host_config_buf = unsafe { + from_raw_parts( + ptr::from_ref(&host_config) as *const u8, + size_of::(), + ) + }; + + let qemu = emu.qemu(); + + self.host_config_location + .write(qemu, host_config_buf) + .unwrap(); + + Ok(None) + } +} + +#[derive(Debug, Clone)] +pub struct PrintfCommand { + content: String, +} + +impl PrintfCommand { + #[must_use] + pub fn new(content: String) -> Self { + Self { content } + } +} + +impl IsCommand for PrintfCommand +where + CM: CommandManager, + S: UsesInput, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + _emu: &mut Emulator, + _state: &mut S, + _input: &S::Input, + _ret_reg: Option, + ) -> Result>, EmulatorDriverError> { + println!("hprintf: {}", self.content); + Ok(None) + } +} + +#[derive(Debug, Clone)] +pub struct SetAgentConfigCommand { + agent_config: bindings::agent_config_t, +} + +impl SetAgentConfigCommand { + #[must_use] + pub fn new(agent_config: bindings::agent_config_t) -> Self { + Self { agent_config } + } +} + +impl IsCommand for SetAgentConfigCommand +where + CM: CommandManager, + S: UsesInput, +{ + fn usable_at_runtime(&self) -> bool { + false + } + + fn run( + &self, + _emu: &mut Emulator, + _state: &mut S, + _input: &S::Input, + _ret_reg: Option, + ) -> Result>, EmulatorDriverError> { + let agent_magic = self.agent_config.agent_magic; + let agent_version = self.agent_config.agent_version; + + assert_eq!(agent_magic, bindings::NYX_AGENT_MAGIC); + assert_eq!(agent_version, bindings::NYX_AGENT_VERSION); + + // TODO: use agent config + + Ok(None) + } +} diff --git a/libafl_qemu/src/command/parser.rs b/libafl_qemu/src/command/parser/mod.rs similarity index 99% rename from libafl_qemu/src/command/parser.rs rename to libafl_qemu/src/command/parser/mod.rs index 8183cafb4a..476245678f 100644 --- a/libafl_qemu/src/command/parser.rs +++ b/libafl_qemu/src/command/parser/mod.rs @@ -20,6 +20,9 @@ use crate::{ GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs, StdEmulatorDriver, }; +#[cfg(any(cpu_target = "i386", cpu_target = "x86_64"))] +pub mod nyx; + pub static EMU_EXIT_KIND_MAP: OnceLock>> = OnceLock::new(); pub trait NativeCommandParser diff --git a/libafl_qemu/src/command/parser/nyx.rs b/libafl_qemu/src/command/parser/nyx.rs new file mode 100644 index 0000000000..5fa074186a --- /dev/null +++ b/libafl_qemu/src/command/parser/nyx.rs @@ -0,0 +1,189 @@ +use std::{ffi::CStr, mem::transmute, sync::OnceLock}; + +use enum_map::EnumMap; +use libafl::{ + executors::ExitKind, + inputs::{HasTargetBytes, UsesInput}, +}; +use libafl_qemu_sys::GuestVirtAddr; +use libc::c_uint; + +use crate::{ + command::{ + nyx::{ + bindings, AcquireCommand, GetHostConfigCommand, GetPayloadCommand, NextPayloadCommand, + NyxCommandManager, PrintfCommand, ReleaseCommand, SetAgentConfigCommand, + }, + parser::NativeCommandParser, + CommandError, CommandManager, NativeExitKind, + }, + modules::EmulatorModuleTuple, + sync_exit::ExitArgs, + IsSnapshotManager, NyxEmulatorDriver, Qemu, QemuMemoryChunk, Regs, +}; + +pub static EMU_EXIT_KIND_MAP: OnceLock>> = OnceLock::new(); + +pub struct AcquireCommandParser; +impl NativeCommandParser for AcquireCommandParser +where + CM: CommandManager, + S: UsesInput, + S::Input: HasTargetBytes, +{ + type OutputCommand = AcquireCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_ACQUIRE; + + fn parse( + _qemu: Qemu, + _arch_regs_map: &'static EnumMap, + ) -> Result { + Ok(AcquireCommand) + } +} + +pub struct GetPayloadCommandParser; +impl NativeCommandParser, NyxEmulatorDriver, ET, S, SM> + for GetPayloadCommandParser +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + type OutputCommand = GetPayloadCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_GET_PAYLOAD; + + fn parse( + qemu: Qemu, + arch_regs_map: &'static EnumMap, + ) -> Result { + let payload_addr = qemu.read_reg(arch_regs_map[ExitArgs::Arg2]).unwrap() as GuestVirtAddr; + + Ok(GetPayloadCommand::new(payload_addr)) + } +} + +pub struct NextPayloadCommandParser; +impl NativeCommandParser, NyxEmulatorDriver, ET, S, SM> + for NextPayloadCommandParser +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + type OutputCommand = NextPayloadCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_NEXT_PAYLOAD; + + fn parse( + _qemu: Qemu, + _arch_regs_map: &'static EnumMap, + ) -> Result { + Ok(NextPayloadCommand) + } +} + +pub struct ReleaseCommandParser; +impl NativeCommandParser, NyxEmulatorDriver, ET, S, SM> + for ReleaseCommandParser +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + type OutputCommand = ReleaseCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_RELEASE; + + fn parse( + _qemu: Qemu, + _arch_regs_map: &'static EnumMap, + ) -> Result { + Ok(ReleaseCommand) + } +} + +pub struct GetHostConfigCommandParser; +impl NativeCommandParser for GetHostConfigCommandParser +where + CM: CommandManager, + S: UsesInput, + S::Input: HasTargetBytes, +{ + type OutputCommand = GetHostConfigCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_GET_HOST_CONFIG; + + fn parse( + qemu: Qemu, + arch_regs_map: &'static EnumMap, + ) -> Result { + let host_config_addr = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])? as GuestVirtAddr; + + Ok(GetHostConfigCommand::new(QemuMemoryChunk::virt( + host_config_addr, + GuestVirtAddr::try_from(size_of::()).unwrap(), + qemu.current_cpu().unwrap(), + ))) + } +} + +pub struct SetAgentConfigCommandParser; +impl NativeCommandParser for SetAgentConfigCommandParser +where + CM: CommandManager, + S: UsesInput, + S::Input: HasTargetBytes, +{ + type OutputCommand = SetAgentConfigCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_SET_AGENT_CONFIG; + + fn parse( + qemu: Qemu, + arch_regs_map: &'static EnumMap, + ) -> Result { + let agent_config_addr = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])? as GuestVirtAddr; + + let mut agent_config_buf: [u8; size_of::()] = + [0; size_of::()]; + + qemu.read_mem(agent_config_addr, &mut agent_config_buf)?; + + let agent_config: bindings::agent_config_t = unsafe { transmute(agent_config_buf) }; + + Ok(SetAgentConfigCommand::new(agent_config)) + } +} + +pub struct PrintfCommandParser; +impl NativeCommandParser for PrintfCommandParser +where + CM: CommandManager, + S: UsesInput, + S::Input: HasTargetBytes, +{ + type OutputCommand = PrintfCommand; + + const COMMAND_ID: c_uint = bindings::HYPERCALL_KAFL_PRINTF; + + fn parse( + qemu: Qemu, + arch_regs_map: &'static EnumMap, + ) -> Result { + let str_addr = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])? as GuestVirtAddr; + + let mut msg_chunk: [u8; bindings::HPRINTF_MAX_SIZE as usize] = + [0; bindings::HPRINTF_MAX_SIZE as usize]; + qemu.read_mem(str_addr, &mut msg_chunk)?; + + let cstr = CStr::from_bytes_until_nul(&msg_chunk).unwrap(); + + Ok(PrintfCommand::new(cstr.to_str().unwrap().to_string())) + } +} diff --git a/libafl_qemu/src/emu/drivers.rs b/libafl_qemu/src/emu/drivers/mod.rs similarity index 94% rename from libafl_qemu/src/emu/drivers.rs rename to libafl_qemu/src/emu/drivers/mod.rs index 2a9d0ff4be..d739fe15c2 100644 --- a/libafl_qemu/src/emu/drivers.rs +++ b/libafl_qemu/src/emu/drivers/mod.rs @@ -14,10 +14,15 @@ use typed_builder::TypedBuilder; use crate::{ command::{CommandError, CommandManager, InputCommand, IsCommand}, modules::EmulatorModuleTuple, - Emulator, EmulatorExitError, EmulatorExitResult, InputLocation, IsSnapshotManager, + Emulator, EmulatorExitError, EmulatorExitResult, InputLocation, IsSnapshotManager, QemuError, QemuShutdownCause, Regs, SnapshotId, SnapshotManagerCheckError, SnapshotManagerError, }; +#[cfg(any(cpu_target = "i386", cpu_target = "x86_64"))] +pub mod nyx; +#[cfg(any(cpu_target = "i386", cpu_target = "x86_64"))] +pub use nyx::{NyxEmulatorDriver, NyxEmulatorDriverBuilder}; + #[derive(Debug, Clone)] pub enum EmulatorDriverResult where @@ -33,6 +38,7 @@ where #[derive(Debug, Clone)] pub enum EmulatorDriverError { + QemuError(QemuError), QemuExitReasonError(EmulatorExitError), SMError(SnapshotManagerError), SMCheckError(SnapshotManagerCheckError), @@ -43,6 +49,12 @@ pub enum EmulatorDriverError { SnapshotNotFound, } +impl From for EmulatorDriverError { + fn from(error: QemuError) -> Self { + EmulatorDriverError::QemuError(error) + } +} + /// An Emulator Driver. // TODO remove 'static when specialization will be stable pub trait EmulatorDriver: 'static + Sized @@ -252,9 +264,9 @@ where return Ok(Some(EmulatorDriverResult::EndOfRun(ExitKind::Timeout))) } EmulatorExitResult::Breakpoint(bp) => (bp.trigger(qemu), None), - EmulatorExitResult::SyncExit(sync_backdoor) => { - let command = sync_backdoor.command().clone(); - (Some(command), Some(sync_backdoor.ret_reg())) + EmulatorExitResult::CustomInsn(custom_insn) => { + let command = custom_insn.command().clone(); + (Some(command), Some(custom_insn.ret_reg())) } }; diff --git a/libafl_qemu/src/emu/drivers/nyx.rs b/libafl_qemu/src/emu/drivers/nyx.rs new file mode 100644 index 0000000000..0eb9b0e75c --- /dev/null +++ b/libafl_qemu/src/emu/drivers/nyx.rs @@ -0,0 +1,223 @@ +use std::{cell::OnceCell, cmp::min, ptr, slice::from_raw_parts}; + +use libafl::{ + executors::ExitKind, + inputs::{HasTargetBytes, UsesInput}, + observers::ObserversTuple, +}; +use libafl_bolts::os::CTRL_C_EXIT; +use typed_builder::TypedBuilder; + +use crate::{ + command::{nyx::bindings, CommandManager, IsCommand}, + modules::EmulatorModuleTuple, + Emulator, EmulatorDriver, EmulatorDriverError, EmulatorDriverResult, EmulatorExitError, + EmulatorExitResult, InputLocation, IsSnapshotManager, Qemu, QemuError, QemuShutdownCause, Regs, + SnapshotId, +}; + +#[derive(Clone, Debug, TypedBuilder)] +#[allow(clippy::struct_excessive_bools)] // cfg dependent +pub struct NyxEmulatorDriver { + #[builder(default = OnceCell::new())] + snapshot_id: OnceCell, + #[builder(default = OnceCell::new())] + input_struct_location: OnceCell, + #[builder(default = OnceCell::new())] + input_location: OnceCell, + #[builder(default = true)] + hooks_locked: bool, + #[cfg(feature = "systemmode")] + #[builder(default = false)] + allow_page_on_start: bool, // when fuzzing starts, module filters will only allow the current page table. + #[cfg(feature = "x86_64")] + #[builder(default = false)] + process_only: bool, // adds x86_64 process address space in the address filters of every module. + #[builder(default = false)] + print_commands: bool, + #[builder(default = (1024 * 1024))] + max_input_size: usize, +} + +impl NyxEmulatorDriver { + pub fn max_input_size(&self) -> usize { + self.max_input_size + } + + pub fn write_input(&self, qemu: Qemu, input: &I) -> Result<(), QemuError> + where + I: HasTargetBytes, + { + let input_len = + i32::try_from(min(self.max_input_size, input.target_bytes().len())).unwrap(); + + let kafl_payload = bindings::kAFL_payload { + size: input_len, + ..Default::default() + }; + + let kafl_payload_buf = unsafe { + from_raw_parts( + ptr::from_ref(&kafl_payload) as *const u8, + size_of::(), + ) + }; + + let input_struct_mem_chunk = &self.input_struct_location.get().unwrap().mem_chunk; + + // TODO: manage endianness correctly. + input_struct_mem_chunk.write(qemu, kafl_payload_buf)?; + + // write struct first + self.input_location + .get() + .unwrap() + .mem_chunk + .write(qemu, input.target_bytes().as_ref())?; + + Ok(()) + } + + pub fn set_input_location(&self, input_location: InputLocation) -> Result<(), InputLocation> { + self.input_location.set(input_location) + } + + pub fn set_input_struct_location( + &self, + input_struct_location: InputLocation, + ) -> Result<(), InputLocation> { + self.input_struct_location.set(input_struct_location) + } + + pub fn set_snapshot_id(&self, snapshot_id: SnapshotId) -> Result<(), SnapshotId> { + self.snapshot_id.set(snapshot_id) + } + + pub fn snapshot_id(&self) -> Option { + Some(*self.snapshot_id.get()?) + } + + // return if was locked or not + pub fn unlock_hooks(&mut self) -> bool { + let was_locked = self.hooks_locked; + self.hooks_locked = false; + was_locked + } + + #[cfg(feature = "systemmode")] + pub fn allow_page_on_start(&self) -> bool { + self.allow_page_on_start + } + + #[cfg(feature = "x86_64")] + pub fn is_process_only(&self) -> bool { + self.process_only + } +} + +impl EmulatorDriver for NyxEmulatorDriver +where + CM: CommandManager, + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, + S::Input: HasTargetBytes, + SM: IsSnapshotManager, +{ + fn first_harness_exec(emulator: &mut Emulator, state: &mut S) { + if !emulator.driver.hooks_locked { + emulator.modules.first_exec_all(emulator.qemu, state); + } + } + + fn pre_harness_exec( + emulator: &mut Emulator, + state: &mut S, + input: &S::Input, + ) { + if !emulator.driver.hooks_locked { + emulator.modules.pre_exec_all(emulator.qemu, state, input); + } + + if emulator.driver.input_location.get().is_some() { + let qemu = emulator.qemu(); + + emulator.driver.write_input(qemu, input).unwrap(); + } + } + + fn post_harness_exec( + emulator: &mut Emulator, + input: &S::Input, + observers: &mut OT, + state: &mut S, + exit_kind: &mut ExitKind, + ) where + OT: ObserversTuple, + { + if !emulator.driver.hooks_locked { + emulator + .modules + .post_exec_all(emulator.qemu, state, input, observers, exit_kind); + } + } + + fn pre_qemu_exec(_emulator: &mut Emulator, _input: &S::Input) {} + + fn post_qemu_exec( + emulator: &mut Emulator, + state: &mut S, + exit_reason: &mut Result, EmulatorExitError>, + input: &S::Input, + ) -> Result>, EmulatorDriverError> { + let qemu = emulator.qemu(); + + let mut exit_reason = match exit_reason { + Ok(exit_reason) => exit_reason, + Err(exit_error) => match exit_error { + EmulatorExitError::UnexpectedExit => { + if let Some(snapshot_id) = emulator.driver.snapshot_id.get() { + emulator.snapshot_manager.restore(qemu, snapshot_id)?; + } + return Ok(Some(EmulatorDriverResult::EndOfRun(ExitKind::Crash))); + } + _ => Err(exit_error.clone())?, + }, + }; + + let (command, ret_reg): (Option, Option) = match &mut exit_reason { + EmulatorExitResult::QemuExit(shutdown_cause) => match shutdown_cause { + QemuShutdownCause::HostSignal(signal) => { + signal.handle(); + return Err(EmulatorDriverError::UnhandledSignal(*signal)); + } + QemuShutdownCause::GuestPanic => { + return Ok(Some(EmulatorDriverResult::EndOfRun(ExitKind::Crash))) + } + QemuShutdownCause::GuestShutdown | QemuShutdownCause::HostQmpQuit => { + log::warn!("Guest shutdown. Stopping fuzzing..."); + std::process::exit(CTRL_C_EXIT); + } + _ => panic!("Unhandled QEMU shutdown cause: {shutdown_cause:?}."), + }, + EmulatorExitResult::Timeout => { + return Ok(Some(EmulatorDriverResult::EndOfRun(ExitKind::Timeout))) + } + EmulatorExitResult::Breakpoint(bp) => (bp.trigger(qemu), None), + EmulatorExitResult::CustomInsn(sync_backdoor) => { + let command = sync_backdoor.command().clone(); + (Some(command), Some(sync_backdoor.ret_reg())) + } + }; + + if let Some(cmd) = command { + if emulator.driver.print_commands { + println!("Received command: {cmd:?}"); + } + cmd.run(emulator, state, input, ret_reg) + } else { + Ok(Some(EmulatorDriverResult::ReturnToHarness( + exit_reason.clone(), + ))) + } + } +} diff --git a/libafl_qemu/src/emu/mod.rs b/libafl_qemu/src/emu/mod.rs index 42820e4ea7..9a75b862e9 100644 --- a/libafl_qemu/src/emu/mod.rs +++ b/libafl_qemu/src/emu/mod.rs @@ -20,7 +20,7 @@ use crate::{ breakpoint::{Breakpoint, BreakpointId}, command::{CommandError, CommandManager, NopCommandManager, StdCommandManager}, modules::EmulatorModuleTuple, - sync_exit::SyncExit, + sync_exit::CustomInsn, Qemu, QemuExitError, QemuExitReason, QemuHooks, QemuInitError, QemuMemoryChunk, QemuParams, QemuShutdownCause, Regs, CPU, }; @@ -62,8 +62,8 @@ where { QemuExit(QemuShutdownCause), // QEMU ended for some reason. Breakpoint(Breakpoint), // Breakpoint triggered. Contains the address of the trigger. - SyncExit(SyncExit), // Synchronous backdoor: The guest triggered a backdoor and should return to LibAFL. - Timeout, // Timeout + CustomInsn(CustomInsn), // Synchronous backdoor: The guest triggered a backdoor and should return to LibAFL. + Timeout, // Timeout } impl Clone for EmulatorExitResult @@ -77,8 +77,8 @@ where EmulatorExitResult::QemuExit(qemu_exit.clone()) } EmulatorExitResult::Breakpoint(bp) => EmulatorExitResult::Breakpoint(bp.clone()), - EmulatorExitResult::SyncExit(sync_exit) => { - EmulatorExitResult::SyncExit(sync_exit.clone()) + EmulatorExitResult::CustomInsn(sync_exit) => { + EmulatorExitResult::CustomInsn(sync_exit.clone()) } EmulatorExitResult::Timeout => EmulatorExitResult::Timeout, } @@ -98,7 +98,7 @@ where EmulatorExitResult::Breakpoint(bp) => { write!(f, "{bp:?}") } - EmulatorExitResult::SyncExit(sync_exit) => { + EmulatorExitResult::CustomInsn(sync_exit) => { write!(f, "{sync_exit:?}") } EmulatorExitResult::Timeout => { @@ -220,6 +220,16 @@ impl InputLocation { ret_register, } } + + #[must_use] + pub fn mem_chunk(&self) -> &QemuMemoryChunk { + &self.mem_chunk + } + + #[must_use] + pub fn ret_register(&self) -> &Option { + &self.ret_register + } } impl From for EmulatorDriverError { @@ -243,7 +253,7 @@ where match self { EmulatorExitResult::QemuExit(shutdown_cause) => write!(f, "End: {shutdown_cause:?}"), EmulatorExitResult::Breakpoint(bp) => write!(f, "{bp}"), - EmulatorExitResult::SyncExit(sync_exit) => { + EmulatorExitResult::CustomInsn(sync_exit) => { write!(f, "Sync exit: {sync_exit:?}") } EmulatorExitResult::Timeout => { @@ -445,7 +455,9 @@ where ED::pre_qemu_exec(self, input); // Run QEMU + log::debug!("Running QEMU..."); let mut exit_reason = self.run_qemu(); + log::debug!("QEMU stopped."); // Handle QEMU exit if let Some(exit_handler_result) = @@ -479,7 +491,7 @@ where .clone(); EmulatorExitResult::Breakpoint(bp.clone()) } - QemuExitReason::SyncExit => EmulatorExitResult::SyncExit(SyncExit::new( + QemuExitReason::SyncExit => EmulatorExitResult::CustomInsn(CustomInsn::new( self.command_manager.parse(self.qemu)?, )), }), diff --git a/libafl_qemu/src/emu/snapshot.rs b/libafl_qemu/src/emu/snapshot.rs index 8d9f1a2c55..77f754a5a8 100644 --- a/libafl_qemu/src/emu/snapshot.rs +++ b/libafl_qemu/src/emu/snapshot.rs @@ -62,6 +62,7 @@ impl Default for NopSnapshotManager { impl IsSnapshotManager for NopSnapshotManager { fn save(&mut self, _qemu: Qemu) -> SnapshotId { + log::warn!("Saving snapshot with the NopSnapshotManager"); SnapshotId { id: 0 } } @@ -70,6 +71,7 @@ impl IsSnapshotManager for NopSnapshotManager { _qemu: Qemu, _snapshot_id: &SnapshotId, ) -> Result<(), SnapshotManagerError> { + log::warn!("Restoring snapshot with the NopSnapshotManager"); Ok(()) } diff --git a/libafl_qemu/src/modules/calls.rs b/libafl_qemu/src/modules/calls.rs index 3817c93243..fe28cb556a 100644 --- a/libafl_qemu/src/modules/calls.rs +++ b/libafl_qemu/src/modules/calls.rs @@ -11,11 +11,12 @@ use libafl_qemu_sys::GuestAddr; use thread_local::ThreadLocal; #[cfg(feature = "systemmode")] -use crate::modules::{NopPageFilter, NOP_PAGE_FILTER}; +use crate::modules::utils::filters::{NopPageFilter, NOP_PAGE_FILTER}; use crate::{ capstone, modules::{ - AddressFilter, EmulatorModule, EmulatorModuleTuple, EmulatorModules, StdAddressFilter, + utils::filters::StdAddressFilter, AddressFilter, EmulatorModule, EmulatorModuleTuple, + EmulatorModules, }, qemu::{ArchExtras, Hook}, Qemu, diff --git a/libafl_qemu/src/modules/cmplog.rs b/libafl_qemu/src/modules/cmplog.rs index e30b705f24..194942023e 100644 --- a/libafl_qemu/src/modules/cmplog.rs +++ b/libafl_qemu/src/modules/cmplog.rs @@ -2,6 +2,7 @@ use capstone::{arch::BuildsCapstone, Capstone, InsnDetail}; use hashbrown::HashMap; use libafl::{inputs::UsesInput, HasMetadata}; +use libafl_bolts::hash_64_fast; use libafl_qemu_sys::GuestAddr; pub use libafl_targets::{ cmps::{ @@ -12,12 +13,14 @@ pub use libafl_targets::{ use serde::{Deserialize, Serialize}; #[cfg(feature = "systemmode")] -use crate::modules::{NopPageFilter, NOP_PAGE_FILTER}; +use crate::modules::utils::filters::{NopPageFilter, NOP_PAGE_FILTER}; #[cfg(feature = "usermode")] use crate::{capstone, qemu::ArchExtras, CallingConvention}; use crate::{ emu::EmulatorModules, - modules::{hash_me, AddressFilter, EmulatorModule, EmulatorModuleTuple, StdAddressFilter}, + modules::{ + utils::filters::StdAddressFilter, AddressFilter, EmulatorModule, EmulatorModuleTuple, + }, qemu::Hook, Qemu, }; @@ -229,7 +232,7 @@ where return None; } } - Some(hash_me(pc.into()) & (CMPLOG_MAP_W as u64 - 1)) + Some(hash_64_fast(pc.into()) & (CMPLOG_MAP_W as u64 - 1)) } pub extern "C" fn trace_cmp1_cmplog(_: *const (), id: u64, v0: u8, v1: u8) { @@ -358,7 +361,7 @@ impl CmpLogRoutinesModule { for detail in insn_detail.groups() { match u32::from(detail.0) { capstone::InsnGroupType::CS_GRP_CALL => { - let k = (hash_me(pc.into())) & (CMPLOG_MAP_W as u64 - 1); + let k = (hash_64_fast(pc.into())) & (CMPLOG_MAP_W as u64 - 1); qemu.hooks().add_instruction_hooks( k, insn.address() as GuestAddr, diff --git a/libafl_qemu/src/modules/drcov.rs b/libafl_qemu/src/modules/drcov.rs index d10f9498ec..e6629ddbd3 100644 --- a/libafl_qemu/src/modules/drcov.rs +++ b/libafl_qemu/src/modules/drcov.rs @@ -8,10 +8,12 @@ use rangemap::RangeMap; use serde::{Deserialize, Serialize}; #[cfg(feature = "systemmode")] -use crate::modules::{NopPageFilter, NOP_PAGE_FILTER}; +use crate::modules::utils::filters::{NopPageFilter, NOP_PAGE_FILTER}; use crate::{ emu::EmulatorModules, - modules::{AddressFilter, EmulatorModule, EmulatorModuleTuple, NopAddressFilter}, + modules::{ + utils::filters::NopAddressFilter, AddressFilter, EmulatorModule, EmulatorModuleTuple, + }, qemu::Hook, Qemu, }; diff --git a/libafl_qemu/src/modules/edges/child.rs b/libafl_qemu/src/modules/edges/child.rs index b823621940..6180d69d32 100644 --- a/libafl_qemu/src/modules/edges/child.rs +++ b/libafl_qemu/src/modules/edges/child.rs @@ -6,8 +6,9 @@ use super::{ }; use crate::{ modules::{ + utils::filters::{StdAddressFilter, StdPageFilter}, AddressFilter, EdgeCoverageModule, EdgeCoverageModuleBuilder, EmulatorModuleTuple, - PageFilter, StdAddressFilter, StdPageFilter, + PageFilter, }, EmulatorModules, Hook, }; diff --git a/libafl_qemu/src/modules/edges/classic.rs b/libafl_qemu/src/modules/edges/classic.rs index ed16c124ef..51f9de4c6d 100644 --- a/libafl_qemu/src/modules/edges/classic.rs +++ b/libafl_qemu/src/modules/edges/classic.rs @@ -8,8 +8,9 @@ use super::{ }; use crate::{ modules::{ + utils::filters::{StdAddressFilter, StdPageFilter}, AddressFilter, EdgeCoverageModule, EdgeCoverageModuleBuilder, EmulatorModuleTuple, - PageFilter, StdAddressFilter, StdPageFilter, + PageFilter, }, EmulatorModules, Hook, }; diff --git a/libafl_qemu/src/modules/edges/full.rs b/libafl_qemu/src/modules/edges/full.rs index 43de4a45d8..ccd6b061fc 100644 --- a/libafl_qemu/src/modules/edges/full.rs +++ b/libafl_qemu/src/modules/edges/full.rs @@ -6,8 +6,9 @@ use super::{ }; use crate::{ modules::{ + utils::filters::{StdAddressFilter, StdPageFilter}, AddressFilter, EdgeCoverageModule, EdgeCoverageModuleBuilder, EmulatorModuleTuple, - PageFilter, StdAddressFilter, StdPageFilter, + PageFilter, }, EmulatorModules, Hook, }; diff --git a/libafl_qemu/src/modules/edges/helpers.rs b/libafl_qemu/src/modules/edges/helpers.rs index 5dd0712617..82183ac0d4 100644 --- a/libafl_qemu/src/modules/edges/helpers.rs +++ b/libafl_qemu/src/modules/edges/helpers.rs @@ -52,6 +52,7 @@ mod generators { use hashbrown::hash_map::Entry; use libafl::{inputs::UsesInput, HasMetadata}; + use libafl_bolts::hash_64_fast; use libafl_qemu_sys::GuestAddr; use super::{ @@ -59,7 +60,7 @@ mod generators { LIBAFL_QEMU_EDGES_MAP_SIZE_PTR, }; use crate::{ - modules::{hash_me, AddressFilter, EdgeCoverageModule, EmulatorModuleTuple, PageFilter}, + modules::{AddressFilter, EdgeCoverageModule, EmulatorModuleTuple, PageFilter}, EmulatorModules, Qemu, }; @@ -192,7 +193,7 @@ mod generators { let mask = get_mask::() as u64; #[expect(clippy::unnecessary_cast)] - let id = (hash_me(src as u64) ^ hash_me(dest as u64)) & mask; + let id = (hash_64_fast(src as u64) ^ hash_64_fast(dest as u64)) & mask; if !IS_CONST_MAP { unsafe { @@ -245,7 +246,7 @@ mod generators { let mask = get_mask::() as u64; - let id = hash_me(pc as u64) & mask; + let id = hash_64_fast(pc as u64) & mask; if !IS_CONST_MAP { unsafe { diff --git a/libafl_qemu/src/modules/mod.rs b/libafl_qemu/src/modules/mod.rs index 83b32f39c2..a63f3276b4 100644 --- a/libafl_qemu/src/modules/mod.rs +++ b/libafl_qemu/src/modules/mod.rs @@ -1,10 +1,16 @@ use core::{fmt::Debug, ops::Range}; -use std::cell::UnsafeCell; -use hashbrown::HashSet; use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple}; use libafl_bolts::tuples::{MatchFirstType, SplitBorrowExtractFirstType}; -use libafl_qemu_sys::{GuestAddr, GuestPhysAddr}; +use libafl_qemu_sys::GuestAddr; +#[cfg(feature = "systemmode")] +use libafl_qemu_sys::GuestPhysAddr; + +use crate::{ + emu::EmulatorModules, + modules::utils::filters::{AddressFilter, PageFilter}, + Qemu, QemuParams, +}; #[cfg(feature = "usermode")] pub mod usermode; @@ -40,7 +46,7 @@ pub mod drcov; #[cfg(not(cpu_target = "hexagon"))] pub use drcov::{DrCovMetadata, DrCovModule, DrCovModuleBuilder}; -use crate::{emu::EmulatorModules, Qemu, QemuParams}; +pub mod utils; /// A module for `libafl_qemu`. // TODO remove 'static when specialization will be stable @@ -374,224 +380,3 @@ where self.1.allow_page_id_all(page_id); } } - -#[derive(Debug, Clone)] -pub enum FilterList { - AllowList(T), - DenyList(T), - None, -} - -impl AddressFilter for FilterList -where - T: AddressFilter, -{ - fn register(&mut self, address_range: Range) { - match self { - FilterList::AllowList(allow_list) => allow_list.register(address_range), - FilterList::DenyList(deny_list) => deny_list.register(address_range), - FilterList::None => {} - } - } - - fn allowed(&self, address: &GuestAddr) -> bool { - match self { - FilterList::AllowList(allow_list) => allow_list.allowed(address), - FilterList::DenyList(deny_list) => !deny_list.allowed(address), - FilterList::None => true, - } - } -} - -impl PageFilter for FilterList -where - T: PageFilter, -{ - fn register(&mut self, page_id: GuestPhysAddr) { - match self { - FilterList::AllowList(allow_list) => allow_list.register(page_id), - FilterList::DenyList(deny_list) => deny_list.register(page_id), - FilterList::None => {} - } - } - - fn allowed(&self, page: &GuestPhysAddr) -> bool { - match self { - FilterList::AllowList(allow_list) => allow_list.allowed(page), - FilterList::DenyList(deny_list) => !deny_list.allowed(page), - FilterList::None => true, - } - } -} - -#[derive(Clone, Debug, Default)] -pub struct AddressFilterVec { - // ideally, we should use a tree - registered_addresses: Vec>, -} -#[derive(Clone, Debug)] -pub struct StdAddressFilter(FilterList); - -impl Default for StdAddressFilter { - fn default() -> Self { - Self(FilterList::None) - } -} - -impl StdAddressFilter { - #[must_use] - pub fn allow_list(registered_addresses: Vec>) -> Self { - StdAddressFilter(FilterList::AllowList(AddressFilterVec::new( - registered_addresses, - ))) - } - - #[must_use] - pub fn deny_list(registered_addresses: Vec>) -> Self { - StdAddressFilter(FilterList::DenyList(AddressFilterVec::new( - registered_addresses, - ))) - } -} - -impl AddressFilterVec { - #[must_use] - pub fn new(registered_addresses: Vec>) -> Self { - Self { - registered_addresses, - } - } -} - -impl AddressFilter for AddressFilterVec { - fn register(&mut self, address_range: Range) { - self.registered_addresses.push(address_range); - Qemu::get().unwrap().flush_jit(); - } - - fn allowed(&self, addr: &GuestAddr) -> bool { - if self.registered_addresses.is_empty() { - return true; - } - - for addr_range in &self.registered_addresses { - if addr_range.contains(addr) { - return true; - } - } - - false - } -} - -impl AddressFilter for StdAddressFilter { - fn register(&mut self, address_range: Range) { - self.0.register(address_range); - } - - fn allowed(&self, address: &GuestAddr) -> bool { - self.0.allowed(address) - } -} - -#[derive(Clone, Debug)] -pub struct PageFilterVec { - registered_pages: HashSet, -} - -#[cfg(feature = "systemmode")] -#[derive(Clone, Debug)] -pub struct StdPageFilter(FilterList); - -#[cfg(feature = "usermode")] -pub type StdPageFilter = NopPageFilter; - -impl Default for PageFilterVec { - fn default() -> Self { - Self { - registered_pages: HashSet::new(), - } - } -} - -#[cfg(feature = "systemmode")] -impl Default for StdPageFilter { - fn default() -> Self { - Self(FilterList::None) - } -} - -impl PageFilter for PageFilterVec { - fn register(&mut self, page_id: GuestPhysAddr) { - self.registered_pages.insert(page_id); - Qemu::get().unwrap().flush_jit(); - } - - fn allowed(&self, paging_id: &GuestPhysAddr) -> bool { - // if self.allowed_pages.is_empty() { - // return true; - // } - - self.registered_pages.contains(paging_id) - } -} - -#[cfg(feature = "systemmode")] -impl PageFilter for StdPageFilter { - fn register(&mut self, page_id: GuestPhysAddr) { - self.0.register(page_id); - } - - fn allowed(&self, page_id: &GuestPhysAddr) -> bool { - self.0.allowed(page_id) - } -} - -// adapted from https://xorshift.di.unimi.it/splitmix64.c -#[must_use] -pub fn hash_me(mut x: u64) -> u64 { - x = (x ^ (x.overflowing_shr(30).0)) - .overflowing_mul(0xbf58476d1ce4e5b9) - .0; - x = (x ^ (x.overflowing_shr(27).0)) - .overflowing_mul(0x94d049bb133111eb) - .0; - x ^ (x.overflowing_shr(31).0) -} - -pub trait AddressFilter: 'static + Debug { - fn register(&mut self, address_range: Range); - - fn allowed(&self, address: &GuestAddr) -> bool; -} - -#[derive(Debug)] -pub struct NopAddressFilter; -impl AddressFilter for NopAddressFilter { - fn register(&mut self, _address: Range) {} - - fn allowed(&self, _address: &GuestAddr) -> bool { - true - } -} - -pub trait PageFilter: 'static + Debug { - fn register(&mut self, page_id: GuestPhysAddr); - - fn allowed(&self, page_id: &GuestPhysAddr) -> bool; -} - -#[derive(Clone, Debug, Default)] -pub struct NopPageFilter; -impl PageFilter for NopPageFilter { - fn register(&mut self, _page_id: GuestPhysAddr) {} - - fn allowed(&self, _page_id: &GuestPhysAddr) -> bool { - true - } -} - -#[cfg(feature = "usermode")] -static mut NOP_ADDRESS_FILTER: UnsafeCell = UnsafeCell::new(NopAddressFilter); -#[cfg(feature = "systemmode")] -static mut NOP_PAGE_FILTER: UnsafeCell = UnsafeCell::new(NopPageFilter); diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index 8c963938bb..a03d8971ab 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -153,7 +153,7 @@ use object::{Object, ObjectSection}; use crate::{ emu::EmulatorModules, - modules::{AddressFilter, StdAddressFilter}, + modules::{utils::filters::StdAddressFilter, AddressFilter}, qemu::{Hook, QemuHooks, SyscallHookResult}, }; diff --git a/libafl_qemu/src/modules/usermode/asan_guest.rs b/libafl_qemu/src/modules/usermode/asan_guest.rs index bf031a800b..9964aa75a0 100644 --- a/libafl_qemu/src/modules/usermode/asan_guest.rs +++ b/libafl_qemu/src/modules/usermode/asan_guest.rs @@ -14,7 +14,9 @@ use libafl_qemu_sys::{GuestAddr, MapInfo}; use crate::sys::libafl_tcg_gen_asan; use crate::{ emu::EmulatorModules, - modules::{AddressFilter, EmulatorModule, EmulatorModuleTuple, StdAddressFilter}, + modules::{ + utils::filters::StdAddressFilter, AddressFilter, EmulatorModule, EmulatorModuleTuple, + }, qemu::{Hook, MemAccessInfo, Qemu}, sys::TCGTemp, QemuParams, diff --git a/libafl_qemu/src/modules/usermode/injections.rs b/libafl_qemu/src/modules/usermode/injections.rs index 3dc87b49c1..6ccfc0d523 100644 --- a/libafl_qemu/src/modules/usermode/injections.rs +++ b/libafl_qemu/src/modules/usermode/injections.rs @@ -23,7 +23,10 @@ use crate::SYS_execve; use crate::{ elf::EasyElf, emu::EmulatorModules, - modules::{EmulatorModule, EmulatorModuleTuple, NopAddressFilter, NOP_ADDRESS_FILTER}, + modules::{ + utils::filters::{NopAddressFilter, NOP_ADDRESS_FILTER}, + EmulatorModule, EmulatorModuleTuple, + }, qemu::{ArchExtras, Hook, SyscallHookResult}, CallingConvention, Qemu, }; diff --git a/libafl_qemu/src/modules/usermode/snapshot.rs b/libafl_qemu/src/modules/usermode/snapshot.rs index 5e5bfaf458..0e9c7e447f 100644 --- a/libafl_qemu/src/modules/usermode/snapshot.rs +++ b/libafl_qemu/src/modules/usermode/snapshot.rs @@ -24,8 +24,9 @@ use crate::SYS_newfstatat; use crate::{ emu::EmulatorModules, modules::{ - asan::AsanModule, EmulatorModule, EmulatorModuleTuple, NopAddressFilter, Range, - NOP_ADDRESS_FILTER, + asan::AsanModule, + utils::filters::{NopAddressFilter, NOP_ADDRESS_FILTER}, + EmulatorModule, EmulatorModuleTuple, Range, }, qemu::{Hook, SyscallHookResult}, Qemu, SYS_brk, SYS_mprotect, SYS_mremap, SYS_munmap, SYS_pread64, SYS_read, SYS_readlinkat, diff --git a/libafl_qemu/src/modules/utils/filters.rs b/libafl_qemu/src/modules/utils/filters.rs new file mode 100644 index 0000000000..1601a57b00 --- /dev/null +++ b/libafl_qemu/src/modules/utils/filters.rs @@ -0,0 +1,221 @@ +//! Helpers to get filtering for modules +//! +//! It is not a module by itself, but instead used as helper to have filters +//! in other modules. + +use std::{cell::UnsafeCell, fmt::Debug, ops::Range}; + +use hashbrown::HashSet; +use libafl_qemu_sys::{GuestAddr, GuestPhysAddr}; + +use crate::Qemu; + +#[derive(Debug, Clone)] +pub enum FilterList { + AllowList(T), + DenyList(T), + None, +} + +impl AddressFilter for FilterList +where + T: AddressFilter, +{ + fn register(&mut self, address_range: Range) { + match self { + FilterList::AllowList(allow_list) => allow_list.register(address_range), + FilterList::DenyList(deny_list) => deny_list.register(address_range), + FilterList::None => {} + } + } + + fn allowed(&self, address: &GuestAddr) -> bool { + match self { + FilterList::AllowList(allow_list) => allow_list.allowed(address), + FilterList::DenyList(deny_list) => !deny_list.allowed(address), + FilterList::None => true, + } + } +} + +impl PageFilter for FilterList +where + T: PageFilter, +{ + fn register(&mut self, page_id: GuestPhysAddr) { + match self { + FilterList::AllowList(allow_list) => allow_list.register(page_id), + FilterList::DenyList(deny_list) => deny_list.register(page_id), + FilterList::None => {} + } + } + + fn allowed(&self, page: &GuestPhysAddr) -> bool { + match self { + FilterList::AllowList(allow_list) => allow_list.allowed(page), + FilterList::DenyList(deny_list) => !deny_list.allowed(page), + FilterList::None => true, + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct AddressFilterVec { + // ideally, we should use a tree + registered_addresses: Vec>, +} +#[derive(Clone, Debug)] +pub struct StdAddressFilter(FilterList); + +impl Default for StdAddressFilter { + fn default() -> Self { + Self(FilterList::None) + } +} + +impl StdAddressFilter { + #[must_use] + pub fn allow_list(registered_addresses: Vec>) -> Self { + StdAddressFilter(FilterList::AllowList(AddressFilterVec::new( + registered_addresses, + ))) + } + + #[must_use] + pub fn deny_list(registered_addresses: Vec>) -> Self { + StdAddressFilter(FilterList::DenyList(AddressFilterVec::new( + registered_addresses, + ))) + } +} + +impl AddressFilterVec { + #[must_use] + pub fn new(registered_addresses: Vec>) -> Self { + Self { + registered_addresses, + } + } +} + +impl AddressFilter for AddressFilterVec { + fn register(&mut self, address_range: Range) { + self.registered_addresses.push(address_range); + Qemu::get().unwrap().flush_jit(); + } + + fn allowed(&self, addr: &GuestAddr) -> bool { + if self.registered_addresses.is_empty() { + return true; + } + + for addr_range in &self.registered_addresses { + if addr_range.contains(addr) { + return true; + } + } + + false + } +} + +impl AddressFilter for StdAddressFilter { + fn register(&mut self, address_range: Range) { + self.0.register(address_range); + } + + fn allowed(&self, address: &GuestAddr) -> bool { + self.0.allowed(address) + } +} + +#[derive(Clone, Debug)] +pub struct PageFilterVec { + registered_pages: HashSet, +} + +#[cfg(feature = "systemmode")] +#[derive(Clone, Debug)] +pub struct StdPageFilter(FilterList); + +#[cfg(feature = "usermode")] +pub type StdPageFilter = NopPageFilter; + +impl Default for PageFilterVec { + fn default() -> Self { + Self { + registered_pages: HashSet::new(), + } + } +} + +#[cfg(feature = "systemmode")] +impl Default for StdPageFilter { + fn default() -> Self { + Self(FilterList::None) + } +} + +impl PageFilter for PageFilterVec { + fn register(&mut self, page_id: GuestPhysAddr) { + self.registered_pages.insert(page_id); + Qemu::get().unwrap().flush_jit(); + } + + fn allowed(&self, paging_id: &GuestPhysAddr) -> bool { + // if self.allowed_pages.is_empty() { + // return true; + // } + + self.registered_pages.contains(paging_id) + } +} + +#[cfg(feature = "systemmode")] +impl PageFilter for StdPageFilter { + fn register(&mut self, page_id: GuestPhysAddr) { + self.0.register(page_id); + } + + fn allowed(&self, page_id: &GuestPhysAddr) -> bool { + self.0.allowed(page_id) + } +} + +pub trait AddressFilter: 'static + Debug { + fn register(&mut self, address_range: Range); + + fn allowed(&self, address: &GuestAddr) -> bool; +} + +#[derive(Debug)] +pub struct NopAddressFilter; +impl AddressFilter for NopAddressFilter { + fn register(&mut self, _address: Range) {} + + fn allowed(&self, _address: &GuestAddr) -> bool { + true + } +} + +pub trait PageFilter: 'static + Debug { + fn register(&mut self, page_id: GuestPhysAddr); + + fn allowed(&self, page_id: &GuestPhysAddr) -> bool; +} + +#[derive(Clone, Debug, Default)] +pub struct NopPageFilter; +impl PageFilter for NopPageFilter { + fn register(&mut self, _page_id: GuestPhysAddr) {} + + fn allowed(&self, _page_id: &GuestPhysAddr) -> bool { + true + } +} + +#[cfg(feature = "usermode")] +pub(crate) static mut NOP_ADDRESS_FILTER: UnsafeCell = + UnsafeCell::new(NopAddressFilter); +#[cfg(feature = "systemmode")] +pub(crate) static mut NOP_PAGE_FILTER: UnsafeCell = UnsafeCell::new(NopPageFilter); diff --git a/libafl_qemu/src/modules/utils/mod.rs b/libafl_qemu/src/modules/utils/mod.rs new file mode 100644 index 0000000000..2589ce38d4 --- /dev/null +++ b/libafl_qemu/src/modules/utils/mod.rs @@ -0,0 +1 @@ +pub mod filters; diff --git a/libafl_qemu/src/qemu/error.rs b/libafl_qemu/src/qemu/error.rs index 6c4ce50ad8..304e50e7d6 100644 --- a/libafl_qemu/src/qemu/error.rs +++ b/libafl_qemu/src/qemu/error.rs @@ -5,14 +5,14 @@ use libafl_qemu_sys::{CPUStatePtr, GuestAddr}; use crate::CallingConvention; -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum QemuError { Init(QemuInitError), Exit(QemuExitError), RW(QemuRWError), } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum QemuInitError { MultipleInstances, NoParametersProvided, @@ -21,19 +21,19 @@ pub enum QemuInitError { TooManyArgs(usize), } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] pub enum QemuExitError { UnknownKind, // Exit reason was not NULL, but exit kind is unknown. Should never happen. UnexpectedExit, // Qemu exited without going through an expected exit point. Can be caused by a crash for example. } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] pub enum QemuRWErrorKind { Read, Write, } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] pub enum QemuRWErrorCause { WrongCallingConvention(CallingConvention, CallingConvention), // expected, given WrongArgument(i32), @@ -42,7 +42,7 @@ pub enum QemuRWErrorCause { WrongMemoryLocation(GuestAddr, usize), // addr, size } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] #[expect(dead_code)] pub struct QemuRWError { kind: QemuRWErrorKind, @@ -142,6 +142,12 @@ impl QemuRWError { } } +impl From for QemuError { + fn from(qemu_rw_error: QemuRWError) -> Self { + QemuError::RW(qemu_rw_error) + } +} + impl From for libafl::Error { fn from(qemu_error: QemuError) -> Self { libafl::Error::runtime(qemu_error) diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index 482830dd01..1204e77bd1 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -675,7 +675,7 @@ impl Qemu { let bp_addr = exit_reason.data.breakpoint.addr; QemuExitReason::Breakpoint(bp_addr) }, - libafl_qemu_sys::libafl_exit_reason_kind_SYNC_EXIT => QemuExitReason::SyncExit, + libafl_qemu_sys::libafl_exit_reason_kind_CUSTOM_INSN => QemuExitReason::SyncExit, #[cfg(feature = "systemmode")] libafl_qemu_sys::libafl_exit_reason_kind_TIMEOUT => QemuExitReason::Timeout, diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index f9549ede64..7353eb4a53 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -286,9 +286,7 @@ pub mod pybind { a6: u64, a7: u64, ) -> SyscallHookResult { - // If we don't deref_addrof we run into the "static-mut-references" lint which is worse. - #[expect(clippy::deref_addrof)] - unsafe { (*(&raw const PY_SYSCALL_HOOK)).as_ref() }.map_or_else( + unsafe { (&raw const PY_SYSCALL_HOOK).read() }.map_or_else( || SyscallHookResult::new(None), |obj| { let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7); diff --git a/libafl_qemu/src/sync_exit.rs b/libafl_qemu/src/sync_exit.rs index 558e28bb60..3693092d8b 100644 --- a/libafl_qemu/src/sync_exit.rs +++ b/libafl_qemu/src/sync_exit.rs @@ -17,7 +17,7 @@ pub enum ExitArgs { Arg6, } -pub struct SyncExit +pub struct CustomInsn where CM: CommandManager, S: UsesInput, @@ -25,7 +25,7 @@ where command: CM::Commands, } -impl Clone for SyncExit +impl Clone for CustomInsn where CM: CommandManager, S: UsesInput, @@ -37,7 +37,7 @@ where } } -impl Debug for SyncExit +impl Debug for CustomInsn where CM: CommandManager, S: UsesInput, @@ -47,7 +47,7 @@ where } } -impl SyncExit +impl CustomInsn where CM: CommandManager, S: UsesInput, diff --git a/utils/libafl_fmt/src/main.rs b/utils/libafl_fmt/src/main.rs index b716c5a78a..7429c6efb3 100644 --- a/utils/libafl_fmt/src/main.rs +++ b/utils/libafl_fmt/src/main.rs @@ -223,6 +223,7 @@ async fn main() -> io::Result<()> { r".*Little-CMS.*", r".*cms_transform_fuzzer.cc.*", r".*sqlite3.*", + r".*libfuzzer_libmozjpeg.*", ]) .expect("Could not create the regex set from the given regex"); From 9f8f47233c8b3671a2591e2a35873fd7af9ba2a8 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 6 Jan 2025 17:34:45 +0100 Subject: [PATCH 24/25] Add migration notes for libafl qemu's Emulator configuration changes (#2818) * add migration notes for libafl qemu latest changes --- MIGRATION.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MIGRATION.md b/MIGRATION.md index 38c27d6041..44a50abde9 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -7,6 +7,9 @@ - Related: `MutVecInput` is deprecated in favor of directly using `&mut Vec` - Related: `MappedInputFunctionMappingMutator` and `ToMappedInputFunctionMappingMutatorMapper` have been removed as now duplicates of `MappingMutator` (previously `FunctionMappingMutator`) and `ToMappingMutator` (previously `ToFunctionMappingMutatorMapper`) - Related: `ToOptionMappingMutatorMapper` and `ToFunctionMappingMutatorMapper` have been renamed to `ToOptionalMutator` and `ToMappingMutator` respectively +- `Qemu` cannot be used to initialize `Emulator` directly anymore. Instead, `Qemu` should be initialized through `Emulator` systematically if `Emulator` should be used. + - Related: `EmulatorBuilder` uses a single function to provide a `Qemu` initializer: `EmulatorBuilder::qemu_parameters`. For now, it can be either a `Vec` or a `QemuConfig` instance. + - Related: Qemu's `AsanModule` does not need any special call to `Qemu` init methods anymore. It is now possible to simply initialize `AsanModule` (or `AsanGuestModule`) with a reference to the environment as parameter. # 0.14.0 -> 0.14.1 - Removed `with_observers` from `Executor` trait. From 719a3c0f07a8b4a665b59782a482fed78a5e0d0b Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 7 Jan 2025 15:07:46 +0100 Subject: [PATCH 25/25] Continue loading inputs even if some fail to deserialize (#2820) * Continue loading inputs even if some fail to deserialize * fmt * fix --- libafl/src/state/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 35ffedba68..3e41cd65a4 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -752,8 +752,14 @@ where EM: EventFirer, Z: Evaluator, { - log::info!("Loading file {:?} ...", &path); - let input = (config.loader)(fuzzer, self, path)?; + log::info!("Loading file {path:?} ..."); + let input = match (config.loader)(fuzzer, self, path) { + Ok(input) => input, + Err(err) => { + log::error!("Skipping input that we could not load from {path:?}: {err:?}"); + return Ok(ExecuteInputResult::None); + } + }; if config.forced { let _: CorpusId = fuzzer.add_input(self, executor, manager, input)?; Ok(ExecuteInputResult::Corpus)