Various updates to librasan
(#3106)
* Add rawmemchr * Add stpncpy * Add strchrnul * Fix strcat * Added strncat * Add wcschr * Minor tweak * Add wcsncmp * Add wcsnlen * Add wcsrchr * Add wmemchr * Fix asan load/store sizes for wide string functions * Refactor patches * Rename tracking functions to prevent collision with allocator * Change return type of asan_sym to make it consistent with the other native functions * Fix mutex re-entrancy issue in Patches by splitting locks * Fix tests on 32-bit platforms --------- Co-authored-by: Your Name <you@example.com>
This commit is contained in:
parent
58607dc333
commit
869edd068d
@ -94,7 +94,7 @@ impl<B: GlobalAlloc + Send, S: Shadow, T: Tracking> 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<B: GlobalAlloc + Send, S: Shadow, T: Tracking> 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);
|
||||
|
@ -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) };
|
||||
}
|
||||
|
@ -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::<FILE>());
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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<Self> {
|
||||
[
|
||||
pub fn lookup<S: Symbols>(&self) -> Result<GuestAddr, S::Error> {
|
||||
S::lookup(self.name.as_ptr() as *const c_char)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PatchedHooks {
|
||||
hooks: Vec<PatchedHook>,
|
||||
}
|
||||
|
||||
impl IntoIterator for PatchedHooks {
|
||||
type Item = PatchedHook;
|
||||
type IntoIter = IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.hooks.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PatchedHooks {
|
||||
fn default() -> Self {
|
||||
Self { hooks: [
|
||||
PatchedHook::new::<unsafe extern "C" fn(size_t, size_t) -> *mut c_void>(
|
||||
c"aligned_alloc",
|
||||
hooks::aligned_alloc::aligned_alloc,
|
||||
@ -124,10 +152,17 @@ impl PatchedHook {
|
||||
c"memrchr",
|
||||
hooks::memrchr::memrchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_void, c_int) -> *mut c_void>(
|
||||
c"rawmemchr",
|
||||
hooks::rawmemchr::rawmemchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut c_char, *const c_char) -> *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::<unsafe extern "C" fn(*const c_char, *const c_char) -> c_int>(
|
||||
c"strcasecmp",
|
||||
hooks::strcasecmp::strcasecmp,
|
||||
@ -144,6 +179,10 @@ impl PatchedHook {
|
||||
c"strchr",
|
||||
hooks::strchr::strchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, c_int) -> *mut c_char>(
|
||||
c"strchrnul",
|
||||
hooks::strchrnul::strchrnul,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char) -> 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::<unsafe extern "C" fn(*const c_char, *const c_char, size_t) -> 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::<unsafe extern "C" fn(*const wchar_t, c_int) -> *mut wchar_t>(
|
||||
c"wcschr",
|
||||
hooks::wcschr::wcschr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const wchar_t, *const wchar_t) -> c_int>(
|
||||
c"wcscmp",
|
||||
hooks::wcscmp::wcscmp,
|
||||
@ -202,7 +248,24 @@ impl PatchedHook {
|
||||
c"wcslen",
|
||||
hooks::wcslen::wcslen,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn (*const wchar_t, *const wchar_t, size_t) -> c_int>(
|
||||
c"wcsncmp",
|
||||
hooks::wcsncmp::wcsncmp,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn ( *const wchar_t, size_t) -> size_t>(
|
||||
c"wcsnlen",
|
||||
hooks::wcsnlen::wcsnlen,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn ( *const wchar_t, c_int) -> *mut wchar_t >(
|
||||
c"wcsrchr",
|
||||
hooks::wcsrchr::wcsrchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn ( *const wchar_t, wchar_t, size_t) -> *mut wchar_t>(
|
||||
c"wmemchr",
|
||||
hooks::wmemchr::wmemchr,
|
||||
),
|
||||
|
||||
]
|
||||
.to_vec()
|
||||
.to_vec() }
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
26
libafl_qemu/librasan/asan/src/hooks/rawmemchr.rs
Normal file
26
libafl_qemu/librasan/asan/src/hooks/rawmemchr.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
49
libafl_qemu/librasan/asan/src/hooks/stpncpy.rs
Normal file
49
libafl_qemu/librasan/asan/src/hooks/stpncpy.rs
Normal file
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
33
libafl_qemu/librasan/asan/src/hooks/strchrnul.rs
Normal file
33
libafl_qemu/librasan/asan/src/hooks/strchrnul.rs
Normal file
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
46
libafl_qemu/librasan/asan/src/hooks/strncat.rs
Normal file
46
libafl_qemu/librasan/asan/src/hooks/strncat.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/wcschr.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/wcschr.rs
Normal file
@ -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::<wchar_t>());
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
62
libafl_qemu/librasan/asan/src/hooks/wcsncmp.rs
Normal file
62
libafl_qemu/librasan/asan/src/hooks/wcsncmp.rs
Normal file
@ -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::<wchar_t>());
|
||||
asan_load(ct as *const c_void, (ct_len + 1) * size_of::<wchar_t>());
|
||||
|
||||
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
|
||||
}
|
||||
}
|
35
libafl_qemu/librasan/asan/src/hooks/wcsnlen.rs
Normal file
35
libafl_qemu/librasan/asan/src/hooks/wcsnlen.rs
Normal file
@ -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::<wchar_t>());
|
||||
len
|
||||
} else {
|
||||
asan_load(cs as *const c_void, maxlen * size_of::<wchar_t>());
|
||||
maxlen
|
||||
}
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/wcsrchr.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/wcsrchr.rs
Normal file
@ -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::<wchar_t>());
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/wmemchr.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/wmemchr.rs
Normal file
@ -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::<wchar_t>());
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -111,7 +111,7 @@ impl<S: Symbols> Host for LibcHost<S> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn alloc(start: GuestAddr, len: usize) -> Result<(), LibcHostError<S>> {
|
||||
fn track(start: GuestAddr, len: usize) -> Result<(), LibcHostError<S>> {
|
||||
unsafe {
|
||||
let syscall = Self::get_syscall()?;
|
||||
let ret = syscall(Self::SYSCALL_NO, HostAction::Alloc as usize, start, len);
|
||||
@ -122,7 +122,7 @@ impl<S: Symbols> Host for LibcHost<S> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dealloc(start: GuestAddr) -> Result<(), LibcHostError<S>> {
|
||||
fn untrack(start: GuestAddr) -> Result<(), LibcHostError<S>> {
|
||||
let syscall = Self::get_syscall()?;
|
||||
let ret = unsafe { syscall(Self::SYSCALL_NO, HostAction::Dealloc as usize, start) };
|
||||
if ret != 0 {
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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<bool, Self::Error>;
|
||||
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>;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<Self, Self::Error>;
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
|
||||
fn mappings() -> Result<Maps, Self::Error> {
|
||||
let reader = Self::new()?;
|
||||
let maps = MapIterator::new(reader).collect::<Vec<MapEntry>>();
|
||||
Ok(Maps { maps })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Maps {
|
||||
maps: Vec<MapEntry>,
|
||||
}
|
||||
|
||||
impl Maps {
|
||||
pub fn writeable<M: Mmap>(
|
||||
&self,
|
||||
addr: GuestAddr,
|
||||
) -> Result<WriteableMapProtection<M>, MapsError<M>> {
|
||||
let mapping = self
|
||||
.maps
|
||||
.iter()
|
||||
.filter(|m| m.contains(addr))
|
||||
.exactly_one()
|
||||
.map_err(|_e| MapsError::MappingNotFound(addr))?;
|
||||
mapping
|
||||
.writeable::<M>()
|
||||
.map_err(|e| MapsError::MmapError(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Maps {
|
||||
type Item = MapEntry;
|
||||
type IntoIter = IntoIter<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.maps.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MapsError<M: Mmap> {
|
||||
#[error("Mapping not found: {0}")]
|
||||
MappingNotFound(GuestAddr),
|
||||
#[error("Mmap error: {0:?}")]
|
||||
MmapError(M::Error),
|
||||
}
|
||||
|
@ -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<Option<BTreeMap<GuestAddr, PatchedHook>>> = Mutex::new(None);
|
||||
|
||||
pub struct PatchedHooks;
|
||||
|
||||
impl PatchedHooks {
|
||||
pub fn init<S: Symbols, P: Patch, R: MapReader, M: Mmap>()
|
||||
-> Result<(), PatchesError<S, P, R, M>> {
|
||||
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<S: Symbols, P: Patch, R: MapReader, M: Mmap>()
|
||||
-> Result<Vec<MapEntry>, PatchesError<S, P, R, M>> {
|
||||
let reader = R::new().map_err(|e| PatchesError::MapReaderError(e))?;
|
||||
Ok(MapIterator::new(reader).collect::<Vec<MapEntry>>())
|
||||
}
|
||||
|
||||
pub fn patch<S: Symbols, P: Patch, R: MapReader, M: Mmap>(
|
||||
patch: PatchedHook,
|
||||
mappings: &[MapEntry],
|
||||
) -> Result<(), PatchesError<S, P, R, M>> {
|
||||
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::<M>()
|
||||
.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<S: Symbols, P: Patch, R: MapReader, M: Mmap> {
|
||||
#[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),
|
||||
}
|
@ -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<Mutex<Patches>> = Once::new();
|
||||
static PATCHED: Mutex<BTreeMap<GuestAddr, GuestAddr>> = 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<P: Patch, M: Mmap>(
|
||||
target: GuestAddr,
|
||||
destination: GuestAddr,
|
||||
) -> Result<(), PatchesError<P, M>> {
|
||||
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<P: Patch, M: Mmap> {
|
||||
#[error("Uninitialized")]
|
||||
Uninitialized(),
|
||||
#[error("Patch error: {0:?}")]
|
||||
PatchError(P::Error),
|
||||
#[error("Maps error: {0:?}")]
|
||||
MapsError(MapsError<M>),
|
||||
}
|
||||
|
@ -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<T: Function> 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<T: Function> FunctionPointer for T {
|
||||
pub enum FunctionPointerError {
|
||||
#[error("Bad address: {0}")]
|
||||
BadAddress(GuestAddr),
|
||||
#[cfg(feature = "hooks")]
|
||||
#[error("Patched address: {0}")]
|
||||
PatchedAddress(PatchesCheckError),
|
||||
PatchedAddress(GuestAddr),
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -19,15 +19,15 @@ pub struct HostTracking<H> {
|
||||
impl<H: Host> Tracking for HostTracking<H> {
|
||||
type Error = HostTrackingError<H>;
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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,
|
||||
|
51
libafl_qemu/librasan/asan/tests/hooks_rawmemchr.rs
Normal file
51
libafl_qemu/librasan/asan/tests/hooks_rawmemchr.rs
Normal file
@ -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 });
|
||||
}
|
||||
}
|
64
libafl_qemu/librasan/asan/tests/hooks_stpncpy.rs
Normal file
64
libafl_qemu/librasan/asan/tests/hooks_stpncpy.rs
Normal file
@ -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));
|
||||
}
|
||||
}
|
67
libafl_qemu/librasan/asan/tests/hooks_strchrnul.rs
Normal file
67
libafl_qemu/librasan/asan/tests/hooks_strchrnul.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
81
libafl_qemu/librasan/asan/tests/hooks_strncat.rs
Normal file
81
libafl_qemu/librasan/asan/tests/hooks_strncat.rs
Normal file
@ -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));
|
||||
}
|
||||
}
|
67
libafl_qemu/librasan/asan/tests/hooks_wcschr.rs
Normal file
67
libafl_qemu/librasan/asan/tests/hooks_wcschr.rs
Normal file
@ -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());
|
||||
}
|
||||
}
|
183
libafl_qemu/librasan/asan/tests/hooks_wcsncmp.rs
Normal file
183
libafl_qemu/librasan/asan/tests/hooks_wcsncmp.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
42
libafl_qemu/librasan/asan/tests/hooks_wcsnlen.rs
Normal file
42
libafl_qemu/librasan/asan/tests/hooks_wcsnlen.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
69
libafl_qemu/librasan/asan/tests/hooks_wcsrchr.rs
Normal file
69
libafl_qemu/librasan/asan/tests/hooks_wcsrchr.rs
Normal file
@ -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());
|
||||
}
|
||||
}
|
63
libafl_qemu/librasan/asan/tests/hooks_wmemchr.rs
Normal file
63
libafl_qemu/librasan/asan/tests/hooks_wmemchr.rs
Normal file
@ -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());
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ fuzz_target!(|data: Vec<GuestAddr>| {
|
||||
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<GuestAddr>| {
|
||||
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<GuestAddr>| {
|
||||
);
|
||||
} 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(()));
|
||||
});
|
||||
|
@ -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<Mutex<GasanFrontend>> = Lazy::new(|| {
|
||||
GasanFrontend::DEFAULT_QUARANTINE_SIZE,
|
||||
)
|
||||
.unwrap();
|
||||
PatchedHooks::init::<GasanSyms, RawPatch, LibcMapReader<GasanSyms>, GasanMmap>().unwrap();
|
||||
let mappings = LibcMapReader::<GasanSyms>::mappings().unwrap();
|
||||
Patches::init(mappings);
|
||||
for hook in PatchedHooks::default() {
|
||||
let target = hook.lookup::<GasanSyms>().unwrap();
|
||||
Patches::apply::<RawPatch, GasanMmap>(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();
|
||||
}
|
||||
|
||||
|
@ -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<Mutex<QasanFrontend>> = Lazy::new(|| {
|
||||
QasanFrontend::DEFAULT_QUARANTINE_SIZE,
|
||||
)
|
||||
.unwrap();
|
||||
PatchedHooks::init::<QasanSyms, RawPatch, LibcMapReader<QasanSyms>, QasanMmap>().unwrap();
|
||||
let mappings = LibcMapReader::<QasanSyms>::mappings().unwrap();
|
||||
Patches::init(mappings);
|
||||
for hook in PatchedHooks::default() {
|
||||
let target = hook.lookup::<QasanSyms>().unwrap();
|
||||
Patches::apply::<RawPatch, QasanMmap>(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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user