From a84256c3bec9e0240cdee1aec93214175720b0c3 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 19 Dec 2020 05:50:17 +0100 Subject: [PATCH] added back shmem --- afl/src/events/shmem.rs | 262 ++++++++++++++++++++++++++++++++++ afl/src/executors/inmemory.rs | 10 +- 2 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 afl/src/events/shmem.rs diff --git a/afl/src/events/shmem.rs b/afl/src/events/shmem.rs new file mode 100644 index 0000000000..8c89419deb --- /dev/null +++ b/afl/src/events/shmem.rs @@ -0,0 +1,262 @@ +//! A generic sharememory region to be used by any functions (queues or feedbacks +// too.) + +use core::slice; +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void}; +use std::{env, ffi::CStr, mem::size_of}; + +use crate::AflError; + +extern "C" { + fn snprintf(_: *mut c_char, _: c_ulong, _: *const c_char, _: ...) -> c_int; + fn strncpy(_: *mut c_char, _: *const c_char, _: c_ulong) -> *mut c_char; + //fn strlen(_: *const c_char) -> c_ulong; + fn shmctl(__shmid: c_int, __cmd: c_int, __buf: *mut shmid_ds) -> c_int; + fn shmget(__key: c_int, __size: c_ulong, __shmflg: c_int) -> c_int; + fn shmat(__shmid: c_int, __shmaddr: *const c_void, __shmflg: c_int) -> *mut c_void; +} +#[derive(Copy, Clone)] +#[repr(C)] +struct ipc_perm { + pub __key: c_int, + pub uid: c_uint, + pub gid: c_uint, + pub cuid: c_uint, + pub cgid: c_uint, + pub mode: c_ushort, + pub __pad1: c_ushort, + pub __seq: c_ushort, + pub __pad2: c_ushort, + pub __glibc_reserved1: c_ulong, + pub __glibc_reserved2: c_ulong, +} + +#[derive(Copy, Clone)] +#[repr(C)] +struct shmid_ds { + pub shm_perm: ipc_perm, + pub shm_segsz: c_ulong, + pub shm_atime: c_long, + pub shm_dtime: c_long, + pub shm_ctime: c_long, + pub shm_cpid: c_int, + pub shm_lpid: c_int, + pub shm_nattch: c_ulong, + pub __glibc_reserved4: c_ulong, + pub __glibc_reserved5: c_ulong, +} + +/// A Shared map +pub trait ShMem: Sized { + /// Creates a nes variable with the given name, strigified to 20 bytes. + fn existing_map_by_shm_bytes( + map_str_bytes: &[u8; 20], + map_size: usize, + ) -> Result; + + /// Initialize from a shm_str with fixed len of 20 + fn existing_from_name(shm_str: &str, map_size: usize) -> Result { + let mut slice: [u8; 20] = [0; 20]; + for (i, val) in shm_str.as_bytes().iter().enumerate() { + slice[i] = *val; + } + Self::existing_map_by_shm_bytes(&slice, map_size) + } + + /// Creates a new map with the given size + fn new_map(map_size: usize) -> Result; + + /// The string to identify this shm + fn shm_str(&self) -> String; + + /// Let's just fix this to a large enough buf + fn shm_str_buf(&self) -> &[u8; 20]; + + /// The actual shared map, in memory + fn map(&self) -> &[u8]; + + /// The actual shared map, mutable + fn map_mut(&mut self) -> &mut [u8]; + + /// Write this map's config to env + fn write_to_env(&self, env_name: &str) -> Result<(), AflError> { + let map_size = self.map().len(); + let map_size_env = format!("{}_SIZE", env_name); + env::set_var(env_name, self.shm_str()); + env::set_var(map_size_env, format!("{}", map_size)); + Ok(()) + } + + /// Reads an existing map config from env vars, then maps it + fn existing_from_env(env_name: &str) -> Result { + let map_shm_str = env::var(env_name)?; + let map_size = str::parse::(&env::var(format!("{}_SIZE", env_name))?)?; + Self::existing_from_name(&map_shm_str, map_size) + } +} + +#[derive(Clone, Debug)] +pub struct AflShmem { + pub shm_str: [u8; 20], + pub shm_id: c_int, + pub map: *mut u8, + pub map_size: usize, +} + +impl ShMem for AflShmem { + fn existing_map_by_shm_bytes( + map_str_bytes: &[u8; 20], + map_size: usize, + ) -> Result { + Self::from_name_slice(map_str_bytes, map_size) + } + + fn new_map(map_size: usize) -> Result { + Self::new(map_size) + } + + fn shm_str(&self) -> String { + unsafe { CStr::from_ptr(self.shm_str.as_ptr() as *const i8) } + .to_string_lossy() + .into() + } + + fn shm_str_buf(&self) -> &[u8; 20] { + &self.shm_str + } + + fn map(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.map, self.map_size) } + } + + fn map_mut(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } + } +} + +/// Deinit sharedmaps on drop +impl Drop for AflShmem { + fn drop(&mut self) { + unsafe { + afl_shmem_deinit(self); + } + } +} + +/// Create an uninitialized shmap +const fn afl_shmem_unitialized() -> AflShmem { + AflShmem { + shm_str: [0; 20], + shm_id: -1, + map: 0 as *mut c_uchar, + map_size: 0, + } +} + +impl AflShmem { + pub fn from_str(shm_str: &CStr, map_size: usize) -> Result { + let mut ret = afl_shmem_unitialized(); + let map = unsafe { afl_shmem_by_str(&mut ret, shm_str, map_size) }; + if map != 0 as *mut u8 { + Ok(ret) + } else { + Err(AflError::Unknown(format!( + "Could not allocate map with id {:?} and size {}", + shm_str, map_size + ))) + } + } + + /// Generate a shared map with a fixed byte array of 20 + pub fn from_name_slice(shm_str: &[u8; 20], map_size: usize) -> Result { + unsafe { + let str_bytes = shm_str as *const [u8; 20] as *const libc::c_char; + Self::from_str(CStr::from_ptr(str_bytes), map_size) + } + } + + pub fn new(map_size: usize) -> Result { + let mut ret = afl_shmem_unitialized(); + let map = unsafe { afl_shmem_init(&mut ret, map_size) }; + if map != 0 as *mut u8 { + Ok(ret) + } else { + Err(AflError::Unknown(format!( + "Could not allocate map of size {}", + map_size + ))) + } + } +} + +/// Deinitialize this shmem instance +unsafe fn afl_shmem_deinit(shm: *mut AflShmem) { + if shm.is_null() || (*shm).map.is_null() { + /* Serialized map id */ + // Not set or not initialized; + return; + } + (*shm).shm_str[0 as usize] = '\u{0}' as u8; + shmctl((*shm).shm_id, 0 as c_int, 0 as *mut shmid_ds); + (*shm).map = 0 as *mut c_uchar; +} + +/// Functions to create Shared memory region, for observation channels and +/// opening inputs and stuff. +unsafe fn afl_shmem_init(shm: *mut AflShmem, map_size: usize) -> *mut c_uchar { + (*shm).map_size = map_size; + (*shm).map = 0 as *mut c_uchar; + (*shm).shm_id = shmget( + 0 as c_int, + map_size as c_ulong, + 0o1000 as c_int | 0o2000 as c_int | 0o600 as c_int, + ); + if (*shm).shm_id < 0 as c_int { + (*shm).shm_str[0] = '\u{0}' as u8; + return 0 as *mut c_uchar; + } + snprintf( + (*shm).shm_str.as_mut_ptr() as *mut i8, + size_of::<[c_char; 20]>() as c_ulong, + b"%d\x00" as *const u8 as *const c_char, + (*shm).shm_id, + ); + (*shm).shm_str + [(size_of::<[c_char; 20]>() as c_ulong).wrapping_sub(1 as c_int as c_ulong) as usize] = + '\u{0}' as u8; + (*shm).map = shmat((*shm).shm_id, 0 as *const c_void, 0 as c_int) as *mut c_uchar; + if (*shm).map == -(1 as c_int) as *mut c_void as *mut c_uchar || (*shm).map.is_null() { + shmctl((*shm).shm_id, 0 as c_int, 0 as *mut shmid_ds); + (*shm).shm_id = -(1 as c_int); + (*shm).shm_str[0 as c_int as usize] = '\u{0}' as u8; + return 0 as *mut c_uchar; + } + return (*shm).map; +} + +/// Uses a shmap id string to open a shared map +unsafe fn afl_shmem_by_str(shm: *mut AflShmem, shm_str: &CStr, map_size: usize) -> *mut c_uchar { + if shm.is_null() || shm_str.to_bytes().len() == 0 || map_size == 0 { + return 0 as *mut c_uchar; + } + (*shm).map = 0 as *mut c_uchar; + (*shm).map_size = map_size; + strncpy( + (*shm).shm_str.as_mut_ptr() as *mut c_char, + shm_str.as_ptr() as *const c_char, + (size_of::<[c_char; 20]>() as c_ulong).wrapping_sub(1 as c_int as c_ulong), + ); + (*shm).shm_id = shm_str + .to_str() + .expect(&format!("illegal shm_str {:?}", shm_str)) + .parse::() + .unwrap(); + (*shm).map = shmat((*shm).shm_id, 0 as *const c_void, 0 as c_int) as *mut c_uchar; + if (*shm).map == -(1 as c_int) as *mut c_void as *mut c_uchar { + (*shm).map = 0 as *mut c_uchar; + (*shm).map_size = 0; + (*shm).shm_str[0] = '\u{0}' as u8; + return 0 as *mut c_uchar; + } + return (*shm).map; +} diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index 6a34ae108f..875e2d7f0e 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -135,7 +135,7 @@ pub mod unix_signals { let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap(); let manager = (EVENT_MANAGER_PTR as *mut EM).as_mut().unwrap(); - + manager.crash(input).expect("Error in sending Crash event"); std::process::exit(139); @@ -162,8 +162,10 @@ pub mod unix_signals { let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap(); let manager = (EVENT_MANAGER_PTR as *mut EM).as_mut().unwrap(); - - manager.timeout(input).expect("Error in sending Timeout event"); + + manager + .timeout(input) + .expect("Error in sending Timeout event"); // TODO: send LLMP. println!("Timeout in fuzz run."); @@ -183,7 +185,7 @@ pub mod unix_signals { R: Rand, { EVENT_MANAGER_PTR = manager as *mut _ as *mut c_void; - + let mut sa: sigaction = mem::zeroed(); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); sa.sa_flags = SA_NODEFER | SA_SIGINFO;