From 1690dbb2cce727b66b6ae9a77b64d88e7db2af80 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 15 Apr 2022 19:25:51 +0200 Subject: [PATCH] Sender id fix (#610) * Starting to fix id issues * add crashing testcase * remove debug flags --- fuzzers/libfuzzer_libpng/Cargo.toml | 2 + fuzzers/libfuzzer_libpng/Makefile.toml | 61 ++++++++++++++++++++++++++ fuzzers/libfuzzer_libpng/src/lib.rs | 10 +++++ libafl/src/bolts/llmp.rs | 36 +++++++++------ libafl/src/events/llmp.rs | 3 +- libafl/src/events/simple.rs | 2 +- libafl/src/monitors/mod.rs | 1 - 7 files changed, 98 insertions(+), 17 deletions(-) diff --git a/fuzzers/libfuzzer_libpng/Cargo.toml b/fuzzers/libfuzzer_libpng/Cargo.toml index 6442715b22..671362b48a 100644 --- a/fuzzers/libfuzzer_libpng/Cargo.toml +++ b/fuzzers/libfuzzer_libpng/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [features] default = ["std"] std = [] +# Forces a crash +crash = [] [profile.release] lto = true diff --git a/fuzzers/libfuzzer_libpng/Makefile.toml b/fuzzers/libfuzzer_libpng/Makefile.toml index 80b60b9cb2..4d9cfaaa3f 100644 --- a/fuzzers/libfuzzer_libpng/Makefile.toml +++ b/fuzzers/libfuzzer_libpng/Makefile.toml @@ -45,6 +45,24 @@ windows_alias = "unsupported" command = "cargo" args = ["build" , "--release"] +[tasks.crash_cxx] +linux_alias = "crash_cxx_unix" +mac_alias = "crash_cxx_unix" +windows_alias = "unsupported" + +[tasks.crash_cxx_unix] +command = "cargo" +args = ["build" , "--release", "--features=crash"] + +[tasks.crash_cc] +linux_alias = "crash_cc_unix" +mac_alias = "crash_cc_unix" +windows_alias = "unsupported" + +[tasks.crash_cc_unix] +command = "cargo" +args = ["build" , "--release", "--features=crash"] + # Library [tasks.lib] linux_alias = "lib_unix" @@ -60,6 +78,20 @@ make -C libpng-1.6.37 CC="${PROJECT_DIR}/target/release/libafl_cc" CXX="${PROJEC ''' dependencies = [ "libpng", "cxx", "cc" ] +# Library +[tasks.crash_lib] +linux_alias = "crash_lib_unix" +mac_alias = "crash_lib_unix" +windows_alias = "unsupported" + +[tasks.crash_lib_unix] +script_runner="@shell" +script=''' +cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes +cd "${PROJECT_DIR}" +make -C libpng-1.6.37 CC="${PROJECT_DIR}/target/release/libafl_cc" CXX="${PROJECT_DIR}/target/release/libafl_cxx" +''' +dependencies = [ "libpng", "crash_cxx", "crash_cc" ] # Harness [tasks.fuzzer] @@ -72,6 +104,17 @@ command = "target/release/libafl_cxx" args = ["${PROJECT_DIR}/harness.cc", "${PROJECT_DIR}/libpng-1.6.37/.libs/libpng16.a", "-I", "${PROJECT_DIR}/libpng-1.6.37/", "-o", "${FUZZER_NAME}", "-lm", "-lz"] dependencies = [ "lib", "cxx", "cc" ] +# Crashing Harness +[tasks.fuzzer_crash] +linux_alias = "fuzzer_crash_unix" +mac_alias = "fuzzer_crash_unix" +windows_alias = "unsupported" + +[tasks.fuzzer_crash_unix] +command = "target/release/libafl_cxx" +args = ["${PROJECT_DIR}/harness.cc", "${PROJECT_DIR}/libpng-1.6.37/.libs/libpng16.a", "-I", "${PROJECT_DIR}/libpng-1.6.37/", "-o", "${FUZZER_NAME}_crash", "-lm", "-lz"] +dependencies = [ "crash_lib", "crash_cxx", "crash_cc" ] + # Run the fuzzer [tasks.run] linux_alias = "run_unix" @@ -87,6 +130,24 @@ sleep 0.2 ''' dependencies = [ "fuzzer" ] + +# Run the fuzzer with a crash +[tasks.crash] +linux_alias = "crash_unix" +mac_alias = "crash_unix" +windows_alias = "unsupported" + +[tasks.crash_unix] +script_runner = "@shell" +script=''' +./${FUZZER_NAME}_crash & +sleep 0.2 +./${FUZZER_NAME}_crash 2>/dev/null +''' +dependencies = [ "fuzzer_crash" ] + + + # Test [tasks.test] linux_alias = "test_unix" diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index b465422568..6449697093 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -5,6 +5,8 @@ use mimalloc::MiMalloc; static GLOBAL: MiMalloc = MiMalloc; use core::time::Duration; +#[cfg(feature = "crash")] +use std::ptr; use std::{env, path::PathBuf}; use libafl::{ @@ -145,6 +147,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mut harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target.as_slice(); + #[cfg(feature = "crash")] + if buf.len() > 4 && buf[4] == 0 { + unsafe { + eprintln!("Crashing (for testing purposes)"); + let addr = ptr::null_mut(); + *addr = 1; + } + } libfuzzer_test_one_input(buf); ExitKind::Ok }; diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index 90545588c9..d873331f63 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -451,7 +451,7 @@ fn next_shmem_size(max_alloc: usize) -> usize { /// Initialize a new `llmp_page`. The size should be relative to /// `llmp_page->messages` -unsafe fn _llmp_page_init(shmem: &mut SHM, sender: u32, allow_reinit: bool) { +unsafe fn _llmp_page_init(shmem: &mut SHM, sender_id: ClientId, allow_reinit: bool) { #[cfg(all(feature = "llmp_debug", feature = "std"))] println!("_llmp_page_init: shmem {:?}", &shmem); let map_size = shmem.len(); @@ -469,7 +469,7 @@ unsafe fn _llmp_page_init(shmem: &mut SHM, sender: u32, allow_reinit } (*page).magic = PAGE_INITIALIZED_MAGIC; - (*page).sender = sender; + (*page).sender_id = sender_id; (*page).current_msg_id.store(0, Ordering::Relaxed); (*page).max_alloc_size = 0; // Don't forget to subtract our own header size @@ -707,7 +707,7 @@ pub struct LlmpPage { /// to check if this page got initialized properly pub magic: u64, /// The id of the sender - pub sender: u32, + pub sender_id: ClientId, /// Set to != 1 by the receiver, once it got mapped. /// It's not safe for the sender to unmap this page before /// (The os may have tidied up the memory when the receiver starts to map) @@ -750,7 +750,7 @@ where SP: ShMemProvider, { /// ID of this sender. - pub id: u32, + pub id: ClientId, /// Ref to the last message this sender sent on the last page. /// If null, a new page (just) started. pub last_msg_sent: *const LlmpMsg, @@ -775,12 +775,16 @@ where /// Create a new [`LlmpSender`] using a given [`ShMemProvider`], and `id`. /// If `keep_pages_forever` is `true`, `ShMem` will never be freed. /// If it is `false`, the pages will be unmapped once they are full, and have been mapped by at least one `LlmpReceiver`. - pub fn new(mut shmem_provider: SP, id: u32, keep_pages_forever: bool) -> Result { + pub fn new( + mut shmem_provider: SP, + id: ClientId, + keep_pages_forever: bool, + ) -> Result { Ok(Self { id, last_msg_sent: ptr::null_mut(), out_shmems: vec![LlmpSharedMap::new( - 0, + id, shmem_provider.new_shmem(LLMP_CFG_INITIAL_MAP_SIZE)?, )], // drop pages to the broker if it already read them @@ -795,6 +799,7 @@ where /// This is only useful if all connected llmp parties start over, for example after a crash. /// # Safety /// Only safe if you really really restart the page on everything connected + /// No receiver should read from this page at a different location. pub unsafe fn reset(&mut self) { _llmp_page_init( &mut self.out_shmems.last_mut().unwrap().shmem, @@ -903,7 +908,7 @@ where }; Ok(Self { - id: 0, + id: unsafe { (*out_shmem.page()).sender_id }, last_msg_sent, out_shmems: vec![out_shmem], // drop pages to the broker if it already read them @@ -1117,7 +1122,7 @@ where // Create a new shard page. let mut new_map_shmem = LlmpSharedMap::new( - (*old_map).sender, + (*old_map).sender_id, self.shmem_provider .new_shmem(next_shmem_size((*old_map).max_alloc_size))?, ); @@ -1135,7 +1140,6 @@ where println!("Setting max alloc size: {:?}", (*old_map).max_alloc_size); (*new_map).max_alloc_size = (*old_map).max_alloc_size; - (*new_map).sender = self.id; /* On the old map, place a last message linking to the new map for the clients * to consume */ @@ -2536,12 +2540,13 @@ where pub fn new( mut shmem_provider: SP, initial_broker_shmem: LlmpSharedMap, + sender_id: ClientId, ) -> Result { Ok(Self { sender: LlmpSender { - id: 0, + id: sender_id, last_msg_sent: ptr::null_mut(), - out_shmems: vec![LlmpSharedMap::new(0, { + out_shmems: vec![LlmpSharedMap::new(sender_id, { shmem_provider.new_shmem(LLMP_CFG_INITIAL_MAP_SIZE)? })], // drop pages to the broker if it already read them @@ -2647,7 +2652,8 @@ where /// Creates a new [`LlmpClient`], reading the map id and len from env pub fn create_using_env(mut shmem_provider: SP, env_var: &str) -> Result { let map = LlmpSharedMap::existing(shmem_provider.existing_from_env(env_var)?); - Self::new(shmem_provider, map) + let client_id = unsafe { (*map.page()).sender_id }; + Self::new(shmem_provider, map, client_id) } #[cfg(feature = "std")] @@ -2689,7 +2695,9 @@ where let map = LlmpSharedMap::existing( shmem_provider.shmem_from_description(broker_shmem_description)?, ); - let mut ret = Self::new(shmem_provider, map)?; + + // We'll set `sender_id` later + let mut ret = Self::new(shmem_provider, map, 0)?; let client_hello_req = TcpRequest::LocalClientHello { shmem_description: ret.sender.out_shmems.first().unwrap().shmem.description(), @@ -2712,7 +2720,7 @@ where ret.sender.id = client_id; // Also set the sender on our initial llmp map correctly. unsafe { - (*ret.sender.out_shmems.first_mut().unwrap().page_mut()).sender = client_id; + (*ret.sender.out_shmems.first_mut().unwrap().page_mut()).sender_id = client_id; } Ok(ret) diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 500afef51b..9971997f70 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -839,7 +839,7 @@ where let mut ctr: u64 = 0; // Client->parent loop loop { - dbg!("Spawning next client (id {})", ctr); + println!("Spawning next client (id {})", ctr); // On Unix, we fork #[cfg(all(unix, feature = "fork"))] @@ -975,6 +975,7 @@ mod tests { let mut llmp_client = LlmpClient::new( shmem_provider.clone(), LlmpSharedMap::new(0, shmem_provider.new_shmem(1024).unwrap()), + 0, ) .unwrap(); diff --git a/libafl/src/events/simple.rs b/libafl/src/events/simple.rs index 272f6ac386..79c3ba10e7 100644 --- a/libafl/src/events/simple.rs +++ b/libafl/src/events/simple.rs @@ -340,7 +340,7 @@ where let mut ctr: u64 = 0; // Client->parent loop loop { - dbg!("Spawning next client (id {})", ctr); + println!("Spawning next client (id {})", ctr); // On Unix, we fork #[cfg(all(unix, feature = "fork"))] diff --git a/libafl/src/monitors/mod.rs b/libafl/src/monitors/mod.rs index 79f4b21274..845094c02e 100644 --- a/libafl/src/monitors/mod.rs +++ b/libafl/src/monitors/mod.rs @@ -906,7 +906,6 @@ pub mod pybind { self.get_mut_monitor().display(event_msg, sender_id); } } - /// Register the classes to the python module pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?;