diff --git a/libafl_qemu/librasan/asan/src/allocator/frontend/default.rs b/libafl_qemu/librasan/asan/src/allocator/frontend/default.rs index c7ee04877d..493a99c04e 100644 --- a/libafl_qemu/librasan/asan/src/allocator/frontend/default.rs +++ b/libafl_qemu/librasan/asan/src/allocator/frontend/default.rs @@ -94,7 +94,7 @@ impl AllocatorFrontend for Defaul ); self.tracking - .alloc(data, len) + .track(data, len) .map_err(|e| DefaultFrontendError::TrackingError(e))?; self.shadow .poison(orig, data - orig, PoisonType::AsanHeapLeftRz) @@ -130,7 +130,7 @@ impl AllocatorFrontend for Defaul ) .map_err(|e| DefaultFrontendError::ShadowError(e))?; self.tracking - .dealloc(addr) + .untrack(addr) .map_err(|e| DefaultFrontendError::TrackingError(e))?; self.quaratine_used += alloc.backend_len; self.quarantine.push_back(alloc); diff --git a/libafl_qemu/librasan/asan/src/exit/libc.rs b/libafl_qemu/librasan/asan/src/exit/libc.rs index 7d7c1696be..2f98a79847 100644 --- a/libafl_qemu/librasan/asan/src/exit/libc.rs +++ b/libafl_qemu/librasan/asan/src/exit/libc.rs @@ -1,4 +1,4 @@ -use core::ffi::{CStr, c_char, c_int}; +use core::ffi::{CStr, c_char, c_int, c_void}; use libc::{SIGABRT, pid_t}; @@ -32,15 +32,15 @@ impl Function for FunctionExit { } unsafe extern "C" { - fn asan_sym(name: *const c_char) -> GuestAddr; + fn asan_sym(name: *const c_char) -> *const c_void; } pub fn abort() -> ! { let getpid_addr = unsafe { asan_sym(FunctionGetpid::NAME.as_ptr() as *const c_char) }; - let fn_getpid = FunctionGetpid::as_ptr(getpid_addr).unwrap(); + let fn_getpid = FunctionGetpid::as_ptr(getpid_addr as GuestAddr).unwrap(); let kill_addr = unsafe { asan_sym(FunctionKill::NAME.as_ptr() as *const c_char) }; - let fn_kill = FunctionKill::as_ptr(kill_addr).unwrap(); + let fn_kill = FunctionKill::as_ptr(kill_addr as GuestAddr).unwrap(); unsafe { asan_swap(false) }; let pid = unsafe { fn_getpid() }; @@ -50,7 +50,7 @@ pub fn abort() -> ! { pub fn exit(status: c_int) -> ! { let exit_addr = unsafe { asan_sym(FunctionExit::NAME.as_ptr() as *const c_char) }; - let fn_exit = FunctionExit::as_ptr(exit_addr).unwrap(); + let fn_exit = FunctionExit::as_ptr(exit_addr as GuestAddr).unwrap(); unsafe { asan_swap(false) }; unsafe { fn_exit(status) }; } diff --git a/libafl_qemu/librasan/asan/src/hooks/fgets.rs b/libafl_qemu/librasan/asan/src/hooks/fgets.rs index 50a1e60345..c6130eb672 100644 --- a/libafl_qemu/librasan/asan/src/hooks/fgets.rs +++ b/libafl_qemu/librasan/asan/src/hooks/fgets.rs @@ -4,7 +4,7 @@ use libc::FILE; use log::trace; use crate::{ - asan_load, asan_panic, asan_store, asan_swap, asan_sym, + GuestAddr, asan_load, asan_panic, asan_store, asan_swap, asan_sym, symbols::{AtomicGuestAddr, Function, FunctionPointer}, }; @@ -36,8 +36,9 @@ pub unsafe extern "C" fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> asan_store(buf as *const c_void, n as usize); asan_load(stream as *const c_void, size_of::()); - let addr = FGETS_ADDR - .get_or_insert_with(|| asan_sym(FunctionFgets::NAME.as_ptr() as *const c_char)); + let addr = FGETS_ADDR.get_or_insert_with(|| { + asan_sym(FunctionFgets::NAME.as_ptr() as *const c_char) as GuestAddr + }); let fn_fgets = FunctionFgets::as_ptr(addr).unwrap(); asan_swap(false); let ret = fn_fgets(buf, n, stream); diff --git a/libafl_qemu/librasan/asan/src/hooks/mmap/libc.rs b/libafl_qemu/librasan/asan/src/hooks/mmap/libc.rs index 5d055125fc..164795aaf2 100644 --- a/libafl_qemu/librasan/asan/src/hooks/mmap/libc.rs +++ b/libafl_qemu/librasan/asan/src/hooks/mmap/libc.rs @@ -4,7 +4,7 @@ use libc::{c_int, c_void}; use log::trace; use crate::{ - asan_swap, asan_sym, asan_track, asan_unpoison, off_t, size_t, + GuestAddr, asan_swap, asan_sym, asan_track, asan_unpoison, off_t, size_t, symbols::{AtomicGuestAddr, Function, FunctionPointer}, }; @@ -41,8 +41,9 @@ pub unsafe extern "C" fn mmap( "mmap - addr: {:p}, len: {:#x}, prot: {:#x}, flags: {:#x}, fd: {:#x}, offset: {:#x}", addr, len, prot, flags, fd, offset ); - let mmap_addr = - MMAP_ADDR.get_or_insert_with(|| asan_sym(FunctionMmap::NAME.as_ptr() as *const c_char)); + let mmap_addr = MMAP_ADDR.get_or_insert_with(|| { + asan_sym(FunctionMmap::NAME.as_ptr() as *const c_char) as GuestAddr + }); asan_swap(false); let fn_mmap = FunctionMmap::as_ptr(mmap_addr).unwrap(); asan_swap(true); diff --git a/libafl_qemu/librasan/asan/src/hooks/mod.rs b/libafl_qemu/librasan/asan/src/hooks/mod.rs index 952a47ae47..e1c95ce8ca 100644 --- a/libafl_qemu/librasan/asan/src/hooks/mod.rs +++ b/libafl_qemu/librasan/asan/src/hooks/mod.rs @@ -28,19 +28,23 @@ pub mod mmap; pub mod munmap; pub mod posix_memalign; pub mod pvalloc; +pub mod rawmemchr; pub mod read; pub mod realloc; pub mod reallocarray; pub mod stpcpy; +pub mod stpncpy; pub mod strcasecmp; pub mod strcasestr; pub mod strcat; pub mod strchr; +pub mod strchrnul; pub mod strcmp; pub mod strcpy; pub mod strdup; pub mod strlen; pub mod strncasecmp; +pub mod strncat; pub mod strncmp; pub mod strncpy; pub mod strndup; @@ -48,25 +52,30 @@ pub mod strnlen; pub mod strrchr; pub mod strstr; pub mod valloc; +pub mod wcschr; pub mod wcscmp; pub mod wcscpy; pub mod wcslen; +pub mod wcsncmp; +pub mod wcsnlen; +pub mod wcsrchr; +pub mod wmemchr; pub mod write; #[cfg(feature = "libc")] pub mod fgets; -use alloc::vec::Vec; +use alloc::vec::{IntoIter, Vec}; use core::ffi::{CStr, c_char, c_int, c_void}; -use crate::{GuestAddr, hooks, size_t, wchar_t}; +use crate::{GuestAddr, hooks, size_t, symbols::Symbols, wchar_t}; unsafe extern "C" { pub fn asprintf(strp: *mut *mut c_char, fmt: *const c_char, ...) -> c_int; pub fn vasprintf(strp: *mut *mut c_char, fmt: *const c_char, va: *const c_void) -> c_int; } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct PatchedHook { pub name: &'static CStr, pub destination: GuestAddr, @@ -79,8 +88,27 @@ impl PatchedHook { Self { name, destination } } - pub fn all() -> Vec { - [ + pub fn lookup(&self) -> Result { + S::lookup(self.name.as_ptr() as *const c_char) + } +} + +pub struct PatchedHooks { + hooks: Vec, +} + +impl IntoIterator for PatchedHooks { + type Item = PatchedHook; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.hooks.into_iter() + } +} + +impl Default for PatchedHooks { + fn default() -> Self { + Self { hooks: [ PatchedHook::new:: *mut c_void>( c"aligned_alloc", hooks::aligned_alloc::aligned_alloc, @@ -124,10 +152,17 @@ impl PatchedHook { c"memrchr", hooks::memrchr::memrchr, ), + PatchedHook::new:: *mut c_void>( + c"rawmemchr", + hooks::rawmemchr::rawmemchr, + ), PatchedHook::new:: *mut c_char>( c"stpcpy", hooks::stpcpy::stpcpy, ), + PatchedHook::new::< + unsafe extern "C" fn(*mut c_char, *const c_char, size_t) -> *mut c_char, + >(c"stpncpy", hooks::stpncpy::stpncpy), PatchedHook::new:: c_int>( c"strcasecmp", hooks::strcasecmp::strcasecmp, @@ -144,6 +179,10 @@ impl PatchedHook { c"strchr", hooks::strchr::strchr, ), + PatchedHook::new:: *mut c_char>( + c"strchrnul", + hooks::strchrnul::strchrnul, + ), PatchedHook::new:: c_int>( c"strcmp", hooks::strcmp::strcmp, @@ -164,6 +203,9 @@ impl PatchedHook { c"strncasecmp", hooks::strncasecmp::strncasecmp, ), + PatchedHook::new::< + unsafe extern "C" fn(*mut c_char, *const c_char, size_t) -> *mut c_char, + >(c"strncat", hooks::strncat::strncat), PatchedHook::new:: c_int>( c"strncmp", hooks::strncmp::strncmp, @@ -190,6 +232,10 @@ impl PatchedHook { PatchedHook::new::< unsafe extern "C" fn(*mut *mut c_char, *const c_char, *const c_void) -> c_int, >(c"vasprintf", hooks::vasprintf), + PatchedHook::new:: *mut wchar_t>( + c"wcschr", + hooks::wcschr::wcschr, + ), PatchedHook::new:: c_int>( c"wcscmp", hooks::wcscmp::wcscmp, @@ -202,7 +248,24 @@ impl PatchedHook { c"wcslen", hooks::wcslen::wcslen, ), + PatchedHook::new:: c_int>( + c"wcsncmp", + hooks::wcsncmp::wcsncmp, + ), + PatchedHook::new:: size_t>( + c"wcsnlen", + hooks::wcsnlen::wcsnlen, + ), + PatchedHook::new:: *mut wchar_t >( + c"wcsrchr", + hooks::wcsrchr::wcsrchr, + ), + PatchedHook::new:: *mut wchar_t>( + c"wmemchr", + hooks::wmemchr::wmemchr, + ), + ] - .to_vec() + .to_vec() } } } diff --git a/libafl_qemu/librasan/asan/src/hooks/munmap/libc.rs b/libafl_qemu/librasan/asan/src/hooks/munmap/libc.rs index 47360a0351..bc89f20afa 100644 --- a/libafl_qemu/librasan/asan/src/hooks/munmap/libc.rs +++ b/libafl_qemu/librasan/asan/src/hooks/munmap/libc.rs @@ -4,7 +4,7 @@ use libc::{c_int, c_void}; use log::trace; use crate::{ - asan_swap, asan_sym, asan_untrack, size_t, + GuestAddr, asan_swap, asan_sym, asan_untrack, size_t, symbols::{AtomicGuestAddr, Function, FunctionPointer}, }; @@ -24,8 +24,9 @@ static MUNMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); pub unsafe extern "C" fn munmap(addr: *mut c_void, len: size_t) -> c_int { unsafe { trace!("munmap - addr: {:p}, len: {:#x}", addr, len); - let mmap_addr = MUNMAP_ADDR - .get_or_insert_with(|| asan_sym(FunctionMunmap::NAME.as_ptr() as *const c_char)); + let mmap_addr = MUNMAP_ADDR.get_or_insert_with(|| { + asan_sym(FunctionMunmap::NAME.as_ptr() as *const c_char) as GuestAddr + }); asan_swap(false); let fn_munmap = FunctionMunmap::as_ptr(mmap_addr).unwrap(); asan_swap(true); diff --git a/libafl_qemu/librasan/asan/src/hooks/rawmemchr.rs b/libafl_qemu/librasan/asan/src/hooks/rawmemchr.rs new file mode 100644 index 0000000000..6c20f6f5d1 --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/rawmemchr.rs @@ -0,0 +1,26 @@ +use core::ffi::{c_char, c_int, c_void}; + +use log::trace; + +use crate::{asan_load, asan_panic}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_rawmemchr")] +pub unsafe extern "C" fn rawmemchr(s: *const c_void, c: c_int) -> *mut c_void { + unsafe { + trace!("rawmemchr - s: {:p}, c: {:#x}", s, c); + + if s.is_null() { + asan_panic(c"rawmemchr - s is null".as_ptr() as *const c_char); + } + + let mut len = 0; + let pc = s as *const c_char; + while *pc.add(len) != c as c_char { + len += 1; + } + asan_load(s, len); + s.add(len) as *mut c_void + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/read/libc.rs b/libafl_qemu/librasan/asan/src/hooks/read/libc.rs index f3045a407b..5886713a02 100644 --- a/libafl_qemu/librasan/asan/src/hooks/read/libc.rs +++ b/libafl_qemu/librasan/asan/src/hooks/read/libc.rs @@ -4,7 +4,7 @@ use libc::{SYS_read, c_int, c_void}; use log::trace; use crate::{ - asan_panic, asan_store, asan_swap, asan_sym, size_t, ssize_t, + GuestAddr, asan_panic, asan_store, asan_swap, asan_sym, size_t, ssize_t, symbols::{AtomicGuestAddr, Function, FunctionPointer}, }; @@ -30,8 +30,9 @@ pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssi } asan_store(buf, count); - let addr = SYSCALL_ADDR - .get_or_insert_with(|| asan_sym(FunctionSyscall::NAME.as_ptr() as *const c_char)); + let addr = SYSCALL_ADDR.get_or_insert_with(|| { + asan_sym(FunctionSyscall::NAME.as_ptr() as *const c_char) as GuestAddr + }); let fn_syscall = FunctionSyscall::as_ptr(addr).unwrap(); asan_swap(false); let ret = fn_syscall(SYS_read, fd, buf, count); diff --git a/libafl_qemu/librasan/asan/src/hooks/stpncpy.rs b/libafl_qemu/librasan/asan/src/hooks/stpncpy.rs new file mode 100644 index 0000000000..b00efbcf5e --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/stpncpy.rs @@ -0,0 +1,49 @@ +use core::{ + cmp::min, + ffi::{c_char, c_void}, + ptr::{copy, write_bytes}, +}; + +use log::trace; + +use crate::{asan_load, asan_panic, asan_store, size_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_stpncpy")] +pub unsafe extern "C" fn stpncpy( + dst: *mut c_char, + src: *const c_char, + dsize: size_t, +) -> *mut c_char { + unsafe { + trace!( + "stpncpy - dst: {:p}, src: {:p}, dsize: {:#x}", + dst, src, dsize + ); + + if dsize == 0 { + return dst; + } + + if dst.is_null() { + asan_panic(c"stpncpy - dst is null".as_ptr() as *const c_char); + } + + if src.is_null() { + asan_panic(c"stpncpy - src is null".as_ptr() as *const c_char); + } + + let mut len = 0; + while *src.add(len) != 0 { + len += 1; + } + asan_load(src as *const c_void, len + 1); + asan_store(dst as *const c_void, dsize); + + let dlen = min(len + 1, dsize); + copy(src, dst, dlen); + write_bytes(dst.add(dlen), 0, dsize - dlen); + dst.add(dsize) + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/strcat.rs b/libafl_qemu/librasan/asan/src/hooks/strcat.rs index c67299f55c..503fad218f 100644 --- a/libafl_qemu/librasan/asan/src/hooks/strcat.rs +++ b/libafl_qemu/librasan/asan/src/hooks/strcat.rs @@ -5,7 +5,7 @@ use core::{ use log::trace; -use crate::{asan_load, asan_panic}; +use crate::{asan_load, asan_panic, asan_store}; /// # Safety /// See man pages @@ -30,7 +30,7 @@ pub unsafe extern "C" fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_cha while *ct.add(ct_len) != 0 { ct_len += 1; } - asan_load(s as *const c_void, s_len + 1); + asan_store(s.add(s_len) as *const c_void, ct_len + 1); asan_load(ct as *const c_void, ct_len + 1); copy(ct, s.add(s_len), ct_len + 1); s diff --git a/libafl_qemu/librasan/asan/src/hooks/strchrnul.rs b/libafl_qemu/librasan/asan/src/hooks/strchrnul.rs new file mode 100644 index 0000000000..8d8314d58a --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/strchrnul.rs @@ -0,0 +1,33 @@ +use core::{ + ffi::{c_char, c_int, c_void}, + slice::from_raw_parts, +}; + +use log::trace; + +use crate::{asan_load, asan_panic}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_strchrnul")] +pub unsafe extern "C" fn strchrnul(cs: *const c_char, c: c_int) -> *mut c_char { + unsafe { + trace!("strchrnul - cs: {:p}, c: {:#x}", cs, c); + + if cs.is_null() { + asan_panic(c"strchrnul - cs is null".as_ptr() as *const c_char); + } + + let mut len = 0; + while *cs.add(len) != 0 { + len += 1; + } + asan_load(cs as *const c_void, len + 1); + let cs_slice = from_raw_parts(cs, len); + let pos = cs_slice.iter().position(|&x| x as c_int == c); + match pos { + Some(pos) => cs.add(pos) as *mut c_char, + None => cs.add(len) as *mut c_char, + } + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/strncat.rs b/libafl_qemu/librasan/asan/src/hooks/strncat.rs new file mode 100644 index 0000000000..2907b1d8b6 --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/strncat.rs @@ -0,0 +1,46 @@ +use core::{ + ffi::{c_char, c_void}, + ptr::copy, +}; + +use log::trace; + +use crate::{asan_load, asan_panic, asan_store, size_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_strncat")] +pub unsafe extern "C" fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char { + unsafe { + trace!("strcat - s: {:p}, ct: {:p}, n: {:#x}", s, ct, n); + + if n == 0 { + return s; + } + + if s.is_null() { + asan_panic(c"strcat - s is null".as_ptr() as *const c_char); + } + + if ct.is_null() { + asan_panic(c"strcat - ct is null".as_ptr() as *const c_char); + } + + let mut s_len = 0; + while *s.add(s_len) != 0 { + s_len += 1; + } + let mut ct_len = 0; + while *ct.add(ct_len) != 0 { + ct_len += 1; + } + + let c_len = ct_len.min(n); + + asan_store(s.add(s_len) as *const c_void, c_len + 1); + asan_load(ct as *const c_void, c_len); + copy(ct, s.add(s_len), c_len); + *s.add(s_len + c_len + 1) = 0; + s + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/wcschr.rs b/libafl_qemu/librasan/asan/src/hooks/wcschr.rs new file mode 100644 index 0000000000..05ca5eaf74 --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/wcschr.rs @@ -0,0 +1,34 @@ +use core::{ + ffi::{c_char, c_int, c_void}, + ptr::null_mut, + slice::from_raw_parts, +}; + +use log::trace; + +use crate::{asan_load, asan_panic, wchar_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_wcschr")] +pub unsafe extern "C" fn wcschr(cs: *const wchar_t, c: c_int) -> *mut wchar_t { + unsafe { + trace!("wcschr - cs: {:p}, c: {:#x}", cs, c); + + if cs.is_null() { + asan_panic(c"wcschr - cs is null".as_ptr() as *const c_char); + } + + let mut len = 0; + while *cs.add(len) != 0 { + len += 1; + } + asan_load(cs as *const c_void, (len + 1) * size_of::()); + let cs_slice = from_raw_parts(cs, len); + let pos = cs_slice.iter().position(|&x| x as c_int == c); + match pos { + Some(pos) => cs.add(pos) as *mut wchar_t, + None => null_mut(), + } + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/wcsncmp.rs b/libafl_qemu/librasan/asan/src/hooks/wcsncmp.rs new file mode 100644 index 0000000000..41c92ee79a --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/wcsncmp.rs @@ -0,0 +1,62 @@ +use core::{ + cmp::Ordering, + ffi::{c_char, c_int, c_void}, + slice::from_raw_parts, +}; + +use log::trace; + +use crate::{asan_load, asan_panic, size_t, wchar_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_wcsncmp")] +pub unsafe extern "C" fn wcsncmp(cs: *const wchar_t, ct: *const wchar_t, n: size_t) -> c_int { + unsafe { + trace!("wcsncmp - cs: {:p}, ct: {:p}, n: {:#x}", cs, ct, n); + + if n == 0 { + return 0; + } + + if cs.is_null() { + asan_panic(c"wcsncmp - cs is null".as_ptr() as *const c_char); + } + + if ct.is_null() { + asan_panic(c"wcsncmp - ct is null".as_ptr() as *const c_char); + } + + let mut cs_len = 0; + while cs_len < n && *cs.add(cs_len) != 0 { + cs_len += 1; + } + let mut ct_len = 0; + while ct_len < n && *ct.add(ct_len) != 0 { + ct_len += 1; + } + asan_load(cs as *const c_void, (cs_len + 1) * size_of::()); + asan_load(ct as *const c_void, (ct_len + 1) * size_of::()); + + let slice1 = from_raw_parts(cs as *const u32, cs_len); + let slice2 = from_raw_parts(ct as *const u32, ct_len); + + for i in 0..cs_len.max(ct_len) { + if i >= cs_len { + return -1; + } + + if i >= ct_len { + return 1; + } + + match slice1[i].cmp(&slice2[i]) { + Ordering::Equal => (), + Ordering::Less => return -1, + Ordering::Greater => return 1, + } + } + + 0 + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/wcsnlen.rs b/libafl_qemu/librasan/asan/src/hooks/wcsnlen.rs new file mode 100644 index 0000000000..8a0f7b04db --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/wcsnlen.rs @@ -0,0 +1,35 @@ +use core::ffi::{c_char, c_void}; + +use log::trace; + +use crate::{asan_load, asan_panic, size_t, wchar_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_wcsnlen")] +pub unsafe extern "C" fn wcsnlen(cs: *const wchar_t, maxlen: size_t) -> size_t { + unsafe { + trace!("wcsnlen - cs: {:p}, maxlen: {:#x}", cs, maxlen); + + if maxlen == 0 { + return 0; + } + + if cs.is_null() { + asan_panic(c"wcsnlen - cs is null".as_ptr() as *const c_char); + } + + let mut len = 0; + while *cs.add(len) != 0 { + len += 1; + } + + if len < maxlen { + asan_load(cs as *const c_void, (len + 1) * size_of::()); + len + } else { + asan_load(cs as *const c_void, maxlen * size_of::()); + maxlen + } + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/wcsrchr.rs b/libafl_qemu/librasan/asan/src/hooks/wcsrchr.rs new file mode 100644 index 0000000000..047ef682b2 --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/wcsrchr.rs @@ -0,0 +1,34 @@ +use core::{ + ffi::{c_char, c_int, c_void}, + ptr::null_mut, + slice::from_raw_parts, +}; + +use log::trace; + +use crate::{asan_load, asan_panic, wchar_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_wcsrchr")] +pub unsafe extern "C" fn wcsrchr(cs: *const wchar_t, c: c_int) -> *mut wchar_t { + unsafe { + trace!("wcsrchr - cs: {:p}, c: {:#x}", cs, c); + + if cs.is_null() { + asan_panic(c"wcsrchr - cs is null".as_ptr() as *const c_char); + } + + let mut len = 0; + while *cs.add(len) != 0 { + len += 1; + } + asan_load(cs as *const c_void, (len + 1) * size_of::()); + let cs_slice = from_raw_parts(cs, len); + let pos = cs_slice.iter().rev().position(|&x| x as c_int == c); + match pos { + Some(pos) => cs.add(len - pos - 1) as *mut wchar_t, + None => null_mut(), + } + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/wmemchr.rs b/libafl_qemu/librasan/asan/src/hooks/wmemchr.rs new file mode 100644 index 0000000000..4799b635f4 --- /dev/null +++ b/libafl_qemu/librasan/asan/src/hooks/wmemchr.rs @@ -0,0 +1,34 @@ +use core::{ + ffi::{c_char, c_void}, + ptr::null_mut, + slice::from_raw_parts, +}; + +use log::trace; + +use crate::{asan_load, asan_panic, size_t, wchar_t}; + +/// # Safety +/// See man pages +#[unsafe(export_name = "patch_wmemchr")] +pub unsafe extern "C" fn wmemchr(cx: *const wchar_t, c: wchar_t, n: size_t) -> *mut wchar_t { + unsafe { + trace!("wmemchr - cx: {:p}, c: {:#x}, n: {:#x}", cx, c, n); + + if n == 0 { + return null_mut(); + } + + if cx.is_null() && n != 0 { + asan_panic(c"wmemchr - cx is null".as_ptr() as *const c_char); + } + + asan_load(cx as *const c_void, n * size_of::()); + let slice = from_raw_parts(cx, n); + let pos = slice.iter().position(|&x| x == c); + match pos { + Some(pos) => cx.add(pos) as *mut wchar_t, + None => null_mut(), + } + } +} diff --git a/libafl_qemu/librasan/asan/src/hooks/write/libc.rs b/libafl_qemu/librasan/asan/src/hooks/write/libc.rs index 2e02f09796..2637f1c47f 100644 --- a/libafl_qemu/librasan/asan/src/hooks/write/libc.rs +++ b/libafl_qemu/librasan/asan/src/hooks/write/libc.rs @@ -4,7 +4,7 @@ use libc::{SYS_write, c_int, c_void}; use log::trace; use crate::{ - asan_load, asan_panic, asan_swap, asan_sym, size_t, ssize_t, + GuestAddr, asan_load, asan_panic, asan_swap, asan_sym, size_t, ssize_t, symbols::{AtomicGuestAddr, Function, FunctionPointer}, }; @@ -30,8 +30,9 @@ pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: size_t) -> } asan_load(buf, count); - let addr = SYSCALL_ADDR - .get_or_insert_with(|| asan_sym(FunctionSyscall::NAME.as_ptr() as *const c_char)); + let addr = SYSCALL_ADDR.get_or_insert_with(|| { + asan_sym(FunctionSyscall::NAME.as_ptr() as *const c_char) as GuestAddr + }); let fn_syscall = FunctionSyscall::as_ptr(addr).unwrap(); asan_swap(false); let ret = fn_syscall(SYS_write, fd, buf, count); diff --git a/libafl_qemu/librasan/asan/src/host/libc.rs b/libafl_qemu/librasan/asan/src/host/libc.rs index cd235659fa..97812acf8b 100644 --- a/libafl_qemu/librasan/asan/src/host/libc.rs +++ b/libafl_qemu/librasan/asan/src/host/libc.rs @@ -111,7 +111,7 @@ impl Host for LibcHost { Ok(()) } - fn alloc(start: GuestAddr, len: usize) -> Result<(), LibcHostError> { + fn track(start: GuestAddr, len: usize) -> Result<(), LibcHostError> { unsafe { let syscall = Self::get_syscall()?; let ret = syscall(Self::SYSCALL_NO, HostAction::Alloc as usize, start, len); @@ -122,7 +122,7 @@ impl Host for LibcHost { Ok(()) } - fn dealloc(start: GuestAddr) -> Result<(), LibcHostError> { + fn untrack(start: GuestAddr) -> Result<(), LibcHostError> { let syscall = Self::get_syscall()?; let ret = unsafe { syscall(Self::SYSCALL_NO, HostAction::Dealloc as usize, start) }; if ret != 0 { diff --git a/libafl_qemu/librasan/asan/src/host/linux.rs b/libafl_qemu/librasan/asan/src/host/linux.rs index 6b0321cd4a..8859a10304 100644 --- a/libafl_qemu/librasan/asan/src/host/linux.rs +++ b/libafl_qemu/librasan/asan/src/host/linux.rs @@ -66,14 +66,14 @@ impl Host for LinuxHost { Ok(()) } - fn alloc(start: GuestAddr, len: usize) -> LinuxHostResult<()> { + fn track(start: GuestAddr, len: usize) -> LinuxHostResult<()> { unsafe { syscall3(Self::sysno(), HostAction::Alloc as usize, start, len)?; }; Ok(()) } - fn dealloc(start: GuestAddr) -> LinuxHostResult<()> { + fn untrack(start: GuestAddr) -> LinuxHostResult<()> { unsafe { syscall2(Self::sysno(), HostAction::Dealloc as usize, start)? }; Ok(()) } diff --git a/libafl_qemu/librasan/asan/src/host/mod.rs b/libafl_qemu/librasan/asan/src/host/mod.rs index a223e652c4..917fc8085a 100644 --- a/libafl_qemu/librasan/asan/src/host/mod.rs +++ b/libafl_qemu/librasan/asan/src/host/mod.rs @@ -39,6 +39,6 @@ pub trait Host: Debug + Send { fn unpoison(start: GuestAddr, len: usize) -> Result<(), Self::Error>; fn is_poison(start: GuestAddr, len: usize) -> Result; fn swap(enabled: bool) -> Result<(), Self::Error>; - fn alloc(start: GuestAddr, len: usize) -> Result<(), Self::Error>; - fn dealloc(start: GuestAddr) -> Result<(), Self::Error>; + fn track(start: GuestAddr, len: usize) -> Result<(), Self::Error>; + fn untrack(start: GuestAddr) -> Result<(), Self::Error>; } diff --git a/libafl_qemu/librasan/asan/src/lib.rs b/libafl_qemu/librasan/asan/src/lib.rs index d63bca14bb..bee96daf94 100644 --- a/libafl_qemu/librasan/asan/src/lib.rs +++ b/libafl_qemu/librasan/asan/src/lib.rs @@ -118,8 +118,7 @@ unsafe extern "C" { pub fn asan_alloc(len: usize, align: usize) -> *mut c_void; pub fn asan_dealloc(addr: *const c_void); pub fn asan_get_size(addr: *const c_void) -> usize; - #[cfg(feature = "libc")] - pub fn asan_sym(name: *const c_char) -> GuestAddr; + pub fn asan_sym(name: *const c_char) -> *const c_void; pub fn asan_page_size() -> usize; pub fn asan_unpoison(addr: *mut c_void, len: usize); pub fn asan_track(addr: *mut c_void, len: usize); diff --git a/libafl_qemu/librasan/asan/src/maps/mod.rs b/libafl_qemu/librasan/asan/src/maps/mod.rs index fac62abde8..44047e22bb 100644 --- a/libafl_qemu/librasan/asan/src/maps/mod.rs +++ b/libafl_qemu/librasan/asan/src/maps/mod.rs @@ -1,5 +1,18 @@ +use alloc::vec::{IntoIter, Vec}; use core::fmt::Debug; +use itertools::Itertools; +use thiserror::Error; + +use crate::{ + GuestAddr, + maps::{ + entry::{MapEntry, WriteableMapProtection}, + iterator::MapIterator, + }, + mmap::Mmap, +}; + mod decode; pub mod entry; @@ -15,4 +28,46 @@ pub trait MapReader: Sized { type Error: Debug; fn new() -> Result; fn read(&mut self, buf: &mut [u8]) -> Result; + fn mappings() -> Result { + let reader = Self::new()?; + let maps = MapIterator::new(reader).collect::>(); + Ok(Maps { maps }) + } +} + +pub struct Maps { + maps: Vec, +} + +impl Maps { + pub fn writeable( + &self, + addr: GuestAddr, + ) -> Result, MapsError> { + let mapping = self + .maps + .iter() + .filter(|m| m.contains(addr)) + .exactly_one() + .map_err(|_e| MapsError::MappingNotFound(addr))?; + mapping + .writeable::() + .map_err(|e| MapsError::MmapError(e)) + } +} + +impl IntoIterator for Maps { + type Item = MapEntry; + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.maps.into_iter() + } +} + +#[derive(Error, Debug)] +pub enum MapsError { + #[error("Mapping not found: {0}")] + MappingNotFound(GuestAddr), + #[error("Mmap error: {0:?}")] + MmapError(M::Error), } diff --git a/libafl_qemu/librasan/asan/src/patch/hooks.rs b/libafl_qemu/librasan/asan/src/patch/hooks.rs deleted file mode 100644 index ab913fac98..0000000000 --- a/libafl_qemu/librasan/asan/src/patch/hooks.rs +++ /dev/null @@ -1,92 +0,0 @@ -use alloc::{collections::BTreeMap, fmt::Debug, vec::Vec}; -use core::ffi::{CStr, c_char}; - -use itertools::Itertools; -use log::{debug, trace}; -use spin::Mutex; -use thiserror::Error; - -use crate::{ - GuestAddr, - hooks::PatchedHook, - maps::{MapReader, entry::MapEntry, iterator::MapIterator}, - mmap::Mmap, - patch::Patch, - symbols::Symbols, -}; - -static PATCHED: Mutex>> = Mutex::new(None); - -pub struct PatchedHooks; - -impl PatchedHooks { - pub fn init() - -> Result<(), PatchesError> { - debug!("Installing patches"); - let mappings = Self::get_mappings()?; - mappings.iter().for_each(|m| trace!("{m:?}")); - for patch in PatchedHook::all() { - Self::patch(patch, &mappings)?; - } - debug!("Patching complete"); - Ok(()) - } - - pub fn get_mappings() - -> Result, PatchesError> { - let reader = R::new().map_err(|e| PatchesError::MapReaderError(e))?; - Ok(MapIterator::new(reader).collect::>()) - } - - pub fn patch( - patch: PatchedHook, - mappings: &[MapEntry], - ) -> Result<(), PatchesError> { - trace!( - "patch: {:?}, destination: {:#x}", - patch.name, patch.destination - ); - let target = S::lookup(patch.name.as_ptr() as *const c_char) - .map_err(|e| PatchesError::SymbolsError(e))?; - trace!("patching: {:#x} -> {:#x}", target, patch.destination); - let mapping = mappings - .iter() - .filter(|m| m.contains(target)) - .exactly_one() - .map_err(|_e| PatchesError::MapError(target))?; - let prot = mapping - .writeable::() - .map_err(|e| PatchesError::MmapError(e))?; - P::patch(target, patch.destination).map_err(|e| PatchesError::PatchError(e))?; - drop(prot); - PATCHED.lock().get_or_insert_default().insert(target, patch); - Ok(()) - } - - pub fn check_patched(addr: GuestAddr) -> Result<(), PatchesCheckError> { - match PATCHED.lock().as_ref().and_then(|p| p.get(&addr)) { - Some(patch) => Err(PatchesCheckError::AddressPatchedError(addr, patch.name))?, - _ => Ok(()), - } - } -} - -#[derive(Error, Debug, PartialEq, Clone)] -pub enum PatchesError { - #[error("Symbols error: {0:?}")] - SymbolsError(S::Error), - #[error("Patch error: {0:?}")] - PatchError(P::Error), - #[error("Map reader error: {0:?}")] - MapReaderError(R::Error), - #[error("Map error: {0:?}")] - MapError(GuestAddr), - #[error("Mmap error: {0:?}")] - MmapError(M::Error), -} - -#[derive(Error, Debug, PartialEq, Clone)] -pub enum PatchesCheckError { - #[error("Address: {0} is patched for {1:?}")] - AddressPatchedError(GuestAddr, &'static CStr), -} diff --git a/libafl_qemu/librasan/asan/src/patch/mod.rs b/libafl_qemu/librasan/asan/src/patch/mod.rs index 370d8c274f..112ce590a0 100644 --- a/libafl_qemu/librasan/asan/src/patch/mod.rs +++ b/libafl_qemu/librasan/asan/src/patch/mod.rs @@ -1,16 +1,65 @@ //! # patch //! This module provides implementations patching function prologues in order //! to re-direct execution to an alternative address. -use alloc::fmt::Debug; - -use crate::GuestAddr; - -#[cfg(feature = "hooks")] -pub mod hooks; - pub mod raw; +use alloc::{collections::BTreeMap, fmt::Debug}; + +use log::trace; +use spin::{Mutex, Once}; +use thiserror::Error; + +use crate::{ + GuestAddr, + maps::{Maps, MapsError}, + mmap::Mmap, +}; + pub trait Patch: Debug { type Error: Debug; fn patch(target: GuestAddr, destination: GuestAddr) -> Result<(), Self::Error>; } + +static PATCHES: Once> = Once::new(); +static PATCHED: Mutex> = Mutex::new(BTreeMap::new()); + +pub struct Patches { + maps: Maps, +} + +impl Patches { + pub fn init(maps: Maps) { + let patches = Mutex::new(Patches { maps }); + PATCHES.call_once(|| patches); + } + + pub fn apply( + target: GuestAddr, + destination: GuestAddr, + ) -> Result<(), PatchesError> { + trace!("patch: {:#x} -> {:#x}", target, destination); + let patches = PATCHES.get().ok_or(PatchesError::Uninitialized())?.lock(); + let prot = patches + .maps + .writeable(target) + .map_err(PatchesError::MapsError)?; + P::patch(target, destination).map_err(|e| PatchesError::PatchError(e))?; + drop(prot); + PATCHED.lock().insert(target, destination); + Ok(()) + } + + pub fn is_patched(addr: GuestAddr) -> bool { + PATCHED.lock().contains_key(&addr) + } +} + +#[derive(Error, Debug)] +pub enum PatchesError { + #[error("Uninitialized")] + Uninitialized(), + #[error("Patch error: {0:?}")] + PatchError(P::Error), + #[error("Maps error: {0:?}")] + MapsError(MapsError), +} diff --git a/libafl_qemu/librasan/asan/src/symbols/mod.rs b/libafl_qemu/librasan/asan/src/symbols/mod.rs index 5966b720de..fefd7a8079 100644 --- a/libafl_qemu/librasan/asan/src/symbols/mod.rs +++ b/libafl_qemu/librasan/asan/src/symbols/mod.rs @@ -12,9 +12,7 @@ use core::{ use thiserror::Error; -use crate::GuestAddr; -#[cfg(feature = "hooks")] -use crate::patch::hooks::{PatchedHooks, PatchesCheckError}; +use crate::{GuestAddr, patch::Patches}; #[cfg(feature = "libc")] pub mod dlsym; @@ -108,8 +106,9 @@ impl FunctionPointer for T { Err(FunctionPointerError::BadAddress(addr))?; } - #[cfg(feature = "hooks")] - PatchedHooks::check_patched(addr).map_err(FunctionPointerError::PatchedAddress)?; + if Patches::is_patched(addr) { + Err(FunctionPointerError::PatchedAddress(addr))?; + } let pp_sym = (&addr) as *const GuestAddr as *const *mut c_void; let p_f = pp_sym as *const Self::Func; @@ -122,7 +121,6 @@ impl FunctionPointer for T { pub enum FunctionPointerError { #[error("Bad address: {0}")] BadAddress(GuestAddr), - #[cfg(feature = "hooks")] #[error("Patched address: {0}")] - PatchedAddress(PatchesCheckError), + PatchedAddress(GuestAddr), } diff --git a/libafl_qemu/librasan/asan/src/test.rs b/libafl_qemu/librasan/asan/src/test.rs index 582f8771ff..d500a1fdfe 100644 --- a/libafl_qemu/librasan/asan/src/test.rs +++ b/libafl_qemu/librasan/asan/src/test.rs @@ -138,8 +138,8 @@ pub unsafe extern "C" fn asan_get_size(addr: *const c_void) -> usize { #[unsafe(no_mangle)] /// # Safety -pub unsafe extern "C" fn asan_sym(name: *const c_char) -> GuestAddr { - TestSyms::lookup(name).unwrap() +pub unsafe extern "C" fn asan_sym(name: *const c_char) -> *const c_void { + TestSyms::lookup(name).unwrap() as *const c_void } #[unsafe(no_mangle)] @@ -166,7 +166,7 @@ pub unsafe extern "C" fn asan_track(addr: *const c_void, len: usize) { FRONTEND .lock() .tracking_mut() - .alloc(addr as GuestAddr, len) + .track(addr as GuestAddr, len) .unwrap(); } @@ -177,7 +177,7 @@ pub unsafe extern "C" fn asan_untrack(addr: *const c_void) { FRONTEND .lock() .tracking_mut() - .dealloc(addr as GuestAddr) + .untrack(addr as GuestAddr) .unwrap(); } diff --git a/libafl_qemu/librasan/asan/src/tracking/guest.rs b/libafl_qemu/librasan/asan/src/tracking/guest.rs index 7937a3b5c3..9d3db62176 100644 --- a/libafl_qemu/librasan/asan/src/tracking/guest.rs +++ b/libafl_qemu/librasan/asan/src/tracking/guest.rs @@ -54,7 +54,7 @@ pub struct GuestTracking { impl Tracking for GuestTracking { type Error = GuestTrackingError; - fn alloc(&mut self, start: GuestAddr, len: usize) -> Result<(), Self::Error> { + fn track(&mut self, start: GuestAddr, len: usize) -> Result<(), Self::Error> { debug!("alloc - start: 0x{:x}, len: 0x{:x}", start, len); if Self::is_out_of_bounds(start, len) { Err(GuestTrackingError::AddressRangeOverflow(start, len))?; @@ -85,7 +85,7 @@ impl Tracking for GuestTracking { Ok(()) } - fn dealloc(&mut self, start: GuestAddr) -> Result<(), Self::Error> { + fn untrack(&mut self, start: GuestAddr) -> Result<(), Self::Error> { debug!("dealloc - start: 0x{:x}", start); let pos = self.ranges.binary_search_by(|item| item.start.cmp(&start)); match pos { diff --git a/libafl_qemu/librasan/asan/src/tracking/host.rs b/libafl_qemu/librasan/asan/src/tracking/host.rs index ad78084e75..80ac4543b2 100644 --- a/libafl_qemu/librasan/asan/src/tracking/host.rs +++ b/libafl_qemu/librasan/asan/src/tracking/host.rs @@ -19,15 +19,15 @@ pub struct HostTracking { impl Tracking for HostTracking { type Error = HostTrackingError; - fn alloc(&mut self, start: GuestAddr, len: usize) -> Result<(), Self::Error> { + fn track(&mut self, start: GuestAddr, len: usize) -> Result<(), Self::Error> { debug!("alloc - start: 0x{:x}, len: 0x{:x}", start, len); /* Here QEMU expects a start and end, rather than start and length */ - H::alloc(start, start + len).map_err(|e| HostTrackingError::HostError(e)) + H::track(start, start + len).map_err(|e| HostTrackingError::HostError(e)) } - fn dealloc(&mut self, start: GuestAddr) -> Result<(), Self::Error> { + fn untrack(&mut self, start: GuestAddr) -> Result<(), Self::Error> { debug!("free - start: 0x{:x}", start); - H::dealloc(start).map_err(|e| HostTrackingError::HostError(e)) + H::untrack(start).map_err(|e| HostTrackingError::HostError(e)) } } diff --git a/libafl_qemu/librasan/asan/src/tracking/mod.rs b/libafl_qemu/librasan/asan/src/tracking/mod.rs index 9447b8be2a..115c7cbb60 100644 --- a/libafl_qemu/librasan/asan/src/tracking/mod.rs +++ b/libafl_qemu/librasan/asan/src/tracking/mod.rs @@ -13,6 +13,6 @@ pub mod host; pub trait Tracking: Sized + Debug + Send { type Error: Debug; - fn alloc(&mut self, start: GuestAddr, len: usize) -> Result<(), Self::Error>; - fn dealloc(&mut self, start: GuestAddr) -> Result<(), Self::Error>; + fn track(&mut self, start: GuestAddr, len: usize) -> Result<(), Self::Error>; + fn untrack(&mut self, start: GuestAddr) -> Result<(), Self::Error>; } diff --git a/libafl_qemu/librasan/asan/tests/guest_tracking.rs b/libafl_qemu/librasan/asan/tests/guest_tracking.rs index 83b6fb1fcc..8828a6ae16 100644 --- a/libafl_qemu/librasan/asan/tests/guest_tracking.rs +++ b/libafl_qemu/librasan/asan/tests/guest_tracking.rs @@ -28,14 +28,14 @@ mod tests { #[test] fn test_max() { let mut tracking = get_tracking(); - assert_eq!(tracking.alloc(GuestAddr::MAX, 1), Ok(())); + assert_eq!(tracking.track(GuestAddr::MAX, 1), Ok(())); } #[test] fn test_out_of_bounds() { let mut tracking = get_tracking(); assert_eq!( - tracking.alloc(GuestAddr::MAX, 2), + tracking.track(GuestAddr::MAX, 2), Err(GuestTrackingError::AddressRangeOverflow(GuestAddr::MAX, 2)) ); } @@ -43,9 +43,9 @@ mod tests { #[test] fn test_track_identical() { let mut tracking = get_tracking(); - assert_eq!(tracking.alloc(0x1000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); assert_eq!( - tracking.alloc(0x1000, 0x1000), + tracking.track(0x1000, 0x1000), Err(GuestTrackingError::TrackingConflict( 0x1000, 0x1000, 0x1000, 0x1000 )) @@ -55,23 +55,23 @@ mod tests { #[test] fn test_track_adjacent_after() { let mut tracking = get_tracking(); - assert_eq!(tracking.alloc(0x1000, 0x1000), Ok(())); - assert_eq!(tracking.alloc(0x2000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x2000, 0x1000), Ok(())); } #[test] fn test_track_adjacent_before() { let mut tracking = get_tracking(); - assert_eq!(tracking.alloc(0x1000, 0x1000), Ok(())); - assert_eq!(tracking.alloc(0x0000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x0000, 0x1000), Ok(())); } #[test] fn test_track_overlapping_start() { let mut tracking = get_tracking(); - assert_eq!(tracking.alloc(0x1000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); assert_eq!( - tracking.alloc(0x0000, 0x1001), + tracking.track(0x0000, 0x1001), Err(GuestTrackingError::TrackingConflict( 0x1000, 0x1000, 0x0000, 0x1001 )) @@ -81,9 +81,9 @@ mod tests { #[test] fn test_track_overlapping_end() { let mut tracking = get_tracking(); - assert_eq!(tracking.alloc(0x1000, 0x1000), Ok(())); + assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); assert_eq!( - tracking.alloc(0x1fff, 0x1001), + tracking.track(0x1fff, 0x1001), Err(GuestTrackingError::TrackingConflict( 0x1000, 0x1000, 0x1fff, 0x1001 )) @@ -96,9 +96,9 @@ mod tests { let mut tracking = get_tracking(); // alloc - start: 0xffffffffb5b5ff21, len: 0x3ff // alloc - start: 0xffffffffb5b60107, len: 0xdb - assert_eq!(tracking.alloc(0xffffffffb5b5ff21, 0x3ff), Ok(())); + assert_eq!(tracking.track(0xffffffffb5b5ff21, 0x3ff), Ok(())); assert_eq!( - tracking.alloc(0xffffffffb5b60107, 0xdb), + tracking.track(0xffffffffb5b60107, 0xdb), Err(GuestTrackingError::TrackingConflict( 0xffffffffb5b5ff21, 0x3ff, diff --git a/libafl_qemu/librasan/asan/tests/hooks_rawmemchr.rs b/libafl_qemu/librasan/asan/tests/hooks_rawmemchr.rs new file mode 100644 index 0000000000..55b10d643d --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_rawmemchr.rs @@ -0,0 +1,51 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::{ + ffi::{c_int, c_void}, + ptr::null_mut, + }; + + use asan::{expect_panic, hooks::rawmemchr::rawmemchr}; + + #[test] + fn test_rawmemchr_null_buffer() { + expect_panic(); + unsafe { rawmemchr(null_mut(), 0) }; + unreachable!() + } + + #[test] + fn test_rawmemchr_find_first() { + let data = "abcdefghij".as_bytes(); + let c = 'a' as c_int; + let ret = unsafe { rawmemchr(data.as_ptr() as *const c_void, c) }; + assert_eq!(ret, data.as_ptr() as *mut c_void); + } + + #[test] + fn test_rawmemchr_find_last() { + let data = "abcdefghij".as_bytes(); + let c = 'j' as c_int; + let ret = unsafe { rawmemchr(data.as_ptr() as *const c_void, c) }; + assert_eq!(ret, unsafe { + data.as_ptr().add(data.len() - 1) as *mut c_void + }); + } + + #[test] + fn test_rawmemchr_find_mid() { + let data = "abcdefghij".as_bytes(); + let c = 'e' as c_int; + let ret = unsafe { rawmemchr(data.as_ptr() as *const c_void, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(4) as *mut c_void }); + } + + #[test] + fn test_rawmemchr_find_repeated() { + let data = "ababababab".as_bytes(); + let c = 'b' as c_int; + let ret = unsafe { rawmemchr(data.as_ptr() as *const c_void, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(1) as *mut c_void }); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_stpncpy.rs b/libafl_qemu/librasan/asan/tests/hooks_stpncpy.rs new file mode 100644 index 0000000000..53a47c838b --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_stpncpy.rs @@ -0,0 +1,64 @@ +#[cfg(test)] +#[cfg(all(feature = "hooks"))] +mod tests { + use core::{ffi::c_char, ptr::null_mut}; + + use asan::{expect_panic, hooks::stpncpy::stpncpy}; + + #[test] + fn test_stpncpy_zero_length() { + let ret = unsafe { stpncpy(null_mut(), null_mut(), 0) }; + assert_eq!(ret, null_mut()); + } + + #[test] + fn test_stpncpy_dst_null() { + let src = [0u8; 10]; + expect_panic(); + unsafe { stpncpy(null_mut(), src.as_ptr() as *const c_char, 10) }; + unreachable!(); + } + + #[test] + fn test_stpncpy_src_null() { + let dst = [0u8; 10]; + expect_panic(); + unsafe { stpncpy(dst.as_ptr() as *mut c_char, null_mut(), dst.len()) }; + unreachable!(); + } + + #[test] + fn test_stpncpy_full() { + let src = [0xffu8; 10]; + let dst = [0u8; 10]; + let ret = unsafe { + stpncpy( + dst.as_ptr() as *mut c_char, + src.as_ptr() as *const c_char, + dst.len(), + ) + }; + assert_eq!(ret, unsafe { dst.as_ptr().add(dst.len()) as *mut c_char }); + } + + #[test] + fn test_stpncpy_partial() { + let mut vec = c"abcdefghijklmnopqrstuvwxyz".to_bytes().to_vec(); + let dst = vec.as_mut_slice(); + let src = c"uvwxyz".to_bytes(); + let ret = unsafe { + stpncpy( + dst.as_ptr() as *mut c_char, + src.as_ptr() as *const c_char, + dst.len(), + ) + }; + assert_eq!(ret, unsafe { dst.as_ptr().add(dst.len()) as *mut c_char }); + let expected = c"uvwxyz".to_bytes(); + expected + .iter() + .zip(dst.iter()) + .for_each(|(x, y)| assert_eq!(*x, *y)); + dst.iter().skip(src.len()).for_each(|x| assert_eq!(*x, 0)); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_strchrnul.rs b/libafl_qemu/librasan/asan/tests/hooks_strchrnul.rs new file mode 100644 index 0000000000..57229603fe --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_strchrnul.rs @@ -0,0 +1,67 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::{ + ffi::{c_char, c_int}, + ptr::null, + }; + + use asan::{expect_panic, hooks::strchrnul::strchrnul}; + + #[test] + fn test_strchrnul_zero_length() { + let data = c""; + let ret = unsafe { strchrnul(data.as_ptr() as *const c_char, 0x88) }; + assert_eq!(ret, data.as_ptr() as *mut c_char); + } + + #[test] + fn test_strchrnul_null_buffer() { + expect_panic(); + unsafe { strchrnul(null(), 0x88) }; + unreachable!() + } + + #[test] + fn test_strchrnul_find_first() { + let data = c"abcdefghij"; + let c = 'a' as c_int; + let ret = unsafe { strchrnul(data.as_ptr() as *const c_char, c) }; + assert_eq!(ret, data.as_ptr() as *mut c_char); + } + + #[test] + fn test_strchrnul_find_last() { + let data = c"abcdefghij"; + let c = 'j' as c_int; + let ret = unsafe { strchrnul(data.as_ptr() as *const c_char, c) }; + assert_eq!(ret, unsafe { + data.as_ptr().add(data.count_bytes() - 1) as *mut c_char + }); + } + + #[test] + fn test_strchrnul_find_mid() { + let data = c"abcdefghij"; + let c = 'e' as c_int; + let ret = unsafe { strchrnul(data.as_ptr() as *const c_char, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(4) as *mut c_char }); + } + + #[test] + fn test_strchrnul_find_repeated() { + let data = c"ababababab"; + let c = 'b' as c_int; + let ret = unsafe { strchrnul(data.as_ptr() as *const c_char, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(1) as *mut c_char }); + } + + #[test] + fn test_strchrnul_not_found() { + let data = c"abcdefghij"; + let c = 'k' as c_int; + let ret = unsafe { strchrnul(data.as_ptr() as *const c_char, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(data.count_bytes()) } + as *mut c_char); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_strncat.rs b/libafl_qemu/librasan/asan/tests/hooks_strncat.rs new file mode 100644 index 0000000000..5cd43a20a8 --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_strncat.rs @@ -0,0 +1,81 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::{ + ffi::c_char, + ptr::{null, null_mut}, + }; + + use asan::{expect_panic, hooks::strncat::strncat}; + + #[test] + fn test_strncat_zero_length() { + let ret = unsafe { strncat(null_mut(), null_mut(), 0) }; + assert_eq!(ret, null_mut()); + } + + #[test] + fn test_strncat_null_s() { + expect_panic(); + let data = [0u8; 10]; + unsafe { strncat(null_mut(), data.as_ptr() as *const c_char, data.len()) }; + unreachable!(); + } + + #[test] + fn test_strncat_null_s2() { + expect_panic(); + let data = [0u8; 10]; + unsafe { strncat(data.as_ptr() as *mut c_char, null(), 10) }; + unreachable!(); + } + + #[test] + fn test_strncat_zero_length_both() { + let data = [0u8; 10]; + let ret = unsafe { + strncat( + data.as_ptr() as *mut c_char, + data.as_ptr() as *const c_char, + data.len(), + ) + }; + assert_eq!(ret, data.as_ptr() as *mut c_char); + } + + #[test] + fn test_strncat_appends() { + let mut vec = "abcde\0zzzzzzzzzzzzzzz".as_bytes().to_vec(); + let s = vec.as_mut_slice(); + let ct = c"fghij"; + let ret = unsafe { + strncat( + s.as_ptr() as *mut c_char, + ct.as_ptr() as *const c_char, + ct.count_bytes(), + ) + }; + assert_eq!(ret, s.as_ptr() as *mut c_char); + let expected = c"abcdefghij"; + expected + .to_bytes() + .iter() + .zip(s.iter()) + .for_each(|(x, y)| assert_eq!(*x, *y)); + } + + #[test] + fn test_strncat_appends_partial() { + let mut vec = "abcde\0zzzzzzzzzzzzzzz".as_bytes().to_vec(); + let s = vec.as_mut_slice(); + let ct = c"fghij"; + let ret = unsafe { strncat(s.as_ptr() as *mut c_char, ct.as_ptr() as *const c_char, 3) }; + assert_eq!(ret, s.as_ptr() as *mut c_char); + let expected = c"abcdefgh"; + expected + .to_bytes() + .iter() + .zip(s.iter()) + .for_each(|(x, y)| assert_eq!(*x, *y)); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_wcschr.rs b/libafl_qemu/librasan/asan/tests/hooks_wcschr.rs new file mode 100644 index 0000000000..12d605aac4 --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_wcschr.rs @@ -0,0 +1,67 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::{ + ffi::c_int, + ptr::{null, null_mut}, + }; + + use asan::{expect_panic, hooks::wcschr::wcschr, wchar_t}; + use widestring::widecstr; + + #[test] + fn test_wcschr_zero_length() { + let data = widecstr!(""); + let ret = unsafe { wcschr(data.as_ptr() as *const wchar_t, 0x88) }; + assert_eq!(ret, null_mut()); + } + + #[test] + fn test_wcschr_null_buffer() { + expect_panic(); + unsafe { wcschr(null(), 0x88) }; + unreachable!() + } + + #[test] + fn test_wcschr_find_first() { + let data = widecstr!("abcdefghij"); + let c = 'a' as c_int; + let ret = unsafe { wcschr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, data.as_ptr() as *mut wchar_t); + } + + #[test] + fn test_wcschr_find_last() { + let data = widecstr!("abcdefghij"); + let c = 'j' as c_int; + let ret = unsafe { wcschr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, unsafe { + data.as_ptr().add(data.len() - 1) as *mut wchar_t + }); + } + + #[test] + fn test_wcschr_find_mid() { + let data = widecstr!("abcdefghij"); + let c = 'e' as c_int; + let ret = unsafe { wcschr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(4) as *mut wchar_t }); + } + + #[test] + fn test_wcschr_find_repeated() { + let data = widecstr!("ababababab"); + let c = 'b' as c_int; + let ret = unsafe { wcschr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(1) as *mut wchar_t }); + } + + #[test] + fn test_wcschr_not_found() { + let data = widecstr!("abcdefghij"); + let c = 'k' as c_int; + let ret = unsafe { wcschr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, null_mut()); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_wcsncmp.rs b/libafl_qemu/librasan/asan/tests/hooks_wcsncmp.rs new file mode 100644 index 0000000000..c6684266cb --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_wcsncmp.rs @@ -0,0 +1,183 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::ptr::null; + + use asan::{expect_panic, hooks::wcsncmp::wcsncmp, wchar_t}; + use widestring::widecstr; + + #[test] + fn test_wcsncmp_zero_length() { + expect_panic(); + let ret = unsafe { wcsncmp(null(), null(), 0) }; + assert_eq!(ret, 0); + } + + #[test] + fn test_wcsncmp_null_s1() { + expect_panic(); + let data = [0u32; 10]; + unsafe { wcsncmp(null(), data.as_ptr() as *const wchar_t, data.len()) }; + unreachable!(); + } + + #[test] + fn test_wcsncmp_null_s2() { + expect_panic(); + let data = [0u32; 10]; + unsafe { wcsncmp(data.as_ptr() as *const wchar_t, null(), data.len()) }; + unreachable!(); + } + + #[test] + fn test_wcsncmp_eq() { + let data = [1u32; 10]; + let ret = unsafe { + wcsncmp( + data.as_ptr() as *const wchar_t, + data.as_ptr() as *const wchar_t, + data.len(), + ) + }; + assert_eq!(ret, 0); + } + + #[test] + fn test_wcsncmp_zero_length_both() { + let data = [0u32; 10]; + let ret = unsafe { + wcsncmp( + data.as_ptr() as *const wchar_t, + data.as_ptr() as *const wchar_t, + data.len(), + ) + }; + assert_eq!(ret, 0); + } + + #[test] + fn test_wcsncmp_zero_length_s1() { + let data1 = [0u32; 10]; + let data2 = [1u32; 10]; + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert!(ret < 0); + } + + #[test] + fn test_wcsncmp_zero_length_s2() { + let data1 = [1u32; 10]; + let data2 = [0u32; 10]; + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert!(ret > 0); + } + + #[test] + fn test_wcsncmp_eq_string() { + let data1 = widecstr!("abcdefghij"); + let data2 = widecstr!("abcdefghij"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert_eq!(ret, 0); + } + + #[test] + fn test_wcsncmp_s1_shorter() { + let data1 = widecstr!("abcdefghi"); + let data2 = widecstr!("abcdefghij"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data2.len(), + ) + }; + assert!(ret < 0); + } + + #[test] + fn test_wcsncmp_s1_longer() { + let data1 = widecstr!("abcdefghij"); + let data2 = widecstr!("abcdefghi"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert!(ret > 0); + } + + #[test] + fn test_wcsncmp_s1_less_than() { + let data1 = widecstr!("abcdefghii"); + let data2 = widecstr!("abcdefghij"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert!(ret < 0); + } + + #[test] + fn test_wcsncmp_s1_greater_than() { + let data1 = widecstr!("abcdefghik"); + let data2 = widecstr!("abcdefghij"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert!(ret > 0); + } + + #[test] + fn test_wcsncmp_case_not_ignored() { + let data1 = widecstr!("abcdefghijklmnopqrstuvwxyz"); + let data2 = widecstr!("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len(), + ) + }; + assert!(ret > 0); + } + + #[test] + fn test_wcsncmp_differ_after_length() { + let data1 = widecstr!("abcdefghijXYZ"); + let data2 = widecstr!("abcdefghijUVW"); + let ret = unsafe { + wcsncmp( + data1.as_ptr() as *const wchar_t, + data2.as_ptr() as *const wchar_t, + data1.len() - 3, + ) + }; + assert_eq!(ret, 0); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_wcsnlen.rs b/libafl_qemu/librasan/asan/tests/hooks_wcsnlen.rs new file mode 100644 index 0000000000..b9c28b1b95 --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_wcsnlen.rs @@ -0,0 +1,42 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::ptr::null; + + use asan::{expect_panic, hooks::wcsnlen::wcsnlen, wchar_t}; + use widestring::widecstr; + + #[test] + fn test_wcsnlen_zero_length() { + let ret = unsafe { wcsnlen(null() as *const wchar_t, 0) }; + assert_eq!(ret, 0); + } + + #[test] + fn test_wcsnlen_cs_null() { + expect_panic(); + unsafe { wcsnlen(null() as *const wchar_t, 10) }; + unreachable!(); + } + + #[test] + fn test_wcsnlen_cs_empty() { + let data = widecstr!(""); + let ret = unsafe { wcsnlen(data.as_ptr() as *const wchar_t, 10) }; + assert_eq!(ret, 0); + } + + #[test] + fn test_wcsnlen_full() { + let data = widecstr!("abcdefghij"); + let ret = unsafe { wcsnlen(data.as_ptr() as *const wchar_t, data.len()) }; + assert_eq!(ret, 10); + } + + #[test] + fn test_wcsnlen_partial() { + let data = widecstr!("abcdefghij"); + let ret = unsafe { wcsnlen(data.as_ptr() as *const wchar_t, 5) }; + assert_eq!(ret, 5); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_wcsrchr.rs b/libafl_qemu/librasan/asan/tests/hooks_wcsrchr.rs new file mode 100644 index 0000000000..98f9506c41 --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_wcsrchr.rs @@ -0,0 +1,69 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::{ + ffi::c_int, + ptr::{null, null_mut}, + }; + + use asan::{expect_panic, hooks::wcsrchr::wcsrchr, wchar_t}; + use widestring::widecstr; + + #[test] + fn test_wcsrchr_zero_length() { + let data = widecstr!(""); + let ret = unsafe { wcsrchr(data.as_ptr() as *const wchar_t, 0x88) }; + assert_eq!(ret, null_mut()); + } + + #[test] + fn test_wcsrchr_null_buffer() { + expect_panic(); + unsafe { wcsrchr(null(), 0x88) }; + unreachable!() + } + + #[test] + fn test_wcsrchr_find_first() { + let data = widecstr!("abcdefghij"); + let c = 'a' as c_int; + let ret = unsafe { wcsrchr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, data.as_ptr() as *mut wchar_t); + } + + #[test] + fn test_wcsrchr_find_last() { + let data = widecstr!("abcdefghij"); + let c = 'j' as c_int; + let ret = unsafe { wcsrchr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, unsafe { + data.as_ptr().add(data.len() - 1) as *mut wchar_t + }); + } + + #[test] + fn test_wcsrchr_find_mid() { + let data = widecstr!("abcdefghij"); + let c = 'e' as c_int; + let ret = unsafe { wcsrchr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, unsafe { data.as_ptr().add(4) as *mut wchar_t }); + } + + #[test] + fn test_wcsrchr_find_repeated() { + let data = widecstr!("ababababab"); + let c = 'b' as c_int; + let ret = unsafe { wcsrchr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, unsafe { + data.as_ptr().add(data.len() - 1) as *mut wchar_t + }); + } + + #[test] + fn test_wcsrchr_not_found() { + let data = widecstr!("abcdefghij"); + let c = 'k' as c_int; + let ret = unsafe { wcsrchr(data.as_ptr() as *const wchar_t, c) }; + assert_eq!(ret, null_mut()); + } +} diff --git a/libafl_qemu/librasan/asan/tests/hooks_wmemchr.rs b/libafl_qemu/librasan/asan/tests/hooks_wmemchr.rs new file mode 100644 index 0000000000..71edf82a48 --- /dev/null +++ b/libafl_qemu/librasan/asan/tests/hooks_wmemchr.rs @@ -0,0 +1,63 @@ +#[cfg(test)] +#[cfg(feature = "hooks")] +mod tests { + use core::ptr::null_mut; + + use asan::{expect_panic, hooks::wmemchr::wmemchr, wchar_t}; + use widestring::widecstr; + + #[test] + fn test_wmemchr_zero_length() { + let ret = unsafe { wmemchr(null_mut(), 0, 0) }; + assert_eq!(ret, null_mut()); + } + + #[test] + fn test_wmemchr_null_buffer() { + expect_panic(); + unsafe { wmemchr(null_mut(), 0, 10) }; + unreachable!() + } + + #[test] + fn test_wmemchr_find_first() { + let data = widecstr!("abcdefghij"); + let c = 'a' as wchar_t; + let ret = unsafe { wmemchr(data.as_ptr() as *const wchar_t, c, data.len()) }; + assert_eq!(ret, data.as_ptr() as *mut wchar_t); + } + + #[test] + fn test_wmemchr_find_last() { + let data = widecstr!("abcdefghij"); + let c = 'j' as wchar_t; + let ret = unsafe { wmemchr(data.as_ptr() as *const wchar_t, c, data.len()) }; + assert_eq!(ret, unsafe { + data.as_ptr().add(data.len() - 1) as *mut wchar_t + }); + } + + #[test] + fn test_wmemchr_find_mid() { + let data = widecstr!("abcdefghij"); + let c = 'e' as wchar_t; + let ret = unsafe { wmemchr(data.as_ptr() as *const wchar_t, c, data.len()) }; + assert_eq!(ret, unsafe { data.as_ptr().add(4) as *mut wchar_t }); + } + + #[test] + fn test_wmemchr_find_repeated() { + let data = widecstr!("ababababab"); + let c = 'b' as wchar_t; + let ret = unsafe { wmemchr(data.as_ptr() as *const wchar_t, c, data.len()) }; + assert_eq!(ret, unsafe { data.as_ptr().add(1) as *mut wchar_t }); + } + + #[test] + fn test_wmemchr_not_found() { + let data = widecstr!("abcdefghij"); + let c = 'k' as wchar_t; + let ret = unsafe { wmemchr(data.as_ptr() as *const wchar_t, c, data.len()) }; + assert_eq!(ret, null_mut()); + } +} diff --git a/libafl_qemu/librasan/fuzz/fuzz_targets/guest_tracking.rs b/libafl_qemu/librasan/fuzz/fuzz_targets/guest_tracking.rs index bb84ce5bfb..807599e2cf 100644 --- a/libafl_qemu/librasan/fuzz/fuzz_targets/guest_tracking.rs +++ b/libafl_qemu/librasan/fuzz/fuzz_targets/guest_tracking.rs @@ -47,7 +47,7 @@ fuzz_target!(|data: Vec| { start.saturating_sub(test_offset) }; - let result = tracking.alloc(start, len); + let result = tracking.track(start, len); if GuestTracking::is_out_of_bounds(start, len) { assert_eq!( result, @@ -61,7 +61,7 @@ fuzz_target!(|data: Vec| { assert_eq!(result, Ok(())); } - let test_result = tracking.alloc(test_start, test_len); + let test_result = tracking.track(test_start, test_len); if GuestTracking::is_out_of_bounds(test_start, test_len) { assert_eq!( test_result, @@ -92,8 +92,8 @@ fuzz_target!(|data: Vec| { ); } else { assert_eq!(test_result, Ok(())); - assert_eq!(tracking.dealloc(test_start), Ok(())); + assert_eq!(tracking.untrack(test_start), Ok(())); } } - assert_eq!(tracking.dealloc(start), Ok(())); + assert_eq!(tracking.untrack(start), Ok(())); }); diff --git a/libafl_qemu/librasan/gasan/src/lib.rs b/libafl_qemu/librasan/gasan/src/lib.rs index 4cfee87e06..f4d4641cad 100644 --- a/libafl_qemu/librasan/gasan/src/lib.rs +++ b/libafl_qemu/librasan/gasan/src/lib.rs @@ -9,10 +9,11 @@ use asan::{ backend::{dlmalloc::DlmallocBackend, mimalloc::MimallocBackend}, frontend::{AllocatorFrontend, default::DefaultFrontend}, }, + hooks::PatchedHooks, logger::libc::LibcLogger, - maps::libc::LibcMapReader, + maps::{MapReader, libc::LibcMapReader}, mmap::libc::LibcMmap, - patch::{hooks::PatchedHooks, raw::RawPatch}, + patch::{Patches, raw::RawPatch}, shadow::{ Shadow, guest::{DefaultShadowLayout, GuestShadow}, @@ -53,7 +54,12 @@ static FRONTEND: Lazy> = Lazy::new(|| { GasanFrontend::DEFAULT_QUARANTINE_SIZE, ) .unwrap(); - PatchedHooks::init::, GasanMmap>().unwrap(); + let mappings = LibcMapReader::::mappings().unwrap(); + Patches::init(mappings); + for hook in PatchedHooks::default() { + let target = hook.lookup::().unwrap(); + Patches::apply::(target, hook.destination).unwrap(); + } Mutex::new(frontend) }); @@ -113,8 +119,8 @@ pub unsafe extern "C" fn asan_get_size(addr: *const c_void) -> usize { #[unsafe(no_mangle)] /// # Safety -pub unsafe extern "C" fn asan_sym(name: *const c_char) -> GuestAddr { - GasanSyms::lookup(name).unwrap() +pub unsafe extern "C" fn asan_sym(name: *const c_char) -> *const c_void { + GasanSyms::lookup(name).unwrap() as *const c_void } #[unsafe(no_mangle)] @@ -141,7 +147,7 @@ pub unsafe extern "C" fn asan_track(addr: *const c_void, len: usize) { FRONTEND .lock() .tracking_mut() - .alloc(addr as GuestAddr, len) + .track(addr as GuestAddr, len) .unwrap(); } @@ -152,7 +158,7 @@ pub unsafe extern "C" fn asan_untrack(addr: *const c_void) { FRONTEND .lock() .tracking_mut() - .dealloc(addr as GuestAddr) + .untrack(addr as GuestAddr) .unwrap(); } diff --git a/libafl_qemu/librasan/qasan/src/lib.rs b/libafl_qemu/librasan/qasan/src/lib.rs index 6050eadd8f..58906ac744 100644 --- a/libafl_qemu/librasan/qasan/src/lib.rs +++ b/libafl_qemu/librasan/qasan/src/lib.rs @@ -9,11 +9,12 @@ use asan::{ backend::{dlmalloc::DlmallocBackend, mimalloc::MimallocBackend}, frontend::{AllocatorFrontend, default::DefaultFrontend}, }, + hooks::PatchedHooks, host::{Host, libc::LibcHost}, logger::libc::LibcLogger, - maps::libc::LibcMapReader, + maps::{MapReader, libc::LibcMapReader}, mmap::libc::LibcMmap, - patch::{hooks::PatchedHooks, raw::RawPatch}, + patch::{Patches, raw::RawPatch}, shadow::{Shadow, host::HostShadow}, symbols::{ Symbols, @@ -52,7 +53,12 @@ static FRONTEND: Lazy> = Lazy::new(|| { QasanFrontend::DEFAULT_QUARANTINE_SIZE, ) .unwrap(); - PatchedHooks::init::, QasanMmap>().unwrap(); + let mappings = LibcMapReader::::mappings().unwrap(); + Patches::init(mappings); + for hook in PatchedHooks::default() { + let target = hook.lookup::().unwrap(); + Patches::apply::(target, hook.destination).unwrap(); + } Mutex::new(frontend) }); @@ -112,8 +118,8 @@ pub unsafe extern "C" fn asan_get_size(addr: *const c_void) -> usize { #[unsafe(no_mangle)] /// # Safety -pub unsafe extern "C" fn asan_sym(name: *const c_char) -> GuestAddr { - QasanSyms::lookup(name).unwrap() +pub unsafe extern "C" fn asan_sym(name: *const c_char) -> *const c_void { + QasanSyms::lookup(name).unwrap() as *const c_void } #[unsafe(no_mangle)] @@ -140,7 +146,7 @@ pub unsafe extern "C" fn asan_track(addr: *const c_void, len: usize) { FRONTEND .lock() .tracking_mut() - .alloc(addr as GuestAddr, len) + .track(addr as GuestAddr, len) .unwrap(); } @@ -151,7 +157,7 @@ pub unsafe extern "C" fn asan_untrack(addr: *const c_void) { FRONTEND .lock() .tracking_mut() - .dealloc(addr as GuestAddr) + .untrack(addr as GuestAddr) .unwrap(); } diff --git a/libafl_qemu/librasan/zasan/src/lib.rs b/libafl_qemu/librasan/zasan/src/lib.rs index 41006c2879..355e18cc46 100644 --- a/libafl_qemu/librasan/zasan/src/lib.rs +++ b/libafl_qemu/librasan/zasan/src/lib.rs @@ -103,8 +103,8 @@ pub unsafe extern "C" fn asan_get_size(addr: *const c_void) -> usize { #[unsafe(no_mangle)] /// # Safety -pub unsafe extern "C" fn asan_sym(name: *const c_char) -> GuestAddr { - ZasanSyms::lookup(name).unwrap() +pub unsafe extern "C" fn asan_sym(name: *const c_char) -> *const c_void { + ZasanSyms::lookup(name).unwrap() as *const c_void } #[unsafe(no_mangle)] @@ -131,7 +131,7 @@ pub unsafe extern "C" fn asan_track(addr: *const c_void, len: usize) { FRONTEND .lock() .tracking_mut() - .alloc(addr as GuestAddr, len) + .track(addr as GuestAddr, len) .unwrap(); } @@ -142,7 +142,7 @@ pub unsafe extern "C" fn asan_untrack(addr: *const c_void) { FRONTEND .lock() .tracking_mut() - .dealloc(addr as GuestAddr) + .untrack(addr as GuestAddr) .unwrap(); }