diff --git a/Cargo.lock b/Cargo.lock index 80f1488ddbb..b44cb9ceed7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -755,6 +755,15 @@ dependencies = [ "walkdir", ] +[[package]] +name = "build_id2" +version = "0.15.4" +dependencies = [ + "ahash", + "rustversion", + "uuid", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -1269,6 +1278,17 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core_affinity2" +version = "0.15.4" +dependencies = [ + "document-features", + "libafl_core", + "libc", + "rustversion", + "serde", +] + [[package]] name = "cpp_demangle" version = "0.4.5" @@ -1474,6 +1494,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "ctor" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec09e802f5081de6157da9a75701d6c713d8dc3ba52571fd4bd25f412644e8a6" +dependencies = [ + "ctor-proc-macro", + "dtor 0.0.6", +] + [[package]] name = "ctor" version = "0.5.0" @@ -1481,7 +1511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" dependencies = [ "ctor-proc-macro", - "dtor", + "dtor 0.1.0", ] [[package]] @@ -1832,15 +1862,30 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" +[[package]] +name = "dtor" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8" +dependencies = [ + "dtor-proc-macro 0.0.5", +] + [[package]] name = "dtor" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" dependencies = [ - "dtor-proc-macro", + "dtor-proc-macro 0.0.6", ] +[[package]] +name = "dtor-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055" + [[package]] name = "dtor-proc-macro" version = "0.0.6" @@ -2042,12 +2087,38 @@ dependencies = [ "pin-project-lite 0.2.16", ] +[[package]] +name = "exceptional" +version = "0.15.4" +dependencies = [ + "document-features", + "libafl_core", + "libc", + "log", + "nix 0.30.1", + "num_enum", + "rustversion", + "windows 0.62.1", + "windows-core 0.62.1", +] + [[package]] name = "fallible-iterator" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +[[package]] +name = "fast_rands" +version = "0.15.4" +dependencies = [ + "document-features", + "pyo3", + "rand_core 0.9.3", + "rustversion", + "serde", +] + [[package]] name = "fastbloom" version = "0.14.0" @@ -3122,15 +3193,18 @@ dependencies = [ "futures", "hashbrown 0.16.0", "libafl_bolts", + "libafl_core", "libafl_derive", "libafl_intelpt", "libc", "libcasr", "libm", + "ll_mp", "log", "meminterval", "mlua", "nix 0.30.1", + "no_std_time", "num-traits", "num_enum", "postcard", @@ -3148,6 +3222,7 @@ dependencies = [ "tide", "tokio", "tuple_list", + "tuple_list_ex", "typed-builder", "uuid", "wait-timeout", @@ -3216,38 +3291,45 @@ version = "0.15.4" dependencies = [ "ahash", "backtrace", + "build_id2", "chrono", "clap", - "ctor", + "core_affinity2", "document-features", "erased-serde", + "exceptional", + "fast_rands", "hashbrown 0.16.0", "hostname", "itertools 0.14.0", + "libafl_core", "libafl_derive", "libc", + "ll_mp", "log", "mach2 0.5.0", + "minibsod", "miniz_oxide", "nix 0.30.1", + "no_std_time", "num_enum", - "once_cell", + "ownedref", "postcard", "pyo3", "rand 0.9.2", - "rand_core 0.9.3", "rustversion", "serde", + "serde_anymap", "serial_test", + "shmem_providers", "static_assertions", "tuple_list", + "tuple_list_ex", "typeid", "uds", - "uuid", "wide", "winapi", "windows 0.62.1", - "windows-core 0.62.1", "windows-result 0.4.1", "xxhash-rust", ] @@ -3262,6 +3344,20 @@ dependencies = [ "which 8.0.0", ] +[[package]] +name = "libafl_core" +version = "0.15.4" +dependencies = [ + "backtrace", + "document-features", + "nix 0.30.1", + "postcard", + "pyo3", + "rustversion", + "serde", + "windows-result 0.4.1", +] + [[package]] name = "libafl_derive" version = "0.15.4" @@ -3377,6 +3473,7 @@ dependencies = [ "just", "libafl", "libafl_bolts", + "libafl_core", "libafl_derive", "libafl_intelpt", "libafl_qemu_sys", @@ -3467,17 +3564,20 @@ version = "0.15.4" dependencies = [ "bindgen 0.72.1", "cc", + "fast_rands", "hashbrown 0.16.0", "libafl", "libafl_bolts", + "libafl_core", "libc", "log", "meminterval", "nix 0.30.1", - "once_cell", + "ownedref", "rangemap", "rustversion", "serde", + "shmem_providers", ] [[package]] @@ -3735,6 +3835,26 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +[[package]] +name = "ll_mp" +version = "0.15.4" +dependencies = [ + "document-features", + "exceptional", + "hostname", + "libafl_core", + "log", + "miniz_oxide", + "nix 0.30.1", + "no_std_time", + "postcard", + "rustversion", + "serde", + "serial_test", + "shmem_providers", + "tuple_list", +] + [[package]] name = "lock_api" version = "0.4.14" @@ -3878,6 +3998,17 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "minibsod" +version = "0.15.4" +dependencies = [ + "document-features", + "exceptional", + "libc", + "mach2 0.4.3", + "rustversion", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4031,6 +4162,14 @@ dependencies = [ "memoffset 0.9.1", ] +[[package]] +name = "no_std_time" +version = "0.15.4" +dependencies = [ + "document-features", + "rustversion", +] + [[package]] name = "nom" version = "7.1.3" @@ -4271,6 +4410,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ownedref" +version = "0.15.4" +dependencies = [ + "document-features", + "libafl_core", + "rustversion", + "serde", +] + [[package]] name = "parking" version = "2.2.1" @@ -4600,9 +4749,9 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.24.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4500adecd7af8e0e9f4dbce15cfee07ce913fbf6ad605cc468b83f2d531ee94" +checksum = "cf41c1a7c32ed72abe5082fb19505b969095c12da9f5732a4bc9878757fd087c" dependencies = [ "dtoa", "itoa", @@ -4612,9 +4761,9 @@ dependencies = [ [[package]] name = "prometheus-client-derive-encode" -version = "0.5.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adf1691c04c0a5ff46ff8f262b58beb07b0dbb61f96f9f54f6cbd82106ed87f" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", @@ -5304,6 +5453,22 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_anymap" +version = "0.15.4" +dependencies = [ + "ahash", + "ctor 0.4.3", + "document-features", + "erased-serde", + "hashbrown 0.16.0", + "libafl_core", + "postcard", + "rustversion", + "serde", + "static_assertions", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -5484,6 +5649,26 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shmem_providers" +version = "0.15.4" +dependencies = [ + "document-features", + "fast_rands", + "hashbrown 0.16.0", + "libafl_core", + "libc", + "log", + "nix 0.30.1", + "postcard", + "rustversion", + "serde", + "serial_test", + "uds", + "uuid", + "windows 0.62.1", +] + [[package]] name = "signal-hook" version = "0.3.18" @@ -5854,7 +6039,7 @@ version = "0.15.4" dependencies = [ "bindgen 0.72.1", "cmake", - "ctor", + "ctor 0.5.0", "libafl", "libafl_bolts", "libc", @@ -6417,6 +6602,19 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "141fb9f71ee586d956d7d6e4d5a9ef8e946061188520140f7591b668841d502e" +[[package]] +name = "tuple_list_ex" +version = "0.15.4" +dependencies = [ + "document-features", + "libafl_core", + "ownedref", + "rustversion", + "serde", + "tuple_list", + "typeid", +] + [[package]] name = "twox-hash" version = "2.1.2" diff --git a/Cargo.toml b/Cargo.toml index 8f96f1d2167..dd4d0e6442c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,58 +1,70 @@ [workspace] resolver = "2" members = [ - "crates/libafl", + "crates/build_id2", + "crates/core_affinity2", + "crates/exceptional", + "crates/fast_rands", "crates/libafl_asan", "crates/libafl_asan/libafl_asan_fuzz", "crates/libafl_asan/libafl_asan_libc", "crates/libafl_bolts", "crates/libafl_cc", - "crates/libafl_concolic/symcc_runtime", "crates/libafl_concolic/symcc_libafl", + "crates/libafl_concolic/symcc_runtime", + "crates/libafl_concolic/test/dump_constraints", + "crates/libafl_concolic/test/runtime_test", + "crates/libafl_core", "crates/libafl_derive", "crates/libafl_frida", "crates/libafl_intelpt", "crates/libafl_libfuzzer", "crates/libafl_nyx", - "crates/libafl_unicorn", - "crates/libafl_targets", - "crates/libafl_tinyinst", "crates/libafl_qemu", "crates/libafl_qemu/libafl_qemu_build", "crates/libafl_qemu/libafl_qemu_runner", "crates/libafl_qemu/libafl_qemu_sys", "crates/libafl_qemu/libvharness_sys", "crates/libafl_sugar", - "crates/libafl_concolic/test/dump_constraints", - "crates/libafl_concolic/test/runtime_test", + "crates/libafl_targets", + "crates/libafl_tinyinst", + "crates/libafl_unicorn", + "crates/libafl", + "crates/ll_mp", + "crates/minibsod", + "crates/no_std_time", + "crates/ownedref", + "crates/serde_anymap", + "crates/shmem_providers", + "crates/tuple_list_ex", "utils/build_and_test_fuzzers", + "utils/ci_runner", + "utils/ci_splitter", "utils/deexit", "utils/drcov_utils", "utils/gramatron/construct_automata", "utils/libafl_benches", "utils/libafl_jumper", - "utils/ci_runner", - "utils/ci_splitter", ] default-members = [ - "crates/libafl", "crates/libafl_bolts", "crates/libafl_cc", "crates/libafl_derive", "crates/libafl_targets", + "crates/libafl", ] exclude = [ "bindings/pylibafl", + "crates/libafl_libfuzzer_runtime", "docs", "fuzzers", - "crates/libafl_libfuzzer_runtime", - "utils/noaslr", + "scripts", "utils/gdb_qemu", "utils/libafl_repo_tools", "utils/multi_machine_generator", - "scripts", + "utils/noaslr", # additional crates "crates/libafl_concolic/test/symcc/util/symcc_fuzzing_helper", ] @@ -65,29 +77,44 @@ readme = "./README.md" [workspace.dependencies] # Internal deps +build_id2 = { path = "./crates/build_id2", version = "0.15.4", default-features = false } +core_affinity2 = { path = "./crates/core_affinity2", version = "0.15.4", default-features = false } +exceptional = { path = "./crates/exceptional", version = "0.15.4", default-features = false } +fast_rands = { path = "./crates/fast_rands", version = "0.15.4", default-features = false } libafl = { path = "./crates/libafl", version = "0.15.4", default-features = false } libafl_bolts = { path = "./crates/libafl_bolts", version = "0.15.4", default-features = false } libafl_cc = { path = "./crates/libafl_cc", version = "0.15.4", default-features = false } -symcc_runtime = { path = "./crates/libafl_concolic/symcc_runtime", version = "0.15.2", default-features = false } -symcc_libafl = { path = "./crates/libafl_concolic/symcc_libafl", version = "0.15.4", default-features = false } +libafl_core = { path = "./crates/libafl_core", version = "0.15.4", default-features = false } libafl_derive = { path = "./crates/libafl_derive", version = "0.15.4", default-features = false } libafl_frida = { path = "./crates/libafl_frida", version = "0.15.4", default-features = false } libafl_intelpt = { path = "./crates/libafl_intelpt", version = "0.15.4", default-features = false } libafl_libfuzzer = { path = "./crates/libafl_libfuzzer", version = "0.15.4", default-features = false } libafl_nyx = { path = "./crates/libafl_nyx", version = "0.15.4", default-features = false } -libafl_targets = { path = "./crates/libafl_targets", version = "0.15.4", default-features = false } -libafl_tinyinst = { path = "./crates/libafl_tinyinst", version = "0.15.4", default-features = false } libafl_qemu = { path = "./crates/libafl_qemu", version = "0.15.4", default-features = false } libafl_qemu_build = { path = "./crates/libafl_qemu/libafl_qemu_build", version = "0.15.4", default-features = false } libafl_qemu_sys = { path = "./crates/libafl_qemu/libafl_qemu_sys", version = "0.15.4", default-features = false } -libvharness_sys = { path = "./crates/libafl_qemu/libvharness_sys", version = "0.15.4", default-features = false } libafl_sugar = { path = "./crates/libafl_sugar", version = "0.15.4", default-features = false } -dump_constraints = { path = "./crates/libafl_concolic/test/dump_constraints", version = "0.15.2", default-features = false } -runtime_test = { path = "./crates/libafl_concolic/test/runtime_test", version = "0.15.2", default-features = false } -build_and_test_fuzzers = { path = "./utils/build_and_test_fuzzers", version = "0.15.2", default-features = false } -deexit = { path = "./utils/deexit", version = "0.15.2", default-features = false } -drcov_utils = { path = "./utils/drcov_utils", version = "0.15.2", default-features = false } -construct_automata = { path = "./utils/gramatron/construct_automata", version = "0.15.2", default-features = false } +libafl_targets = { path = "./crates/libafl_targets", version = "0.15.4", default-features = false } +libafl_tinyinst = { path = "./crates/libafl_tinyinst", version = "0.15.4", default-features = false } +ll_mp = { path = "./crates/ll_mp", version = "0.15.4", default-features = false } +minibsod = { path = "./crates/minibsod", version = "0.15.4", default-features = false } +no_std_time = { path = "./crates/no_std_time", version = "0.15.4", default-features = false } +ownedref = { path = "./crates/ownedref", version = "0.15.4", default-features = false } +serde_anymap = { path = "./crates/serde_anymap", version = "0.15.4", default-features = false } +shmem_providers = { path = "./crates/shmem_providers", version = "0.15.4", default-features = false } +tuple_list_ex = { path = "./crates/tuple_list_ex", version = "0.15.4", default-features = false } + +# Concolic fuzzing crates +dump_constraints = { path = "./crates/libafl_concolic/test/dump_constraints", version = "0.15.4", default-features = false } +runtime_test = { path = "./crates/libafl_concolic/test/runtime_test", version = "0.15.4", default-features = false } +symcc_libafl = { path = "./crates/libafl_concolic/symcc_libafl", version = "0.15.4", default-features = false } +symcc_runtime = { path = "./crates/libafl_concolic/symcc_runtime", version = "0.15.4", default-features = false } + +# Utils +build_and_test_fuzzers = { path = "./utils/build_and_test_fuzzers", version = "0.15.4", default-features = false } +construct_automata = { path = "./utils/gramatron/construct_automata", version = "0.15.4", default-features = false } +deexit = { path = "./utils/deexit", version = "0.15.4", default-features = false } +drcov_utils = { path = "./utils/drcov_utils", version = "0.15.4", default-features = false } libafl_benches = { path = "./utils/libafl_benches", version = "0.15.4", default-features = false } libafl_jumper = { path = "./utils/libafl_jumper", version = "0.15.4", default-features = false } @@ -101,12 +128,16 @@ capstone = "0.13.0" # Disassembler used in libafl_unicorn to provide disassembly clap = "4.5.49" cc = "1.2.40" cmake = "0.1.54" +ctor = "0.4.0" document-features = "0.2.11" +erased-serde = { version = "0.4.5", default-features = false } # erased serde fastbloom = { version = "0.14.0", default-features = false } +fs2 = "0.4.3" # Used by OnDisk Corpus for file locking hashbrown = { version = "0.16.0", default-features = false } # A faster hashmap, nostd compatible just = "=1.40.0" libc = "0.2.177" # For (*nix) libc libipt = { version = "0.4.0", features = ["libipt_master"] } +libvharness_sys = { path = "./crates/libafl_qemu/libvharness_sys", version = "0.15.4", default-features = false } log = "0.4.28" meminterval = "0.4.2" mimalloc = { version = "0.1.48", default-features = false } @@ -123,15 +154,17 @@ rangemap = "1.6.0" regex = "1.12.2" rustversion = "1.0.22" serde = { version = "1.0.228", default-features = false } # serialization lib -serial_test = { version = "3.2.0", default-features = false } serde_json = { version = "1.0.145", default-features = false } serde_yaml = { version = "0.9.34" } # For parsing the injections yaml file +serial_test = { version = "3.2.0", default-features = false } static_assertions = "1.1.0" strum = "0.27.2" strum_macros = "0.27.2" toml = "0.9.7" # For parsing the injections toml file +tuple_list = { version = "0.1.3" } typed-builder = "0.22.0" # Implement the builder pattern at compiletime typeid = "1.0.3" # Safe type_eq that doesn't rely on std specialization +unicorn-engine = "2.0.1" # Used in libafl_unicorn uuid = { version = "1.18.1", features = ["serde", "v4"] } which = "8.0.0" windows = "0.62.1" @@ -139,7 +172,6 @@ windows-core = "0.62.1" z3 = { git = "https://github.com/prove-rs/z3.rs", rev = "z3-v0.18.2", default-features = false, features = [ "bundled", ] } -fs2 = "0.4.3" # Used by OnDisk Corpus for file locking [workspace.lints.rust] # Deny @@ -167,21 +199,21 @@ std_instead_of_core = "deny" cargo = { level = "warn", priority = -1 } # Allow -negative_feature_names = "allow" # TODO: turn into 'warn' when working -multiple_crate_versions = "allow" # TODO: turn into `warn` when working -unreadable_literal = "allow" -type_repetition_in_bounds = "allow" -missing_errors_doc = "allow" cast_possible_truncation = "allow" -used_underscore_binding = "allow" -ptr_as_ptr = "allow" +comparison_chain = "allow" # This lint makes **ZERO** sense +missing_errors_doc = "allow" missing_panics_doc = "allow" module_name_repetitions = "allow" -unsafe_derive_deserialize = "allow" +multiple_crate_versions = "allow" # TODO: turn into `warn` when working +negative_feature_names = "allow" # TODO: turn into 'warn' when working +ptr_as_ptr = "allow" similar_names = "allow" -too_many_lines = "allow" -comparison_chain = "allow" # This lint makes **ZERO** sense struct_field_names = "allow" # ???? +too_many_lines = "allow" +type_repetition_in_bounds = "allow" +unreadable_literal = "allow" +unsafe_derive_deserialize = "allow" +used_underscore_binding = "allow" [workspace.lints.rustdoc] # Deny diff --git a/crates/LICENSE-APACHE b/crates/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/LICENSE-MIT b/crates/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/build_id2/Cargo.toml b/crates/build_id2/Cargo.toml new file mode 100644 index 00000000000..5acfa2c2582 --- /dev/null +++ b/crates/build_id2/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "build_id2" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Updated and maintained build id library" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "build-id"] +edition = "2024" +rust-version = "1.87" +categories = ["os"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = [] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +uuid = { workspace = true } +ahash = { workspace = true } + +[lints] +workspace = true diff --git a/crates/build_id2/LICENSE-APACHE b/crates/build_id2/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/build_id2/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/build_id2/LICENSE-MIT b/crates/build_id2/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/build_id2/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/build_id2/README.md b/crates/build_id2/README.md new file mode 100644 index 00000000000..b2e2d40cc49 --- /dev/null +++ b/crates/build_id2/README.md @@ -0,0 +1,81 @@ +# build_id2: a maintained way to uniquely represent the build of the current binary + + LibAFL logo + +The `build_id2` crate is a maintained and updated fork of build_id. +With it, you can obtain a Uuid uniquely representing the build of the current binary. + +This is intended to be used to check that different processes are indeed invocations of identically laid out binaries. + +As such: + +* It is guaranteed to be identical within multiple invocations of the same binary. +* It is guaranteed to be different across binaries with different code or data segments or layout. +* Equality is unspecified if the binaries have identical code and data segments and layout but differ immaterially (e.g. if a timestamp is included in the binary at compile time). + +## Usage + +Add the following to your `Cargo.toml`: + +```toml +[dependencies] +build_id2 = "0.15.4" +``` + +Then, you can use the `get` function to get the build id: + +```rust +# let remote_build_id = build_id2::get(); +let local_build_id = build_id2::get(); +if local_build_id == remote_build_id { + println!("We're running the same binary as remote!"); +} else { + println!("We're running a different binary to remote"); +} +``` + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_bolts/src/build_id.rs b/crates/build_id2/src/lib.rs similarity index 71% rename from crates/libafl_bolts/src/build_id.rs rename to crates/build_id2/src/lib.rs index 876ac1a6610..598c8671379 100644 --- a/crates/libafl_bolts/src/build_id.rs +++ b/crates/build_id2/src/lib.rs @@ -1,16 +1,59 @@ //! Based on //! (C) Alec Mocatta under license MIT or Apache 2 +//! +//! Maintained by the `LibAFL` team. +#![doc = include_str!("../README.md")] +/*! */ +#![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( + 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 + ) +)] use core::{ any::TypeId, - hash::{Hash, Hasher}, + hash::{BuildHasher, Hash, Hasher}, }; use std::{env, fs::File, io, sync::OnceLock}; +use ahash::RandomState; use uuid::Uuid; -use crate::hasher_std; - static BUILD_ID: OnceLock = OnceLock::new(); /// Returns a [Uuid] uniquely representing the build of the current binary. @@ -29,8 +72,8 @@ static BUILD_ID: OnceLock = OnceLock::new(); /// # Examples /// /// ``` -/// # let remote_build_id = libafl_bolts::build_id::get(); -/// let local_build_id = libafl_bolts::build_id::get(); +/// # let remote_build_id = build_id2::get(); +/// let local_build_id = build_id2::get(); /// if local_build_id == remote_build_id { /// println!("We're running the same binary as remote!"); /// } else { @@ -79,7 +122,7 @@ fn from_type_id(mut hasher: H) -> H { } fn calculate() -> Uuid { - let hasher = hasher_std(); + let hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); let hasher = from_exe(hasher.clone()).unwrap_or(hasher); let mut hasher = from_type_id(hasher); diff --git a/crates/core_affinity2/Cargo.toml b/crates/core_affinity2/Cargo.toml new file mode 100644 index 00000000000..d6c657a37bb --- /dev/null +++ b/crates/core_affinity2/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "core_affinity2" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Core Affinity crate to bind to cores, cross platform" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "core-affinity", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +document-features = ["dep:document-features"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } +serde = { workspace = true, features = ["alloc", "derive"] } +libafl_core = { workspace = true, features = ["alloc", "std"] } +libc = { workspace = true } + +[lints] +workspace = true diff --git a/crates/core_affinity2/LICENSE-APACHE b/crates/core_affinity2/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/core_affinity2/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/core_affinity2/LICENSE-MIT b/crates/core_affinity2/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/core_affinity2/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/core_affinity2/README.md b/crates/core_affinity2/README.md new file mode 100644 index 00000000000..bf58b89238f --- /dev/null +++ b/crates/core_affinity2/README.md @@ -0,0 +1,98 @@ +# Core_Affinity2: Manage CPU affinities even harder + + LibAFL logo + +A crate to manage CPU core affinity for threads, maintained as part of the [LibAFL](https://github.com/AFLplusplus/LibAFL) project. + +`core_affinity2` allows you to get the list of available cores on a system and to pin the current thread to a specific core. + +Pinning threads to cores can improve performance by reducing cache misses and avoiding thread migration between cores. This is particularly useful in performance-sensitive applications like fuzzing, scientific computing, and real-time systems. + +This crate is a fork of the original [`core_affinity`](https://crates.io/crates/core_affinity) crate, with updates and continued maintenance. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +core_affinity2 = "0.15.4" # Replace with the latest version +``` + +### Example: Pinning threads to cores + +Here is an example of how to get the available core IDs and spawn a thread for each, pinning it to the respective core. + +```rust +use std::thread; +use core_affinity2::{get_core_ids, CoreId}; + +fn main() { + // Get the available core IDs + if let Some(core_ids) = get_core_ids() { + let core_count = core_ids.len(); + println!("Found {} cores:", core_count); + + let handles: Vec<_> = core_ids.into_iter().map(|id| { + thread::spawn(move || { + // Pin this thread to a single CPU core. + if id.set_affinity().is_ok() { + println!("Thread {:?} is running on core {:?}", thread::current().id(), id); + // Do some work here + } else { + eprintln!("Could not pin thread to core {:?}", id); + } + }) + }).collect(); + + for handle in handles { + handle.join().unwrap(); + } + } else { + println!("Could not get core IDs."); + } +} +``` + +### Parsing core ranges + +The `Cores` struct provides a convenient way to work with a set of cores, including parsing from a command-line string. + +```rust +use core_affinity2::Cores; + +// Parse a comma-separated list of cores and ranges +let cores = Cores::from_cmdline("0,2-4,7").unwrap(); +assert_eq!(cores.ids, vec![0.into(), 2.into(), 3.into(), 4.into(), 7.into()]); + +// "all" will use all available cores +// let all_cores = Cores::from_cmdline("all").unwrap(); +``` + +## Supported Platforms + +`core_affinity2` is cross-platform and supports the following operating systems: + +- Linux +- Windows +- macOS (x86_64 and aarch64) +- FreeBSD +- NetBSD +- OpenBSD +- Dragonfly BSD +- Solaris / Illumos +- Haiku + +Note that on some platforms (like macOS on aarch64), it's not possible to pin a thread to a specific core, but the library will still try to request the highest performance for the thread. + +## `no_std` Support + +This crate has `no_std` support. + +## Contributing + +Contributions are welcome! Please see the main [LibAFL `CONTRIBUTING.md`](https://github.com/AFLplusplus/LibAFL/blob/main/CONTRIBUTING.md) for more information. + +## License + +This crate is licensed under either of the [MIT License](LICENSE-MIT) or the [Apache License 2.0](LICENSE-APACHE). \ No newline at end of file diff --git a/crates/libafl_bolts/src/core_affinity.rs b/crates/core_affinity2/src/lib.rs similarity index 94% rename from crates/libafl_bolts/src/core_affinity.rs rename to crates/core_affinity2/src/lib.rs index ae8bad52173..71b7b91827f 100644 --- a/crates/libafl_bolts/src/core_affinity.rs +++ b/crates/core_affinity2/src/lib.rs @@ -6,11 +6,11 @@ //! //! ```rust //! # use std::thread; -//! use libafl_bolts::core_affinity; +//! use core_affinity2; //! //! // Retrieve the IDs of all active CPU cores. //! # #[cfg(not(miri))] -//! let core_ids = core_affinity::get_core_ids().unwrap(); +//! let core_ids = core_affinity2::get_core_ids().unwrap(); //! //! // Create a thread for each active CPU core. //! # #[cfg(not(miri))] @@ -32,16 +32,64 @@ //! ``` //! //! *This file is a fork of * +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[macro_use] +extern crate std; +#[doc(hidden)] +pub extern crate alloc; use alloc::{ string::{String, ToString}, vec::Vec, }; +use libafl_core::Error; use serde::{Deserialize, Serialize}; -use crate::Error; - /// This function tries to retrieve information /// on all the "cores" active on this system. pub fn get_core_ids() -> Result, Error> { @@ -97,7 +145,6 @@ pub struct Cores { pub ids: Vec, } -#[cfg(feature = "std")] impl Cores { /// Pick all cores pub fn all() -> Result { @@ -196,7 +243,6 @@ impl From> for Cores { } } -#[cfg(feature = "std")] impl TryFrom<&str> for Cores { type Error = Error; fn try_from(cores: &str) -> Result { @@ -249,8 +295,9 @@ mod linux { #[cfg(target_os = "dragonfly")] const CPU_SETSIZE: libc::c_int = 256; + use libafl_core::Error; + use super::CoreId; - use crate::Error; #[allow(trivial_numeric_casts)] pub fn get_core_ids() -> Result, Error> { @@ -380,7 +427,7 @@ mod haiku { use alloc::vec::Vec; use std::thread::available_parallelism; - use crate::core_affinity::{CoreId, Error}; + use crate::{CoreId, Error}; #[expect(clippy::unnecessary_wraps)] pub fn get_core_ids() -> Result, Error> { @@ -413,7 +460,7 @@ mod windows { Threading::{GetCurrentThread, SetThreadGroupAffinity}, }; - use crate::core_affinity::{CoreId, Error}; + use crate::{CoreId, Error}; pub fn get_core_ids() -> Result, Error> { let mut core_ids: Vec = Vec::new(); @@ -594,6 +641,7 @@ mod apple { use alloc::vec::Vec; use std::thread::available_parallelism; + use libafl_core::Error; #[cfg(target_arch = "x86_64")] use libc::{ KERN_SUCCESS, THREAD_AFFINITY_POLICY, THREAD_AFFINITY_POLICY_COUNT, integer_t, @@ -604,7 +652,6 @@ mod apple { use libc::{pthread_set_qos_class_self_np, qos_class_t::QOS_CLASS_USER_INITIATED}; use super::CoreId; - use crate::Error; #[cfg(target_arch = "x86_64")] #[repr(C)] @@ -691,13 +738,13 @@ mod netbsd { use alloc::vec::Vec; use std::thread::available_parallelism; + use libafl_core::Error; use libc::{ _cpuset, _cpuset_create, _cpuset_destroy, _cpuset_set, _cpuset_size, pthread_self, pthread_setaffinity_np, }; use super::CoreId; - use crate::Error; #[expect(trivial_numeric_casts)] pub fn get_core_ids() -> Result, Error> { @@ -753,8 +800,9 @@ mod openbsd { use alloc::vec::Vec; use std::thread::available_parallelism; + use libafl_core::Error; + use super::CoreId; - use crate::Error; #[expect(trivial_numeric_casts)] pub fn get_core_ids() -> Result, Error> { @@ -781,8 +829,9 @@ mod solaris { use alloc::vec::Vec; use std::thread::available_parallelism; + use libafl_core::Error; + use super::CoreId; - use crate::Error; #[expect(clippy::unnecessary_wraps)] pub fn get_core_ids() -> Result, Error> { diff --git a/crates/exceptional/Cargo.toml b/crates/exceptional/Cargo.toml new file mode 100644 index 00000000000..536454763dc --- /dev/null +++ b/crates/exceptional/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "exceptional" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Everything for your exception and signal handling needs" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["nix", "libafl_core/std", "alloc"] + +## Enables all features that allocate in `no_std` +alloc = ["libafl_core/alloc"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } +libafl_core = { workspace = true } +nix = { workspace = true, optional = true, default-features = false, features = [ + "fs", + "signal", + "socket", + "poll", +] } +num_enum = { workspace = true, default-features = false } + +[target.'cfg(unix)'.dependencies] +libc = { workspace = true } + +[target.'cfg(windows)'.dependencies] +log = { workspace = true } +windows = { workspace = true, features = [ + "Win32_Foundation", + "Win32_Security", + "Win32_System_Console", + "Win32_System_Diagnostics_Debug", + "Win32_System_Kernel", + "Win32_System_Memory", + "Win32_System_SystemInformation", + "Win32_System_Threading", +] } +windows-core = { workspace = true } + +[lints] +workspace = true diff --git a/crates/exceptional/LICENSE-APACHE b/crates/exceptional/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/exceptional/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/exceptional/LICENSE-MIT b/crates/exceptional/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/exceptional/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/exceptional/README.md b/crates/exceptional/README.md new file mode 100644 index 00000000000..53eea1337a8 --- /dev/null +++ b/crates/exceptional/README.md @@ -0,0 +1,49 @@ +# Excpetional: A handy library to handle OS Signals and Exception + + LibAFL logo + +The `exceptional` crate, part of [`LibAFL`](https://github.com/AFLplusplus/LibAFL), exposes (very!) low-level features to handle exceptions on Unix and Windows operating systems. + +The `LibAFL` project is written and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/exceptional/src/lib.rs b/crates/exceptional/src/lib.rs new file mode 100644 index 00000000000..7e150bc363f --- /dev/null +++ b/crates/exceptional/src/lib.rs @@ -0,0 +1,61 @@ +/*! + * Everything for your exception and signal handling needs + */ +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[cfg(feature = "alloc")] +#[doc(hidden)] +pub extern crate alloc; + +#[cfg(unix)] +pub mod unix_signals; + +#[cfg(all(windows, feature = "std"))] +#[expect(missing_docs, overflowing_literals)] +pub mod windows_exceptions; diff --git a/crates/libafl_bolts/src/os/unix_signals.rs b/crates/exceptional/src/unix_signals.rs similarity index 99% rename from crates/libafl_bolts/src/os/unix_signals.rs rename to crates/exceptional/src/unix_signals.rs index a2ed3ee2ba4..855f8471afb 100644 --- a/crates/libafl_bolts/src/os/unix_signals.rs +++ b/crates/exceptional/src/unix_signals.rs @@ -16,6 +16,7 @@ use core::{ mem, }; +use libafl_core::format; /// armv7 `libc` does not feature a `uncontext_t` implementation #[cfg(target_arch = "arm")] pub use libc::c_ulong; @@ -246,6 +247,7 @@ pub struct ucontext_t { pub mcontext_data: mcontext64, } +use libafl_core::Error; #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] use libc::ssize_t; #[cfg(not(any( @@ -265,8 +267,6 @@ use libc::{ pub use libc::{c_void, siginfo_t}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use crate::Error; - unsafe extern "C" { /// The `libc` `getcontext` /// For some reason, it's not available on `MacOS`. diff --git a/crates/libafl_bolts/src/os/windows_exceptions.rs b/crates/exceptional/src/windows_exceptions.rs similarity index 98% rename from crates/libafl_bolts/src/os/windows_exceptions.rs rename to crates/exceptional/src/windows_exceptions.rs index 9504348b8fb..db62f7bf45a 100644 --- a/crates/libafl_bolts/src/os/windows_exceptions.rs +++ b/crates/exceptional/src/windows_exceptions.rs @@ -10,6 +10,7 @@ use core::{ }; use std::os::raw::{c_long, c_void}; +use libafl_core::Error; use num_enum::FromPrimitive; pub use windows::Win32::{ Foundation::NTSTATUS, @@ -23,21 +24,18 @@ pub use windows::Win32::{ }; pub use windows_core::BOOL; -use crate::Error; - /// The special exit code when the target exited through ctrl-c pub const CTRL_C_EXIT: i32 = -1073741510; -// For VEH +/// For VEH const EXCEPTION_CONTINUE_EXECUTION: c_long = -1; -// For VEH +/// For VEH const EXCEPTION_CONTINUE_SEARCH: c_long = 0; // For SEH // const EXCEPTION_EXECUTE_HANDLER: c_long = 1; -// From https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/crt/signal.h pub const SIGINT: i32 = 2; pub const SIGILL: i32 = 4; pub const SIGABRT_COMPAT: i32 = 6; @@ -48,7 +46,6 @@ pub const SIGBREAK: i32 = 21; pub const SIGABRT: i32 = 22; pub const SIGABRT2: i32 = 22; -// From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611 pub const STATUS_WAIT_0: i32 = 0x00000000; pub const STATUS_ABANDONED_WAIT_0: i32 = 0x00000080; pub const STATUS_USER_APC: i32 = 0x000000C0; @@ -97,7 +94,6 @@ pub const STATUS_SXS_EARLY_DEACTIVATION: i32 = 0xC015000F; pub const STATUS_SXS_INVALID_DEACTIVATION: i32 = 0xC0150010; pub const STATUS_NOT_IMPLEMENTED: i32 = 0xC0000002; -// from https://github.com/x64dbg/x64dbg/blob/4d631707b89d97e199844c08f5b65d8ea5d5d3f3/bin/exceptiondb.txt pub const STATUS_WX86_UNSIMULATE: i32 = 0x4000001C; pub const STATUS_WX86_CONTINUE: i32 = 0x4000001D; pub const STATUS_WX86_SINGLE_STEP: i32 = 0x4000001E; @@ -133,7 +129,6 @@ pub const VCPP_EXCEPTION_ERROR_PROC_NOT_FOUND: i32 = 0xC06D007F; #[derive(Debug, FromPrimitive, Copy, Clone)] #[repr(i32)] pub enum ExceptionCode { - // From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611 WaitZero = STATUS_WAIT_0, AbandonedWaitZero = STATUS_ABANDONED_WAIT_0, UserApc = STATUS_USER_APC, @@ -181,7 +176,7 @@ pub enum ExceptionCode { SxsEarlyDeactivation = STATUS_SXS_EARLY_DEACTIVATION, SxsInvalidDeactivation = STATUS_SXS_INVALID_DEACTIVATION, NotImplemented = STATUS_NOT_IMPLEMENTED, - // from https://github.com/x64dbg/x64dbg/blob/4d631707b89d97e199844c08f5b65d8ea5d5d3f3/bin/exceptiondb.txt + Wx86Unsimulate = STATUS_WX86_UNSIMULATE, Wx86Continue = STATUS_WX86_CONTINUE, Wx86SingleStep = STATUS_WX86_SINGLE_STEP, @@ -535,6 +530,7 @@ unsafe extern "C" fn handle_signal(_signum: i32) { } /// Setup Win32 exception handlers in a somewhat rusty way. +/// /// # Safety /// Exception handlers are usually ugly, handle with care! #[cfg(feature = "alloc")] @@ -589,22 +585,26 @@ pub unsafe fn setup_exception_handler( Ok(()) } -#[cfg(feature = "alloc")] +#[cfg(feature = "std")] pub(crate) trait CtrlHandler { /// Handle an exception fn handle(&mut self, ctrl_type: u32) -> bool; } +#[cfg(feature = "std")] struct CtrlHandlerHolder { handler: UnsafeCell<*mut dyn CtrlHandler>, } /// Keep track of which handler is registered for which exception +#[cfg(feature = "std")] static mut CTRL_HANDLER: Option = None; /// Set `ConsoleCtrlHandler` to catch Ctrl-C +/// /// # Safety /// Same safety considerations as in `setup_exception_handler` +#[cfg(feature = "std")] pub(crate) unsafe fn setup_ctrl_handler( handler: *mut T, ) -> Result<(), Error> { @@ -632,6 +632,7 @@ pub(crate) unsafe fn setup_ctrl_handler( } } +#[cfg(feature = "std")] unsafe extern "system" fn ctrl_handler(ctrl_type: u32) -> BOOL { let handler = unsafe { ptr::read_volatile(&raw const (CTRL_HANDLER)) }; match handler { diff --git a/crates/fast_rands/Cargo.toml b/crates/fast_rands/Cargo.toml new file mode 100644 index 00000000000..d67c2c4398d --- /dev/null +++ b/crates/fast_rands/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "fast_rands" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Non-cryptographically, but quite fast, RNG implementations" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["alloc"] + +## Enables all features that allocate in `no_std` +alloc = [] + +## If set, libafl_rand's `rand` implementations will implement `rand_core::CoreRng` +## and, inversely, all seedable `rand_core::RngCore` types can be used as Rng for LibAFL. +rand_trait = ["rand_core"] + +## Enable python support for Rand +python = ["pyo3"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +serde = { workspace = true, default-features = false, features = [ + "derive", +] } # serialization lib +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } +rand_core = { version = "0.9.0", optional = true } +pyo3 = { workspace = true, optional = true, features = ["serde", "macros"] } + +[lints] +workspace = true diff --git a/crates/fast_rands/LICENSE-APACHE b/crates/fast_rands/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/fast_rands/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/fast_rands/LICENSE-MIT b/crates/fast_rands/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/fast_rands/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/fast_rands/README.md b/crates/fast_rands/README.md new file mode 100644 index 00000000000..8645ce38c5c --- /dev/null +++ b/crates/fast_rands/README.md @@ -0,0 +1,71 @@ +# `Fast_Rands`: Get (non-cryptographically secure!) Random Numbers Faster. + + LibAFL logo + +The `faster_rands` crate is a collection of a range of fast RNGs, such as [RomuRand](https://www.romu-random.org/) and others. +It can be used together with [`LibAFL`](https://github.com/AFLplusplus/LibAFL) or any place that needs random numbers, _as long as you don't rely on the randomness for security_. + +## Usage + +```rust +use fast_rands::{Rand, StdRand}; +use core::num::NonZeroUsize; + +// Create a new random number generator with a random seed +let mut rand = StdRand::new(); + +// Get a random u64 +let n = rand.next(); + +// Get a random number below 100 +let below_100 = rand.below(NonZeroUsize::new(100).unwrap()); + +// Get a random number between 50 and 100 (inclusive) +let between_50_and_100 = rand.between(50, 100); +``` + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/libafl_bolts/src/rands/mod.rs b/crates/fast_rands/src/lib.rs similarity index 88% rename from crates/libafl_bolts/src/rands/mod.rs rename to crates/fast_rands/src/lib.rs index 8ad2e94ea77..da95fa0ad10 100644 --- a/crates/libafl_bolts/src/rands/mod.rs +++ b/crates/fast_rands/src/lib.rs @@ -1,4 +1,54 @@ -//! The random number generators of `LibAFL` +//! The fast random number generators of `LibAFL` +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[doc(hidden)] +pub extern crate alloc; #[cfg(all(not(feature = "std"), target_has_atomic = "ptr"))] use core::sync::atomic::{AtomicUsize, Ordering}; @@ -559,6 +609,7 @@ impl XkcdRand { #[cfg(feature = "python")] /// `Rand` Python bindings pub mod pybind { + use pyo3::prelude::*; use serde::{Deserialize, Serialize}; @@ -640,22 +691,55 @@ pub mod pybind { m.add_class::()?; Ok(()) } + + #[macro_export] + /// Unwrap the mutable body of this wrapper + macro_rules! unwrap_me_mut_body { + ($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),*}) => { + match &mut $wrapper { + $( + $wrapper_type::$wrapper_option(py_wrapper) => { + Python::attach(|py| -> PyResult<_> { + let mut borrowed = py_wrapper.borrow_mut(py); + let $name = &mut borrowed.inner; + Ok($body) + }) + .unwrap() + } + )* + } + }; + ($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),*}, { $($wrapper_optional:tt($pw:ident) => $code_block:block)* }) => { + match &mut $wrapper { + $( + $wrapper_type::$wrapper_option(py_wrapper) => { + Python::with_gil(|py| -> PyResult<_> { + let mut borrowed = py_wrapper.borrow_mut(py); + let $name = &mut borrowed.inner; + Ok($body) + }) + .unwrap() + } + )* + $($wrapper_type::$wrapper_optional($pw) => { $code_block })* + } + }; + } } #[cfg(test)] mod tests { + use core::num::NonZero; + use crate::{ - nonzero, - rands::{ - Rand, RomuDuoJrRand, RomuTrioRand, Sfc64Rand, StdRand, XorShift64Rand, - Xoshiro256PlusPlusRand, - }, + Rand, RomuDuoJrRand, RomuTrioRand, Sfc64Rand, StdRand, XorShift64Rand, + Xoshiro256PlusPlusRand, }; fn test_single_rand(rand: &mut R) { assert_ne!(rand.next(), rand.next()); - assert!(rand.below(nonzero!(100)) < 100); - assert_eq!(rand.below(nonzero!(1)), 0); + assert!(rand.below(NonZero::new(100).unwrap()) < 100); + assert_eq!(rand.below(NonZero::new(1).unwrap()), 0); assert_eq!(rand.between(10, 10), 10); assert!(rand.between(11, 20) > 10); } diff --git a/crates/libafl_bolts/src/rands/loaded_dice.rs b/crates/fast_rands/src/loaded_dice.rs similarity index 88% rename from crates/libafl_bolts/src/rands/loaded_dice.rs rename to crates/fast_rands/src/loaded_dice.rs index 321c653b2cf..93f8cdb8618 100644 --- a/crates/libafl_bolts/src/rands/loaded_dice.rs +++ b/crates/fast_rands/src/loaded_dice.rs @@ -7,8 +7,8 @@ A simple module that implements a random sampler implementing the [alias method] Assume we want to sample from the following distribution: `p(0)=0.5, p(1)=0.3, p(2)=0.1, p(3)=0.1`: ```rust -# extern crate libafl_bolts; -use libafl_bolts::rands::{StdRand, loaded_dice::LoadedDiceSampler}; +# extern crate fast_rands; +use fast_rands::{StdRand, loaded_dice::LoadedDiceSampler}; fn main() { let mut rand = StdRand::new(); let mut sampler = LoadedDiceSampler::new(&[0.5, 0.3, 0.1, 0.1]).unwrap(); @@ -22,10 +22,22 @@ fn main() { Original code by @eqv, see */ -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; +use core::fmt::{self, Debug, Formatter}; use super::Rand; -use crate::Error; + +/// An illegal argument got passed to a function. +pub struct IllegalArgumentError; + +impl Debug for IllegalArgumentError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "LoadedDiceError(Tried to construct LoadedDiceSampler with empty probs array)" + ) + } +} /// Helper struct for [`LoadedDiceSampler`] #[derive(Debug, Clone, PartialEq)] @@ -54,11 +66,9 @@ pub struct LoadedDiceSampler { impl LoadedDiceSampler { /// Create a new [`LoadedDiceSampler`] with the given probabilities - pub fn new(probs: &[f64]) -> Result { + pub fn new(probs: &[f64]) -> Result { if probs.is_empty() { - return Err(Error::illegal_argument( - "Tried to construct LoadedDiceSampler with empty probs array", - )); + return Err(IllegalArgumentError); } let entries = LoadedDiceSampler::construct_table(probs); Ok(Self { entries }) @@ -113,7 +123,7 @@ mod tests { use alloc::vec::Vec; use super::LoadedDiceSampler; - use crate::rands::{Rand, StdRand}; + use crate::{Rand, StdRand}; #[test] #[expect(clippy::cast_precision_loss)] diff --git a/crates/libafl/Cargo.toml b/crates/libafl/Cargo.toml index 1e003a444af..af6f7f95d2b 100644 --- a/crates/libafl/Cargo.toml +++ b/crates/libafl/Cargo.toml @@ -31,19 +31,19 @@ workspace = true [features] default = [ - "std", "derive", + "errors_backtrace", + "fork", + "gzip", + "libafl_bolts/xxh3", + "llmp_broker_timeouts", "llmp_compression", "llmp_small_maps", - "llmp_broker_timeouts", "rand_trait", - "fork", - "gzip", "regex", "serdeany_autoreg", - "libafl_bolts/xxh3", "simd", - "errors_backtrace", + "std", ] document-features = ["dep:document-features"] @@ -52,19 +52,20 @@ document-features = ["dep:document-features"] ## Enables features that need rust's `std` lib to work, like print, env, ... support std = [ + "backtrace", + "bincode", + "dep:nix", + "fastbloom", + "fs2", + "libafl_bolts/std", + "ll_mp/std", "serde_json", "serde_json/std", - "dep:nix", "serde/std", - "bincode", - "wait-timeout", - "uuid", - "backtrace", "serial_test", - "libafl_bolts/std", "typed-builder", - "fastbloom", - "fs2", + "uuid", + "wait-timeout", ] ## Tracks the Feedbacks and the Objectives that were interesting for a Testcase @@ -106,7 +107,7 @@ tcp_manager = ["tokio", "std"] tcp_compression = ["tcp_manager", "libafl_bolts/gzip"] ## Enable multi-machine support -multi_machine = ["tokio", "std", "enumflags2", "ahash/std", "send_wrapper"] +multi_machine = ["tokio", "std", "enumflags2", "ahash/std", "dep:send_wrapper"] ## Enables the `NaiveTokenizer` and `StacktraceObserver` regex = ["std", "dep:regex"] @@ -177,18 +178,16 @@ serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"] llmp_broker_timeouts = ["std"] ## If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. -llmp_bind_public = ["libafl_bolts/llmp_bind_public"] +llmp_bind_public = ["ll_mp/llmp_bind_public"] ## Enables llmp compression using GZip -llmp_compression = ["libafl_bolts/llmp_compression"] +llmp_compression = ["ll_mp/llmp_compression", "libafl_bolts/gzip"] ## Enables debug output for LLMP (also needs a `logger` installed) -llmp_debug = ["std", "libafl_bolts/llmp_debug"] +llmp_debug = ["std", "ll_mp/llmp_debug"] ## Reduces the initial map size for llmp -llmp_small_maps = [ - "libafl_bolts/llmp_small_maps", -] # reduces initial map size for llmp +llmp_small_maps = ["ll_mp/llmp_small_maps"] # reduces initial map size for llmp ## Grammar mutator. nautilus = ["std", "serde_json/std", "rand_trait", "regex-syntax", "regex"] @@ -200,7 +199,7 @@ nautilus_py = ["nautilus", "dep:pyo3"] lua_mutator = ["mlua"] ## Use the best SIMD implementation by our benchmark -simd = ["libafl_bolts/simd"] +simd = ["libafl_bolts/simd", "libafl_bolts/wide"] [[example]] name = "tui_mock" @@ -220,50 +219,61 @@ static_assertions = { workspace = true } [dependencies] libafl_bolts = { workspace = true, features = ["alloc"] } +libafl_core = { workspace = true } libafl_derive = { workspace = true, default-features = true, optional = true } libafl_intelpt = { workspace = true, default-features = true, optional = true } +ll_mp = { workspace = true } +no_std_time = { workspace = true } +tuple_list_ex = { workspace = true } -rustversion = { workspace = true } -tuple_list = { version = "0.1.3" } +ahash = { workspace = true } # The hash function already used in hashbrown +arbitrary-int = { workspace = true } +arrayvec = { version = "0.7.6", optional = true, default-features = false } # used for fixed-len collects +async-std = { version = "1.13.0", features = ["attributes"], optional = true } +backtrace = { workspace = true, optional = true } # Used to get the stacktrace in StacktraceObserver +bincode = { version = "2.0.1", optional = true, features = ["serde"] } +bitbybit = { workspace = true } +bitvec = { version = "1.0.1", optional = true, features = [ + "serde", +] } # used for string range storage +cadence = { version = "1.5.0", optional = true } # For the statsd monitor +clap = { workspace = true, optional = true } +const_format = "0.2.33" # used for providing helpful compiler output +const_panic = { version = "0.2.9", default-features = false } # similarly, for formatting const panic output +crossterm = { version = "0.29.0", optional = true } +enumflags2 = { version = "0.7.10", optional = true } +fastbloom = { workspace = true, optional = true } +fs2 = { workspace = true, optional = true } # used by OnDisk Corpus for file locking +futures = { version = "0.3.30", optional = true } hashbrown = { workspace = true, features = [ "serde", "default-hasher", + "raw-entry", ], default-features = false } # A faster hashmap, nostd compatible -num-traits = { workspace = true, default-features = false } -serde = { workspace = true, features = ["alloc"] } # serialization lib -postcard = { workspace = true } # no_std compatible serde serialization format -bincode = { version = "2.0.1", optional = true, features = ["serde"] } -bitbybit = { workspace = true } -arbitrary-int = { workspace = true } -ahash = { workspace = true } # The hash function already used in hashbrown +libcasr = { version = "2.12.1", optional = true } +libm = "0.2.8" +log = { workspace = true } meminterval = { workspace = true, features = ["serde"] } -backtrace = { workspace = true, optional = true } # Used to get the stacktrace in StacktraceObserver -typed-builder = { workspace = true, optional = true } # Implement the builder pattern at compiletime -send_wrapper = { version = "0.6.0", optional = true } # To move data between threads - -serde_json = { workspace = true, optional = true, default-features = false, features = [ - "alloc", -] } nix = { workspace = true, optional = true, features = [ "signal", "ptrace", "personality", "fs", ] } -regex = { workspace = true, optional = true } -uuid = { workspace = true, optional = true, features = ["serde", "v4"] } -libm = "0.2.8" +num_enum = { workspace = true, optional = true } +num-traits = { workspace = true, default-features = false } +postcard = { workspace = true } # no_std compatible serde serialization format +prometheus-client = { version = "0.23.0", optional = true } # For the prometheus monitor +pyo3 = { workspace = true, optional = true } ratatui = { version = "0.29.0", default-features = false, features = [ 'crossterm', ], optional = true } # Commandline rendering, for TUI Monitor -crossterm = { version = "0.29.0", optional = true } - -cadence = { version = "1.5.0", optional = true } # For the statsd monitor -prometheus-client = { version = "0.24.0", optional = true } # For the prometheus monitor +send_wrapper = { version = "0.6.0", optional = true } # To move data between threads +serde = { workspace = true, features = ["alloc", "derive"] } +serde_json = { workspace = true, default-features = false, features = [ + "alloc", +], optional = true } tide = { version = "0.16.0", optional = true } -async-std = { version = "1.13.0", features = ["attributes"], optional = true } -futures = { version = "0.3.30", optional = true } -log = { workspace = true } tokio = { version = "1.40.0", optional = true, features = [ "sync", "net", @@ -273,26 +283,14 @@ tokio = { version = "1.40.0", optional = true, features = [ "rt-multi-thread", "time", ] } # used for TCP Event Manager and multi-machine -enumflags2 = { version = "0.7.10", optional = true } - +tuple_list = { workspace = true } +typed-builder = { workspace = true, optional = true } # Implement the builder pattern at compiletime +uuid = { workspace = true, optional = true, features = ["serde", "v4"] } wait-timeout = { version = "0.2.0", optional = true } # used by CommandExecutor to wait for child process -libcasr = { version = "2.12.1", optional = true } - -bitvec = { version = "1.0.1", optional = true, features = [ - "serde", -] } # used for string range storage - -arrayvec = { version = "0.7.6", optional = true, default-features = false } # used for fixed-len collects - -const_format = "0.2.33" # used for providing helpful compiler output -const_panic = { version = "0.2.9", default-features = false } # similarly, for formatting const panic output - -pyo3 = { workspace = true, optional = true } +regex = { workspace = true, optional = true } regex-syntax = { version = "0.8.4", optional = true } # For nautilus -fs2 = { workspace = true, optional = true } # used by OnDisk Corpus for file locking - z3 = { workspace = true, optional = true } # for concolic mutation # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) @@ -303,9 +301,6 @@ serial_test = { workspace = true, optional = true, default-features = false, fea # Document all features of this crate (for `cargo doc`) document-features = { workspace = true, optional = true } # Optional -clap = { workspace = true, optional = true } -num_enum = { workspace = true, optional = true } -fastbloom = { workspace = true, optional = true } # For Lua Mutators # TODO: macros is not needed/ a temporary fix for docsrs, see mlua = { version = "0.11.4", features = [ diff --git a/crates/libafl/src/common/nautilus/grammartec/recursion_info.rs b/crates/libafl/src/common/nautilus/grammartec/recursion_info.rs index 549e1302ef1..db756dacc69 100644 --- a/crates/libafl/src/common/nautilus/grammartec/recursion_info.rs +++ b/crates/libafl/src/common/nautilus/grammartec/recursion_info.rs @@ -89,7 +89,11 @@ impl RecursionInfo { for v in &mut weights { *v /= norm; } - LoadedDiceSampler::new(&weights) + LoadedDiceSampler::new(&weights).map_err(|err| { + Error::illegal_argument(format!( + "Could not crate LoadedDiceSampler for depths {depths:?}: {err:?}" + )) + }) } pub fn get_random_recursion_pair(&mut self, rand: &mut R) -> (NodeId, NodeId) { diff --git a/crates/libafl/src/events/llmp/restarting.rs b/crates/libafl/src/events/llmp/restarting.rs index 154e779ca55..24220d1aae7 100644 --- a/crates/libafl/src/events/llmp/restarting.rs +++ b/crates/libafl/src/events/llmp/restarting.rs @@ -16,17 +16,14 @@ use core::{ #[cfg(feature = "std")] use std::net::TcpStream; +#[cfg(feature = "std")] +use libafl_bolts::llmp::{TcpRequest, TcpResponse, recv_tcp_msg, send_tcp_msg}; #[cfg(any(windows, not(feature = "fork")))] use libafl_bolts::os::startable_self; #[cfg(all(unix, not(miri)))] use libafl_bolts::os::unix_signals::setup_signal_handler; #[cfg(all(feature = "fork", unix))] use libafl_bolts::os::{ForkResult, fork}; -#[cfg(feature = "std")] -use libafl_bolts::{ - IP_LOCALHOST, - llmp::{TcpRequest, TcpResponse, recv_tcp_msg, send_tcp_msg}, -}; #[cfg(feature = "llmp_compression")] use libafl_bolts::{ compress::GzipCompressor, @@ -43,6 +40,8 @@ use libafl_bolts::{ staterestore::StateRestorer, tuples::tuple_list, }; +#[cfg(feature = "std")] +use libafl_core::IP_LOCALHOST; use serde::{Serialize, de::DeserializeOwned}; use typed_builder::TypedBuilder; diff --git a/crates/libafl/src/events/mod.rs b/crates/libafl/src/events/mod.rs index 7fb8c62ddb7..2f4c948c17d 100644 --- a/crates/libafl/src/events/mod.rs +++ b/crates/libafl/src/events/mod.rs @@ -519,7 +519,7 @@ where { state .introspection_stats_mut() - .set_current_time(libafl_bolts::cpu::read_time_counter()); + .set_current_time(no_std_time::read_time_counter()); // Send the current monitor over to the manager. This `.clone` shouldn't be // costly as `ClientPerfStats` impls `Copy` since it only contains `u64`s diff --git a/crates/libafl/src/executors/differential.rs b/crates/libafl/src/executors/differential.rs index 06bbedf8510..c636cb43f6a 100644 --- a/crates/libafl/src/executors/differential.rs +++ b/crates/libafl/src/executors/differential.rs @@ -14,7 +14,7 @@ use libafl_bolts::{ ownedref::OwnedMutPtr, tuples::{MatchName, RefIndexable}, }; -use serde::{Deserialize, Serialize}; +use serde::{self, Deserialize, Serialize}; use super::HasTimeout; use crate::{ diff --git a/crates/libafl/src/executors/mod.rs b/crates/libafl/src/executors/mod.rs index ce971884b66..985cf350dff 100644 --- a/crates/libafl/src/executors/mod.rs +++ b/crates/libafl/src/executors/mod.rs @@ -36,6 +36,7 @@ pub mod forkserver; pub mod inprocess; pub mod nop; /// SAND() implementation +#[cfg(feature = "simd")] pub mod sand; /// The module for inproc fork executor diff --git a/crates/libafl/src/feedbacks/mod.rs b/crates/libafl/src/feedbacks/mod.rs index 18bfcde983d..ba080fa7713 100644 --- a/crates/libafl/src/feedbacks/mod.rs +++ b/crates/libafl/src/feedbacks/mod.rs @@ -106,13 +106,13 @@ pub trait Feedback: StateInitializer + Named { S: HasClientPerfMonitor, { // Start a timer for this feedback - let start_time = libafl_bolts::cpu::read_time_counter(); + let start_time = no_std_time::read_time_counter(); // Execute this feedback let ret = self.is_interesting(state, manager, input, observers, exit_kind); // Get the elapsed time for checking this feedback - let elapsed = libafl_bolts::cpu::read_time_counter() - start_time; + let elapsed = no_std_time::read_time_counter() - start_time; // Add this stat to the feedback metrics state diff --git a/crates/libafl/src/monitors/stats/perf_stats.rs b/crates/libafl/src/monitors/stats/perf_stats.rs index 343bc85dec5..054cf999b8f 100644 --- a/crates/libafl/src/monitors/stats/perf_stats.rs +++ b/crates/libafl/src/monitors/stats/perf_stats.rs @@ -9,10 +9,10 @@ use serde::{Deserialize, Serialize}; /// Client performance statistics #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ClientPerfStats { - /// Starting counter (in clock cycles from `read_time_counter`) + /// Starting counter (in clock cycles from [`no_std_time::read_time_counter`]) start_time: u64, - /// Current counter in the fuzzer (in clock cycles from `read_time_counter` + /// Current counter in the fuzzer (in clock cycles from [`no_std_time::read_time_counter`]) current_time: u64, /// Clock cycles spent in the scheduler @@ -128,7 +128,7 @@ impl ClientPerfStats { /// the current clock counter #[must_use] pub fn new() -> Self { - let start_time = libafl_bolts::cpu::read_time_counter(); + let start_time = no_std_time::read_time_counter(); Self { start_time, @@ -152,7 +152,7 @@ impl ClientPerfStats { /// Start a timer with the current time counter #[inline] pub fn start_timer(&mut self) { - self.timer_start = Some(libafl_bolts::cpu::read_time_counter()); + self.timer_start = Some(no_std_time::read_time_counter()); } /// Update the current [`ClientPerfStats`] with the given [`ClientPerfStats`] @@ -178,7 +178,7 @@ impl ClientPerfStats { } Some(timer_start) => { // Calculate the elapsed time - let elapsed = libafl_bolts::cpu::read_time_counter() - timer_start; + let elapsed = no_std_time::read_time_counter() - timer_start; // Reset the timer self.timer_start = None; diff --git a/crates/libafl/src/mutators/havoc_mutations.rs b/crates/libafl/src/mutators/havoc_mutations.rs index 3cfba015822..7e61c8ac782 100644 --- a/crates/libafl/src/mutators/havoc_mutations.rs +++ b/crates/libafl/src/mutators/havoc_mutations.rs @@ -1,8 +1,7 @@ //! [`crate::mutators::Mutator`] collection equivalent to AFL++'s havoc mutations -use libafl_bolts::{ - map_tuple_list_type, merge_tuple_list_type, - tuples::{Map, Merge, tuple_list, tuple_list_type}, +use libafl_bolts::tuples::{ + Map, Merge, map_tuple_list_type, merge_tuple_list_type, tuple_list, tuple_list_type, }; use crate::mutators::{ diff --git a/crates/libafl/src/mutators/numeric.rs b/crates/libafl/src/mutators/numeric.rs index 6665aac8a08..be37f32b16d 100644 --- a/crates/libafl/src/mutators/numeric.rs +++ b/crates/libafl/src/mutators/numeric.rs @@ -4,11 +4,12 @@ use alloc::borrow::Cow; use core::marker::PhantomData; use libafl_bolts::{ - Error, Named, map_tuple_list_type, merge_tuple_list_type, + Error, Named, rands::Rand, tuples::{Map as _, Merge}, }; use tuple_list::{tuple_list, tuple_list_type}; +use tuple_list_ex::{map_tuple_list_type, merge_tuple_list_type}; use super::{MutationResult, Mutator, ToMappingMutator, ToStateAwareMappingMutator}; use crate::{ diff --git a/crates/libafl/src/observers/stacktrace.rs b/crates/libafl/src/observers/stacktrace.rs index 77ca29a8c8c..0046a171131 100644 --- a/crates/libafl/src/observers/stacktrace.rs +++ b/crates/libafl/src/observers/stacktrace.rs @@ -16,7 +16,7 @@ use std::{ }; use backtrace::Backtrace; -use libafl_bolts::{Named, ownedref::OwnedRefMut}; +use libafl_bolts::{Named, ownedref::OwnedRefMut, shmem::ShMem}; #[allow(unused_imports)] // expect breaks here for some reason #[cfg(feature = "casr")] use libcasr::{ @@ -156,6 +156,29 @@ impl<'a> BacktraceObserver<'a> { } } + /// [`BacktraceObserver`], with the `backtrace_hash` pointing to the given [`ShMem`]. + /// + /// # Panics + /// Panics if the given shared mem is smaller than `sizeof::()` + /// + /// # Safety + /// The shared memory needs to point to a valid u64 hash int. + /// Any use of this [`OwnedRefMut`] will dereference a pointer to the given shared memory accordingly + pub unsafe fn from_shmem( + observer_name: S, + shmem: &mut SHM, + harness_type: HarnessType, + ) -> Self + where + S: Into>, + { + Self::new( + observer_name, + unsafe { OwnedRefMut::from_mut_ptr(shmem.as_mut_ptr_of().unwrap()) }, + harness_type, + ) + } + /// Creates a new [`BacktraceObserver`] with the given name, owning a new `backtrace_hash` variable. #[must_use] pub fn owned(observer_name: S, harness_type: HarnessType) -> Self diff --git a/crates/libafl_asan/libafl_asan_libc/Cargo.toml b/crates/libafl_asan/libafl_asan_libc/Cargo.toml index a0bf1b54bb7..0cb73c78d7d 100644 --- a/crates/libafl_asan/libafl_asan_libc/Cargo.toml +++ b/crates/libafl_asan/libafl_asan_libc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_asan_libc" -description = "Dummy libc library for use with LibAFL Asan library" +description = "Dummy libc library for use with LibAFL ASan library" edition = "2024" rust-version = "1.87" keywords = ["fuzzing", "address", "sanitizer", "asan", "libc"] diff --git a/crates/libafl_bolts/Cargo.toml b/crates/libafl_bolts/Cargo.toml index 3d9993f34dd..57591a42d77 100644 --- a/crates/libafl_bolts/Cargo.toml +++ b/crates/libafl_bolts/Cargo.toml @@ -27,14 +27,12 @@ all-features = true [features] default = [ - "std", + "alloc", "derive", - "llmp_compression", - "llmp_small_maps", - "rand_trait", "gzip", + "rand_trait", "serdeany_autoreg", - "alloc", + "std", "xxh3", ] document-features = ["dep:document-features"] @@ -44,29 +42,51 @@ document-features = ["dep:document-features"] ## Enables features that need rust's `std` lib to work, like print, env, ... support std = [ + "alloc", + "backtrace", + "build_id2", + "core_affinity2", + "exceptional/std", + "fast_rands/std", "hostname", + "libafl_core/nix", + "libafl_core/std", + "ll_mp/std", + "minibsod", "nix", + "no_std_time/std", "serde/std", - "uuid", - "backtrace", - "uds", "serial_test", - "alloc", + "shmem_providers/std", "simd", + "uds", ] ## Enables all features that allocate in `no_std` -alloc = ["serde/alloc", "hashbrown", "postcard", "erased-serde/alloc", "ahash"] +alloc = [ + "ahash", + "erased-serde/alloc", + "fast_rands/alloc", + "hashbrown", + "libafl_core/alloc", + "ll_mp/alloc", + "no_std_time/alloc", + "postcard", + "serde_anymap", + "serde/alloc", + "shmem_providers/alloc", + "tuple_list_ex/alloc", +] ## Provide the `#[derive(SerdeAny)]` macro. derive = ["libafl_derive"] ## If set, libafl_bolt's `rand` implementations will implement `rand_core::CoreRng` ## and, inversely, all seedable `rand_core::RngCore` types can be used as Rng for LibAFL. -rand_trait = ["rand_core"] +rand_trait = ["fast_rands/rand_trait"] ## Will build the `pyo3` bindings -python = ["pyo3", "std"] +python = ["pyo3", "std", "libafl_core/python", "fast_rands/python"] ## Expose `libafl::prelude` for direct access to all types without additional `use` directives prelude = [] @@ -81,10 +101,10 @@ qemu_cli = ["cli"] frida_cli = ["cli"] ## Stores the backtraces of all generated `Error`s. Good for debugging, but may come with a slight performance hit. -errors_backtrace = ["backtrace"] +errors_backtrace = ["libafl_core/errors_backtrace"] ## Enables gzip compression in certain parts of the lib -gzip = ["miniz_oxide", "alloc"] +gzip = ["miniz_oxide", "alloc", "ll_mp/gzip"] ## Replaces `ahash` with the potentially faster [`xxh3`](https://github.com/Cyan4973/xxHash) in some parts of the lib. ## This yields a stable and fast hash, but may increase the resulting binary size slightly @@ -98,25 +118,24 @@ xxh3 = ["xxhash-rust"] ## With this feature, stored state remains deserializable across multiple compilations of LibAFL. ## The rust doc specifically states that "multiple types may map to the same type name", so it could potentially lead to bugs. ## However, we make sure that no two types with the same name ever exist. -stable_anymap = [] +stable_anymap = ["serde_anymap/stable_anymap"] ## Automatically register all `#[derive(SerdeAny)]` types at startup. -serdeany_autoreg = ["ctor"] - +serdeany_autoreg = ["serde_anymap/serdeany_autoreg"] #! ### LLMP features ## If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. -llmp_bind_public = ["alloc"] +llmp_bind_public = ["ll_mp/llmp_bind_public"] ## Enables llmp compression using GZip -llmp_compression = ["alloc", "gzip"] +llmp_compression = ["ll_mp/llmp_compression"] ## Enables debug output for LLMP (also needs a `logger` installed) -llmp_debug = ["alloc", "std"] +llmp_debug = ["ll_mp/llmp_debug"] ## Reduces the initial map size for llmp -llmp_small_maps = ["alloc"] +llmp_small_maps = ["ll_mp/llmp_small_maps"] #! ### Stable SIMD features @@ -133,54 +152,62 @@ chrono = "0.4.42" itertools = "0.14.0" [dependencies] +build_id2 = { workspace = true, optional = true } +core_affinity2 = { workspace = true, optional = true } +exceptional = { workspace = true } +fast_rands = { workspace = true } +libafl_core = { workspace = true, features = ["serde"] } libafl_derive = { workspace = true, default-features = true, optional = true } +ll_mp = { workspace = true } +minibsod = { workspace = true, optional = true } +no_std_time = { workspace = true } +ownedref = { workspace = true } +serde_anymap = { workspace = true, optional = true } +shmem_providers = { workspace = true } static_assertions = { workspace = true } +tuple_list_ex = { workspace = true, features = ["serde"] } typeid = { workspace = true } -tuple_list = { version = "0.1.3" } +ahash = { workspace = true, optional = true } # The hash function already used in hashbrown +backtrace = { workspace = true, default-features = true, optional = true } # Used to get the stacktrace in StacktraceObserver +clap = { workspace = true, features = [ + "derive", + "wrap_help", +], optional = true } # CLI parsing, for libafl_bolts::cli / the `cli` feature +erased-serde = { workspace = true, default-features = false, optional = true } # erased serde hashbrown = { workspace = true, features = [ "serde", "default-hasher", "raw-entry", ], default-features = false, optional = true } # A faster hashmap, nostd compatible -xxhash-rust = { version = "0.8.12", features = [ - "xxh3", -], optional = true } # xxh3 hashing for rust -serde = { workspace = true, default-features = false, features = [ - "derive", -] } # serialization lib -erased-serde = { version = "0.4.5", default-features = false, optional = true } # erased serde -postcard = { workspace = true, optional = true } # no_std compatible serde serialization format -num_enum = { workspace = true, default-features = false } -ahash = { workspace = true, optional = true } # The hash function already used in hashbrown -backtrace = { workspace = true, default-features = true, optional = true } # Used to get the stacktrace in StacktraceObserver - -ctor = { optional = true, version = "0.5.0" } -miniz_oxide = { version = "0.8.0", optional = true } hostname = { version = "0.4.0", optional = true } # Is there really no gethostname in the stdlib? -rand_core = { version = "0.9.0", optional = true } +log = { workspace = true } +miniz_oxide = { version = "0.8.0", optional = true } nix = { workspace = true, optional = true, default-features = false, features = [ "fs", "signal", "socket", "poll", ] } -uuid = { workspace = true, optional = true, features = ["serde", "v4"] } -clap = { workspace = true, features = [ - "derive", - "wrap_help", -], optional = true } # CLI parsing, for libafl_bolts::cli / the `cli` feature -log = { workspace = true } +num_enum = { workspace = true, default-features = false } +postcard = { workspace = true, optional = true } # no_std compatible serde serialization format pyo3 = { workspace = true, optional = true, features = ["serde", "macros"] } +serde = { workspace = true, default-features = false, features = [ + "derive", +], optional = true } # serialization lib +tuple_list = { workspace = true } +xxhash-rust = { version = "0.8.12", features = [ + "xxh3", +], optional = true } # xxh3 hashing for rust # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) serial_test = { workspace = true, optional = true, default-features = false, features = [ "logging", ] } +rustversion = { workspace = true } # optional stable simd wide = { version = "0.7.33", optional = true } -rustversion = { workspace = true } # Document all features of this crate (for `cargo doc`) document-features = { workspace = true, optional = true } @@ -195,16 +222,14 @@ uds = { version = "0.4.2", optional = true, default-features = false } [target.'cfg(windows)'.dependencies] windows = { workspace = true, features = [ "Win32_Foundation", - "Win32_System_Threading", + "Win32_Security", + "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_Kernel", "Win32_System_Memory", - "Win32_Security", "Win32_System_SystemInformation", - "Win32_System_Console", + "Win32_System_Threading", ] } -windows-core = { workspace = true } -once_cell = "1.10.0" winapi = { version = "0.3", features = [ "fileapi", "handleapi", @@ -226,11 +251,6 @@ mach2 = "0.5.0" #opt-level = 3 #debug = true -[[example]] -name = "llmp_test" -path = "./examples/llmp_test/main.rs" -required-features = ["std"] - [[example]] name = "simd" diff --git a/crates/libafl_bolts/README.md b/crates/libafl_bolts/README.md index eaa61ad6b32..6f8dddab111 100644 --- a/crates/libafl_bolts/README.md +++ b/crates/libafl_bolts/README.md @@ -2,19 +2,19 @@ LibAFL logo -The `libafl_bolts` crate exposes a lot of low-level features of LibAFL for projects that are unrelated to fuzzing, or just fuzzers completely different to LibAFL. +The `libafl_bolts` crate is a toolshed combinding a lot of low-level features and crates LibAFL uses. It can be a good starting point for low-level projects, even those that are not specifically fuzzers. Some cross-platform things in bolts include (but are not limited to): -* SerdeAnyMap: a map that stores and retrieves elements by type and is serializable and deserializable -* ShMem: A cross-platform (Windows, Linux, Android, MacOS) shared memory implementation -* LLMP: A fast, lock-free IPC mechanism via SharedMap -* Core_affinity: A maintained version of `core_affinity` that can be used to get core information and bind processes to cores -* Rands: Fast random number generators for fuzzing (like [RomuRand](https://www.romu-random.org/)) -* MiniBSOD: get and print information about the current process state including important registers. -* Tuples: Haskel-like compile-time tuple lists -* Os: OS specific stuff like signal handling, windows exception handling, pipes, and helpers for `fork` +* `SerdeAnyMap`: a map that stores and retrieves elements by type and is serializable and deserializable +* `ShMem`: A cross-platform (Windows, Linux, Android, MacOS) shared memory implementation +* `LL_MP`: A fast, lock-free IPC mechanism via SharedMap +* `Core_affinity`: A maintained version of `core_affinity` that can be used to get core information and bind processes to cores +* `Rands`: Fast random number generators for fuzzing (like [RomuRand](https://www.romu-random.org/)) +* `MiniBSOD`: get and print information about the current process state including important registers. +* `Tuples`: Haskel-like compile-time tuple lists +* `Os`: OS specific stuff like signal handling, windows exception handling, pipes, and helpers for `fork` -LibAFL_bolts is written and maintained by +`LibAFL_bolts` is written and maintained by * [Andrea Fioraldi](https://twitter.com/andreafioraldi) * [Dominik Maier](https://twitter.com/domenuk) @@ -27,12 +27,13 @@ LibAFL_bolts is written and maintained by For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 Even though we will gladly assist you in finishing up your PR, try to -- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/crates/libafl/build.rs#L26)) -- run `cargo nightly fmt` on your code before pushing -- check the output of `cargo clippy --all` or `./clippy.sh` -- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. -Some of the parts in this list may be hard, don't be afraid to open a PR if you cannot fix them by yourself, so we can help. +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. #### License diff --git a/crates/libafl_bolts/src/compress.rs b/crates/libafl_bolts/src/compress.rs index 3cf189638e7..c62d8b5d09e 100644 --- a/crates/libafl_bolts/src/compress.rs +++ b/crates/libafl_bolts/src/compress.rs @@ -62,12 +62,8 @@ impl GzipCompressor { /// Decompression. pub fn decompress(&self, buf: &[u8]) -> Result, Error> { - let decompressed = decompress_to_vec(buf); - - match decompressed { - Ok(buf) => Ok(buf), - Err(_) => Err(Error::compression()), - } + decompress_to_vec(buf) + .map_err(|err| Error::illegal_state(format!("Failed to decompress: {err:?}"))) } } diff --git a/crates/libafl_bolts/src/lib.rs b/crates/libafl_bolts/src/lib.rs index c5694218e59..946a8ea7a52 100644 --- a/crates/libafl_bolts/src/lib.rs +++ b/crates/libafl_bolts/src/lib.rs @@ -1,7 +1,7 @@ /*! * Welcome to `LibAFL_bolts` */ -#![doc = include_str!("../../../README.md")] +#![doc = include_str!("../README.md")] /*! */ #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] #![no_std] @@ -46,21 +46,6 @@ ) )] -/// We need some sort of "[`String`]" for errors in `no_alloc`... -/// We can only support `'static` without allocator, so let's do that. -#[cfg(not(feature = "alloc"))] -type String = &'static str; - -/// A simple non-allocating "format" string wrapper for no-std. -/// -/// Problem is that we really need a non-allocating format... -/// This one simply returns the `fmt` string. -/// Good enough for simple errors, for anything else, use the `alloc` feature. -#[cfg(not(feature = "alloc"))] -macro_rules! format { - ($fmt:literal) => {{ $fmt }}; -} - #[cfg(feature = "std")] #[macro_use] extern crate std; @@ -69,13 +54,10 @@ extern crate std; #[doc(hidden)] pub extern crate alloc; -#[cfg(feature = "ctor")] -#[doc(hidden)] -pub use ctor; -#[cfg(feature = "alloc")] -pub mod anymap; #[cfg(feature = "std")] -pub mod build_id; +pub use build_id2 as build_id; +#[cfg(feature = "alloc")] +pub use serde_anymap::anymap; #[cfg(all( any(feature = "cli", feature = "frida_cli", feature = "qemu_cli"), feature = "std" @@ -84,29 +66,21 @@ pub mod cli; #[cfg(feature = "gzip")] pub mod compress; #[cfg(feature = "std")] -pub mod core_affinity; -pub mod cpu; +pub use core_affinity2 as core_affinity; #[cfg(feature = "std")] pub mod fs; #[cfg(feature = "alloc")] -pub mod llmp; +pub use ll_mp as llmp; pub mod math; #[cfg(feature = "std")] -pub mod minibsod; +pub use minibsod; pub mod os; #[cfg(feature = "alloc")] -pub mod ownedref; -pub mod rands; -#[cfg(feature = "alloc")] -pub mod serdeany; -pub mod shmem; +pub use serde_anymap::serdeany; #[cfg(feature = "std")] pub mod staterestore; -#[cfg(feature = "alloc")] -pub mod subrange; -// TODO: reenable once ahash works in no-alloc #[cfg(any(feature = "xxh3", feature = "alloc"))] -pub mod tuples; +pub use tuple_list_ex as tuples; #[cfg(all(feature = "std", unix))] pub mod argparse; @@ -115,6 +89,17 @@ pub use argparse::*; #[cfg(feature = "std")] pub mod target_args; +pub use fast_rands as rands; +pub use libafl_core::{ + AsIter, AsIterMut, AsSlice, AsSliceMut, ClientId, Error, HasLen, HasRefCnt, Named, Truncate, +}; +#[cfg(feature = "alloc")] +pub use no_std_time::format_duration; +pub use no_std_time::{current_milliseconds, current_nanos, current_time}; +pub use ownedref::{self, subrange}; +#[cfg(feature = "alloc")] +pub use serde_anymap::impl_serdeany; +pub use shmem_providers as shmem; #[cfg(feature = "std")] pub use target_args::*; @@ -138,25 +123,25 @@ pub mod bolts_prelude { pub use super::fs::*; #[cfg(all(feature = "std", unix))] pub use super::minibsod::*; + pub use super::os::*; #[cfg(feature = "std")] pub use super::staterestore::*; #[cfg(feature = "alloc")] pub use super::{anymap::*, llmp::*, ownedref::*, rands::*, serdeany::*, shmem::*, tuples::*}; - pub use super::{cpu::*, os::*}; } #[cfg(all(unix, feature = "std"))] use alloc::boxed::Box; #[cfg(feature = "alloc")] -use alloc::{borrow::Cow, string::ToString, vec::Vec}; +use alloc::string::String; +#[cfg(feature = "alloc")] +use alloc::string::ToString; #[cfg(all(not(feature = "xxh3"), feature = "alloc"))] use core::hash::BuildHasher; #[cfg(any(feature = "xxh3", feature = "alloc"))] use core::hash::{Hash, Hasher}; #[cfg(all(unix, feature = "std"))] use core::mem; -#[cfg(feature = "std")] -use std::time::{SystemTime, UNIX_EPOCH}; #[cfg(all(unix, feature = "std"))] use std::{ fs::File, @@ -169,76 +154,12 @@ use std::{ // TODO: re-enable once is resolved. #[cfg(all(not(feature = "xxh3"), feature = "alloc"))] use ahash::RandomState; -use log::SetLoggerError; -use serde::{Deserialize, Serialize}; -#[cfg(feature = "xxh3")] -use xxhash_rust::xxh3::xxh3_64; - -/// The client ID == the sender id. -#[repr(transparent)] -#[derive( - Debug, Default, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, -)] -pub struct ClientId(pub u32); - -use core::{ - array::TryFromSliceError, - fmt::{self, Display}, - num::{ParseIntError, TryFromIntError}, - ops::{Deref, DerefMut}, - time, -}; -#[cfg(feature = "std")] -use std::{env::VarError, io}; - #[cfg(feature = "libafl_derive")] pub use libafl_derive::SerdeAny; #[cfg(feature = "std")] use log::{Metadata, Record}; -#[cfg(feature = "alloc")] -use { - alloc::string::{FromUtf8Error, String}, - core::cell::{BorrowError, BorrowMutError}, - core::str::Utf8Error, -}; - -/// Localhost addr, this is used, for example, for LLMP Client, which connects to this address -pub const IP_LOCALHOST: &str = "127.0.0.1"; - -/// We need fixed names for many parts of this lib. -#[cfg(feature = "alloc")] -pub trait Named { - /// Provide the name of this element. - fn name(&self) -> &Cow<'static, str>; -} - -#[cfg(feature = "errors_backtrace")] -/// Error Backtrace type when `errors_backtrace` feature is enabled (== [`backtrace::Backtrace`]) -pub type ErrorBacktrace = backtrace::Backtrace; - -#[cfg(not(feature = "errors_backtrace"))] -#[derive(Debug, Default)] -/// ZST to use when `errors_backtrace` is disabled -pub struct ErrorBacktrace; - -#[cfg(not(feature = "errors_backtrace"))] -impl ErrorBacktrace { - /// Nop - #[must_use] - pub fn new() -> Self { - Self - } -} - -#[cfg(feature = "errors_backtrace")] -fn display_error_backtrace(f: &mut fmt::Formatter, err: &ErrorBacktrace) -> fmt::Result { - write!(f, "\nBacktrace: {err:?}") -} -#[cfg(not(feature = "errors_backtrace"))] -#[expect(clippy::unnecessary_wraps)] -fn display_error_backtrace(_f: &mut fmt::Formatter, _err: &ErrorBacktrace) -> fmt::Result { - fmt::Result::Ok(()) -} +#[cfg(feature = "xxh3")] +use xxhash_rust::xxh3::xxh3_64; /// Returns the standard input [`Hasher`] /// @@ -300,418 +221,6 @@ pub fn generic_hash_std(input: &I) -> u64 { hasher.finish() } -/// Main error struct for `LibAFL` -#[derive(Debug)] -pub enum Error { - /// Serialization error - Serialize(String, ErrorBacktrace), - /// Compression error - #[cfg(feature = "gzip")] - Compression(ErrorBacktrace), - /// Optional val was supposed to be set, but isn't. - EmptyOptional(String, ErrorBacktrace), - /// Key not in Map - KeyNotFound(String, ErrorBacktrace), - /// Key already exists and should not overwrite - KeyExists(String, ErrorBacktrace), - /// No elements in the current item - Empty(String, ErrorBacktrace), - /// End of iteration - IteratorEnd(String, ErrorBacktrace), - /// This is not supported (yet) - NotImplemented(String, ErrorBacktrace), - /// You're holding it wrong - IllegalState(String, ErrorBacktrace), - /// The argument passed to this method or function is not valid - IllegalArgument(String, ErrorBacktrace), - /// The performed action is not supported on the current platform - Unsupported(String, ErrorBacktrace), - /// Shutting down, not really an error. - ShuttingDown, - /// OS error, wrapping a [`io::Error`] - #[cfg(feature = "std")] - OsError(io::Error, String, ErrorBacktrace), - /// Something else happened - Unknown(String, ErrorBacktrace), - /// Error with the corpora - InvalidCorpus(String, ErrorBacktrace), - /// Error specific to a runtime like QEMU or Frida - Runtime(String, ErrorBacktrace), - /// The `Input` was invalid. - InvalidInput(String, ErrorBacktrace), -} - -impl Error { - /// Serialization error - #[must_use] - pub fn serialize(arg: S) -> Self - where - S: Into, - { - Error::Serialize(arg.into(), ErrorBacktrace::new()) - } - - #[cfg(feature = "gzip")] - /// Compression error - #[must_use] - pub fn compression() -> Self { - Error::Compression(ErrorBacktrace::new()) - } - - /// Optional val was supposed to be set, but isn't. - #[must_use] - pub fn empty_optional(arg: S) -> Self - where - S: Into, - { - Error::EmptyOptional(arg.into(), ErrorBacktrace::new()) - } - - /// The `Input` was invalid - #[must_use] - pub fn invalid_input(reason: S) -> Self - where - S: Into, - { - Error::InvalidInput(reason.into(), ErrorBacktrace::new()) - } - - /// Key not in Map - #[must_use] - pub fn key_not_found(arg: S) -> Self - where - S: Into, - { - Error::KeyNotFound(arg.into(), ErrorBacktrace::new()) - } - - /// Key already exists in Map - #[must_use] - pub fn key_exists(arg: S) -> Self - where - S: Into, - { - Error::KeyExists(arg.into(), ErrorBacktrace::new()) - } - - /// No elements in the current item - #[must_use] - pub fn empty(arg: S) -> Self - where - S: Into, - { - Error::Empty(arg.into(), ErrorBacktrace::new()) - } - - /// End of iteration - #[must_use] - pub fn iterator_end(arg: S) -> Self - where - S: Into, - { - Error::IteratorEnd(arg.into(), ErrorBacktrace::new()) - } - - /// This is not supported (yet) - #[must_use] - pub fn not_implemented(arg: S) -> Self - where - S: Into, - { - Error::NotImplemented(arg.into(), ErrorBacktrace::new()) - } - - /// You're holding it wrong - #[must_use] - pub fn illegal_state(arg: S) -> Self - where - S: Into, - { - Error::IllegalState(arg.into(), ErrorBacktrace::new()) - } - - /// The argument passed to this method or function is not valid - #[must_use] - pub fn illegal_argument(arg: S) -> Self - where - S: Into, - { - Error::IllegalArgument(arg.into(), ErrorBacktrace::new()) - } - - /// Shutting down, not really an error. - #[must_use] - pub fn shutting_down() -> Self { - Error::ShuttingDown - } - - /// This operation is not supported on the current architecture or platform - #[must_use] - pub fn unsupported(arg: S) -> Self - where - S: Into, - { - Error::Unsupported(arg.into(), ErrorBacktrace::new()) - } - - /// OS error with additional message - #[cfg(feature = "std")] - #[must_use] - pub fn os_error(err: io::Error, msg: S) -> Self - where - S: Into, - { - Error::OsError(err, msg.into(), ErrorBacktrace::new()) - } - - /// OS error from [`io::Error::last_os_error`] with additional message - #[cfg(feature = "std")] - #[must_use] - pub fn last_os_error(msg: S) -> Self - where - S: Into, - { - Error::OsError( - io::Error::last_os_error(), - msg.into(), - ErrorBacktrace::new(), - ) - } - - /// Something else happened - #[must_use] - pub fn unknown(arg: S) -> Self - where - S: Into, - { - Error::Unknown(arg.into(), ErrorBacktrace::new()) - } - - /// Error with corpora - #[must_use] - pub fn invalid_corpus(arg: S) -> Self - where - S: Into, - { - Error::InvalidCorpus(arg.into(), ErrorBacktrace::new()) - } - - /// Error specific to some runtime, like QEMU or Frida - #[must_use] - pub fn runtime(arg: S) -> Self - where - S: Into, - { - Error::Runtime(arg.into(), ErrorBacktrace::new()) - } -} - -impl core::error::Error for Error { - #[cfg(feature = "std")] - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - if let Self::OsError(err, _, _) = self { - Some(err) - } else { - None - } - } -} - -impl Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Serialize(s, b) => { - write!(f, "Error in Serialization: `{0}`", &s)?; - display_error_backtrace(f, b) - } - #[cfg(feature = "gzip")] - Self::Compression(b) => { - write!(f, "Error in decompression")?; - display_error_backtrace(f, b) - } - Self::EmptyOptional(s, b) => { - write!(f, "Optional value `{0}` was not set", &s)?; - display_error_backtrace(f, b) - } - Self::KeyNotFound(s, b) => { - write!(f, "Key: `{0}` - not found", &s)?; - display_error_backtrace(f, b) - } - Self::KeyExists(s, b) => { - write!(f, "Key: `{0}` - already exists", &s)?; - display_error_backtrace(f, b) - } - Self::Empty(s, b) => { - write!(f, "No items in {0}", &s)?; - display_error_backtrace(f, b) - } - Self::IteratorEnd(s, b) => { - write!(f, "All elements have been processed in {0} iterator", &s)?; - display_error_backtrace(f, b) - } - Self::NotImplemented(s, b) => { - write!(f, "Not implemented: {0}", &s)?; - display_error_backtrace(f, b) - } - Self::IllegalState(s, b) => { - write!(f, "Illegal state: {0}", &s)?; - display_error_backtrace(f, b) - } - Self::IllegalArgument(s, b) => { - write!(f, "Illegal argument: {0}", &s)?; - display_error_backtrace(f, b) - } - Self::Unsupported(s, b) => { - write!( - f, - "The operation is not supported on the current platform: {0}", - &s - )?; - display_error_backtrace(f, b) - } - Self::ShuttingDown => write!(f, "Shutting down!"), - #[cfg(feature = "std")] - Self::OsError(err, s, b) => { - write!(f, "OS error: {0}: {1}", &s, err)?; - display_error_backtrace(f, b) - } - Self::Unknown(s, b) => { - write!(f, "Unknown error: {0}", &s)?; - display_error_backtrace(f, b) - } - Self::InvalidCorpus(s, b) => { - write!(f, "Invalid corpus: {0}", &s)?; - display_error_backtrace(f, b) - } - Self::Runtime(s, b) => { - write!(f, "Runtime error: {0}", &s)?; - display_error_backtrace(f, b) - } - Self::InvalidInput(s, b) => { - write!(f, "Encountered an invalid input: {0}", &s)?; - display_error_backtrace(f, b) - } - } - } -} - -#[cfg(feature = "alloc")] -impl From for Error { - fn from(err: BorrowError) -> Self { - Self::illegal_state(format!( - "Couldn't borrow from a RefCell as immutable: {err:?}" - )) - } -} - -#[cfg(feature = "alloc")] -impl From for Error { - fn from(err: BorrowMutError) -> Self { - Self::illegal_state(format!( - "Couldn't borrow from a RefCell as mutable: {err:?}" - )) - } -} - -/// Stringify the postcard serializer error -#[cfg(feature = "alloc")] -impl From for Error { - fn from(err: postcard::Error) -> Self { - Self::serialize(format!("{err:?}")) - } -} - -#[cfg(all(unix, feature = "std"))] -impl From for Error { - fn from(err: nix::Error) -> Self { - Self::unknown(format!("Unix error: {err:?}")) - } -} - -/// Create an AFL Error from io Error -#[cfg(feature = "std")] -impl From for Error { - fn from(err: io::Error) -> Self { - Self::os_error(err, "io::Error ocurred") - } -} - -#[cfg(feature = "alloc")] -impl From for Error { - fn from(err: FromUtf8Error) -> Self { - Self::unknown(format!("Could not convert byte / utf-8: {err:?}")) - } -} - -#[cfg(feature = "alloc")] -impl From for Error { - fn from(err: Utf8Error) -> Self { - Self::unknown(format!("Could not convert byte / utf-8: {err:?}")) - } -} - -#[cfg(feature = "std")] -impl From for Error { - fn from(err: VarError) -> Self { - Self::empty(format!("Could not get env var: {err:?}")) - } -} - -impl From for Error { - #[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)] // 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)] // 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)] // err is unused without std - fn from(err: SetLoggerError) -> Self { - Self::illegal_state(format!("Failed to register logger: {err:?}")) - } -} - -#[cfg(windows)] -impl From for Error { - #[allow(unused_variables)] // err is unused without std - fn from(err: windows_result::Error) -> Self { - Self::unknown(format!("Windows API error: {err:?}")) - } -} - -#[cfg(feature = "python")] -impl From for Error { - fn from(err: pyo3::PyErr) -> Self { - pyo3::Python::attach(|py| { - if err - .matches( - py, - pyo3::types::PyType::new::(py), - ) - .unwrap() - { - Self::shutting_down() - } else { - Self::illegal_state(format!("Python exception: {err:?}")) - } - }) - } -} - /// The purpose of this module is to alleviate imports of many components by adding a glob import. #[cfg(feature = "prelude")] pub mod prelude { @@ -720,278 +229,6 @@ pub mod prelude { pub use super::{bolts_prelude::*, *}; } -#[cfg(all(any(doctest, test), not(feature = "std")))] -/// Provide custom time in `no_std` tests. -#[unsafe(no_mangle)] -pub unsafe extern "C" fn external_current_millis() -> u64 { - // TODO: use "real" time here - 1000 -} - -/// Trait to convert into an Owned type -pub trait IntoOwned { - /// Returns if the current type is an owned type. - #[must_use] - fn is_owned(&self) -> bool; - - /// Transfer the current type into an owned type. - #[must_use] - fn into_owned(self) -> Self; -} - -/// Can be converted to a slice -pub trait AsSlice<'a> { - /// Type of the entries of this slice - type Entry: 'a; - /// Type of the reference to this slice - type SliceRef: Deref; - - /// Convert to a slice - fn as_slice(&'a self) -> Self::SliceRef; -} - -/// Can be converted to a slice -pub trait AsSizedSlice<'a, const N: usize> { - /// Type of the entries of this slice - type Entry: 'a; - /// Type of the reference to this slice - type SliceRef: Deref; - - /// Convert to a slice - fn as_sized_slice(&'a self) -> Self::SliceRef; -} - -impl<'a, T, R: ?Sized> AsSlice<'a> for R -where - T: 'a, - R: Deref, -{ - type Entry = T; - type SliceRef = &'a [T]; - - fn as_slice(&'a self) -> Self::SliceRef { - self - } -} - -impl<'a, T, const N: usize, R: ?Sized> AsSizedSlice<'a, N> for R -where - T: 'a, - R: Deref, -{ - type Entry = T; - type SliceRef = &'a [T; N]; - - fn as_sized_slice(&'a self) -> Self::SliceRef { - self - } -} - -/// Can be converted to a mutable slice -pub trait AsSliceMut<'a>: AsSlice<'a> { - /// Type of the mutable reference to this slice - type SliceRefMut: DerefMut; - - /// Convert to a slice - fn as_slice_mut(&'a mut self) -> Self::SliceRefMut; -} - -/// Can be converted to a mutable slice -pub trait AsSizedSliceMut<'a, const N: usize>: AsSizedSlice<'a, N> { - /// Type of the mutable reference to this slice - type SliceRefMut: DerefMut; - - /// Convert to a slice - fn as_sized_slice_mut(&'a mut self) -> Self::SliceRefMut; -} - -impl<'a, T, R: ?Sized> AsSliceMut<'a> for R -where - T: 'a, - R: DerefMut, -{ - type SliceRefMut = &'a mut [T]; - - fn as_slice_mut(&'a mut self) -> Self::SliceRefMut { - &mut *self - } -} - -impl<'a, T, const N: usize, R: ?Sized> AsSizedSliceMut<'a, N> for R -where - T: 'a, - R: DerefMut, -{ - type SliceRefMut = &'a mut [T; N]; - - fn as_sized_slice_mut(&'a mut self) -> Self::SliceRefMut { - &mut *self - } -} - -/// Create an `Iterator` from a reference -pub trait AsIter<'it> { - /// The item type - type Item: 'it; - /// The ref type - type Ref: Deref; - /// The iterator type - type IntoIter: Iterator; - - /// Create an iterator from &self - fn as_iter(&'it self) -> Self::IntoIter; -} - -impl<'it, S, T> AsIter<'it> for S -where - S: AsSlice<'it, Entry = T, SliceRef = &'it [T]>, - T: 'it, -{ - type Item = S::Entry; - type Ref = &'it Self::Item; - type IntoIter = core::slice::Iter<'it, Self::Item>; - - fn as_iter(&'it self) -> Self::IntoIter { - self.as_slice().iter() - } -} - -/// Create an `Iterator` from a mutable reference -pub trait AsIterMut<'it>: AsIter<'it> { - /// The ref type - type RefMut: DerefMut; - /// The iterator type - type IntoIterMut: Iterator; - - /// Create an iterator from &mut self - fn as_iter_mut(&'it mut self) -> Self::IntoIterMut; -} - -impl<'it, S, T> AsIterMut<'it> for S -where - S: AsSliceMut<'it, Entry = T, SliceRef = &'it [T], SliceRefMut = &'it mut [T]>, - T: 'it, -{ - type RefMut = &'it mut Self::Item; - type IntoIterMut = core::slice::IterMut<'it, Self::Item>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { - self.as_slice_mut().iter_mut() - } -} - -/// Has a length field -pub trait HasLen { - /// The length - fn len(&self) -> usize; - - /// Returns `true` if it has no elements. - fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -#[cfg(feature = "alloc")] -impl HasLen for Vec { - #[inline] - fn len(&self) -> usize { - Vec::::len(self) - } -} - -impl HasLen for &mut T { - fn len(&self) -> usize { - self.deref().len() - } -} - -/// Has a ref count -pub trait HasRefCnt { - /// The ref count - fn refcnt(&self) -> isize; - /// The ref count, mutable - fn refcnt_mut(&mut self) -> &mut isize; -} - -/// Trait to truncate slices and maps to a new size -pub trait Truncate { - /// Reduce the size of the slice - fn truncate(&mut self, len: usize); -} - -/// Current time -#[cfg(feature = "std")] -#[must_use] -#[inline] -pub fn current_time() -> time::Duration { - SystemTime::now().duration_since(UNIX_EPOCH).unwrap() -} - -// external defined function in case of `no_std` -// -// Define your own `external_current_millis()` function via `extern "C"` -// which is linked into the binary and called from here. -#[cfg(all(not(any(doctest, test)), not(feature = "std")))] -unsafe extern "C" { - //#[unsafe(no_mangle)] - fn external_current_millis() -> u64; -} - -/// Current time (fixed fallback for `no_std`) -#[cfg(not(feature = "std"))] -#[inline] -#[must_use] -pub fn current_time() -> time::Duration { - let millis = unsafe { external_current_millis() }; - time::Duration::from_millis(millis) -} - -/// Gets current nanoseconds since [`UNIX_EPOCH`] -#[must_use] -#[inline] -pub fn current_nanos() -> u64 { - current_time().as_nanos() as u64 -} - -/// Gets current milliseconds since [`UNIX_EPOCH`] -#[must_use] -#[inline] -pub fn current_milliseconds() -> u64 { - current_time().as_millis() as u64 -} - -/// Format a `Duration` into a HMS string -#[cfg(feature = "alloc")] -#[must_use] -pub fn format_duration(duration: &time::Duration) -> String { - const MINS_PER_HOUR: u64 = 60; - const HOURS_PER_DAY: u64 = 24; - - const SECS_PER_MINUTE: u64 = 60; - const SECS_PER_HOUR: u64 = SECS_PER_MINUTE * MINS_PER_HOUR; - const SECS_PER_DAY: u64 = SECS_PER_HOUR * HOURS_PER_DAY; - - let total_secs = duration.as_secs(); - let secs = total_secs % SECS_PER_MINUTE; - - if total_secs < SECS_PER_MINUTE { - format!("{secs}s") - } else { - let mins = (total_secs / SECS_PER_MINUTE) % MINS_PER_HOUR; - if total_secs < SECS_PER_HOUR { - format!("{mins}m-{secs}s") - } else { - let hours = (total_secs / SECS_PER_HOUR) % HOURS_PER_DAY; - if total_secs < SECS_PER_DAY { - format!("{hours}h-{mins}m-{secs}s") - } else { - let days = total_secs / SECS_PER_DAY; - format!("{days}days {hours}h-{mins}m-{secs}s") - } - } - } -} - /// Format a number with thousands separators #[cfg(feature = "alloc")] #[must_use] @@ -1065,8 +302,8 @@ impl SimpleStdoutLogger { /// register stdout logger pub fn set_logger() -> Result<(), Error> { - log::set_logger(&LIBAFL_STDOUT_LOGGER)?; - Ok(()) + log::set_logger(&LIBAFL_STDOUT_LOGGER) + .map_err(|err| Error::illegal_state(format!("Failed to set logger: {err:?}"))) } } @@ -1118,8 +355,8 @@ pub fn get_thread_id() -> u64 { #[cfg(target_os = "windows")] mod windows_logging { use core::ptr; + use std::cell::OnceCell; - use once_cell::sync::OnceCell; use winapi::um::{ fileapi::WriteFile, handleapi::INVALID_HANDLE_VALUE, processenv::GetStdHandle, winbase::STD_OUTPUT_HANDLE, winnt::HANDLE, @@ -1231,8 +468,8 @@ impl SimpleStderrLogger { /// register stderr logger pub fn set_logger() -> Result<(), Error> { - log::set_logger(&LIBAFL_STDERR_LOGGER)?; - Ok(()) + log::set_logger(&LIBAFL_STDERR_LOGGER) + .map_err(|err| Error::illegal_state(format!("Could not set logger: {err:?}"))) } } @@ -1295,9 +532,9 @@ impl SimpleFdLogger { unsafe { let logger = &mut *logger; logger.set_fd(log_fd); - log::set_logger(logger)?; + log::set_logger(logger) + .map_err(|err| Error::illegal_state(format!("Could not set logger: {err:?}"))) } - Ok(()) } } @@ -1466,39 +703,6 @@ pub mod pybind { }; } - #[macro_export] - macro_rules! unwrap_me_mut_body { - ($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),*}) => { - match &mut $wrapper { - $( - $wrapper_type::$wrapper_option(py_wrapper) => { - Python::attach(|py| -> PyResult<_> { - let mut borrowed = py_wrapper.borrow_mut(py); - let $name = &mut borrowed.inner; - Ok($body) - }) - .unwrap() - } - )* - } - }; - ($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),*}, { $($wrapper_optional:tt($pw:ident) => $code_block:block)* }) => { - match &mut $wrapper { - $( - $wrapper_type::$wrapper_option(py_wrapper) => { - Python::with_gil(|py| -> PyResult<_> { - let mut borrowed = py_wrapper.borrow_mut(py); - let $name = &mut borrowed.inner; - Ok($body) - }) - .unwrap() - } - )* - $($wrapper_type::$wrapper_optional($pw) => { $code_block })* - } - }; - } - #[macro_export] macro_rules! impl_serde_pyobjectwrapper { ($struct_name:ident, $inner:tt) => { @@ -1569,29 +773,6 @@ pub mod pybind { } } -/// Create a [`Vec`] of the given type with `nb_elts` elements, initialized in place. -/// The closure must initialize [`Vec`] (of size `nb_elts` * `sizeo_of::()`). -/// -/// # Safety -/// -/// The input closure should fully initialize the new [`Vec`], not leaving any uninitialized bytes. -// TODO: Use MaybeUninit API at some point. -#[cfg(feature = "alloc")] -#[expect(clippy::uninit_vec)] -pub unsafe fn vec_init(nb_elts: usize, init_fn: F) -> Result, E> -where - F: FnOnce(&mut Vec) -> Result<(), E>, -{ - unsafe { - let mut new_vec: Vec = Vec::with_capacity(nb_elts); - new_vec.set_len(nb_elts); - - init_fn(&mut new_vec)?; - - Ok(new_vec) - } -} - #[cfg(test)] mod tests { diff --git a/crates/libafl_bolts/src/math.rs b/crates/libafl_bolts/src/math.rs index f9ac732a132..2755335d127 100644 --- a/crates/libafl_bolts/src/math.rs +++ b/crates/libafl_bolts/src/math.rs @@ -2,7 +2,7 @@ use core::ops::AddAssign; -use crate::Error; +use libafl_core::{Error, format}; /// Returns the cumulative distribution function for a discrete distribution. pub fn calculate_cumulative_distribution_in_place(probabilities: &mut [f32]) -> Result<(), Error> { diff --git a/crates/libafl_bolts/src/os/mod.rs b/crates/libafl_bolts/src/os.rs similarity index 96% rename from crates/libafl_bolts/src/os/mod.rs rename to crates/libafl_bolts/src/os.rs index 64f37c3c9e0..ca44c34966b 100644 --- a/crates/libafl_bolts/src/os/mod.rs +++ b/crates/libafl_bolts/src/os.rs @@ -1,19 +1,5 @@ //! Operating System specific abstractions -#[cfg(any(unix, all(windows, feature = "std")))] -use crate::Error; - -#[cfg(all(unix, feature = "std"))] -pub mod unix_shmem_server; - -#[cfg(unix)] -pub mod unix_signals; -#[cfg(unix)] -pub use unix_signals::CTRL_C_EXIT; - -#[cfg(all(unix, feature = "alloc"))] -pub mod pipes; - #[cfg(all(unix, feature = "std"))] use alloc::{borrow::Cow, ffi::CString}; #[cfg(all(unix, feature = "std"))] @@ -29,15 +15,25 @@ use std::{ sync::OnceLock, }; +#[cfg(unix)] +pub use exceptional::unix_signals; +#[cfg(unix)] +pub use exceptional::unix_signals::CTRL_C_EXIT; +#[cfg(windows)] +pub use exceptional::windows_exceptions; +#[cfg(unix)] +use libafl_core::format; // Allow a few extra features we need for the whole module -#[cfg(all(windows, feature = "std"))] -#[expect(missing_docs, overflowing_literals)] -pub mod windows_exceptions; #[cfg(unix)] use libc::pid_t; +#[cfg(all(unix, feature = "std"))] +pub use shmem_providers::pipes; #[cfg(all(windows, feature = "std"))] pub use windows_exceptions::CTRL_C_EXIT; +#[cfg(any(unix, all(windows, feature = "std")))] +use crate::Error; + /// A file that we keep open, pointing to /dev/null #[cfg(all(feature = "std", unix))] static NULL_FILE: OnceLock = OnceLock::new(); diff --git a/crates/libafl_bolts/src/simd.rs b/crates/libafl_bolts/src/simd.rs index dddec96b1ca..ff760ce812a 100644 --- a/crates/libafl_bolts/src/simd.rs +++ b/crates/libafl_bolts/src/simd.rs @@ -131,7 +131,7 @@ where } } -/// Unforunately we have to keep this type due to [`wide`] might not `PartialOrd` +/// Unfortunately we have to keep this type due to [`wide`] might not `PartialOrd` #[cfg(feature = "wide")] #[derive(Debug)] pub struct SimdMinReducer; diff --git a/crates/libafl_bolts/src/staterestore.rs b/crates/libafl_bolts/src/staterestore.rs index c75b2772eb6..76e71d22d98 100644 --- a/crates/libafl_bolts/src/staterestore.rs +++ b/crates/libafl_bolts/src/staterestore.rs @@ -17,12 +17,10 @@ use std::{ }; use ahash::RandomState; +use libafl_core::{AsSlice, Error}; use serde::{Serialize, de::DeserializeOwned}; -use crate::{ - AsSlice, Error, - shmem::{ShMem, ShMemProvider}, -}; +use crate::shmem::{ShMem, ShMemProvider}; /// If the saved page content equals exactly this buf, the restarted child wants to exit cleanly. const EXITING_MAGIC: &[u8; 16] = b"LIBAFL_EXIT_NOW\0"; diff --git a/crates/libafl_cc/src/lib.rs b/crates/libafl_cc/src/lib.rs index 767a005df5f..2d8adadaa1c 100644 --- a/crates/libafl_cc/src/lib.rs +++ b/crates/libafl_cc/src/lib.rs @@ -1,4 +1,6 @@ //! Compiler Wrapper from `LibAFL` +#![doc = include_str!("../README.md")] +/*! */ #![cfg_attr(not(test), warn( missing_debug_implementations, diff --git a/crates/libafl_core/Cargo.toml b/crates/libafl_core/Cargo.toml new file mode 100644 index 00000000000..42da2a360f0 --- /dev/null +++ b/crates/libafl_core/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "libafl_core" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "A platform-independent shared memory library for Rust" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = [] +document-features = ["dep:document-features"] +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["alloc"] + +## Enables all features that allocate in `no_std` +alloc = [] + +## Stores the backtraces of all generated `Error`s. Good for debugging, but may come with a slight performance hit. +errors_backtrace = ["std", "dep:backtrace"] + +## Enable python error conversion +python = ["dep:pyo3"] + +## Enables nix error conversion +nix = ["dep:nix"] + +## Enables postcard error conversion +postcard = ["dep:postcard"] + +## Enables Serde support for some types +serde = ["dep:serde", "alloc"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +document-features = { workspace = true, optional = true } +backtrace = { workspace = true, default-features = true, optional = true } +postcard = { workspace = true, optional = true } +nix = { workspace = true, optional = true } +pyo3 = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive", "alloc"], optional = true } + +[target.'cfg(windows)'.dependencies] +windows-result = "0.4.1" + + +[lints] +workspace = true diff --git a/crates/libafl_core/LICENSE-APACHE b/crates/libafl_core/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/libafl_core/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/libafl_core/LICENSE-MIT b/crates/libafl_core/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/libafl_core/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/libafl_core/README.md b/crates/libafl_core/README.md new file mode 100644 index 00000000000..40dda6b538b --- /dev/null +++ b/crates/libafl_core/README.md @@ -0,0 +1,51 @@ +# `LibAFL_core`: Minimal set of core functions shared between `LibAFL` crates + + LibAFL logo + +The `libafl_core` crate has a range of useful functions shared across the [`LibAFL`](https://github.com/AFLplusplus/LibAFL) codebase. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_core/src/lib.rs b/crates/libafl_core/src/lib.rs new file mode 100644 index 00000000000..955a38f6bf4 --- /dev/null +++ b/crates/libafl_core/src/lib.rs @@ -0,0 +1,834 @@ +/*! + * `LibAFL_core` contains core traits used across all crates, including the [`Error`] enum and various traits. + */ +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +/// We need some sort of "[`String`]" for errors in `no_alloc`... +/// We can only support `'static` without allocator, so let's do that. +#[cfg(not(feature = "alloc"))] +type String = &'static str; + +/// A simple non-allocating "format" string wrapper for no-std. +/// +/// Problem is that we really need a non-allocating format... +/// This one simply returns the `fmt` string. +/// Good enough for simple errors, for anything else, use the `alloc` feature. +#[macro_export] +#[cfg(not(feature = "alloc"))] +macro_rules! format { + ($fmt:literal) => {{ $fmt }}; + ($fmt:literal, $($arg:tt)*) => {{ $fmt }}; +} +/// Re-export of the "format" macro +#[cfg(feature = "alloc")] +pub use alloc::{borrow::Cow, format}; + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[cfg(feature = "alloc")] +#[doc(hidden)] +pub extern crate alloc; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use core::{ + array::TryFromSliceError, + fmt::{self, Display}, + num::{ParseIntError, TryFromIntError}, + ops::{Deref, DerefMut}, +}; +#[cfg(feature = "std")] +use std::{env::VarError, io}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "alloc")] +use { + alloc::string::{FromUtf8Error, String}, + core::cell::{BorrowError, BorrowMutError}, + core::str::Utf8Error, +}; + +/// Localhost addr, this is used, for example, for LLMP Client, which connects to this address +pub const IP_LOCALHOST: &str = "127.0.0.1"; + +/// The client ID for various use cases across `LibAFL` +#[repr(transparent)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ClientId(pub u32); + +#[cfg(feature = "errors_backtrace")] +/// Error Backtrace type when `errors_backtrace` feature is enabled (== [`Backtrace`](std::backtrace::Backtrace`)) +pub type ErrorBacktrace = std::backtrace::Backtrace; + +#[cfg(not(feature = "errors_backtrace"))] +#[derive(Debug, Default)] +/// ZST to use when `errors_backtrace` is disabled +pub struct ErrorBacktrace; + +#[cfg(not(feature = "errors_backtrace"))] +impl ErrorBacktrace { + /// Nop + #[must_use] + pub fn capture() -> Self { + Self + } +} + +#[cfg(feature = "errors_backtrace")] +fn display_error_backtrace(f: &mut fmt::Formatter, err: &ErrorBacktrace) -> fmt::Result { + write!(f, "\nBacktrace: {err:?}") +} +#[cfg(not(feature = "errors_backtrace"))] +#[expect(clippy::unnecessary_wraps)] +fn display_error_backtrace(_f: &mut fmt::Formatter, _err: &ErrorBacktrace) -> fmt::Result { + fmt::Result::Ok(()) +} + +/// Main error struct for `LibAFL` +#[derive(Debug)] +pub enum Error { + /// Serialization error + Serialize(String, ErrorBacktrace), + /// Compression error + Compression(ErrorBacktrace), + /// Optional val was supposed to be set, but isn't. + EmptyOptional(String, ErrorBacktrace), + /// Key not in Map + KeyNotFound(String, ErrorBacktrace), + /// Key already exists and should not overwrite + KeyExists(String, ErrorBacktrace), + /// No elements in the current item + Empty(String, ErrorBacktrace), + /// End of iteration + IteratorEnd(String, ErrorBacktrace), + /// This is not supported (yet) + NotImplemented(String, ErrorBacktrace), + /// You're holding it wrong + IllegalState(String, ErrorBacktrace), + /// The argument passed to this method or function is not valid + IllegalArgument(String, ErrorBacktrace), + /// The performed action is not supported on the current platform + Unsupported(String, ErrorBacktrace), + /// Shutting down, not really an error. + ShuttingDown, + /// OS error, wrapping a [`io::Error`] + #[cfg(feature = "std")] + OsError(io::Error, String, ErrorBacktrace), + /// Something else happened + Unknown(String, ErrorBacktrace), + /// Error with the corpora + InvalidCorpus(String, ErrorBacktrace), + /// Error specific to a runtime like QEMU or Frida + Runtime(String, ErrorBacktrace), + /// The `Input` was invalid. + InvalidInput(String, ErrorBacktrace), +} + +impl Error { + /// Serialization error + #[must_use] + pub fn serialize(arg: S) -> Self + where + S: Into, + { + Error::Serialize(arg.into(), ErrorBacktrace::capture()) + } + + /// Compression error + #[must_use] + pub fn compression() -> Self { + Error::Compression(ErrorBacktrace::capture()) + } + + /// Optional val was supposed to be set, but isn't. + #[must_use] + pub fn empty_optional(arg: S) -> Self + where + S: Into, + { + Error::EmptyOptional(arg.into(), ErrorBacktrace::capture()) + } + + /// The `Input` was invalid + #[must_use] + pub fn invalid_input(reason: S) -> Self + where + S: Into, + { + Error::InvalidInput(reason.into(), ErrorBacktrace::capture()) + } + + /// Key not in Map + #[must_use] + pub fn key_not_found(arg: S) -> Self + where + S: Into, + { + Error::KeyNotFound(arg.into(), ErrorBacktrace::capture()) + } + + /// Key already exists in Map + #[must_use] + pub fn key_exists(arg: S) -> Self + where + S: Into, + { + Error::KeyExists(arg.into(), ErrorBacktrace::capture()) + } + + /// No elements in the current item + #[must_use] + pub fn empty(arg: S) -> Self + where + S: Into, + { + Error::Empty(arg.into(), ErrorBacktrace::capture()) + } + + /// End of iteration + #[must_use] + pub fn iterator_end(arg: S) -> Self + where + S: Into, + { + Error::IteratorEnd(arg.into(), ErrorBacktrace::capture()) + } + + /// This is not supported (yet) + #[must_use] + pub fn not_implemented(arg: S) -> Self + where + S: Into, + { + Error::NotImplemented(arg.into(), ErrorBacktrace::capture()) + } + + /// You're holding it wrong + #[must_use] + pub fn illegal_state(arg: S) -> Self + where + S: Into, + { + Error::IllegalState(arg.into(), ErrorBacktrace::capture()) + } + + /// The argument passed to this method or function is not valid + #[must_use] + pub fn illegal_argument(arg: S) -> Self + where + S: Into, + { + Error::IllegalArgument(arg.into(), ErrorBacktrace::capture()) + } + + /// Shutting down, not really an error. + #[must_use] + pub fn shutting_down() -> Self { + Error::ShuttingDown + } + + /// This operation is not supported on the current architecture or platform + #[must_use] + pub fn unsupported(arg: S) -> Self + where + S: Into, + { + Error::Unsupported(arg.into(), ErrorBacktrace::capture()) + } + + /// OS error with additional message + #[cfg(feature = "std")] + #[must_use] + pub fn os_error(err: io::Error, msg: S) -> Self + where + S: Into, + { + Error::OsError(err, msg.into(), ErrorBacktrace::capture()) + } + + /// OS error from [`io::Error::last_os_error`] with additional message + #[cfg(feature = "std")] + #[must_use] + pub fn last_os_error(msg: S) -> Self + where + S: Into, + { + Error::OsError( + io::Error::last_os_error(), + msg.into(), + ErrorBacktrace::capture(), + ) + } + + /// Something else happened + #[must_use] + pub fn unknown(arg: S) -> Self + where + S: Into, + { + Error::Unknown(arg.into(), ErrorBacktrace::capture()) + } + + /// Error with corpora + #[must_use] + pub fn invalid_corpus(arg: S) -> Self + where + S: Into, + { + Error::InvalidCorpus(arg.into(), ErrorBacktrace::capture()) + } + + /// Error specific to some runtime, like QEMU or Frida + #[must_use] + pub fn runtime(arg: S) -> Self + where + S: Into, + { + Error::Runtime(arg.into(), ErrorBacktrace::capture()) + } +} + +impl core::error::Error for Error { + #[cfg(feature = "std")] + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + if let Self::OsError(err, _, _) = self { + Some(err) + } else { + None + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Serialize(s, b) => { + write!(f, "Error in Serialization: `{0}`", &s)?; + display_error_backtrace(f, b) + } + Self::Compression(b) => { + write!(f, "Error in decompression")?; + display_error_backtrace(f, b) + } + Self::EmptyOptional(s, b) => { + write!(f, "Optional value `{0}` was not set", &s)?; + display_error_backtrace(f, b) + } + Self::KeyNotFound(s, b) => { + write!(f, "Key: `{0}` - not found", &s)?; + display_error_backtrace(f, b) + } + Self::KeyExists(s, b) => { + write!(f, "Key: `{0}` - already exists", &s)?; + display_error_backtrace(f, b) + } + Self::Empty(s, b) => { + write!(f, "No items in {0}", &s)?; + display_error_backtrace(f, b) + } + Self::IteratorEnd(s, b) => { + write!(f, "All elements have been processed in {0} iterator", &s)?; + display_error_backtrace(f, b) + } + Self::NotImplemented(s, b) => { + write!(f, "Not implemented: {0}", &s)?; + display_error_backtrace(f, b) + } + Self::IllegalState(s, b) => { + write!(f, "Illegal state: {0}", &s)?; + display_error_backtrace(f, b) + } + Self::IllegalArgument(s, b) => { + write!(f, "Illegal argument: {0}", &s)?; + display_error_backtrace(f, b) + } + Self::Unsupported(s, b) => { + write!( + f, + "The operation is not supported on the current platform: {0}", + &s + )?; + display_error_backtrace(f, b) + } + Self::ShuttingDown => write!(f, "Shutting down!"), + #[cfg(feature = "std")] + Self::OsError(err, s, b) => { + write!(f, "OS error: {0}: {1}", &s, err)?; + display_error_backtrace(f, b) + } + Self::Unknown(s, b) => { + write!(f, "Unknown error: {0}", &s)?; + display_error_backtrace(f, b) + } + Self::InvalidCorpus(s, b) => { + write!(f, "Invalid corpus: {0}", &s)?; + display_error_backtrace(f, b) + } + Self::Runtime(s, b) => { + write!(f, "Runtime error: {0}", &s)?; + display_error_backtrace(f, b) + } + Self::InvalidInput(s, b) => { + write!(f, "Encountered an invalid input: {0}", &s)?; + display_error_backtrace(f, b) + } + } + } +} + +#[cfg(feature = "alloc")] +impl From for Error { + fn from(err: BorrowError) -> Self { + Self::illegal_state(format!( + "Couldn't borrow from a RefCell as immutable: {err:?}" + )) + } +} + +#[cfg(feature = "alloc")] +impl From for Error { + fn from(err: BorrowMutError) -> Self { + Self::illegal_state(format!( + "Couldn't borrow from a RefCell as mutable: {err:?}" + )) + } +} + +/// Stringify the postcard serializer error +#[cfg(all(feature = "alloc", feature = "postcard"))] +impl From for Error { + fn from(err: postcard::Error) -> Self { + Self::serialize(format!("{err:?}")) + } +} + +#[cfg(all(unix, feature = "std", feature = "nix"))] +impl From for Error { + fn from(err: nix::Error) -> Self { + Self::unknown(format!("Unix error: {err:?}")) + } +} + +/// Create an AFL Error from io Error +#[cfg(feature = "std")] +impl From for Error { + fn from(err: io::Error) -> Self { + Self::os_error(err, "io::Error ocurred") + } +} + +#[cfg(feature = "alloc")] +impl From for Error { + fn from(err: FromUtf8Error) -> Self { + Self::unknown(format!("Could not convert byte / utf-8: {err:?}")) + } +} + +#[cfg(feature = "alloc")] +impl From for Error { + fn from(err: Utf8Error) -> Self { + Self::unknown(format!("Could not convert byte / utf-8: {err:?}")) + } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(err: VarError) -> Self { + Self::empty(format!("Could not get env var: {err:?}")) + } +} + +impl From for Error { + #[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)] // 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)] // err is unused without std + fn from(err: TryFromSliceError) -> Self { + Self::illegal_argument(format!("Could not convert slice: {err:?}")) + } +} + +#[cfg(windows)] +impl From for Error { + #[allow(unused_variables)] // err is unused without std + fn from(err: windows_result::Error) -> Self { + Self::unknown(format!("Windows API error: {err:?}")) + } +} + +#[cfg(feature = "python")] +impl From for Error { + fn from(err: pyo3::PyErr) -> Self { + pyo3::Python::attach(|py| { + if err + .matches( + py, + pyo3::types::PyType::new::(py), + ) + .unwrap() + { + Self::shutting_down() + } else { + Self::illegal_state(format!("Python exception: {err:?}")) + } + }) + } +} + +/// Trait to convert into an Owned type +pub trait IntoOwned { + /// Returns if the current type is an owned type. + #[must_use] + fn is_owned(&self) -> bool; + + /// Transfer the current type into an owned type. + #[must_use] + fn into_owned(self) -> Self; +} + +/// Can be converted to a slice +pub trait AsSlice<'a> { + /// Type of the entries of this slice + type Entry: 'a; + /// Type of the reference to this slice + type SliceRef: Deref; + + /// Convert to a slice + fn as_slice(&'a self) -> Self::SliceRef; +} + +/// Can be converted to a slice +pub trait AsSizedSlice<'a, const N: usize> { + /// Type of the entries of this slice + type Entry: 'a; + /// Type of the reference to this slice + type SliceRef: Deref; + + /// Convert to a slice + fn as_sized_slice(&'a self) -> Self::SliceRef; +} + +impl<'a, T, R: ?Sized> AsSlice<'a> for R +where + T: 'a, + R: Deref, +{ + type Entry = T; + type SliceRef = &'a [T]; + + fn as_slice(&'a self) -> Self::SliceRef { + self + } +} + +impl<'a, T, const N: usize, R: ?Sized> AsSizedSlice<'a, N> for R +where + T: 'a, + R: Deref, +{ + type Entry = T; + type SliceRef = &'a [T; N]; + + fn as_sized_slice(&'a self) -> Self::SliceRef { + self + } +} + +/// Can be converted to a mutable slice +pub trait AsSliceMut<'a>: AsSlice<'a> { + /// Type of the mutable reference to this slice + type SliceRefMut: DerefMut; + + /// Convert to a slice + fn as_slice_mut(&'a mut self) -> Self::SliceRefMut; +} + +/// Can be converted to a mutable slice +pub trait AsSizedSliceMut<'a, const N: usize>: AsSizedSlice<'a, N> { + /// Type of the mutable reference to this slice + type SliceRefMut: DerefMut; + + /// Convert to a slice + fn as_sized_slice_mut(&'a mut self) -> Self::SliceRefMut; +} + +impl<'a, T, R: ?Sized> AsSliceMut<'a> for R +where + T: 'a, + R: DerefMut, +{ + type SliceRefMut = &'a mut [T]; + + fn as_slice_mut(&'a mut self) -> Self::SliceRefMut { + &mut *self + } +} + +impl<'a, T, const N: usize, R: ?Sized> AsSizedSliceMut<'a, N> for R +where + T: 'a, + R: DerefMut, +{ + type SliceRefMut = &'a mut [T; N]; + + fn as_sized_slice_mut(&'a mut self) -> Self::SliceRefMut { + &mut *self + } +} + +/// Create an `Iterator` from a reference +pub trait AsIter<'it> { + /// The item type + type Item: 'it; + /// The ref type + type Ref: Deref; + /// The iterator type + type IntoIter: Iterator; + + /// Create an iterator from &self + fn as_iter(&'it self) -> Self::IntoIter; +} + +impl<'it, S, T> AsIter<'it> for S +where + S: AsSlice<'it, Entry = T, SliceRef = &'it [T]>, + T: 'it, +{ + type Item = S::Entry; + type Ref = &'it Self::Item; + type IntoIter = core::slice::Iter<'it, Self::Item>; + + fn as_iter(&'it self) -> Self::IntoIter { + self.as_slice().iter() + } +} + +/// Create an `Iterator` from a mutable reference +pub trait AsIterMut<'it>: AsIter<'it> { + /// The ref type + type RefMut: DerefMut; + /// The iterator type + type IntoIterMut: Iterator; + + /// Create an iterator from &mut self + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut; +} + +impl<'it, S, T> AsIterMut<'it> for S +where + S: AsSliceMut<'it, Entry = T, SliceRef = &'it [T], SliceRefMut = &'it mut [T]>, + T: 'it, +{ + type RefMut = &'it mut Self::Item; + type IntoIterMut = core::slice::IterMut<'it, Self::Item>; + + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { + self.as_slice_mut().iter_mut() + } +} + +/// Has a ref count +pub trait HasRefCnt { + /// The ref count + fn refcnt(&self) -> isize; + /// The ref count, mutable + fn refcnt_mut(&mut self) -> &mut isize; +} + +/// Zero-cost way to construct [`core::num::NonZeroUsize`] at compile-time. +#[macro_export] +macro_rules! nonzero { + // TODO: Further simplify with `unwrap`/`expect` once MSRV includes + // https://github.com/rust-lang/rust/issues/67441 + ($val:expr) => { + const { + match core::num::NonZero::new($val) { + Some(x) => x, + None => panic!("Value passed to `nonzero!` was zero"), + } + } + }; +} + +/// Get a [`core::ptr::NonNull`] to a global static mut (or similar). +/// +/// The same as [`core::ptr::addr_of_mut`] or `&raw mut`, but wrapped in said [`NonNull`](core::ptr::NonNull). +#[macro_export] +macro_rules! nonnull_raw_mut { + ($val:expr) => { + // # Safety + // The pointer to a value will never be null (unless we're on an archaic OS in a CTF challenge). + unsafe { core::ptr::NonNull::new(&raw mut $val).unwrap_unchecked() } + }; +} + +/// Create a [`Vec`] of the given type with `nb_elts` elements, initialized in place. +/// The closure must initialize [`Vec`] (of size `nb_elts` * `sizeo_of::()`). +/// +/// # Safety +/// +/// The input closure should fully initialize the new [`Vec`], not leaving any uninitialized bytes. +// TODO: Use MaybeUninit API at some point. +#[cfg(feature = "alloc")] +#[expect(clippy::uninit_vec)] +pub unsafe fn vec_init(nb_elts: usize, init_fn: F) -> Result, E> +where + F: FnOnce(&mut Vec) -> Result<(), E>, +{ + unsafe { + let mut new_vec: Vec = Vec::with_capacity(nb_elts); + new_vec.set_len(nb_elts); + + init_fn(&mut new_vec)?; + + Ok(new_vec) + } +} + +/// We need fixed names for many parts of this lib. +#[cfg(feature = "alloc")] +pub trait Named { + /// Provide the name of this element. + fn name(&self) -> &Cow<'static, str>; +} + +#[cfg(feature = "alloc")] +impl Named for () { + #[inline] + fn name(&self) -> &Cow<'static, str> { + static NAME: Cow<'static, str> = Cow::Borrowed("()"); + &NAME + } +} + +/// Has a length field +pub trait HasLen { + /// The length + fn len(&self) -> usize; + + /// Returns `true` if it has no elements. + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[cfg(feature = "alloc")] +impl HasLen for Vec { + #[inline] + fn len(&self) -> usize { + Vec::::len(self) + } +} + +impl HasLen for &mut T { + fn len(&self) -> usize { + self.deref().len() + } +} + +impl HasLen for (Head, Tail) +where + Tail: HasLen, +{ + #[inline] + fn len(&self) -> usize { + self.1.len() + 1 + } +} + +impl HasLen for (Tail,) +where + Tail: HasLen, +{ + #[inline] + fn len(&self) -> usize { + self.0.len() + } +} + +impl HasLen for () { + #[inline] + fn len(&self) -> usize { + 0 + } +} + +/// Trait to truncate slices and maps to a new size +pub trait Truncate { + /// Reduce the size of the slice + fn truncate(&mut self, len: usize); +} + +impl Truncate for &[T] { + fn truncate(&mut self, len: usize) { + *self = &self[..len]; + } +} + +impl Truncate for &mut [T] { + fn truncate(&mut self, len: usize) { + let value = core::mem::take(self); + let len = value.len().min(len); + let truncated = value + .get_mut(..len) + .expect("Truncate with len <= len() should always work"); + let _: &mut [T] = core::mem::replace(self, truncated); + } +} diff --git a/crates/libafl_derive/Cargo.toml b/crates/libafl_derive/Cargo.toml index ecb6aedb774..e62437c1f33 100644 --- a/crates/libafl_derive/Cargo.toml +++ b/crates/libafl_derive/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Andrea Fioraldi "] description = "Derive proc-macro crate for LibAFL" documentation = "https://docs.rs/libafl_derive" repository = "https://github.com/AFLplusplus/LibAFL/" -readme = "../../README.md" +readme = "./README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing"] edition = "2024" diff --git a/crates/libafl_derive/README.md b/crates/libafl_derive/README.md new file mode 100644 index 00000000000..c25bcb2b61a --- /dev/null +++ b/crates/libafl_derive/README.md @@ -0,0 +1,51 @@ +# LibAFL_derive: Derive Macros for LibAFL + + LibAFL logo + +The `libafl_derive` crate offers derive macros, such as `#[derive(SerdeAny)]`. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_derive/src/lib.rs b/crates/libafl_derive/src/lib.rs index fe723de932f..ba91c58c7f8 100644 --- a/crates/libafl_derive/src/lib.rs +++ b/crates/libafl_derive/src/lib.rs @@ -1,5 +1,5 @@ //! Derives for `LibAFL` - +#![doc = include_str!("../README.md")] #![no_std] #![cfg_attr(not(test), warn( missing_debug_implementations, diff --git a/crates/libafl_frida/Cargo.toml b/crates/libafl_frida/Cargo.toml index 402189ffd49..ce9f36b19d6 100644 --- a/crates/libafl_frida/Cargo.toml +++ b/crates/libafl_frida/Cargo.toml @@ -5,7 +5,7 @@ authors = ["s1341 "] description = "Frida backend library for LibAFL" documentation = "https://docs.rs/libafl_frida" repository = "https://github.com/AFLplusplus/LibAFL/" -readme = "../../README.md" +readme = "./README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "frida", "instrumentation"] edition = "2024" diff --git a/crates/libafl_frida/README.md b/crates/libafl_frida/README.md new file mode 100644 index 00000000000..cabbd39154d --- /dev/null +++ b/crates/libafl_frida/README.md @@ -0,0 +1,51 @@ +# LibAFL_frida: Binary-Only Frida Instrumentation for LibAFL + + LibAFL logo + +The `libafl_frida` crate offers binary-only instrumentation for `LibAFL` using the Frida dynamic instrumentation toolkit. It allows fuzzing closed-source binaries and applications on various platforms, including Android and iOS. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_frida/src/lib.rs b/crates/libafl_frida/src/lib.rs index 629183c58ef..5f7b1cf6cb9 100644 --- a/crates/libafl_frida/src/lib.rs +++ b/crates/libafl_frida/src/lib.rs @@ -6,6 +6,7 @@ It can report coverage and, on supported architectures, even reports memory acce Additional documentation is available in [the `LibAFL` book](https://aflplus.plus/libafl-book/advanced_features/frida.html). */ +#![doc = include_str!("../README.md")] #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] #![cfg_attr(not(test), warn( missing_debug_implementations, diff --git a/crates/libafl_intelpt/README.md b/crates/libafl_intelpt/README.md index d1df5f2b315..274b25e3b7d 100644 --- a/crates/libafl_intelpt/README.md +++ b/crates/libafl_intelpt/README.md @@ -5,4 +5,50 @@ This module is a wrapper around the `IntelPT` kernel driver, exposing functional At the moment only `Linux` hosts are supported. You can run `sudo -E cargo test intel_pt_check_availability -- --show-output` to check if your host has all the features -used by this crate. +used by this crate. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/libafl_intelpt/src/lib.rs b/crates/libafl_intelpt/src/lib.rs index 29937dc3aa7..0c2632fe292 100644 --- a/crates/libafl_intelpt/src/lib.rs +++ b/crates/libafl_intelpt/src/lib.rs @@ -2,7 +2,7 @@ //! //! This crate interacts with the linux kernel (specifically with perf) and therefore it only works //! on linux hosts - +#![doc = include_str!("../README.md")] // Just in case this crate will have real `no_std` support in the future #![no_std] #![cfg(target_arch = "x86_64")] diff --git a/crates/libafl_libfuzzer/runtime/Cargo.toml.template b/crates/libafl_libfuzzer/runtime/Cargo.toml.template index f26330afd52..c5e14e6f7e8 100644 --- a/crates/libafl_libfuzzer/runtime/Cargo.toml.template +++ b/crates/libafl_libfuzzer/runtime/Cargo.toml.template @@ -73,7 +73,7 @@ log = { version = "0.4.22", features = ["release_max_level_info"] } mimalloc = { version = "0.1.43", default-features = false } num-traits = { version = "0.2.19", default-features = true } rand = "0.8.5" -serde = { version = "1.0.210", default-features = true, features = [ +serde = { version = "1.0.228", default-features = true, features = [ "derive", ] } # serialization lib hashbrown = { version = "0.16.0", default-features = true, features = [ diff --git a/crates/libafl_nyx/Cargo.toml b/crates/libafl_nyx/Cargo.toml index df259193feb..6620841be9d 100644 --- a/crates/libafl_nyx/Cargo.toml +++ b/crates/libafl_nyx/Cargo.toml @@ -39,7 +39,7 @@ libafl_targets = { workspace = true, default-features = true, features = [ nix = { workspace = true, default-features = true, features = ["fs"] } typed-builder = { workspace = true } regex = "1.12.2" -serde = { version = "1.0.210", default-features = false, features = [ +serde = { workspace = true, default-features = false, features = [ "alloc", ] } # serialization lib diff --git a/crates/libafl_qemu/Cargo.toml b/crates/libafl_qemu/Cargo.toml index 6e61284a64b..47b6f024991 100644 --- a/crates/libafl_qemu/Cargo.toml +++ b/crates/libafl_qemu/Cargo.toml @@ -115,6 +115,7 @@ clippy = ["libafl_qemu_sys/clippy", "libvharness_sys/clippy"] [dependencies] libafl = { workspace = true, features = ["std", "derive", "regex"] } libafl_bolts = { workspace = true, features = ["std", "derive"] } +libafl_core = { workspace = true, features = ["std"] } libafl_targets = { workspace = true, default-features = true } libafl_qemu_sys = { workspace = true } libafl_derive = { workspace = true, default-features = true } diff --git a/crates/libafl_qemu/src/qemu/mod.rs b/crates/libafl_qemu/src/qemu/mod.rs index 23ddc64ddf8..193c5b46b69 100644 --- a/crates/libafl_qemu/src/qemu/mod.rs +++ b/crates/libafl_qemu/src/qemu/mod.rs @@ -55,7 +55,7 @@ pub use systemmode::*; mod hooks; pub use hooks::*; -use libafl_bolts::{AsSliceMut, vec_init}; +use libafl_core::{AsSliceMut, vec_init}; static mut QEMU_IS_INITIALIZED: bool = false; static mut QEMU_IS_RUNNING: bool = false; diff --git a/crates/libafl_sugar/Cargo.toml b/crates/libafl_sugar/Cargo.toml index 49e712d0420..8db39051438 100644 --- a/crates/libafl_sugar/Cargo.toml +++ b/crates/libafl_sugar/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Andrea Fioraldi "] description = "Sugar builders to create common fuzzers with LibAFL" documentation = "https://docs.rs/libafl_sugar" repository = "https://github.com/AFLplusplus/LibAFL/" -readme = "../../README.md" +readme = "./README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing"] edition = "2024" diff --git a/crates/libafl_sugar/README.md b/crates/libafl_sugar/README.md new file mode 100644 index 00000000000..124061f84c2 --- /dev/null +++ b/crates/libafl_sugar/README.md @@ -0,0 +1,51 @@ +# LibAFL_Sugar: High-level usable wrappers for LibAFL + + LibAFL logo + +The `libafl_sugar` crate offers high-level, usable wrappers for `LibAFL`, simplifying common fuzzing tasks and providing a more ergonomic API for building fuzzers. It aims to reduce boilerplate and make `LibAFL` more accessible to new users, while still retaining the flexibility and power of the underlying framework. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_sugar/src/forkserver.rs b/crates/libafl_sugar/src/forkserver.rs index aacbf55d985..e32fdd7ba7f 100644 --- a/crates/libafl_sugar/src/forkserver.rs +++ b/crates/libafl_sugar/src/forkserver.rs @@ -34,7 +34,6 @@ use libafl_bolts::{ AsSliceMut, StdTargetArgs, core_affinity::Cores, nonzero, - ownedref::OwnedRefMut, rands::StdRand, shmem::{ShMem, ShMemProvider, UnixShMemProvider}, tuples::{Merge, tuple_list}, @@ -271,8 +270,7 @@ impl ForkserverBytesCoverageSugar<'_> { unsafe { cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } - let cmpmap = - unsafe { OwnedRefMut::::from_shmem(&mut cmplog_shmem) }; + let cmpmap = unsafe { AflppCmpLogMap::from_shmem(&mut cmplog_shmem) }; let cmplog_observer = StdCmpObserver::new("cmplog", cmpmap, true); diff --git a/crates/libafl_sugar/src/lib.rs b/crates/libafl_sugar/src/lib.rs index c358e7d6fb8..a08aa1cc062 100644 --- a/crates/libafl_sugar/src/lib.rs +++ b/crates/libafl_sugar/src/lib.rs @@ -1,4 +1,5 @@ //! Sugar API to simplify the life of users of `LibAFL` that just want to fuzz. +#![doc = include_str!("../README.md")] /*! */ #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] #![cfg_attr(not(test), warn( diff --git a/crates/libafl_targets/Cargo.toml b/crates/libafl_targets/Cargo.toml index 48635167bac..946ce75cd32 100644 --- a/crates/libafl_targets/Cargo.toml +++ b/crates/libafl_targets/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Andrea Fioraldi "] description = "Common code for target instrumentation that can be used combined with LibAFL" documentation = "https://docs.rs/libafl_targets" repository = "https://github.com/AFLplusplus/LibAFL/" -readme = "../../README.md" +readme = "./README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing"] edition = "2024" @@ -69,7 +69,7 @@ whole_archive = [] # use +whole-archive to ensure the presence of weak symbols cmplog_extended_instrumentation = [ "cmplog", # without `cmplog`, extended instrumentation won't compile ] # support for aflpp cmplog map, we will remove this once aflpp and libafl cmplog shares the same LLVM passes. -function-logging = ["common"] +function-logging = ["common", "std"] track_hit_feedbacks = ["libafl/track_hit_feedbacks"] [build-dependencies] bindgen = "0.72.1" @@ -79,10 +79,13 @@ rustversion = "1.0.22" [dependencies] libafl = { workspace = true, features = [], default-features = false } libafl_bolts = { workspace = true, features = [] } +libafl_core = { workspace = true, features = [] } +fast_rands = { workspace = true } +ownedref = { workspace = true } +shmem_providers = { workspace = true } libc = { workspace = true } nix = { workspace = true, optional = true } hashbrown = { workspace = true, default-features = true } -once_cell = "1.19.0" log = { workspace = true } rustversion = { workspace = true } diff --git a/crates/libafl_targets/README.md b/crates/libafl_targets/README.md new file mode 100644 index 00000000000..13a8f888886 --- /dev/null +++ b/crates/libafl_targets/README.md @@ -0,0 +1,51 @@ +# LibAFL_targets: Target-Specific code to be injected for LibAFL Fuzzing + + LibAFL logo + +The `libafl_targets` crate provides target-specific code that can be injected into programs for `LibAFL` fuzzing. This includes various instrumentation techniques and helper functions to facilitate the fuzzing process. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_targets/src/call.rs b/crates/libafl_targets/src/call.rs index d0581e18e09..22a95a459a0 100644 --- a/crates/libafl_targets/src/call.rs +++ b/crates/libafl_targets/src/call.rs @@ -1,10 +1,11 @@ use core::marker::PhantomData; +use std::cell::LazyCell; use hashbrown::HashMap; use libafl::executors::hooks::ExecutorHook; -use once_cell::sync::Lazy; + /// The list of functions that this execution has observed -pub static mut FUNCTION_LIST: Lazy> = Lazy::new(HashMap::new); +pub static mut FUNCTION_LIST: LazyCell> = LazyCell::new(HashMap::new); #[unsafe(no_mangle)] /// The runtime code inserted at every callinst invokation (if you used the function-logging.cc) diff --git a/crates/libafl_targets/src/cmps/mod.rs b/crates/libafl_targets/src/cmps/mod.rs index f80491e0df3..b52eec3a685 100644 --- a/crates/libafl_targets/src/cmps/mod.rs +++ b/crates/libafl_targets/src/cmps/mod.rs @@ -12,12 +12,10 @@ use core::{ ptr, slice, }; -use libafl::{ - Error, - observers::{CmpMap, CmpValues, CmplogBytes, cmp::AflppCmpLogHeader}, -}; -use libafl_bolts::HasLen; +use libafl::observers::{CmpMap, CmpValues, CmplogBytes, cmp::AflppCmpLogHeader}; +use libafl_bolts::{Error, HasLen, ownedref::OwnedRefMut}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use shmem_providers::ShMem; pub use stages::*; use crate::{CMPLOG_MAP_H, CMPLOG_MAP_W}; @@ -510,6 +508,18 @@ impl HasLen for AflppCmpLogMap { } impl AflppCmpLogMap { + /// Returns a new [`OwnedRefMut`] to an [`AflppCmpLogMap`], pointing to the given [`ShMem`]. + /// + /// # Panics + /// Panics if the given shared mem is too small + /// + /// # Safety + /// The shared memory needs to start with a valid [`AflppCmpLogMap`] object. + /// Any use of this [`OwnedRefMut`] will dereference a pointer to the given shared memory accordingly + pub unsafe fn from_shmem(shmem: &mut SHM) -> OwnedRefMut<'_, Self> { + unsafe { OwnedRefMut::from_mut_ptr(shmem.as_mut_ptr_of().unwrap()) } + } + #[must_use] #[expect(clippy::cast_ptr_alignment)] /// Instantiate a new boxed zeroed `AflppCmpLogMap`. This should be used to create a new diff --git a/crates/libafl_targets/src/coverage.rs b/crates/libafl_targets/src/coverage.rs index 032b09794a4..03e7ac7bfc1 100644 --- a/crates/libafl_targets/src/coverage.rs +++ b/crates/libafl_targets/src/coverage.rs @@ -10,7 +10,9 @@ use alloc::borrow::Cow; #[cfg(any(target_os = "linux", target_vendor = "apple"))] -use libafl::{Error, mutators::Tokens}; +use libafl::mutators::Tokens; +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +use libafl_bolts::Error; use crate::{ACCOUNTING_MAP_SIZE, EDGES_MAP_ALLOCATED_SIZE, EDGES_MAP_DEFAULT_SIZE}; diff --git a/crates/libafl_targets/src/drcov.rs b/crates/libafl_targets/src/drcov.rs index c26b202e0de..d51825fc5a9 100644 --- a/crates/libafl_targets/src/drcov.rs +++ b/crates/libafl_targets/src/drcov.rs @@ -12,7 +12,7 @@ use std::{ }; use hashbrown::HashSet; -use libafl::Error; +use libafl_bolts::Error; use rangemap::RangeMap; /// A basic block struct diff --git a/crates/libafl_targets/src/forkserver.rs b/crates/libafl_targets/src/forkserver.rs index 0620ff081f6..0c9465fef7c 100644 --- a/crates/libafl_targets/src/forkserver.rs +++ b/crates/libafl_targets/src/forkserver.rs @@ -10,22 +10,20 @@ use std::{ use libafl::executors::forkserver::FS_NEW_OPT_AUTODTCT; #[cfg(feature = "cmplog")] use libafl::executors::forkserver::SHM_CMPLOG_ENV_VAR; -use libafl::{ - Error, - executors::forkserver::{ - AFL_MAP_SIZE_ENV_VAR, FORKSRV_FD, FS_ERROR_SHM_OPEN, FS_NEW_OPT_MAPSIZE, - FS_NEW_OPT_SHDMEM_FUZZ, FS_NEW_VERSION_MAX, FS_OPT_ERROR, MAX_INPUT_SIZE_DEFAULT, - SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, SHM_FUZZ_MAP_SIZE_ENV_VAR, SHMEM_FUZZ_HDR_SIZE, - }, +use libafl::executors::forkserver::{ + AFL_MAP_SIZE_ENV_VAR, FORKSRV_FD, FS_ERROR_SHM_OPEN, FS_NEW_OPT_MAPSIZE, + FS_NEW_OPT_SHDMEM_FUZZ, FS_NEW_VERSION_MAX, FS_OPT_ERROR, MAX_INPUT_SIZE_DEFAULT, SHM_ENV_VAR, + SHM_FUZZ_ENV_VAR, SHM_FUZZ_MAP_SIZE_ENV_VAR, SHMEM_FUZZ_HDR_SIZE, }; use libafl_bolts::{ + Error, os::{ChildHandle, ForkResult}, - shmem::{ShMem, ShMemId, ShMemProvider}, }; use nix::{ sys::signal::{SigHandler, Signal}, unistd::Pid, }; +use shmem_providers::{ShMem, ShMemId, ShMemProvider}; #[cfg(feature = "cmplog_extended_instrumentation")] use crate::cmps::EXTENDED_CMPLOG_MAP_PTR; diff --git a/crates/libafl_targets/src/lib.rs b/crates/libafl_targets/src/lib.rs index bf9e2c4cbe4..a5629b7c6f9 100644 --- a/crates/libafl_targets/src/lib.rs +++ b/crates/libafl_targets/src/lib.rs @@ -1,4 +1,5 @@ //! `libafl_targets` contains runtime code, injected in the target itself during compilation. +#![doc = include_str!("../README.md")] #![no_std] // For `std::simd` #![cfg_attr(nightly, feature(portable_simd))] diff --git a/crates/libafl_targets/src/libfuzzer/mutators.rs b/crates/libafl_targets/src/libfuzzer/mutators.rs index 52bfb634ee2..bfa804c66d9 100644 --- a/crates/libafl_targets/src/libfuzzer/mutators.rs +++ b/crates/libafl_targets/src/libfuzzer/mutators.rs @@ -6,8 +6,8 @@ use alloc::{ }; use core::{cell::RefCell, marker::PhantomData, ops::Deref}; +use fast_rands::Rand; use libafl::{ - Error, corpus::{Corpus, CorpusId}, inputs::{BytesInput, HasMutatorBytes, ResizableMutator}, mutators::{ @@ -16,7 +16,7 @@ use libafl::{ random_corpus_id_with_disabled, state::{HasCorpus, HasMaxSize, HasRand}, }; -use libafl_bolts::{AsSlice, HasLen, Named, rands::Rand}; +use libafl_core::{AsSlice, Error, HasLen, Named}; unsafe extern "C" { fn libafl_targets_has_libfuzzer_custom_mutator() -> bool; diff --git a/crates/libafl_targets/src/libfuzzer/observers/oom.rs b/crates/libafl_targets/src/libfuzzer/observers/oom.rs index bc8f3b1522e..4bdfe2676c0 100644 --- a/crates/libafl_targets/src/libfuzzer/observers/oom.rs +++ b/crates/libafl_targets/src/libfuzzer/observers/oom.rs @@ -6,12 +6,11 @@ use core::{ }; use libafl::{ - Error, executors::ExitKind, feedbacks::{Feedback, StateInitializer}, observers::Observer, }; -use libafl_bolts::Named; +use libafl_core::{Error, Named}; use libc::SIGABRT; use serde::{Deserialize, Serialize}; diff --git a/crates/libafl_targets/src/sancov_8bit.rs b/crates/libafl_targets/src/sancov_8bit.rs index 9ce2fa4ab6a..33d3f6b9c7c 100644 --- a/crates/libafl_targets/src/sancov_8bit.rs +++ b/crates/libafl_targets/src/sancov_8bit.rs @@ -1,7 +1,8 @@ //! [`LLVM` `8-bit-counters`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`. use alloc::vec::Vec; -use libafl_bolts::{AsSlice, AsSliceMut, ownedref::OwnedMutSlice}; +use libafl_core::{AsSlice, AsSliceMut}; +use ownedref::OwnedMutSlice; /// A [`Vec`] of `8-bit-counters` maps for multiple modules. /// They are initialized by calling [`__sanitizer_cov_8bit_counters_init`]( diff --git a/crates/libafl_tinyinst/README.md b/crates/libafl_tinyinst/README.md index d463404f647..963a7308622 100644 --- a/crates/libafl_tinyinst/README.md +++ b/crates/libafl_tinyinst/README.md @@ -1,5 +1,7 @@ # LibAFL TinyInst +LibAFL logo + `TinyInst` binary-only instrumentation backend for `LibAFL`. ## Requirements @@ -7,3 +9,50 @@ - `Visual Studio 17 2022`. It's not tested, it *should* work on older versions too. - `cxxbridge-cmd` to generate bridge files between Rust and c++, you can install this with `cargo install cxxbridge-cmd`. - `cmake` is needed to build tinyinst. + + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/libafl_tinyinst/src/lib.rs b/crates/libafl_tinyinst/src/lib.rs index dc22e7c31a3..d19954d49c6 100644 --- a/crates/libafl_tinyinst/src/lib.rs +++ b/crates/libafl_tinyinst/src/lib.rs @@ -1,7 +1,7 @@ /*! The tinyinst module for `LibAFL`. */ - +#![doc = include_str!("../README.md")] #![cfg_attr(not(test), warn( missing_debug_implementations, missing_docs, diff --git a/crates/libafl_unicorn/Cargo.toml b/crates/libafl_unicorn/Cargo.toml index e393282c937..961b44c1c45 100644 --- a/crates/libafl_unicorn/Cargo.toml +++ b/crates/libafl_unicorn/Cargo.toml @@ -5,7 +5,7 @@ authors = [""] description = "Unicorn backend library for LibAFL" documentation = "https://docs.rs/" repository = "https://github.com/AFLplusplus/" -readme = "../../README.md" +readme = "./README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "unicorn"] edition = "2024" diff --git a/crates/libafl_unicorn/README.md b/crates/libafl_unicorn/README.md new file mode 100644 index 00000000000..07e00170394 --- /dev/null +++ b/crates/libafl_unicorn/README.md @@ -0,0 +1,51 @@ +# LibAFL_unicorn: Unicorn Instrumentation for LibAFL + + LibAFL logo + +The `libafl_unicorn` crate offers an interface to the Unicorn Engine, a lightweight, multi-platform, multi-architecture CPU emulator framework. It allows `LibAFL` to fuzz targets that require emulation, providing fine-grained control over the emulated environment, including memory, registers, and I/O. This enables fuzzing of firmware, embedded systems, and other scenarios where direct execution is not feasible or desirable. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_unicorn/src/emu.rs b/crates/libafl_unicorn/src/emu.rs index f46165c7dd7..6afe0f10d39 100644 --- a/crates/libafl_unicorn/src/emu.rs +++ b/crates/libafl_unicorn/src/emu.rs @@ -1,3 +1,4 @@ +//! Debugging utilities for the unicorn emulator use capstone::{ Capstone, arch::{self, BuildsCapstone, BuildsCapstoneSyntax}, @@ -11,6 +12,7 @@ use unicorn_engine::{ use crate::helper::get_stack_pointer; // TODO: For some reason, the compiled program start by substracting 0x10 to SP +/// Dumps the memory around the stack pointer pub fn memory_dump(emu: &Unicorn<()>, len: u64) { let sp = get_stack_pointer(emu); for i in 0..len { @@ -33,8 +35,8 @@ pub fn memory_dump(emu: &Unicorn<()>, len: u64) { } } -// Display some register values and disassemble the instructions around the program counter -// address. The thumb_mode parameter is only taken into account when the architecture used is ARM. +/// Display some register values and disassemble the instructions around the program counter +/// address. The thumb_mode parameter is only taken into account when the architecture used is ARM. pub fn debug_print(emu: &Unicorn<()>, thumb_mode: bool) { log::debug!("Status when crash happened:"); diff --git a/crates/libafl_unicorn/src/helper.rs b/crates/libafl_unicorn/src/helper.rs index f5ff5881d82..1954dd2fd77 100644 --- a/crates/libafl_unicorn/src/helper.rs +++ b/crates/libafl_unicorn/src/helper.rs @@ -1,5 +1,7 @@ +//! Helper functions for the unicorn emulator use unicorn_engine::{RegisterARM, RegisterARM64, RegisterRISCV, RegisterX86, unicorn_const::Arch}; +/// Returns the stack pointer for the current architecture pub fn get_stack_pointer(emu: &unicorn_engine::Unicorn<()>) -> u64 { match emu.get_arch() { Arch::ARM => emu.reg_read(RegisterARM::SP).unwrap(), diff --git a/crates/libafl_unicorn/src/hooks.rs b/crates/libafl_unicorn/src/hooks.rs index 46bb72133a5..27bdd0cdd69 100644 --- a/crates/libafl_unicorn/src/hooks.rs +++ b/crates/libafl_unicorn/src/hooks.rs @@ -1,6 +1,8 @@ +//! Hooks for the unicorn emulator use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR}; use unicorn_engine::Unicorn; +/// Hook that is called for every basic block fn coverage_hook(_emu: &mut unicorn_engine::Unicorn<()>, pc: u64, _: u32) { unsafe { let id = pc % EDGES_MAP_DEFAULT_SIZE as u64; @@ -11,6 +13,7 @@ fn coverage_hook(_emu: &mut unicorn_engine::Unicorn<()>, pc: u64, _: u32) { } } +/// Sets the `coverage_hook` for the emulator pub fn set_coverage_hook(emu: &mut Unicorn<()>) { emu.add_block_hook(0x0, !0x0_u64, coverage_hook).unwrap(); } diff --git a/crates/libafl_unicorn/src/lib.rs b/crates/libafl_unicorn/src/lib.rs index f6cef3da8ff..74084542105 100644 --- a/crates/libafl_unicorn/src/lib.rs +++ b/crates/libafl_unicorn/src/lib.rs @@ -1,3 +1,8 @@ +#![doc = include_str!("../README.md")] +/*! +This crate provides unicorn emulation for `LibAFL`. +*/ + pub mod emu; pub mod helper; pub mod hooks; diff --git a/crates/ll_mp/Cargo.toml b/crates/ll_mp/Cargo.toml new file mode 100644 index 00000000000..ea15594dfe4 --- /dev/null +++ b/crates/ll_mp/Cargo.toml @@ -0,0 +1,93 @@ +[package] +name = "ll_mp" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "A library for low level message passing" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "ipc", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc", "gzip", "llmp_compression", "llmp_small_maps"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = [ + "alloc", + "hostname", + "libafl_core/std", + "nix", + "serial_test", + "shmem_providers/std", +] + +## Enables all features that allocate in `no_std` +alloc = [ + "exceptional/alloc", + "libafl_core/alloc", + "libafl_core/serde", + "postcard", + "shmem_providers/alloc", +] + +## Enables gzip compression in certain parts of the lib +gzip = ["miniz_oxide", "alloc"] + +#! ### LLMP features + +## If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. +llmp_bind_public = ["alloc"] + +## Enables llmp compression using GZip +llmp_compression = ["alloc", "gzip"] + +## Enables debug output for LLMP (also needs a `logger` installed) +llmp_debug = ["alloc", "std"] + +## Reduces the initial map size for llmp +llmp_small_maps = ["alloc"] + + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } +exceptional = { workspace = true } +hostname = { version = "0.4.0", optional = true } # Is there really no gethostname in the stdlib? +libafl_core = { workspace = true } +log = { workspace = true } +miniz_oxide = { version = "0.8.0", optional = true } +nix = { workspace = true, features = ["socket"], optional = true } +no_std_time = { workspace = true } +postcard = { workspace = true, optional = true } # no_std compatible serde serialization format +serde = { workspace = true, features = ["alloc", "derive"] } +serial_test = { workspace = true, optional = true } +shmem_providers = { workspace = true } +tuple_list = { workspace = true } + +[[example]] +name = "llmp_test" +path = "./examples/llmp_test/main.rs" +required-features = ["std"] + +[lints] +workspace = true diff --git a/crates/ll_mp/LICENSE-APACHE b/crates/ll_mp/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/ll_mp/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/ll_mp/LICENSE-MIT b/crates/ll_mp/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/ll_mp/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/ll_mp/README.md b/crates/ll_mp/README.md new file mode 100644 index 00000000000..8b87920bb2e --- /dev/null +++ b/crates/ll_mp/README.md @@ -0,0 +1,180 @@ +# LL_MP: Low Level Message Passing for fast IPC. + + LibAFL logo + +This crate provides a low-level message passing (LLMP) mechanism designed for high-performance inter-process communication (IPC), particularly useful in fuzzing scenarios. It leverages shared memory to achieve lock-free communication between processes, minimizing overhead and maximizing throughput. + +## How it works + +To send new messages, the clients place a new message at the end of their +`client_out_mem`. If the current map is filled up, they place an end of page (`EOP`) +msg and alloc a new [`ShMem`]. +Once the broker mapped this same page, it flags it as safe for unmapping. + +```text +[client0] [client1] ... [clientN] + | | / +[client0_out] [client1_out] ... [clientN_out] + | / / + |________________/ / + |________________________________/ + \|/ +[broker] +``` + +After the broker received a new message for clientN, (`clientN_out->current_id +!= last_message->message_id`) the broker will copy the message content to its +own, centralized page. + +The clients periodically check (`current_broadcast_shmem->current_id != +last_message->message_id`) for new incoming messages. If the page is filled up, +the broker instead creates a new page and places an end of page (`EOP`) +message in its queue. The `EOP` buf contains the new description to +access the shared map. The clients then switch over to read from that new +current map. + +```text +[broker] + | +[current_broadcast_shmem] + | + |___________________________________ + |_________________ \ + | \ \ + | | | + \|/ \|/ \|/ +[client0] [client1] ... [clientN] +``` + +In the future, if we would need zero copy, the `current_broadcast_shmem` could instead +list the `client_out_shmem` ID an offset for each message. In that case, the clients +also need to create a new [`ShMem`] each time their bufs are filled up. + + +## Usage Example + +Here is a simple example of a broker and a client communicating in the same process using threads. In a real-world scenario, the client and broker would run in separate processes. + +This example requires the `llmp_serde` feature to be enabled, which allows sending and receiving `serde`-serializable structs. + +```rust +use libafl_bolts::llmp; +use serde::{Serialize, Deserialize}; +use std::{thread, time::Duration}; + +const BROKER_PORT: u16 = 1337; + +// A simple message type that we can serialize +#[derive(Serialize, Deserialize, Debug)] +struct MyMessage { + data: String, +} + +// The client part +fn client_logic() { + // Give the broker a moment to start + thread::sleep(Duration::from_millis(100)); + + // Connect to the broker over TCP + let mut client = llmp::LlmpClient::new(llmp::LlmpConnection::Tcp { port: BROKER_PORT }, 0).expect("Failed to connect to broker"); + + // Create a message + let msg = MyMessage { + data: "Hello from client!".to_string(), + }; + + // Send the message to the broker + client.send_obj(&msg).expect("Failed to send message"); + println!("Client sent a message."); +} + +// The broker part +fn main() { + // Create a new broker listening on a TCP port + let mut broker = llmp::LlmpBroker::new(llmp::LlmpConnection::Tcp { port: BROKER_PORT }).expect("Failed to start broker"); + + // Spawn a client thread + let client_handle = thread::spawn(client_logic); + + println!("Broker started, waiting for message..."); + + // Block until we receive a message + let (client_id, msg) = loop { + // Handle events, this is non-blocking + broker.loop_once().unwrap(); + + // Try to receive a message. + // This is also non-blocking and will return Ok(None) if no message is available. + if let Ok(Some(msg)) = broker.recv_obj::() { + break msg; + } + + // Don't spin the CPU + thread::sleep(Duration::from_millis(10)); + }; + + println!("Broker received: '{:?}' from client {:?}", msg, client_id); + + // Clean up + client_handle.join().unwrap(); +} +``` + +## Fancy features + +* **Shared Memory IPC**: Utilizes shared memory segments for efficient data exchange between processes. +* **Lock-Free Design**: Employs atomic operations and careful memory management to avoid locks, reducing contention and improving performance. +* **Message-Based Communication**: Provides a clear message-passing interface for sending and receiving data. +* **Scalability**: Designed to scale across multiple processes and potentially multiple machines (when combined with other networking layers). +* **Fuzzing-Oriented**: Optimized for the specific needs of fuzzing, such as rapid test case delivery and feedback collection. + +## LLMP != LLVM != LLM + +It is _not_ related to LLMs, nor to LLVM. +Although it is probably more related to LLVM than LLMs. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_bolts/examples/llmp_test/main.rs b/crates/ll_mp/examples/llmp_test/main.rs similarity index 91% rename from crates/libafl_bolts/examples/llmp_test/main.rs rename to crates/ll_mp/examples/llmp_test/main.rs index 2ac4d09413b..8cdf3e3aaf2 100644 --- a/crates/libafl_bolts/examples/llmp_test/main.rs +++ b/crates/ll_mp/examples/llmp_test/main.rs @@ -11,13 +11,13 @@ use core::time::Duration; #[cfg(all(feature = "std", not(target_os = "haiku")))] use std::{thread, time}; -use libafl_bolts::llmp::{LlmpBrokerInner, LlmpMsgHookResult}; #[cfg(all(feature = "std", not(target_os = "haiku")))] -use libafl_bolts::{ - ClientId, Error, SimpleStderrLogger, - llmp::{self, Flags, LlmpHook, Tag}, - shmem::{ShMemProvider, StdShMemProvider}, -}; +use libafl_core::{ClientId, Error}; +#[cfg(all(feature = "std", not(target_os = "haiku")))] +use ll_mp::{self, Flags, LlmpHook, Tag}; +use ll_mp::{LlmpBrokerInner, LlmpMsgHookResult}; +#[cfg(all(feature = "std", not(target_os = "haiku")))] +use shmem_providers::{ShMemProvider, StdShMemProvider}; use tuple_list::tuple_list; #[cfg(all(feature = "std", not(target_os = "haiku")))] @@ -35,13 +35,10 @@ const BROKER_TIMEOUT: Duration = Duration::from_secs(10); #[cfg(all(feature = "std", not(target_os = "haiku")))] const SLEEP_BETWEEN_FORWARDS: Duration = Duration::from_millis(5); -#[cfg(all(feature = "std", not(target_os = "haiku")))] -static LOGGER: SimpleStderrLogger = SimpleStderrLogger::new(); - #[cfg(all(feature = "std", not(target_os = "haiku")))] fn adder_loop(port: u16) -> Result<(), Box> { let shmem_provider = StdShMemProvider::new()?; - let mut client = llmp::LlmpClient::create_attach_to_tcp(shmem_provider, port)?; + let mut client = ll_mp::LlmpClient::create_attach_to_tcp(shmem_provider, port)?; let mut last_result: u32 = 0; let mut current_result: u32 = 0; loop { @@ -78,7 +75,7 @@ fn adder_loop(port: u16) -> Result<(), Box> { #[cfg(all(feature = "std", not(target_os = "haiku")))] fn large_msg_loop(port: u16) -> Result<(), Box> { - let mut client = llmp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new()?, port)?; + let mut client = ll_mp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new()?, port)?; #[cfg(not(target_vendor = "apple"))] let meg_buf = vec![1u8; 1 << 20]; @@ -170,7 +167,7 @@ fn main() { fn main() -> Result<(), Box> { /* The main node has a broker, and a few worker threads */ - use libafl_bolts::llmp::Broker; + use ll_mp::Broker; let mode = std::env::args() .nth(1) @@ -185,13 +182,13 @@ fn main() -> Result<(), Box> { .unwrap_or_else(|| "4242".into()) .parse::()?; - log::set_logger(&LOGGER).unwrap(); + // log::set_logger(..) log::set_max_level(log::LevelFilter::Trace); println!("Launching in mode {mode} on port {port}"); match mode.as_str() { "broker" => { - let mut broker = llmp::LlmpBroker::new( + let mut broker = ll_mp::LlmpBroker::new( StdShMemProvider::new()?, tuple_list!(LlmpExampleHook::new()), )?; @@ -201,7 +198,7 @@ fn main() -> Result<(), Box> { broker.loop_with_timeouts(BROKER_TIMEOUT, Some(SLEEP_BETWEEN_FORWARDS)); } "b2b" => { - let mut broker = llmp::LlmpBroker::new( + let mut broker = ll_mp::LlmpBroker::new( StdShMemProvider::new()?, tuple_list!(LlmpExampleHook::new()), )?; @@ -212,7 +209,7 @@ fn main() -> Result<(), Box> { } "ctr" => { let mut client = - llmp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new()?, port)?; + ll_mp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new()?, port)?; let mut counter: u32 = 0; loop { counter = counter.wrapping_add(1); @@ -229,7 +226,7 @@ fn main() -> Result<(), Box> { } "exiting" => { let mut client = - llmp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new()?, port)?; + ll_mp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new()?, port)?; for i in 0..10_u32 { client.send_buf(_TAG_SIMPLE_U32_V1, &i.to_le_bytes())?; println!("Exiting Client writing {i}"); diff --git a/crates/libafl_bolts/src/llmp.rs b/crates/ll_mp/src/lib.rs similarity index 98% rename from crates/libafl_bolts/src/llmp.rs rename to crates/ll_mp/src/lib.rs index f09da558764..92720d0f21d 100644 --- a/crates/libafl_bolts/src/llmp.rs +++ b/crates/ll_mp/src/lib.rs @@ -56,12 +56,60 @@ For broker2broker communication, all messages are forwarded via network sockets. Check out the `llmp_test` example in ./examples, or build it with `cargo run --example llmp_test`. */ +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; #[cfg(feature = "std")] use alloc::boxed::Box; #[cfg(feature = "std")] use alloc::string::ToString; -use alloc::{string::String, vec::Vec}; +use alloc::{string::String, vec, vec::Vec}; #[cfg(not(target_pointer_width = "64"))] use core::sync::atomic::AtomicU32; #[cfg(target_pointer_width = "64")] @@ -79,6 +127,8 @@ use core::{ }; #[cfg(feature = "std")] use core::{mem::offset_of, net::SocketAddr, ptr::write_unaligned}; +#[cfg(all(debug_assertions, feature = "llmp_debug", feature = "std"))] +use std::backtrace::Backtrace; #[cfg(feature = "std")] use std::{ env, @@ -88,28 +138,27 @@ use std::{ thread, }; -#[cfg(all(debug_assertions, feature = "llmp_debug", feature = "std"))] -use backtrace::Backtrace; +#[cfg(all(unix, feature = "alloc"))] +use exceptional::unix_signals::SignalHandler; +#[cfg(all(unix, feature = "alloc", not(miri)))] +use exceptional::unix_signals::setup_signal_handler; +#[cfg(unix)] +use exceptional::unix_signals::{Signal, siginfo_t, ucontext_t}; +#[cfg(all(windows, feature = "std"))] +use exceptional::windows_exceptions::{CtrlHandler, setup_ctrl_handler}; +#[cfg(feature = "std")] +use libafl_core::IP_LOCALHOST; +use libafl_core::{ClientId, Error, format}; #[cfg(all(unix, feature = "std"))] #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] use nix::sys::socket::{self, sockopt::ReusePort}; +#[cfg(feature = "std")] +use no_std_time::current_time; use serde::{Deserialize, Serialize}; +use shmem_providers::{ShMem, ShMemDescription, ShMemId, ShMemProvider}; #[cfg(feature = "std")] use tuple_list::tuple_list; -#[cfg(all(unix, not(miri)))] -use crate::os::unix_signals::setup_signal_handler; -#[cfg(unix)] -use crate::os::unix_signals::{Signal, SignalHandler, siginfo_t, ucontext_t}; -#[cfg(all(windows, feature = "std"))] -use crate::os::windows_exceptions::{CtrlHandler, setup_ctrl_handler}; -use crate::{ - ClientId, Error, - shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider}, -}; -#[cfg(feature = "std")] -use crate::{IP_LOCALHOST, current_time}; - /// The max number of pages a [`client`] may have mapped that were not yet read by the [`broker`] /// Usually, this value should not exceed `1`, else the broker cannot keep up with the amount of incoming messages. /// Instead of increasing this value, you may consider sending new messages at a lower rate, else your Sender will eventually `OOM`. @@ -276,6 +325,7 @@ pub enum TcpRequest { }, } +#[cfg(feature = "std")] impl TryFrom<&Vec> for TcpRequest { type Error = Error; @@ -284,6 +334,7 @@ impl TryFrom<&Vec> for TcpRequest { } } +#[cfg(feature = "std")] impl TryFrom> for TcpRequest { type Error = Error; @@ -305,6 +356,7 @@ pub struct TcpRemoteNewMessage { payload: Vec, } +#[cfg(feature = "std")] impl TryFrom<&Vec> for TcpRemoteNewMessage { type Error = Error; @@ -313,6 +365,7 @@ impl TryFrom<&Vec> for TcpRemoteNewMessage { } } +#[cfg(feature = "std")] impl TryFrom> for TcpRemoteNewMessage { type Error = Error; @@ -349,6 +402,7 @@ pub enum TcpResponse { }, } +#[cfg(feature = "std")] impl TryFrom<&Vec> for TcpResponse { type Error = Error; @@ -357,6 +411,7 @@ impl TryFrom<&Vec> for TcpResponse { } } +#[cfg(feature = "std")] impl TryFrom> for TcpResponse { type Error = Error; @@ -1130,7 +1185,7 @@ where #[cfg(all(feature = "llmp_debug", feature = "std"))] { #[cfg(debug_assertions)] - let bt = Backtrace::new(); + let bt = Backtrace::capture(); #[cfg(not(debug_assertions))] let bt = ""; let shm = self.out_shmems.last().unwrap(); @@ -2006,7 +2061,7 @@ where #[cfg(feature = "llmp_debug")] //{ //#[cfg(debug_assertions)] - //let bt = Backtrace::new(); + //let bt = Backtrace::capture(); //#[cfg(not(debug_assertions))] //let bt = ""; log::info!( @@ -2408,7 +2463,7 @@ impl Brokers { self.llmp_brokers.push(broker); } - #[cfg(any(all(unix, not(miri)), all(windows, feature = "std")))] + #[cfg(any(all(unix, feature = "alloc", not(miri)), all(windows, feature = "std")))] fn setup_handlers() { #[cfg(all(unix, not(miri)))] if let Err(e) = unsafe { setup_signal_handler(&raw mut LLMP_SIGHANDLER_STATE) } { @@ -2437,7 +2492,7 @@ impl Brokers { /// 5 millis of sleep can't hurt to keep busywait not at 100% #[cfg(feature = "std")] pub fn loop_with_timeouts(&mut self, timeout: Duration, sleep_time: Option) { - use super::current_milliseconds; + use no_std_time::current_milliseconds; #[cfg(any(all(unix, not(miri)), all(windows, feature = "std")))] Self::setup_handlers(); @@ -2613,7 +2668,7 @@ where /// 5 millis of sleep can't hurt to keep busywait not at 100% #[cfg(feature = "std")] pub fn loop_with_timeouts(&mut self, timeout: Duration, sleep_time: Option) { - use super::current_milliseconds; + use no_std_time::current_milliseconds; #[cfg(any(all(unix, not(miri)), all(windows, feature = "std")))] Self::setup_handlers(); @@ -2877,7 +2932,7 @@ where } } - #[cfg(any(all(unix, not(miri)), all(windows, feature = "std")))] + #[cfg(any(all(unix, feature = "alloc", not(miri)), all(windows, feature = "std")))] fn setup_handlers() { #[cfg(all(unix, not(miri)))] if let Err(e) = unsafe { setup_signal_handler(&raw mut LLMP_SIGHANDLER_STATE) } { @@ -3873,17 +3928,18 @@ impl LlmpClient { #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] mod tests { + use alloc::vec; use core::time::Duration; use std::thread::sleep; use serial_test::serial; + use shmem_providers::{ShMemProvider, StdShMemProvider}; use super::{ LlmpClient, LlmpConnection::{self, IsBroker, IsClient}, Tag, }; - use crate::shmem::{ShMemProvider, StdShMemProvider}; #[test] #[serial] diff --git a/crates/minibsod/Cargo.toml b/crates/minibsod/Cargo.toml new file mode 100644 index 00000000000..80091363a2a --- /dev/null +++ b/crates/minibsod/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "minibsod" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "A library to dump current register states, etc., on crash" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "bsod"] +edition = "2024" +rust-version = "1.87" +categories = ["os"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +document-features = ["dep:document-features"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } +libc = { workspace = true } +exceptional = { workspace = true, features = ["alloc"] } + +[target.'cfg(target_vendor = "apple")'.dependencies] +mach2 = "0.4.2" + +[lints] +workspace = true diff --git a/crates/minibsod/LICENSE-APACHE b/crates/minibsod/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/minibsod/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/minibsod/LICENSE-MIT b/crates/minibsod/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/minibsod/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/minibsod/README.md b/crates/minibsod/README.md new file mode 100644 index 00000000000..d3a6b25d5ca --- /dev/null +++ b/crates/minibsod/README.md @@ -0,0 +1,116 @@ +# MinBSOD: Create a dump of registers, stacktrace, and program state + +LibAFL logo + +The `minibsod` crate provides a cross-platform library to generate a "mini blue screen of death" (MinBSOD) on program crashes. It is designed to provide developers with a quick overview of the program's state at the time of a critical failure. This is particularly useful for debugging and triaging crashes in complex applications, such as fuzzing targets. + +`minibsod` is a part of the [LibAFL](https://github.com/AFLplusplus/LibAFL) project. + +## Features + +* **Crash Information:** Dumps the signal (on Unix) or exception code (on Windows) that caused the crash. +* **Register State:** Prints the content of all important CPU registers at the time of the crash. +* **Stack Backtrace:** Displays a stack backtrace to help identify the call sequence that led to the crash. +* **Memory Mappings:** Shows the process's memory mappings to provide context about the memory layout. +* **Cross-Platform:** Supports a wide range of operating systems and architectures. + +## Usage + +To use `minibsod`, you need to set up a signal handler (on Unix-like systems) or an exception handler (on Windows) that calls the `generate_minibsod` function. + +Here is a conceptual example for Unix-like systems: + +```rust +use std::io::{stdout, BufWriter}; +use exceptional::unix_signals::{ucontext_t, Sig, Signal, SignalHandler, SignalHandlerFlags}; +use libc::siginfo_t; +use minibsod::generate_minibsod; + +extern "C" fn handle_crash( + signal: Signal, + siginfo: &mut siginfo_t, + ucontext: &mut ucontext_t, +) { + let mut writer = BufWriter::new(stdout()); + // The generate_minibsod function will print a detailed crash report to the writer. + generate_minibsod(&mut writer, signal, siginfo, Some(ucontext)).unwrap(); +} + +fn setup_signal_handler() { + let handler = SignalHandler::new( + handle_crash, + // A list of signals to handle. + [ + Sig::Ill, + Sig::Abrt, + Sig::Bus, + Sig::Segv, + Sig::Trap, + Sig::Sys, + ], + SignalHandlerFlags::empty(), + ); + // Install the handler. + handler.install().unwrap(); +} + +fn main() { + setup_signal_handler(); + + // Your application logic here. + // If a handled signal occurs, the handle_crash function will be called. + + // For example, to trigger a crash: + // unsafe { + // *(0xdeadbeef as *mut u32) = 0; + // } +} +``` + +On Windows, you would use a similar approach with `SetUnhandledExceptionFilter` to set up a top-level exception handler. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_bolts/src/minibsod.rs b/crates/minibsod/src/lib.rs similarity index 96% rename from crates/libafl_bolts/src/minibsod.rs rename to crates/minibsod/src/lib.rs index 115be72c021..dddb73e0b7a 100644 --- a/crates/libafl_bolts/src/minibsod.rs +++ b/crates/minibsod/src/lib.rs @@ -1,5 +1,53 @@ //! Implements a mini-bsod generator. //! It dumps all important registers and prints a stacktrace. +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![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( + 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 + ) +)] + +#[macro_use] +extern crate std; +#[doc(hidden)] +pub extern crate alloc; #[cfg(unix)] use alloc::vec::Vec; @@ -9,6 +57,8 @@ use std::io::{BufWriter, Write}; #[cfg(any(target_os = "solaris", target_os = "illumos"))] use std::process::Command; +#[cfg(unix)] +use exceptional::unix_signals::{Signal, ucontext_t}; #[cfg(unix)] use libc::siginfo_t; #[cfg(target_vendor = "apple")] @@ -23,9 +73,6 @@ use mach2::{ #[cfg(windows)] use windows::Win32::System::Diagnostics::Debug::{CONTEXT, EXCEPTION_POINTERS}; -#[cfg(unix)] -use crate::os::unix_signals::{Signal, ucontext_t}; - /// Necessary info to print a mini-BSOD. #[derive(Debug)] #[cfg(unix)] @@ -1134,7 +1181,7 @@ pub fn generate_minibsod( writeln!(writer, "Received signal {signal}")?; } writeln!(writer, "{:━^100}", " BACKTRACE ")?; - writeln!(writer, "{:?}", backtrace::Backtrace::new())?; + writeln!(writer, "{:?}", std::backtrace::Backtrace::force_capture())?; writeln!(writer, "{:━^100}", " MAPS ")?; write_minibsod(writer) } @@ -1182,7 +1229,9 @@ mod tests { use std::io::{BufWriter, stdout}; - use crate::{minibsod::dump_registers, os::unix_signals::ucontext}; + use exceptional::unix_signals::ucontext; + + use crate::dump_registers; #[test] #[cfg_attr(miri, ignore)] diff --git a/crates/no_std_time/Cargo.toml b/crates/no_std_time/Cargo.toml new file mode 100644 index 00000000000..514d7de4069 --- /dev/null +++ b/crates/no_std_time/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "no_std_time" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Time measurments that work in no_std environments" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["alloc"] + +## Enables all features that allocate in `no_std` +alloc = [] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } + +[lints] +workspace = true diff --git a/crates/no_std_time/LICENSE-APACHE b/crates/no_std_time/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/no_std_time/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/no_std_time/LICENSE-MIT b/crates/no_std_time/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/no_std_time/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/no_std_time/README.md b/crates/no_std_time/README.md new file mode 100644 index 00000000000..5f8c9783167 --- /dev/null +++ b/crates/no_std_time/README.md @@ -0,0 +1,120 @@ +# `No_Std_Time`: `no_std`-friendly timing and timestamping + +LibAFL logo + +The `no_std_time` crate provides `no_std`-friendly timing and high-performance timestamping utilities. It is a core component of the [LibAFL](https://github.com/AFLplusplus/LibAFL) fuzzing framework. + +This crate offers two main pieces of functionality: +1. A way to get the current system time as a `Duration`, even in `no_std` environments. +2. A high-performance time counter using CPU-specific instructions (`rdtsc`, etc.) for fast measurements. + +## Usage + +### Getting the Current Time + +You can get the current time using the `current_time()` function. + +With the `std` feature enabled (the default), this works out of the box: +```rust +use no_std_time::current_time; + +let time = current_time(); +println!("Current time: {:?}", time); +``` + +In a `no_std` environment, you must provide an implementation for `external_current_millis` that returns the milliseconds since the UNIX epoch. + +```rust +// In your no_std binary: +#[no_mangle] +pub extern "C" fn external_current_millis() -> u64 { + // Return time from your platform-specific source, e.g., an RTC. + 1678886400000 +} +``` + +### High-Performance Timestamping + +For high-performance measurements, `read_time_counter()` provides access to fast, low-level CPU cycle counters. This is useful for profiling and performance-critical code. + +```rust +use no_std_time::read_time_counter; + +let start = read_time_counter(); +// ... do some work ... +let end = read_time_counter(); +let elapsed = end - start; +println!("Work took {} cycles", elapsed); +``` + +This function is optimized for the following architectures: +- `x86` and `x86_64` (using `rdtsc`) +- `aarch64` (using `cntvct_el0`) +- `arm` (using the performance monitor unit) +- `riscv32` and `riscv64` (using `rdcycle`) + +On other architectures, it falls back to a system-time-based implementation. + +### Formatting Durations + +The crate includes a utility to format a `Duration` into a human-readable string. This requires the `alloc` feature. + +```rust +use core::time::Duration; +use no_std_time::format_duration; + +let duration = Duration::from_secs(3661); +let formatted = format_duration(&duration); +assert_eq!(formatted, "1h-1m-1s"); +``` + +## Features + +- `std` (default): Enables functionality that depends on the standard library, such as getting the system time automatically. +- `alloc` (default): Enables features that require heap allocation, such as `format_duration`. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/no_std_time/src/lib.rs b/crates/no_std_time/src/lib.rs new file mode 100644 index 00000000000..b42f5d14675 --- /dev/null +++ b/crates/no_std_time/src/lib.rs @@ -0,0 +1,144 @@ +//! Time functions that can be used on `no_std` +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[cfg(feature = "alloc")] +#[macro_use] +#[doc(hidden)] +pub extern crate alloc; + +use core::time; + +pub mod time_counters; +#[cfg(feature = "alloc")] +use alloc::string::String; +#[cfg(feature = "std")] +use std::time::{SystemTime, UNIX_EPOCH}; + +pub use time_counters::read_time_counter; + +/// Format a `Duration` into a HMS string +#[cfg(feature = "alloc")] +#[must_use] +pub fn format_duration(duration: &time::Duration) -> String { + const MINS_PER_HOUR: u64 = 60; + const HOURS_PER_DAY: u64 = 24; + + const SECS_PER_MINUTE: u64 = 60; + const SECS_PER_HOUR: u64 = SECS_PER_MINUTE * MINS_PER_HOUR; + const SECS_PER_DAY: u64 = SECS_PER_HOUR * HOURS_PER_DAY; + + let total_secs = duration.as_secs(); + let secs = total_secs % SECS_PER_MINUTE; + + if total_secs < SECS_PER_MINUTE { + format!("{secs}s") + } else { + let mins = (total_secs / SECS_PER_MINUTE) % MINS_PER_HOUR; + if total_secs < SECS_PER_HOUR { + format!("{mins}m-{secs}s") + } else { + let hours = (total_secs / SECS_PER_HOUR) % HOURS_PER_DAY; + if total_secs < SECS_PER_DAY { + format!("{hours}h-{mins}m-{secs}s") + } else { + let days = total_secs / SECS_PER_DAY; + format!("{days}days {hours}h-{mins}m-{secs}s") + } + } + } +} + +#[cfg(all(any(doctest, test), not(feature = "std")))] +/// Provide custom time in `no_std` tests. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn external_current_millis() -> u64 { + // TODO: use "real" time here + 1000 +} + +/// Current time +#[cfg(feature = "std")] +#[must_use] +#[inline] +pub fn current_time() -> time::Duration { + SystemTime::now().duration_since(UNIX_EPOCH).unwrap() +} + +// external defined function in case of `no_std` +// +// Define your own `external_current_millis()` function via `extern "C"` +// which is linked into the binary and called from here. +#[cfg(all(not(any(doctest, test)), not(feature = "std")))] +unsafe extern "C" { + //#[unsafe(no_mangle)] + fn external_current_millis() -> u64; +} + +/// Current time (fixed fallback for `no_std`) +#[cfg(not(feature = "std"))] +#[inline] +#[must_use] +pub fn current_time() -> time::Duration { + let millis = unsafe { external_current_millis() }; + time::Duration::from_millis(millis) +} + +/// Gets current nanoseconds since [`UNIX_EPOCH`] +#[must_use] +#[inline] +pub fn current_nanos() -> u64 { + current_time().as_nanos() as u64 +} + +/// Gets current milliseconds since [`UNIX_EPOCH`] +#[must_use] +#[inline] +pub fn current_milliseconds() -> u64 { + current_time().as_millis() as u64 +} diff --git a/crates/libafl_bolts/src/cpu.rs b/crates/no_std_time/src/time_counters.rs similarity index 100% rename from crates/libafl_bolts/src/cpu.rs rename to crates/no_std_time/src/time_counters.rs diff --git a/crates/ownedref/Cargo.toml b/crates/ownedref/Cargo.toml new file mode 100644 index 00000000000..d6b564f5f24 --- /dev/null +++ b/crates/ownedref/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "ownedref" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Library to pass around references that will be owned types on deserialization" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["alloc"] + +## Enables all features that allocate in `no_std` +alloc = [] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } + +libafl_core = { workspace = true } +serde = { workspace = true } + +[lints] +workspace = true diff --git a/crates/ownedref/LICENSE-APACHE b/crates/ownedref/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/ownedref/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/ownedref/LICENSE-MIT b/crates/ownedref/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/ownedref/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/ownedref/README.md b/crates/ownedref/README.md new file mode 100644 index 00000000000..a42efd2fa20 --- /dev/null +++ b/crates/ownedref/README.md @@ -0,0 +1,141 @@ +# `OwnedRef`: Owned references for the masses + + LibAFL logo + +The `ownedref` crate provides a set of wrappers that abstract over accessing data that can be either owned or borrowed (referenced). The primary purpose of these wrappers is to enable serialization of data structures that contain references or raw pointers. + +A key feature is the ability to serialize references by transparently converting any borrowed data to an owned form. This is particularly useful in applications like serialization for IPC or saving state, where we can't save memory addresses but need to preserve the data they point to. + +When you have a struct that contains references, you can't directly serialize it with `serde`. `ownedref` provides wrapper types that can be used in place of references. These wrappers are enums that can hold either a reference or an owned value. When serializing, they always serialize the underlying data, and when deserializing, they create an owned value. + +This allows you to work with references for performance within your application, and seamlessly serialize and deserialize your data structures when needed. + +## Wrappers + +The crate provides the following wrappers: + +- `OwnedRef<'a, T>`: Wraps a `&'a T` or `Box`. +- `OwnedRefMut<'a, T>`: Wraps a `&'a mut T` or `Box`. +- `OwnedSlice<'a, T>`: Wraps a `&'a [T]` or `Vec`. +- `OwnedMutSlice<'a, T>`: Wraps a `&'a mut [T]` or `Vec`. +- `OwnedMutSizedSlice<'a, T, const N: usize>`: Wraps a `&'a mut [T; N]` or `Box<[T; N]>`. +- `OwnedPtr`: Wraps a `*const T` or `Box`. +- `OwnedMutPtr`: Wraps a `*mut T` or `Box`. + +## Usage + +Here are some examples of how to use the `ownedref` wrappers. + +### `OwnedRef` + +`OwnedRef` can be used to hold either a reference to a value or an owned value. + +```rust +use ownedref::OwnedRef; +use serde::{Serialize, Deserialize}; + +// A struct that can be either borrowed or owned. +#[derive(Serialize, Deserialize, Debug)] +struct MyStruct<'a> { + data: OwnedRef<'a, [u8]>, +} + +// Create an instance with a borrowed reference. +let data = vec![1, 2, 3, 4]; +let borrowed_struct = MyStruct { data: OwnedRef::Ref(data.as_slice()) }; + +// You can access the data using `as_ref`. +assert_eq!(borrowed_struct.data.as_ref(), &[1, 2, 3, 4]); + +// Serialize the struct. This will copy the data. +let serialized = serde_json::to_string(&borrowed_struct).unwrap(); +println!("Serialized: {}", serialized); + +// Deserialize the struct. This will create an owned value. +let deserialized_struct: MyStruct = serde_json::from_str(&serialized).unwrap(); +assert_eq!(deserialized_struct.data.as_ref(), &[1, 2, 3, 4]); + +// The deserialized struct now owns the data. +match deserialized_struct.data { + OwnedRef::Owned(_) => println!("Data is owned."), + _ => panic!("Data should be owned after deserialization."), +} +``` + +### `OwnedSlice` + +`OwnedSlice` is useful for slices of data. + +```rust +use ownedref::OwnedSlice; +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct DataContainer<'a> { + slice: OwnedSlice<'a, u32>, +} + +fn main() { + // With a borrowed slice + let original_data = vec![10, 20, 30]; + let container_borrowed = DataContainer { + slice: OwnedSlice::from(original_data.as_slice()), + }; + + assert_eq!(container_borrowed.slice.as_ref(), &[10, 20, 30]); + + let serialized = serde_json::to_string(&container_borrowed).unwrap(); + println!("Serialized: {}", serialized); + + // Deserialize into an owned version + let container_deserialized: DataContainer = serde_json::from_str(&serialized).unwrap(); + assert_eq!(container_deserialized.slice.as_ref(), &[10, 20, 30]); + assert!(container_deserialized.slice.is_owned()); +} +``` + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + diff --git a/crates/libafl_bolts/src/ownedref.rs b/crates/ownedref/src/lib.rs similarity index 95% rename from crates/libafl_bolts/src/ownedref.rs rename to crates/ownedref/src/lib.rs index 10a3f7de857..55cde7a147e 100644 --- a/crates/libafl_bolts/src/ownedref.rs +++ b/crates/ownedref/src/lib.rs @@ -1,5 +1,57 @@ //! Wrappers that abstracts references (or pointers) and owned data accesses. -// The serialization is towards owned, allowing to serialize pointers without troubles. +//! The serialization is towards owned, allowing to serialize pointers without troubles. +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[doc(hidden)] +pub extern crate alloc; + +pub mod subrange; use alloc::{boxed::Box, vec::Vec}; use core::{ @@ -11,18 +63,16 @@ use core::{ slice::{Iter, IterMut, SliceIndex}, }; +use libafl_core::{AsSizedSlice, AsSizedSliceMut, AsSlice, AsSliceMut, IntoOwned, Truncate}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::{ - AsSizedSlice, AsSizedSliceMut, AsSlice, AsSliceMut, IntoOwned, Truncate, shmem::ShMem, -}; - /// Constant size array visitor for serde deserialization. /// Mostly taken from mod arrays { use alloc::{boxed::Box, fmt, vec::Vec}; use core::{convert::TryInto, marker::PhantomData}; + use libafl_core::format; use serde::{ Deserialize, Deserializer, de::{SeqAccess, Visitor}, @@ -89,23 +139,6 @@ impl UnsafeMarker { } } -impl Truncate for &[T] { - fn truncate(&mut self, len: usize) { - *self = &self[..len]; - } -} - -impl Truncate for &mut [T] { - fn truncate(&mut self, len: usize) { - let value = core::mem::take(self); - let len = value.len().min(len); - let truncated = value - .get_mut(..len) - .expect("Truncate with len <= len() should always work"); - let _: &mut [T] = core::mem::replace(self, truncated); - } -} - /// Wrap a reference and convert to a [`Box`] on serialize #[derive(Debug)] pub enum OwnedRef<'a, T> @@ -183,18 +216,6 @@ impl OwnedRef<'_, T> where T: Sized + 'static, { - /// Returns a new [`OwnedRef`], pointing to the given [`ShMem`]. - /// - /// # Panics - /// Panics if the given shared mem is too small - /// - /// # Safety - /// The shared memory needs to start with a valid object of type `T`. - /// Any use of this [`OwnedRef`] will dereference a pointer to the shared memory accordingly. - pub unsafe fn from_shmem(shmem: &mut SHM) -> Self { - unsafe { Self::from_ptr(shmem.as_mut_ptr_of().unwrap()) } - } - /// Returns a new [`OwnedRef`], owning the given value. pub fn owned(val: T) -> Self { Self::Owned(Box::new(val)) @@ -316,18 +337,6 @@ impl OwnedRefMut<'_, T> where T: Sized + 'static, { - /// Returns a new [`OwnedRefMut`], pointing to the given [`ShMem`]. - /// - /// # Panics - /// Panics if the given shared mem is too small - /// - /// # Safety - /// The shared memory needs to start with a valid object of type `T`. - /// Any use of this [`OwnedRefMut`] will dereference a pointer to the shared memory accordingly. - pub unsafe fn from_shmem(shmem: &mut SHM) -> Self { - unsafe { Self::from_mut_ptr(shmem.as_mut_ptr_of().unwrap()) } - } - /// Returns a new [`OwnedRefMut`], owning the given value. pub fn owned(val: T) -> Self { Self::Owned(Box::new(val)) diff --git a/crates/libafl_bolts/src/subrange.rs b/crates/ownedref/src/subrange.rs similarity index 99% rename from crates/libafl_bolts/src/subrange.rs rename to crates/ownedref/src/subrange.rs index 1228723a3a6..65d787fe970 100644 --- a/crates/libafl_bolts/src/subrange.rs +++ b/crates/ownedref/src/subrange.rs @@ -6,10 +6,9 @@ use core::{ ops::{Bound, Range, RangeBounds}, }; -use crate::{ - HasLen, - ownedref::{OwnedMutSlice, OwnedSlice}, -}; +use libafl_core::HasLen; + +use crate::{OwnedMutSlice, OwnedSlice}; /// An immutable contiguous subslice of a byte slice. /// It is mostly useful to cheaply wrap a subslice of a given input. @@ -35,6 +34,20 @@ pub struct SubRangeMutSlice<'a, T> { range: Range, } +impl HasLen for SubRangeSlice<'_, T> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl HasLen for SubRangeMutSlice<'_, T> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + /// Slice wrapper keeping track of the current read position. /// Convenient wrapper when the slice must be split in multiple sub-slices and read sequentially. #[derive(Debug)] @@ -96,20 +109,6 @@ impl<'a, T> From<&'a [T]> for SliceReader<'a, T> { } } -impl HasLen for SubRangeSlice<'_, T> { - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} - -impl HasLen for SubRangeMutSlice<'_, T> { - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} - /// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) pub fn start_index(range: &R) -> usize where diff --git a/crates/serde_anymap/Cargo.toml b/crates/serde_anymap/Cargo.toml new file mode 100644 index 00000000000..ec2739ab97d --- /dev/null +++ b/crates/serde_anymap/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "serde_anymap" +description = "A map that can retrieve values by type - and is SerDe serializable" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "stable_anymap"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["libafl_core/std", "erased-serde/std", "serde/std"] + +## Create keys that are more stable between compilations +stable_anymap = [] +serdeany_autoreg = ["ctor"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } + +ahash = { workspace = true } +ctor = { workspace = true, optional = true } +erased-serde = { workspace = true, default-features = false, features = [ + "alloc", +] } +hashbrown = { workspace = true } +libafl_core = { workspace = true } +postcard = { workspace = true } +serde = { workspace = true } +static_assertions = { workspace = true } + +[lints] +workspace = true diff --git a/crates/serde_anymap/LICENSE-APACHE b/crates/serde_anymap/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/serde_anymap/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/serde_anymap/LICENSE-MIT b/crates/serde_anymap/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/serde_anymap/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/serde_anymap/README.md b/crates/serde_anymap/README.md new file mode 100644 index 00000000000..ee43d39ebc0 --- /dev/null +++ b/crates/serde_anymap/README.md @@ -0,0 +1,216 @@ +# `Serde_AnyMap`: A serializable map that stores and retrieves elements by type. + +LibAFL logo + +`SerdeAnyMap` provides map-like data structures that can store values of different types and can be serialized and deserialized with `Serde`. The values are stored and retrieved using their `TypeId` as the key, making it a powerful tool for dynamic, type-safe data storage. + +There are two main types provided by this crate: +- `SerdeAnyMap`: A simple map from `TypeId` to a value of that type. +- `NamedSerdeAnyMap`: A map from `TypeId` to a further map of `String` names to values, allowing you to store multiple instances of the same type under different names. + +## How to Use + +### 1. Add `serde_anymap` to your dependencies + +```toml +[dependencies] +serde_anymap = "0.1.0" +# For automatic type registration (recommended) +serde_anymap = { version = "0.1.0", features = ["serdeany_autoreg"] } +``` + +### 2. Define Your Types and Implement `SerdeAny` + +To be stored in a `SerdeAnyMap`, your types must implement the `SerdeAny` trait. The easiest way to do this is with the `impl_serdeany!` macro. Your types must also derive `Serialize` and `Deserialize`. + +```rust +use serde::{Serialize, Deserialize}; +use serde_anymap::impl_serdeany; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct MyConfig { + is_enabled: bool, + port: u16, +} +impl_serdeany!(MyConfig); + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct UserData(String); +impl_serdeany!(UserData); +``` + +### 3. Use `SerdeAnyMap` + +You can now insert instances of your types into the map and retrieve them by type. + +```rust +# use serde::{Serialize, Deserialize}; +# use serde_anymap::impl_serdeany; +# #[derive(Debug, Serialize, Deserialize, PartialEq)] +# struct MyConfig { is_enabled: bool, port: u16 } +# impl_serdeany!(MyConfig); +# #[derive(Debug, Serialize, Deserialize, PartialEq)] +# struct UserData(String); +# impl_serdeany!(UserData); +use serde_anymap::serdeany::SerdeAnyMap; + +let mut map = SerdeAnyMap::new(); + +map.insert(MyConfig { is_enabled: true, port: 8080 }); +map.insert(UserData("John Doe".to_string())); + +// Retrieve values by type +assert_eq!(map.get::().unwrap().port, 8080); +assert_eq!(map.get::().unwrap().0, "John Doe"); + +// You can also get mutable access +let config = map.get_mut::().unwrap(); +config.port = 9090; +assert_eq!(map.get::().unwrap().port, 9090); +``` + +### 4. Serialization and Deserialization + +The real power of `serde_anymap` is its ability to serialize and deserialize these heterogeneous maps. + +**Important:** For deserialization to work, the types you are deserializing must be registered. See the "Type Registration" section below. + +```rust +# use serde::{Serialize, Deserialize}; +# use serde_anymap::{impl_serdeany, serdeany::{SerdeAnyMap, RegistryBuilder}}; +# #[derive(Debug, Serialize, Deserialize, PartialEq)] +# struct MyConfig { is_enabled: bool, port: u16 } +# impl_serdeany!(MyConfig); +# #[derive(Debug, Serialize, Deserialize, PartialEq)] +# struct UserData(String); +# impl_serdeany!(UserData); +# let mut map = SerdeAnyMap::new(); +# map.insert(MyConfig { is_enabled: true, port: 8080 }); +# map.insert(UserData("John Doe".to_string())); +// This is only needed if you don't use the `serdeany_autoreg` feature +#[cfg(not(feature = "serdeany_autoreg"))] +unsafe { + RegistryBuilder::register::(); + RegistryBuilder::register::(); +} + +// Serialize the map to a JSON string +let serialized = serde_json::to_string_pretty(&map).unwrap(); +println!("{}", serialized); + +// Deserialize it back +let deserialized: SerdeAnyMap = serde_json::from_str(&serialized).unwrap(); + +assert!(deserialized.get::().is_some()); +assert_eq!(deserialized.get::().unwrap(), map.get::().unwrap()); +assert_eq!(deserialized.get::().unwrap(), map.get::().unwrap()); +``` + +## Type Registration + +For `serde_anymap` to deserialize a generic `dyn SerdeAny` trait object, it needs a way to map a serialized type identifier back to a concrete type. This is done via a global type registry. + +#### Automatic Registration (Recommended) + +The easiest way to handle registration is to enable the `serdeany_autoreg` feature. This uses the [`ctor`](https://crates.io/crates/ctor) crate to automatically run registration code for each type when your program starts. The `impl_serdeany!` macro handles this for you. + +```toml +# In your Cargo.toml +serde_anymap = { version = "0.1.0", features = ["serdeany_autoreg"] } +``` + +With this feature, you don't need to do anything else. Just use `impl_serdeany!` and it works. + +#### Manual Registration + +If you cannot use `serdeany_autoreg`, you must register your types manually at the start of your program. + +```rust +use serde_anymap::serdeany::RegistryBuilder; + +// This must be done before any deserialization happens. +// It is safe to call multiple times. +unsafe { + RegistryBuilder::register::(); + RegistryBuilder::register::(); +} + +// Your application logic... +``` + +## `NamedSerdeAnyMap` + +If you need to store multiple objects of the same type, you can use `NamedSerdeAnyMap`, which adds a string name as a key. + +```rust +# use serde::{Serialize, Deserialize}; +# use serde_anymap::{impl_serdeany, serdeany::{NamedSerdeAnyMap, RegistryBuilder}}; +# #[derive(Debug, Serialize, Deserialize, PartialEq)] +# struct UserData(String); +# impl_serdeany!(UserData); +# #[cfg(not(feature = "serdeany_autoreg"))] +# unsafe { RegistryBuilder::register::(); } +let mut named_map = NamedSerdeAnyMap::new(); + +named_map.insert("user1", UserData("Alice".to_string())); +named_map.insert("user2", UserData("Bob".to_string())); + +assert_eq!(named_map.get::("user1").unwrap().0, "Alice"); +assert_eq!(named_map.get::("user2").unwrap().0, "Bob"); + +let serialized = serde_json::to_string(&named_map).unwrap(); +let deserialized: NamedSerdeAnyMap = serde_json::from_str(&serialized).unwrap(); + +assert_eq!(deserialized.get::("user1").unwrap().0, "Alice"); +``` + +## Features + +- `serdeany_autoreg`: Enables automatic type registration at program startup. Highly recommended. +- `stable_anymap`: Uses the type name (`&'static str`) as the key instead of `TypeId`. This makes the serialized output more stable across different compilations, but it can be slightly slower and may cause issues if you have types with the same name in different modules. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/libafl_bolts/src/anymap.rs b/crates/serde_anymap/src/anymap.rs similarity index 100% rename from crates/libafl_bolts/src/anymap.rs rename to crates/serde_anymap/src/anymap.rs diff --git a/crates/serde_anymap/src/lib.rs b/crates/serde_anymap/src/lib.rs new file mode 100644 index 00000000000..1af74ea4f11 --- /dev/null +++ b/crates/serde_anymap/src/lib.rs @@ -0,0 +1,58 @@ +//! A map that can retrieve values by type - and is `Serde` serializable. +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[doc(hidden)] +pub extern crate alloc; + +#[cfg(feature = "serdeany_autoreg")] +#[doc(hidden)] +pub use ctor; + +pub mod anymap; +pub mod serdeany; diff --git a/crates/libafl_bolts/src/serdeany.rs b/crates/serde_anymap/src/serdeany.rs similarity index 99% rename from crates/libafl_bolts/src/serdeany.rs rename to crates/serde_anymap/src/serdeany.rs index 9535c039639..9f6d6cb11dc 100644 --- a/crates/libafl_bolts/src/serdeany.rs +++ b/crates/serde_anymap/src/serdeany.rs @@ -24,7 +24,7 @@ pub type TypeRepr = u128; pub type TypeRepr = Cow<'static, str>; /// Error string when no types at all have been registered yet. -pub(crate) const ERR_EMPTY_TYPES_REGISTER: &str = "Empty types registry. Please enable the `serdeany_autoreg` feature in libafl_bolts or register all required types manually using RegistryBuilder::register()."; +pub(crate) const ERR_EMPTY_TYPES_REGISTER: &str = "Empty types registry. Please enable the `serdeany_autoreg` feature for serde_anymap or register all required types manually using RegistryBuilder::register()."; #[cfg(not(feature = "stable_anymap"))] fn type_repr() -> TypeRepr @@ -124,14 +124,12 @@ pub mod serdeany_registry { DefaultHashBuilder, HashMap, hash_map::{Values, ValuesMut}, }; + use libafl_core::{Error, format}; use serde::{Deserialize, Serialize, de}; - use crate::{ - Error, - serdeany::{ - DeserializeCallback, DeserializeCallbackSeed, SerdeAny, TypeRepr, type_repr, - type_repr_owned, - }, + use crate::serdeany::{ + DeserializeCallback, DeserializeCallbackSeed, SerdeAny, TypeRepr, type_repr, + type_repr_owned, }; /// A [`HashMap`] that maps from [`TypeRepr`] to a deserializer and its [`TypeRepr`]. diff --git a/crates/shmem_providers/Cargo.toml b/crates/shmem_providers/Cargo.toml new file mode 100644 index 00000000000..8f8887a7984 --- /dev/null +++ b/crates/shmem_providers/Cargo.toml @@ -0,0 +1,90 @@ +[package] +name = "shmem_providers" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Platform independent shared memory providers for Windows, Linux, Android, iOS, ..." +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "shmem", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = [ + "alloc", + "libafl_core/std", + "uds", + "nix", + "libafl_core/nix", + "serial_test", + "uuid", +] + +## Enables all features that allocate in `no_std` +alloc = ["libafl_core/alloc", "hashbrown", "postcard", "libafl_core/postcard"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } +fast_rands = { workspace = true } +libafl_core = { workspace = true } +log = { workspace = true } +postcard = { workspace = true, optional = true } # no_std compatible serde serialization format +serde = { workspace = true, features = ["derive"] } +hashbrown = { workspace = true, features = [ + "serde", + "default-hasher", +], default-features = false, optional = true } # A faster hashmap, nostd compatible + +# optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) +serial_test = { workspace = true, optional = true, default-features = false, features = [ + "logging", +] } +uuid = { workspace = true, optional = true } + +[target.'cfg(unix)'.dependencies] +libc = { workspace = true } +uds = { version = "0.4.2", optional = true, default-features = false } +nix = { workspace = true, optional = true, default-features = false, features = [ + "fs", + "signal", + "socket", + "poll", +] } + +[target.'cfg(windows)'.dependencies] +windows = { workspace = true, features = [ + "Win32_Foundation", + "Win32_Security", + "Win32_System_Console", + "Win32_System_Diagnostics_Debug", + "Win32_System_Kernel", + "Win32_System_Memory", + "Win32_System_SystemInformation", + "Win32_System_Threading", +] } + +[lints] +workspace = true diff --git a/crates/shmem_providers/LICENSE-APACHE b/crates/shmem_providers/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/shmem_providers/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/shmem_providers/LICENSE-MIT b/crates/shmem_providers/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/shmem_providers/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/shmem_providers/README.md b/crates/shmem_providers/README.md new file mode 100644 index 00000000000..963c96a4890 --- /dev/null +++ b/crates/shmem_providers/README.md @@ -0,0 +1,78 @@ +# `shmem_providers`: Cross-Platform Shared Memory for High-Performance IPC + +LibAFL logo + +`shmem_providers` is a crate that provides a unified, cross-platform API for creating and using shared memory. Shared memory is a key component for high-performance inter-process communication (IPC), which is essential for fuzzing with `LibAFL`. For example, it's used to share coverage maps, corpus inputs, or other data between the fuzzer process and the target application without expensive copies. + +This crate abstracts away the platform-specific details of shared memory implementation, allowing developers to write portable code that works across Windows, Linux, macOS, Android, and other Unix-like systems. + +## Core Abstractions + +The crate exposes two main traits: + +- **`ShMem`**: Represents a segment of shared memory. It behaves like a mutable byte slice (`&mut [u8]`), allowing direct memory manipulation. Each segment has a unique `ShMemId` that can be used to reopen it from another process. +- **`ShMemProvider`**: A factory for creating and accessing `ShMem` segments. It handles the OS-specific logic for allocating, mapping, and managing shared memory regions. + +By using the `StdShMemProvider` type alias, you can use the default, recommended provider for the current target platform, simplifying the creation of cross-platform tools. + +## Platform Implementations + +`shmem_providers` automatically selects the best implementation for your target OS: + +- **Windows**: Uses `CreateFileMappingA` and `MapViewOfFile` for shared memory. +- **Linux**: Prefers modern mechanisms like `memfd_create` where available, falling back to POSIX (`shm_open` and `mmap`) or System V IPC (`shmget`/`shmat`). +- **macOS**: Uses `shm_open` and `mmap`. Due to kernel behavior on macOS, it often requires a server-based approach (`ShMemService`) to reliably manage and clean up shared memory segments between processes. +- **Android**: Uses the `ashmem` subsystem, which is Android's specialized shared memory mechanism. + +## Advanced Features + +The crate also includes advanced abstractions for complex scenarios: + +- **`ShMemService`**: A server-based provider for platforms that require a central process to manage shared memory lifecycles. This is particularly useful on macOS. +- **`RcShMemProvider`**: A reference-counted wrapper that allows a provider to be safely shared across threads and handles the necessary setup and teardown logic across `fork()` calls in multi-process applications. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/libafl_bolts/src/shmem.rs b/crates/shmem_providers/src/lib.rs similarity index 96% rename from crates/libafl_bolts/src/shmem.rs rename to crates/shmem_providers/src/lib.rs index 315fae65641..83271261788 100644 --- a/crates/libafl_bolts/src/shmem.rs +++ b/crates/shmem_providers/src/lib.rs @@ -1,5 +1,65 @@ //! A generic shared memory region to be used by any functions (queues or feedbacks //! too.) +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[doc(hidden)] +pub extern crate alloc; + +#[cfg(feature = "alloc")] +use alloc::vec; + +pub use libafl_core::Error; + +#[cfg(all(unix, feature = "std"))] +pub mod pipes; +#[cfg(all(feature = "std", unix, not(target_os = "haiku")))] +pub mod unix_shmem_server; #[cfg(feature = "alloc")] use alloc::{rc::Rc, string::ToString, vec::Vec}; @@ -29,11 +89,10 @@ pub use unix_shmem::{UnixShMem, UnixShMemProvider}; #[cfg(all(windows, feature = "std"))] pub use win32_shmem::{Win32ShMem, Win32ShMemProvider}; -use crate::Error; #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] -use crate::os::pipes::Pipe; +use crate::pipes::Pipe; #[cfg(all(feature = "std", unix, not(target_os = "haiku")))] -pub use crate::os::unix_shmem_server::{ServedShMem, ServedShMemProvider, ShMemService}; +pub use crate::unix_shmem_server::{ServedShMem, ServedShMemProvider, ShMemService}; /// The standard sharedmem provider #[cfg(all(windows, feature = "std"))] @@ -681,16 +740,14 @@ pub mod unix_shmem { }; use std::{io, path::Path, process}; + use fast_rands::{Rand, StdRand}; + use libafl_core::Error; use libc::{ c_int, c_uchar, close, fcntl, ftruncate, mmap, munmap, shm_open, shm_unlink, shmat, shmctl, shmdt, shmget, }; - use crate::{ - Error, - rands::{Rand, StdRand}, - shmem::{ShMem, ShMemId, ShMemProvider}, - }; + use crate::{ShMem, ShMemId, ShMemProvider}; /// The max number of bytes used when generating names for [`MmapShMem`]s. pub const MAX_MMAP_FILENAME_LEN: usize = 20; @@ -1017,7 +1074,7 @@ pub mod unix_shmem { } fn new_shmem(&mut self, map_size: usize) -> Result { - let mut rand = StdRand::with_seed(crate::rands::random_seed()); + let mut rand = StdRand::with_seed(fast_rands::random_seed()); let id = rand.next() as u32; let mut full_file_name = format!("libafl_{}_{}", process::id(), id); // leave one byte space for the null byte. @@ -1188,10 +1245,7 @@ pub mod unix_shmem { open, }; - use crate::{ - Error, - shmem::{ShMem, ShMemId, ShMemProvider}, - }; + use crate::{Error, ShMem, ShMemId, ShMemProvider}; /// An ashmem based impl for linux/android #[derive(Debug, Clone)] @@ -1409,10 +1463,7 @@ pub mod unix_shmem { use libc::{MAP_SHARED, PROT_READ, PROT_WRITE, close, fstat, ftruncate, mmap, munmap}; use nix::sys::memfd::{MFdFlags, memfd_create}; - use crate::{ - Error, - shmem::{ShMem, ShMemId, ShMemProvider}, - }; + use crate::{Error, ShMem, ShMemId, ShMemProvider}; /// An memfd based impl for linux/android #[cfg(unix)] @@ -1609,10 +1660,7 @@ pub mod win32_shmem { core::PCSTR, }; - use crate::{ - Error, - shmem::{ShMem, ShMemId, ShMemProvider}, - }; + use crate::{Error, ShMem, ShMemId, ShMemProvider}; const INVALID_HANDLE_VALUE: *mut c_void = -1isize as *mut c_void; @@ -1806,7 +1854,7 @@ impl ShMemCursor { where SHM: DerefMut, { - use crate::AsSliceMut; + use libafl_core::AsSliceMut; &mut (self.inner.as_slice_mut()[self.pos..]) } } @@ -1860,7 +1908,7 @@ where let effective_new_pos = match pos { std::io::SeekFrom::Start(s) => s, std::io::SeekFrom::End(offset) => { - use crate::AsSlice; + use libafl_core::AsSlice; let map_len = self.inner.as_slice().len(); let signed_pos = i64::try_from(map_len).unwrap(); let effective = signed_pos.checked_add(offset).unwrap(); @@ -1885,12 +1933,10 @@ where #[cfg(all(feature = "std", not(target_os = "haiku")))] #[cfg(test)] mod tests { + use libafl_core::{AsSlice, AsSliceMut, Error}; use serial_test::serial; - use crate::{ - AsSlice, AsSliceMut, Error, - shmem::{ShMemProvider, StdShMemProvider}, - }; + use crate::{ShMemProvider, StdShMemProvider}; #[test] #[serial] @@ -1914,7 +1960,7 @@ mod tests { process::{Command, Stdio}, }; - use crate::shmem::{MmapShMemProvider, ShMem as _, ShMemId}; + use crate::{MmapShMemProvider, ShMem as _, ShMemId}; // relies on the fact that the ID in a ShMemDescription is always a string for MmapShMem match env::var("SHMEM_SIZE") { @@ -1975,7 +2021,7 @@ mod tests { #[cfg_attr(miri, ignore)] #[cfg(unix)] fn test_mmap_shmem_release() -> Result<(), Error> { - use crate::shmem::MmapShMemProvider; + use crate::MmapShMemProvider; let mut provider = MmapShMemProvider::new()?; let mut shmem = provider.new_shmem(1024)?; diff --git a/crates/libafl_bolts/src/os/pipes.rs b/crates/shmem_providers/src/pipes.rs similarity index 100% rename from crates/libafl_bolts/src/os/pipes.rs rename to crates/shmem_providers/src/pipes.rs diff --git a/crates/libafl_bolts/src/os/unix_shmem_server.rs b/crates/shmem_providers/src/unix_shmem_server.rs similarity index 99% rename from crates/libafl_bolts/src/os/unix_shmem_server.rs rename to crates/shmem_providers/src/unix_shmem_server.rs index 04fcb145bf8..4d3172cf0bb 100644 --- a/crates/libafl_bolts/src/os/unix_shmem_server.rs +++ b/crates/shmem_providers/src/unix_shmem_server.rs @@ -39,6 +39,7 @@ use std::{ thread, }; +#[cfg(feature = "alloc")] use hashbrown::HashMap; use nix::poll::PollTimeout; #[cfg(all(feature = "std", unix))] @@ -47,10 +48,7 @@ use serde::{Deserialize, Serialize}; #[cfg(all(unix, feature = "std"))] use uds::{UnixListenerExt, UnixSocketAddr, UnixStreamExt}; -use crate::{ - Error, - shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider}, -}; +use crate::{Error, ShMem, ShMemDescription, ShMemId, ShMemProvider}; /// The default server name for our abstract shmem server #[cfg(all(unix, not(target_vendor = "apple")))] diff --git a/crates/tuple_list_ex/Cargo.toml b/crates/tuple_list_ex/Cargo.toml new file mode 100644 index 00000000000..d13ef86759b --- /dev/null +++ b/crates/tuple_list_ex/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "tuple_list_ex" +version.workspace = true +authors = [ + "Andrea Fioraldi ", + "Dominik Maier ", +] +description = "Useful Haskel-like extensions for the tuple_list crate" +documentation = "https://docs.rs/libafl" +repository = "https://github.com/AFLplusplus/LibAFL/" +readme = "./README.md" +license = "MIT OR Apache-2.0" +keywords = ["os", "no-std"] +edition = "2024" +rust-version = "1.87" +categories = ["embedded", "os", "no-std"] + +[package.metadata.docs.rs] +features = ["document-features"] +all-features = true + +[features] +default = ["std", "alloc"] +document-features = ["dep:document-features"] + +#! # Feature Flags +#! ### General Features + +## Enables features that need rust's `std` lib to work, like print, env, ... support +std = ["alloc"] + +## Enables all features that allocate in `no_std` +alloc = ["ownedref"] + +## Enables serde support for tuple lists +serde = ["alloc", "dep:serde"] + +[build-dependencies] +rustversion = { workspace = true } + +[dev-dependencies] + +[dependencies] +# Document all features of this crate (for `cargo doc`) +document-features = { workspace = true, optional = true } + +libafl_core = { workspace = true } + +serde = { workspace = true, default-features = false, features = [ + "derive", + "alloc", +], optional = true } +tuple_list = { workspace = true } +typeid = { workspace = true } +ownedref = { workspace = true, optional = true } + +[lints] +workspace = true diff --git a/crates/tuple_list_ex/LICENSE-APACHE b/crates/tuple_list_ex/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/crates/tuple_list_ex/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/crates/tuple_list_ex/LICENSE-MIT b/crates/tuple_list_ex/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/crates/tuple_list_ex/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/crates/tuple_list_ex/README.md b/crates/tuple_list_ex/README.md new file mode 100644 index 00000000000..ab89b16eb9e --- /dev/null +++ b/crates/tuple_list_ex/README.md @@ -0,0 +1,166 @@ +# Tuple_List_Ex: Added functionality for tuple_lists + +LibAFL logo + +This crate adds handy features to the Haskel-like [`tuple_list`](https://docs.rs/tuple_list/latest/tuple_list/) crate. + +It's part of the `LibAFL` project. + +## Usage + +This crate provides a variety of traits that extend the functionality of `tuple_list`. Here are a few examples: + +### `MatchFirstType` + +Get the first element of a specific type from a tuple list. +```rust +use tuple_list::tuple_list; +use tuple_list_ex::MatchFirstType; + +// Create a tuple list +let tuple = tuple_list!(1i32, "hello", 3.0f64); + +// Get the first element of a specific type +let first_i32: Option<&i32> = tuple.match_first_type(); +assert_eq!(first_i32, Some(&1)); + +let first_f64: Option<&f64> = tuple.match_first_type(); +assert_eq!(first_f64, Some(&3.0)); +``` + +### `Prepend`, `Append`, and `Merge` + +Modify tuple lists by adding elements or merging them. +```rust +use tuple_list::tuple_list; +use tuple_list_ex::{Prepend, Append, Merge}; + +let tuple = tuple_list!(1i32, "hello"); + +// Prepend an element +let prepended = tuple.prepend(true); +assert_eq!(prepended, (true, (1, ("hello", ())))); + +// Append an element +let appended = prepended.append(3.0f64); +assert_eq!(appended, ((true, (1, ("hello", ()))), 3.0f64)); + +// Merge two tuple lists +let other_tuple = tuple_list!(4u8, 5u16); +let merged = prepended.merge(other_tuple); +assert_eq!(merged, (true, (1, ("hello", (4, (5, ())))))); +``` + +### `NamedTuple` and `MatchName` + +Access elements by name for tuples containing `Named` elements. +```rust +# #[cfg(feature = "alloc")] +# { +use tuple_list::tuple_list; +use tuple_list_ex::{NamedTuple, MatchName}; +use libafl_core::Named; +use std::borrow::Cow; + +struct MyNamed { + name: &'static str, +} + +impl Named for MyNamed { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +let named_tuple = tuple_list!(MyNamed { name: "first" }, MyNamed { name: "second" }); + +// Get names +let names = named_tuple.names(); +assert_eq!(names, vec!["first", "second"]); + +// Get an element by name +let second: Option<&MyNamed> = named_tuple.match_name("second"); +assert!(second.is_some()); +assert_eq!(second.unwrap().name(), "second"); +# } +``` + +## Features + +This crate has the following features: + +* `std`: (Default) Enables features that require the standard library. +* `alloc`: (Default) Enables features that require allocation, like `IntoVec` and `NamedTuple`. +* `serde`: Enables `serde` support for `Handle`. + +## Provided Traits and Functionality + +Here is a list of the traits and functionality provided by this crate: + +* **`SplitBorrow`**: Borrows each member of the tuple, returning a new tuple of references. +* **`IntoVec`**: Converts a tuple list into a `Vec`. +* **`HasConstLen`**: Provides the length of the tuple list as a const `usize`. +* **`MatchFirstType`**: Gets the first element of a specific type. +* **`ExtractFirstRefType`** and **`ExtractFirstRefMutType`**: Takes the first element of a given type. +* **`SplitBorrowExtractFirstType`**: A combination of `SplitBorrow` and `ExtractFirstRefType`. +* **`MatchType`**: Applies a function to all elements of a specific type. +* **`NamedTuple`**: For tuples where each element has a name. +* **`MatchName`**: Finds an element by its name. +* **`Handled`**, **`Handle`**, **`MatchNameRef`**: A system for referencing tuple elements by a handle (name + type). +* **`GetAll`**: Retrieves multiple elements from a tuple list using a list of handles. +* **`RefIndexable`**: Allows indexing a tuple list with `[]` using handles. +* **`Prepend`**: Adds an element to the beginning of a tuple list. +* **`Append`**: Adds an element to the end of a tuple list. +* **`Merge`**: Merges two tuple lists. +* **`Map`**, **`MappingFunctor`**: Maps each element of a tuple list to a new type. +* **Macros**: + * `tuple_for_each!`: Iterates over a tuple. + * `tuple_for_each_mut!`: Iterates over a tuple with mutable access. + * `map_tuple_list_type!`: Gets the resulting type of a map operation. + * `merge_tuple_list_type!`: Gets the resulting type of a merge operation. + +## The `LibAFL` Project + +The `LibAFL` project is part of [`AFLplusplus`](https://github.com/AFLplusplus) and maintained by + +* [Andrea Fioraldi](https://twitter.com/andreafioraldi) +* [Dominik Maier](https://twitter.com/domenuk) +* [s1341](https://twitter.com/srubenst1341) +* [Dongjia Zhang](https://github.com/tokatoka) +* [Addison Crump](https://github.com/addisoncrump) + +## Contributing + +For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 + +Even though we will gladly assist you in finishing up your PR, try to + +* keep all the crates compiling with *stable* rust (hide the eventual non-stable code under `cfg`s.) +* run `cargo nightly fmt` on your code before pushing +* check the output of `cargo clippy --all` or `./clippy.sh` +* run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. + +Some parts in this list may sound hard, but don't be afraid to open a PR if you cannot fix them by yourself. We will gladly assist. + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + +
+ + +Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled +using the respective feature in each crate when it is present, such as the +'agpl' feature of the libafl crate. + \ No newline at end of file diff --git a/crates/libafl_bolts/src/tuples.rs b/crates/tuple_list_ex/src/lib.rs similarity index 93% rename from crates/libafl_bolts/src/tuples.rs rename to crates/tuple_list_ex/src/lib.rs index ee2164b9ad5..6efe145476c 100644 --- a/crates/libafl_bolts/src/tuples.rs +++ b/crates/tuple_list_ex/src/lib.rs @@ -1,4 +1,55 @@ //! Compiletime lists/tuples used throughout the `LibAFL` universe +#![doc = include_str!("../README.md")] +/*! */ +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![no_std] +#![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( + 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 + ) +)] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; +#[cfg(feature = "alloc")] +#[doc(hidden)] +pub extern crate alloc; #[cfg(feature = "alloc")] use alloc::{borrow::Cow, vec::Vec}; @@ -11,17 +62,13 @@ use core::{ ops::{Deref, DerefMut, Index, IndexMut}, }; -#[cfg(feature = "alloc")] +use libafl_core::Named; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; pub use tuple_list::{TupleList, tuple_list, tuple_list_type}; -use crate::HasLen; -#[cfg(feature = "alloc")] -use crate::Named; -#[cfg(any(feature = "xxh3", feature = "alloc"))] -use crate::hash_std; #[cfg(feature = "alloc")] -use crate::tuples::seal::{InnerBorrowMut, StackedExtract}; +use crate::seal::StackedExtract; /// Returns if the type `T` is equal to `U`, ignoring lifetimes. #[must_use] @@ -112,85 +159,6 @@ where const LEN: usize = 1 + Tail::LEN; } -impl HasLen for (Head, Tail) -where - Tail: HasLen, -{ - #[inline] - fn len(&self) -> usize { - self.1.len() + 1 - } -} - -impl HasLen for (Tail,) -where - Tail: HasLen, -{ - #[inline] - fn len(&self) -> usize { - self.0.len() - } -} - -impl HasLen for () { - #[inline] - fn len(&self) -> usize { - 0 - } -} - -/// Finds the `const_name` and `name_id` -pub trait HasNameId { - /// Gets the `const_name` for this entry - fn const_name(&self) -> &'static str; - - /// Gets the `name_id` for this entry - fn name_id(&self) -> u64 { - hash_std(self.const_name().as_bytes()) - } -} - -/// Gets the id and `const_name` for the given index in a tuple -pub trait HasNameIdTuple: HasConstLen { - /// Gets the `const_name` for the entry at the given index - fn const_name_for(&self, index: usize) -> Option<&'static str>; - - /// Gets the `name_id` for the entry at the given index - fn name_id_for(&self, index: usize) -> Option; -} - -impl HasNameIdTuple for () { - fn const_name_for(&self, _index: usize) -> Option<&'static str> { - None - } - - fn name_id_for(&self, _index: usize) -> Option { - None - } -} - -impl HasNameIdTuple for (Head, Tail) -where - Head: HasNameId, - Tail: HasNameIdTuple, -{ - fn const_name_for(&self, index: usize) -> Option<&'static str> { - if index == 0 { - Some(self.0.const_name()) - } else { - self.1.const_name_for(index - 1) - } - } - - fn name_id_for(&self, index: usize) -> Option { - if index == 0 { - Some(self.0.name_id()) - } else { - self.1.name_id_for(index - 1) - } - } -} - /// Returns the first element with the given type pub trait MatchFirstType { /// Returns the first element with the given type as borrow, or [`None`] @@ -405,15 +373,6 @@ impl NamedTuple for () { } } -#[cfg(feature = "alloc")] -impl Named for () { - #[inline] - fn name(&self) -> &Cow<'static, str> { - static NAME: Cow<'static, str> = Cow::Borrowed("Empty"); - &NAME - } -} - #[cfg(feature = "alloc")] impl NamedTuple for (Head, Tail) where @@ -498,11 +457,11 @@ pub trait Handled: Named { impl Handled for N where N: Named {} /// Object with the type T and the name associated with its concrete value -#[derive(Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg(feature = "alloc")] pub struct Handle { name: Cow<'static, str>, - #[serde(skip)] + #[cfg_attr(feature = "serde", serde(skip))] phantom: PhantomData, } @@ -619,6 +578,17 @@ where fn get_all_mut(&mut self, _handles: ()) -> Self::GetAllMutResult<'_> {} } +/// Returns a mutably borrowed element +pub trait InnerBorrowMut { + /// The type we need borrowed + type Borrowed<'a> + where + Self: 'a; + + /// Returns the borrow + fn inner_borrow_mut(&mut self) -> Self::Borrowed<'_>; +} + #[cfg(feature = "alloc")] mod seal { //! The logic in this section enables the [`super::GetAll::get_all_mut`] implementation. @@ -667,20 +637,10 @@ mod seal { //! [Some(a), Some(c), None] //! ``` + use libafl_core::Named; use tuple_list::tuple_list; - use crate::{ - Named, - tuples::{Handle, Merge, type_eq}, - }; - - pub trait InnerBorrowMut { - type Borrowed<'a> - where - Self: 'a; - - fn inner_borrow_mut(&mut self) -> Self::Borrowed<'_>; - } + use crate::{Handle, InnerBorrowMut, Merge, type_eq}; impl InnerBorrowMut for (Head, Tail) where @@ -1067,7 +1027,7 @@ macro_rules! tuple_for_each_mut { #[macro_export] macro_rules! map_tuple_list_type { ($Tuple:ty, $Mapper:ty) => { - <$Tuple as $crate::tuples::Map<$Mapper>>::MapResult + <$Tuple as $crate::Map<$Mapper>>::MapResult }; } @@ -1102,13 +1062,13 @@ macro_rules! merge_tuple_list_type { // Base case: when only two types are provided, apply the Merge trait directly ($Type1:ty, $Type2:ty) => { - <$Type1 as $crate::tuples::Merge<$Type2>>::MergeResult + <$Type1 as $crate::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, + <$Type1 as $crate::Merge<$Type2>>::MergeResult, $( $rest ),+ ) }; @@ -1147,11 +1107,11 @@ impl PlusOne for (Head, Tail) where mod test { use core::marker::PhantomData; + #[cfg(feature = "alloc")] + use ownedref::OwnedMutSlice; use tuple_list::{tuple_list, tuple_list_type}; - #[cfg(feature = "alloc")] - use crate::ownedref::OwnedMutSlice; - use crate::tuples::{Map, MappingFunctor, Merge, type_eq}; + use crate::{Map, MappingFunctor, Merge, type_eq}; #[test] // for type name tests @@ -1247,11 +1207,11 @@ mod test { let mut t = tuple_list!(1, "a"); tuple_for_each!(f1, core::fmt::Display, t, |x| { - log::info!("{x}"); + println!("{x}"); }); tuple_for_each_mut!(f2, core::fmt::Display, t, |x| { - log::info!("{x}"); + println!("{x}"); }); } @@ -1264,7 +1224,7 @@ mod test { use tuple_list::{tuple_list, tuple_list_type}; - use crate::tuples::{GetAll as _, Handle, Handled as _, MatchNameRef, Named}; + use crate::{GetAll as _, Handle, Handled as _, MatchNameRef, Named}; #[derive(Debug, PartialEq)] struct MyHandled(String, Cow<'static, str>); 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 f840803134e..5173ed5259d 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 @@ -55,11 +55,15 @@ pub fn main() { }; // Create a stacktrace observer let mut bt = shmem_provider.new_on_shmem::>(None).unwrap(); - let bt_observer = BacktraceObserver::new( - "BacktraceObserver", - unsafe { OwnedRefMut::from_shmem(&mut bt) }, - libafl::observers::HarnessType::Child, - ); + // # Safety + // We just created the shmem and it's large enough. + let bt_observer = unsafe { + BacktraceObserver::from_shmem( + "BacktraceObserver", + &mut bt, + libafl::observers::HarnessType::Child, + ) + }; // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks let mut feedback = MaxMapFeedback::new(&observer); 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 43c3c9a5019..dae8d591f46 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 @@ -67,12 +67,15 @@ 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( - "BacktraceObserver", - unsafe { OwnedRefMut::from_shmem(&mut bt) }, - libafl::observers::HarnessType::Child, - ); + // # Safety + // We just created the shmem and it's large enough. + let bt_observer = unsafe { + BacktraceObserver::from_shmem( + "BacktraceObserver", + &mut bt, + libafl::observers::HarnessType::Child, + ) + }; // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks let mut feedback = MaxMapFeedback::new(&observer); diff --git a/fuzzers/baby/tutorial/Cargo.toml b/fuzzers/baby/tutorial/Cargo.toml index 9df0903f5a7..9a8d96e317f 100644 --- a/fuzzers/baby/tutorial/Cargo.toml +++ b/fuzzers/baby/tutorial/Cargo.toml @@ -32,7 +32,7 @@ libafl_targets = { path = "../../../crates/libafl_targets", features = [ "libfuzzer", "sancov_cmplog", ] } -serde = { version = "1.0.210", default-features = false, features = [ +serde = { version = "1.0.228", default-features = false, features = [ "alloc", ] } # serialization lib lain = { version = "0.5.6", features = [ diff --git a/fuzzers/baby/tutorial/src/input.rs b/fuzzers/baby/tutorial/src/input.rs index 6e0a864aecd..49441d56016 100644 --- a/fuzzers/baby/tutorial/src/input.rs +++ b/fuzzers/baby/tutorial/src/input.rs @@ -1,4 +1,4 @@ -#![expect(unexpected_cfgs)] // deriving NewFuzzed etc. introduces these +#![allow(unexpected_cfgs)] // deriving NewFuzzed etc. introduces these use std::hash::Hash; use lain::prelude::*; diff --git a/fuzzers/baby/tutorial/src/mutator.rs b/fuzzers/baby/tutorial/src/mutator.rs index d2813012099..a83cfe5b54e 100644 --- a/fuzzers/baby/tutorial/src/mutator.rs +++ b/fuzzers/baby/tutorial/src/mutator.rs @@ -52,7 +52,6 @@ impl LainMutator { } impl Default for LainMutator { - #[must_use] fn default() -> Self { Self::new() } diff --git a/fuzzers/binary_only/frida_executable_libpng/Cargo.toml b/fuzzers/binary_only/frida_executable_libpng/Cargo.toml index 049e0c946a1..001818ac997 100644 --- a/fuzzers/binary_only/frida_executable_libpng/Cargo.toml +++ b/fuzzers/binary_only/frida_executable_libpng/Cargo.toml @@ -41,7 +41,7 @@ log = { version = "0.4.22", features = ["release_max_level_info"] } num-traits = "0.2.19" rangemap = "1.5.1" clap = { version = "4.5.18", features = ["derive"] } -serde = "1.0.210" +serde = "1.0.228" mimalloc = { version = "0.1.43", default-features = false } backtrace = "0.3.74" diff --git a/fuzzers/binary_only/qemu_tmin/Cargo.toml b/fuzzers/binary_only/qemu_tmin/Cargo.toml index 601231231bf..49e97782167 100644 --- a/fuzzers/binary_only/qemu_tmin/Cargo.toml +++ b/fuzzers/binary_only/qemu_tmin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "qemu_tmin" -version = "0.15.1" +version = "0.15.4" authors = [ "Andrea Fioraldi ", "Dominik Maier ", diff --git a/fuzzers/forkserver/forkserver_capture_stdout/Cargo.toml b/fuzzers/forkserver/forkserver_capture_stdout/Cargo.toml index 016b1d6fd3c..e7d1019ac29 100644 --- a/fuzzers/forkserver/forkserver_capture_stdout/Cargo.toml +++ b/fuzzers/forkserver/forkserver_capture_stdout/Cargo.toml @@ -20,5 +20,5 @@ libafl = { path = "../../../crates/libafl", features = ["std", "derive"] } libafl_bolts = { path = "../../../crates/libafl_bolts" } log = { version = "0.4.22", features = ["release_max_level_info"] } nix = { version = "0.30.1", features = ["signal"] } -serde = "1.0.219" +serde = "1.0.228" serde_json = "1.0.140" diff --git a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs index 1e547fd16d1..99fc78698d9 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs @@ -356,7 +356,7 @@ fn fuzz( unsafe { cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } - let cmpmap = unsafe { OwnedRefMut::::from_shmem(&mut cmplog_shmem) }; + let cmpmap = unsafe { AflppCmpLogMap::from_shmem(&mut cmplog_shmem) }; let cmplog_observer = StdCmpObserver::new("cmplog", cmpmap, true); diff --git a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs index 3775a3bc335..2e6d5661093 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs @@ -359,7 +359,7 @@ fn fuzz( unsafe { cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } - let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) }; + let cmpmap = unsafe { AflppCmpLogMap::from_shmem(&mut cmplog_shmem) }; let cmplog_observer = AflppCmpLogObserver::new("cmplog", cmpmap, true); let cmplog_ref = cmplog_observer.handle(); diff --git a/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs index a3b06f7ff09..6d42988324c 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs @@ -405,7 +405,7 @@ fn fuzz( unsafe { cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } - let cmpmap = unsafe { OwnedRefMut::::from_shmem(&mut cmplog_shmem) }; + let cmpmap = unsafe { AflppCmpLogMap::from_shmem(&mut cmplog_shmem) }; let cmplog_observer = StdCmpObserver::new("cmplog", cmpmap, true); diff --git a/fuzzers/forkserver/libafl-fuzz/Cargo.toml b/fuzzers/forkserver/libafl-fuzz/Cargo.toml index a471dc20ce7..65ba9a371f8 100644 --- a/fuzzers/forkserver/libafl-fuzz/Cargo.toml +++ b/fuzzers/forkserver/libafl-fuzz/Cargo.toml @@ -30,7 +30,7 @@ log = { version = "0.4.22", features = ["release_max_level_info"] } memmap2 = "0.9.4" nix = { version = "0.30.1", features = ["fs"] } regex = "1.10.5" -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.228", features = ["derive"] } [target.'cfg(target_os = "linux")'.dependencies] libafl_nyx = { path = "../../../crates/libafl_nyx", optional = true } diff --git a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs index 144293f1c78..b7722fed84e 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs @@ -481,7 +481,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, { unsafe { cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } - let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) }; + let cmpmap = unsafe { AflppCmpLogMap::from_shmem(&mut cmplog_shmem) }; // Create the CmpLog observer. let cmplog_observer = AflppCmpLogObserver::new("cmplog", cmpmap, true); diff --git a/fuzzers/full_system/nyx_libxml2_parallel/Cargo.lock b/fuzzers/full_system/nyx_libxml2_parallel/Cargo.lock index 9f3cfb4ed59..b86e5198d79 100644 --- a/fuzzers/full_system/nyx_libxml2_parallel/Cargo.lock +++ b/fuzzers/full_system/nyx_libxml2_parallel/Cargo.lock @@ -100,6 +100,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "825297538d77367557b912770ca3083f778a196054b3ee63b22673c4a3cae0a5" +[[package]] +name = "arbitrary-int" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c858caffa49edfc4ecc45a4bec37abd3e88041a2903816f10f990b7b41abc281" + [[package]] name = "autocfg" version = "1.4.0" @@ -135,18 +141,29 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "bincode" -version = "1.3.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" dependencies = [ + "bincode_derive", "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", ] [[package]] name = "bindgen" -version = "0.71.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags 2.9.1", "cexpr", @@ -164,11 +181,11 @@ dependencies = [ [[package]] name = "bitbybit" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb157f9753a7cddfcf4a4f5fed928fbf4ce1b7b64b6bcc121d7a9f95d698997b" +checksum = "ec187a89ab07e209270175faf9e07ceb2755d984954e58a2296e325ddece2762" dependencies = [ - "arbitrary-int", + "arbitrary-int 1.3.0", "proc-macro2", "quote", "syn 2.0.101", @@ -186,6 +203,15 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "build_id2" +version = "0.15.4" +dependencies = [ + "ahash", + "rustversion", + "uuid", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -200,9 +226,9 @@ checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" [[package]] name = "byteorder" -version = "1.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" [[package]] name = "cbindgen" @@ -225,10 +251,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.24" +version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -268,9 +295,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -278,9 +305,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -291,9 +318,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -309,9 +336,12 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cobs" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] [[package]] name = "colorchoice" @@ -329,17 +359,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "config" -version = "0.1.0" -source = "git+https://github.com/nyx-fuzz/libnyx.git?rev=f07a41fcf0a01be5f8b8397b26cb914a149b9198#f07a41fcf0a01be5f8b8397b26cb914a149b9198" -dependencies = [ - "libc", - "ron", - "serde", - "serde_derive", -] - [[package]] name = "const_fn" version = "0.4.11" @@ -372,6 +391,16 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2459fc9262a1aa204eb4b5764ad4f189caec88aea9634389c0a25f8be7f6265e" +[[package]] +name = "core_affinity2" +version = "0.15.4" +dependencies = [ + "libafl_core", + "libc", + "rustversion", + "serde", +] + [[package]] name = "ctor" version = "0.4.2" @@ -476,15 +505,34 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "exceptional" +version = "0.15.4" +dependencies = [ + "libafl_core", + "libc", + "num_enum", + "rustversion", +] + +[[package]] +name = "fast_rands" +version = "0.15.4" +dependencies = [ + "rand_core 0.9.3", + "rustversion", + "serde", +] + [[package]] name = "fastbloom" -version = "0.9.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cea6e7f512d43b098939ff4d5a5d6fe3db07971e1d05176fe26c642d33f5b8" +checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" dependencies = [ "getrandom 0.3.3", + "libm", "siphasher", - "wide 0.7.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -493,6 +541,18 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "fs2" version = "0.4.3" @@ -513,29 +573,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fuzz_runner" -version = "0.1.0" -source = "git+https://github.com/nyx-fuzz/libnyx.git?rev=f07a41fcf0a01be5f8b8397b26cb914a149b9198#f07a41fcf0a01be5f8b8397b26cb914a149b9198" -dependencies = [ - "byteorder", - "colored", - "config", - "derivative", - "fs4", - "glob", - "libc", - "nix 0.26.4", - "quick-error", - "rand", - "serde", - "serde_derive", - "snafu", - "subprocess", - "time", - "timeout-readwrite", -] - [[package]] name = "getrandom" version = "0.1.16" @@ -567,26 +604,27 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", - "serde", -] +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] [[package]] name = "heck" @@ -608,7 +646,7 @@ checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" dependencies = [ "cfg-if", "libc", - "windows-link", + "windows-link 0.1.1", ] [[package]] @@ -670,10 +708,10 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libafl" -version = "0.15.2" +version = "0.15.4" dependencies = [ "ahash", - "arbitrary-int", + "arbitrary-int 2.0.0", "backtrace", "bincode", "bitbybit", @@ -681,14 +719,17 @@ dependencies = [ "const_panic", "fastbloom", "fs2", - "hashbrown 0.14.5", + "hashbrown 0.16.0", "libafl_bolts", + "libafl_core", "libafl_derive", "libc", "libm", + "ll_mp", "log", "meminterval", - "nix 0.29.0", + "nix 0.30.1", + "no_std_time", "num-traits", "postcard", "regex", @@ -697,6 +738,7 @@ dependencies = [ "serde_json", "serial_test", "tuple_list", + "tuple_list_ex", "typed-builder", "uuid", "wait-timeout", @@ -706,34 +748,42 @@ dependencies = [ [[package]] name = "libafl_bolts" -version = "0.15.2" +version = "0.15.4" dependencies = [ "ahash", "backtrace", + "build_id2", "clap", - "ctor", + "core_affinity2", "erased-serde", - "hashbrown 0.14.5", + "exceptional", + "fast_rands", + "hashbrown 0.16.0", "hostname", + "libafl_core", "libafl_derive", "libc", + "ll_mp", "log", - "mach2", + "mach2 0.5.0", + "minibsod", "miniz_oxide", - "nix 0.29.0", + "nix 0.30.1", + "no_std_time", "num_enum", - "once_cell", + "ownedref", "postcard", - "rand_core 0.9.3", "rustversion", "serde", + "serde_anymap", "serial_test", + "shmem_providers", "static_assertions", "tuple_list", + "tuple_list_ex", "typeid", "uds", - "uuid", - "wide 0.7.32 (git+https://github.com/Lokathor/wide?rev=71b5df0b2620da753836fafce5f99076181a49fe)", + "wide", "winapi", "windows", "windows-result", @@ -742,7 +792,7 @@ dependencies = [ [[package]] name = "libafl_cc" -version = "0.15.2" +version = "0.15.4" dependencies = [ "cc", "glob", @@ -750,9 +800,21 @@ dependencies = [ "which", ] +[[package]] +name = "libafl_core" +version = "0.15.4" +dependencies = [ + "backtrace", + "nix 0.30.1", + "postcard", + "rustversion", + "serde", + "windows-result", +] + [[package]] name = "libafl_derive" -version = "0.15.2" +version = "0.15.4" dependencies = [ "proc-macro2", "quote", @@ -761,13 +823,13 @@ dependencies = [ [[package]] name = "libafl_nyx" -version = "0.15.2" +version = "0.15.4" dependencies = [ "libafl", "libafl_bolts", "libafl_targets", "libnyx", - "nix 0.29.0", + "nix 0.30.1", "regex", "serde", "typed-builder", @@ -775,27 +837,30 @@ dependencies = [ [[package]] name = "libafl_targets" -version = "0.15.2" +version = "0.15.4" dependencies = [ "bindgen", "cc", - "hashbrown 0.14.5", + "fast_rands", + "hashbrown 0.16.0", "libafl", "libafl_bolts", + "libafl_core", "libc", "log", - "nix 0.29.0", - "once_cell", + "nix 0.30.1", + "ownedref", "rangemap", "rustversion", "serde", + "shmem_providers", ] [[package]] name = "libc" -version = "0.2.172" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" @@ -815,13 +880,50 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libnyx" -version = "0.1.0" -source = "git+https://github.com/nyx-fuzz/libnyx.git?rev=f07a41fcf0a01be5f8b8397b26cb914a149b9198#f07a41fcf0a01be5f8b8397b26cb914a149b9198" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d34256f134550fb15f6967b105a77b0d3d99d2f665ff67249b4ee72e1beb2a7" dependencies = [ "cbindgen", - "config", - "fuzz_runner", "libc", + "libnyx_config", + "libnyx_fuzz_runner", +] + +[[package]] +name = "libnyx_config" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816b7a1f5e45a2a437305cb7d1b4f0760ef38ab3016367ca4bcdd25bab0d3f7a" +dependencies = [ + "libc", + "ron", + "serde", + "serde_derive", +] + +[[package]] +name = "libnyx_fuzz_runner" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e982711034d47e339d505f3e3b6e14776d0ae8510b8ac159e767156105dfc7b3" +dependencies = [ + "byteorder", + "colored", + "derivative", + "fs4", + "glob", + "libc", + "libnyx_config", + "nix 0.26.4", + "quick-error", + "rand", + "serde", + "serde_derive", + "snafu", + "subprocess", + "time", + "timeout-readwrite", ] [[package]] @@ -830,6 +932,25 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "ll_mp" +version = "0.15.4" +dependencies = [ + "exceptional", + "hostname", + "libafl_core", + "log", + "miniz_oxide", + "nix 0.30.1", + "no_std_time", + "postcard", + "rustversion", + "serde", + "serial_test", + "shmem_providers", + "tuple_list", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -842,9 +963,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "mach2" @@ -855,6 +976,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1b95cd5421ec55b445b5ae102f5ea0e768de1f82bd3001e11f426c269c3aea" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -863,9 +993,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "meminterval" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f8614cf855d251be1c2138d330c04f134923fddec0dcfc8b6f58ac499bf248" +checksum = "8e0f9a537564310a87dc77d5c88a407e27dd0aa740e070f0549439cfcc68fcfd" dependencies = [ "num-traits", "serde", @@ -889,6 +1019,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minibsod" +version = "0.15.4" +dependencies = [ + "exceptional", + "libc", + "mach2 0.4.2", + "rustversion", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -919,9 +1059,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags 2.9.1", "cfg-if", @@ -930,6 +1070,13 @@ dependencies = [ "memoffset 0.9.1", ] +[[package]] +name = "no_std_time" +version = "0.15.4" +dependencies = [ + "rustversion", +] + [[package]] name = "nom" version = "7.1.3" @@ -951,18 +1098,19 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", @@ -971,7 +1119,7 @@ dependencies = [ [[package]] name = "nyx_libxml2_parallel" -version = "0.15.2" +version = "0.15.4" dependencies = [ "libafl", "libafl_bolts", @@ -1001,6 +1149,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "ownedref" +version = "0.15.4" +dependencies = [ + "libafl_core", + "rustversion", + "serde", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1032,9 +1189,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "postcard" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" dependencies = [ "cobs", "embedded-io 0.4.0", @@ -1078,9 +1235,9 @@ dependencies = [ [[package]] name = "quick-error" -version = "2.0.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +checksum = "7ac990ab4e038dd8481a5e3fd00641067fcfc674ad663f3222752ed5284e05d4" [[package]] name = "quote" @@ -1146,9 +1303,9 @@ dependencies = [ [[package]] name = "rangemap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223" [[package]] name = "redox_syscall" @@ -1161,9 +1318,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -1173,9 +1330,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -1235,9 +1392,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -1292,18 +1449,43 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_anymap" +version = "0.15.4" +dependencies = [ + "ahash", + "ctor", + "erased-serde", + "hashbrown 0.16.0", + "libafl_core", + "postcard", + "rustversion", + "serde", + "static_assertions", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -1312,14 +1494,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -1376,6 +1559,23 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shmem_providers" +version = "0.15.4" +dependencies = [ + "fast_rands", + "hashbrown 0.16.0", + "libafl_core", + "libc", + "log", + "nix 0.30.1", + "postcard", + "rustversion", + "serde", + "serial_test", + "uds", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -1534,6 +1734,26 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "time" version = "0.2.27" @@ -1628,20 +1848,32 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "141fb9f71ee586d956d7d6e4d5a9ef8e946061188520140f7591b668841d502e" +[[package]] +name = "tuple_list_ex" +version = "0.15.4" +dependencies = [ + "libafl_core", + "ownedref", + "rustversion", + "serde", + "tuple_list", + "typeid", +] + [[package]] name = "typed-builder" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce63bcaf7e9806c206f7d7b9c1f38e0dce8bb165a80af0898161058b19248534" +checksum = "398a3a3c918c96de527dc11e6e846cd549d4508030b8a33e1da12789c856b81a" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60d8d828da2a3d759d3519cdf29a5bac49c77d039ad36d0782edadbf9cd5415b" +checksum = "0e48cea23f68d1f78eb7bc092881b6bb88d3d6b5b7e6234f6f9c911da1ffb221" dependencies = [ "proc-macro2", "quote", @@ -1675,6 +1907,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1683,9 +1921,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -1699,6 +1937,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "wait-timeout" version = "0.2.1" @@ -1783,11 +2027,10 @@ dependencies = [ [[package]] name = "which" -version = "7.0.3" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ - "either", "env_home", "rustix", "winsafe", @@ -1795,18 +2038,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.32" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" -dependencies = [ - "bytemuck", - "safe_arch", -] - -[[package]] -name = "wide" -version = "0.7.32" -source = "git+https://github.com/Lokathor/wide?rev=71b5df0b2620da753836fafce5f99076181a49fe#71b5df0b2620da753836fafce5f99076181a49fe" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" dependencies = [ "bytemuck", "safe_arch", @@ -1836,32 +2070,54 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.59.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ "windows-core", - "windows-targets 0.53.0", ] [[package]] name = "windows-core" -version = "0.59.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", + "windows-link 0.2.1", "windows-result", "windows-strings", - "windows-targets 0.53.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link 0.2.1", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -1870,9 +2126,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -1885,22 +2141,38 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link 0.2.1", +] + [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -1944,6 +2216,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" diff --git a/fuzzers/full_system/nyx_libxml2_parallel/src/bin/libafl_cc.rs b/fuzzers/full_system/nyx_libxml2_parallel/src/bin/libafl_cc.rs index eae59d52db1..ef5082c961c 100644 --- a/fuzzers/full_system/nyx_libxml2_parallel/src/bin/libafl_cc.rs +++ b/fuzzers/full_system/nyx_libxml2_parallel/src/bin/libafl_cc.rs @@ -1,6 +1,6 @@ use std::env; -use libafl_cc::{ClangWrapper, CompilerWrapper, ToolWrapper}; +use libafl_cc::{ClangWrapper, ToolWrapper}; pub fn main() { let args: Vec = env::args().collect(); diff --git a/fuzzers/full_system/nyx_libxml2_parallel/src/main.rs b/fuzzers/full_system/nyx_libxml2_parallel/src/main.rs index b0a4eb44050..f6d9bae2cd5 100644 --- a/fuzzers/full_system/nyx_libxml2_parallel/src/main.rs +++ b/fuzzers/full_system/nyx_libxml2_parallel/src/main.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use libafl::{ corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase}, diff --git a/fuzzers/fuzz_anything/baby_no_std/Cargo.lock b/fuzzers/fuzz_anything/baby_no_std/Cargo.lock index 526ce7b47e0..7c26be0e911 100644 --- a/fuzzers/fuzz_anything/baby_no_std/Cargo.lock +++ b/fuzzers/fuzz_anything/baby_no_std/Cargo.lock @@ -118,6 +118,24 @@ dependencies = [ "typeid", ] +[[package]] +name = "exceptional" +version = "0.15.3" +dependencies = [ + "libafl_core", + "libc", + "num_enum", + "rustversion", +] + +[[package]] +name = "fast_rands" +version = "0.15.3" +dependencies = [ + "rustversion", + "serde", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -139,8 +157,10 @@ dependencies = [ "const_panic", "hashbrown", "libafl_bolts", + "libafl_core", "libc", "libm", + "ll_mp", "log", "meminterval", "num-traits", @@ -158,23 +178,40 @@ version = "0.15.3" dependencies = [ "ahash", "erased-serde", + "exceptional", + "fast_rands", "hashbrown", + "libafl_core", "libc", + "ll_mp", "log", "mach2", + "no_std_time", "num_enum", - "once_cell", + "ownedref", "postcard", "rustversion", "serde", + "serde_anymap", + "shmem_providers", "static_assertions", "tuple_list", + "tuple_list_ex", "typeid", "winapi", "windows", "windows-result", ] +[[package]] +name = "libafl_core" +version = "0.15.3" +dependencies = [ + "postcard", + "rustversion", + "serde", +] + [[package]] name = "libc" version = "0.2.174" @@ -187,6 +224,21 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "ll_mp" +version = "0.15.3" +dependencies = [ + "exceptional", + "libafl_core", + "log", + "no_std_time", + "postcard", + "rustversion", + "serde", + "shmem_providers", + "tuple_list", +] + [[package]] name = "log" version = "0.4.27" @@ -212,6 +264,13 @@ dependencies = [ "serde", ] +[[package]] +name = "no_std_time" +version = "0.15.3" +dependencies = [ + "rustversion", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -248,6 +307,15 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "ownedref" +version = "0.15.3" +dependencies = [ + "libafl_core", + "rustversion", + "serde", +] + [[package]] name = "postcard" version = "1.1.2" @@ -293,6 +361,20 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_anymap" +version = "0.15.3" +dependencies = [ + "ahash", + "erased-serde", + "hashbrown", + "libafl_core", + "postcard", + "rustversion", + "serde", + "static_assertions", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -304,6 +386,20 @@ dependencies = [ "syn", ] +[[package]] +name = "shmem_providers" +version = "0.15.3" +dependencies = [ + "fast_rands", + "hashbrown", + "libafl_core", + "libc", + "log", + "postcard", + "rustversion", + "serde", +] + [[package]] name = "static-alloc" version = "0.2.6" @@ -356,6 +452,18 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "141fb9f71ee586d956d7d6e4d5a9ef8e946061188520140f7591b668841d502e" +[[package]] +name = "tuple_list_ex" +version = "0.15.3" +dependencies = [ + "libafl_core", + "ownedref", + "rustversion", + "serde", + "tuple_list", + "typeid", +] + [[package]] name = "typeid" version = "1.0.3" diff --git a/fuzzers/structure_aware/baby_fuzzer_nautilus/Cargo.lock b/fuzzers/structure_aware/baby_fuzzer_nautilus/Cargo.lock index 24e08429a0e..c49934634a5 100644 --- a/fuzzers/structure_aware/baby_fuzzer_nautilus/Cargo.lock +++ b/fuzzers/structure_aware/baby_fuzzer_nautilus/Cargo.lock @@ -52,7 +52,7 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "baby_fuzzer_nautilus" -version = "0.15.2" +version = "0.15.3" dependencies = [ "libafl", "libafl_bolts", @@ -76,11 +76,22 @@ dependencies = [ [[package]] name = "bincode" -version = "1.3.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" dependencies = [ + "bincode_derive", "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", ] [[package]] @@ -101,6 +112,15 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "build_id2" +version = "0.15.3" +dependencies = [ + "ahash", + "rustversion", + "uuid", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -157,6 +177,16 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2459fc9262a1aa204eb4b5764ad4f189caec88aea9634389c0a25f8be7f6265e" +[[package]] +name = "core_affinity2" +version = "0.15.3" +dependencies = [ + "libafl_core", + "libc", + "rustversion", + "serde", +] + [[package]] name = "ctor" version = "0.4.2" @@ -210,15 +240,33 @@ dependencies = [ "typeid", ] +[[package]] +name = "exceptional" +version = "0.15.3" +dependencies = [ + "libafl_core", + "libc", + "num_enum", + "rustversion", +] + +[[package]] +name = "fast_rands" +version = "0.15.3" +dependencies = [ + "rand_core", + "rustversion", + "serde", +] + [[package]] name = "fastbloom" -version = "0.9.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cea6e7f512d43b098939ff4d5a5d6fe3db07971e1d05176fe26c642d33f5b8" +checksum = "29ec576c163744bef8707859f6aeb322bcf56b8da61215d99f77d6e33160ff01" dependencies = [ "getrandom", "siphasher", - "wide 0.7.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -288,7 +336,7 @@ dependencies = [ [[package]] name = "libafl" -version = "0.15.2" +version = "0.15.3" dependencies = [ "ahash", "arbitrary-int", @@ -301,9 +349,11 @@ dependencies = [ "fs2", "hashbrown", "libafl_bolts", + "libafl_core", "libafl_derive", "libc", "libm", + "ll_mp", "log", "meminterval", "nix", @@ -325,48 +375,78 @@ dependencies = [ [[package]] name = "libafl_bolts" -version = "0.15.2" +version = "0.15.3" dependencies = [ "ahash", "backtrace", - "ctor", + "build_id2", + "core_affinity2", "erased-serde", + "exceptional", + "fast_rands", "hashbrown", "hostname", + "libafl_core", "libafl_derive", + "libafl_wide", "libc", + "ll_mp", "log", "mach2", + "minibsod", "miniz_oxide", "nix", + "no_std_time", "num_enum", "once_cell", + "ownedref", "postcard", - "rand_core", "rustversion", "serde", + "serde_anymap", "serial_test", + "shmem_providers", "static_assertions", "tuple_list", + "tuple_list_ex", "typeid", "uds", "uuid", - "wide 0.7.32 (git+https://github.com/Lokathor/wide?rev=71b5df0b2620da753836fafce5f99076181a49fe)", "winapi", "windows", "windows-result", "xxhash-rust", ] +[[package]] +name = "libafl_core" +version = "0.15.3" +dependencies = [ + "nix", + "postcard", + "rustversion", + "serde", +] + [[package]] name = "libafl_derive" -version = "0.15.2" +version = "0.15.3" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "libafl_wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f28d525f6e361b6cd55c0da5347027860a902d638d15194c16dc2f39a5ba9f" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "libc" version = "0.2.172" @@ -379,6 +459,26 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "ll_mp" +version = "0.15.3" +dependencies = [ + "backtrace", + "exceptional", + "hostname", + "libafl_core", + "log", + "miniz_oxide", + "nix", + "no_std_time", + "postcard", + "rustversion", + "serde", + "serial_test", + "shmem_providers", + "tuple_list", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -429,6 +529,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minibsod" +version = "0.15.3" +dependencies = [ + "exceptional", + "libc", + "mach2", + "rustversion", +] + [[package]] name = "miniz_oxide" version = "0.8.8" @@ -440,9 +550,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags", "cfg-if", @@ -451,6 +561,13 @@ dependencies = [ "memoffset", ] +[[package]] +name = "no_std_time" +version = "0.15.3" +dependencies = [ + "rustversion", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -495,6 +612,15 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "ownedref" +version = "0.15.3" +dependencies = [ + "libafl_core", + "rustversion", + "serde", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -655,6 +781,21 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_anymap" +version = "0.15.3" +dependencies = [ + "ahash", + "ctor", + "erased-serde", + "hashbrown", + "libafl_core", + "postcard", + "rustversion", + "serde", + "static_assertions", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -702,6 +843,23 @@ dependencies = [ "syn", ] +[[package]] +name = "shmem_providers" +version = "0.15.3" +dependencies = [ + "fast_rands", + "hashbrown", + "libafl_core", + "libc", + "log", + "nix", + "postcard", + "rustversion", + "serde", + "serial_test", + "uds", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -737,6 +895,18 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "141fb9f71ee586d956d7d6e4d5a9ef8e946061188520140f7591b668841d502e" +[[package]] +name = "tuple_list_ex" +version = "0.15.3" +dependencies = [ + "libafl_core", + "ownedref", + "rustversion", + "serde", + "tuple_list", + "typeid", +] + [[package]] name = "typed-builder" version = "0.21.0" @@ -784,6 +954,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "uuid" version = "1.17.0" @@ -802,6 +978,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "wait-timeout" version = "0.2.1" @@ -878,25 +1060,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wide" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" -dependencies = [ - "bytemuck", - "safe_arch", -] - -[[package]] -name = "wide" -version = "0.7.32" -source = "git+https://github.com/Lokathor/wide?rev=71b5df0b2620da753836fafce5f99076181a49fe#71b5df0b2620da753836fafce5f99076181a49fe" -dependencies = [ - "bytemuck", - "safe_arch", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/utils/multi_machine_generator/Cargo.toml b/utils/multi_machine_generator/Cargo.toml index 36da21703b7..e738478897c 100644 --- a/utils/multi_machine_generator/Cargo.toml +++ b/utils/multi_machine_generator/Cargo.toml @@ -10,5 +10,5 @@ edition = "2024" [dependencies] petgraph = "0.6" clap = { version = "4.5", features = ["derive"] } -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0"