Move some C functions to Rust from sancov_cmp.c (#2003)

* some

* a

* clp

* aa

* just new line

* fix

* fxi

* fix
This commit is contained in:
Dongjia "toka" Zhang 2024-04-06 01:03:01 +02:00 committed by GitHub
parent 90c627a7e7
commit 17aae94efc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 182 additions and 133 deletions

View File

@ -15,7 +15,7 @@ void *__libafl_asan_region_is_poisoned(void *beg, size_t size) {
return NULL; return NULL;
} }
#pragma comment( \ #pragma comment( \
linker, \ linker, \
"/alternatename:__asan_region_is_poisoned=__libafl_asan_region_is_poisoned") "/alternatename:__asan_region_is_poisoned=__libafl_asan_region_is_poisoned")

View File

@ -6,7 +6,6 @@
#ifdef SANCOV_CMPLOG #ifdef SANCOV_CMPLOG
#include "cmplog.h" #include "cmplog.h"
#include <sanitizer/common_interface_defs.h>
#endif #endif
void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
@ -116,69 +115,6 @@ void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) {
__sanitizer_cov_trace_cmp8(arg1, arg2); __sanitizer_cov_trace_cmp8(arg1, arg2);
} }
#ifdef SANCOV_CMPLOG
void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
const void *s2, size_t n, int result) {
if (result != 0) {
uintptr_t k = (uintptr_t)called_pc;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_len(k, s1, s2, MIN(n, 32));
}
}
void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
const char *s2, size_t n, int result) {
if (result != 0) {
n = MIN(n, 32);
uintptr_t k = (uintptr_t)called_pc;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
size_t actual_len;
for (actual_len = 0; actual_len < n; actual_len++) {
if (s1[actual_len] == 0 || s2[actual_len] == 0) { break; }
}
__libafl_targets_cmplog_routines_len(k, (const uint8_t *)s1,
(const uint8_t *)s2, actual_len);
}
}
void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
const char *s2, size_t n, int result) {
__sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
}
void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
const char *s2, int result) {
if (result != 0) {
uintptr_t k = (uintptr_t)called_pc;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
size_t actual_len;
for (actual_len = 0; actual_len < 32; actual_len++) {
if (s1[actual_len] == 0 || s2[actual_len] == 0) { break; }
}
__libafl_targets_cmplog_routines_len(k, (const uint8_t *)s1,
(const uint8_t *)s2, actual_len);
}
}
void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
const char *s2, int result) {
__sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
}
// strstr, strcasestr, memmem unhandled
#endif
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"

View File

@ -1,9 +1,12 @@
//! Sanitizer Coverage comparison functions //! Sanitizer Coverage comparison functions
use core::{mem, ptr, slice}; use core::{
cmp,
ffi::{c_char, c_int, c_void},
ptr,
};
static mut PCS_BEG: *const usize = ptr::null(); use crate::CMPLOG_MAP_W;
static mut PCS_END: *const usize = ptr::null();
extern "C" { extern "C" {
@ -28,73 +31,110 @@ extern "C" {
/// Trace a switch statement /// Trace a switch statement
pub fn __sanitizer_cov_trace_switch(val: u64, cases: *const u64); pub fn __sanitizer_cov_trace_switch(val: u64, cases: *const u64);
/// cmplog internal api
pub fn __libafl_targets_cmplog_routines_len(k: usize, s1: *const u8, s2: *const u8, len: usize);
}
/// overriding `__sanitizer_weak_hook_memcmp`
/// # Safety
/// this function has raw pointer access
#[no_mangle]
pub unsafe extern "C" fn __sanitizer_weak_hook_memcmp(
called_pc: *const c_void,
s1: *const c_void,
s2: *const c_void,
n: usize,
result: c_int,
) {
if result != 0 {
let k: usize = called_pc as usize;
let k = (k >> 4) ^ (k << 8);
let k = k & (CMPLOG_MAP_W - 1);
__libafl_targets_cmplog_routines_len(k, s1 as *const u8, s2 as *const u8, cmp::min(n, 32));
}
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn __sanitizer_cov_pcs_init(pcs_beg: *const usize, pcs_end: *const usize) { /// overriding `__sanitizer_weak_hook_strncmp`
// "The Unsafe Code Guidelines also notably defines that usize and isize are respectively compatible with uintptr_t and intptr_t defined in C." /// # Safety
assert!( /// this function has raw pointer access
pcs_beg == PCS_BEG || PCS_BEG.is_null(), pub unsafe extern "C" fn __sanitizer_weak_hook_strncmp(
"__sanitizer_cov_pcs_init can be called only once." called_pc: *const c_void,
); s1: *const c_char,
assert!( s2: *const c_char,
pcs_end == PCS_END || PCS_END.is_null(), n: usize,
"__sanitizer_cov_pcs_init can be called only once." result: c_int,
); ) {
if result != 0 {
let n = cmp::min(n, 32);
let k: usize = called_pc as usize;
let k = (k >> 4) ^ (k << 8);
let k = k & (CMPLOG_MAP_W - 1);
let mut actual_len = 0;
while actual_len < n {
let c1 = ptr::read(s1.add(actual_len));
let c2 = ptr::read(s2.add(actual_len));
PCS_BEG = pcs_beg; if c1 == 0 || c2 == 0 {
PCS_END = pcs_end; break;
}
/// An entry to the `sanitizer_cov` `pc_table`
#[repr(C, packed)]
#[derive(Debug, PartialEq, Eq)]
pub struct PcTableEntry {
addr: usize,
flags: usize,
}
impl PcTableEntry {
/// Returns whether the PC corresponds to a function entry point.
#[must_use]
pub fn is_function_entry(&self) -> bool {
self.flags == 0x1
} }
actual_len += 1;
/// Returns the address associated with this PC. }
#[must_use] __libafl_targets_cmplog_routines_len(k, s1 as *const u8, s2 as *const u8, actual_len);
pub fn addr(&self) -> usize {
self.addr
} }
} }
/// Returns a slice containing the PC table. #[no_mangle]
#[must_use] /// overriding `__sanitizer_weak_hook_strncasecmps`
pub fn sanitizer_cov_pc_table() -> Option<&'static [PcTableEntry]> { /// # Safety
// SAFETY: Once PCS_BEG and PCS_END have been initialized, will not be written to again. So /// this function has raw pointer access
// there's no TOCTOU issue. pub unsafe extern "C" fn __sanitizer_weak_hook_strncasecmp(
unsafe { called_pc: *const c_void,
if PCS_BEG.is_null() || PCS_END.is_null() { s1: *const c_char,
return None; s2: *const c_char,
n: usize,
result: c_int,
) {
__sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
}
#[no_mangle]
/// overriding `__sanitizer_weak_hook_strcmp`
/// # Safety
/// this function has raw pointer access
pub unsafe extern "C" fn __sanitizer_weak_hook_strcmp(
called_pc: *const c_void,
s1: *const c_char,
s2: *const c_char,
result: c_int,
) {
if result != 0 {
let k: usize = called_pc as usize;
let k = (k >> 4) ^ (k << 8);
let k = k & (CMPLOG_MAP_W - 1);
let mut actual_len = 0;
while actual_len < 32 {
let c1 = ptr::read(s1.add(actual_len));
let c2 = ptr::read(s2.add(actual_len));
if c1 == 0 || c2 == 0 {
break;
} }
let len = PCS_END.offset_from(PCS_BEG); actual_len += 1;
assert!( }
len > 0, __libafl_targets_cmplog_routines_len(k, s1 as *const u8, s2 as *const u8, actual_len);
"Invalid PC Table bounds - start: {PCS_BEG:x?} end: {PCS_END:x?}"
);
assert_eq!(
len % 2,
0,
"PC Table size is not evens - start: {PCS_BEG:x?} end: {PCS_END:x?}"
);
assert_eq!(
(PCS_BEG as usize) % mem::align_of::<PcTableEntry>(),
0,
"Unaligned PC Table - start: {PCS_BEG:x?} end: {PCS_END:x?}"
);
Some(slice::from_raw_parts(
PCS_BEG as *const PcTableEntry,
(len / 2).try_into().unwrap(),
))
} }
} }
#[no_mangle]
/// overriding `__sanitizer_weak_hook_strcmp`
/// # Safety
/// this function has raw pointer access
pub unsafe extern "C" fn __sanitizer_weak_hook_strcasecmp(
called_pc: *const c_void,
s1: *const c_char,
s2: *const c_char,
result: c_int,
) {
__sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
}

View File

@ -3,6 +3,7 @@
#[rustversion::nightly] #[rustversion::nightly]
#[cfg(feature = "sancov_ngram4")] #[cfg(feature = "sancov_ngram4")]
use core::simd::num::SimdUint; use core::simd::num::SimdUint;
use core::{mem, ptr, slice};
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ctx"))] #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ctx"))]
use libafl::executors::{hooks::ExecutorHook, HasObservers}; use libafl::executors::{hooks::ExecutorHook, HasObservers};
@ -282,3 +283,75 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32
} }
} }
} }
static mut PCS_BEG: *const usize = ptr::null();
static mut PCS_END: *const usize = ptr::null();
#[no_mangle]
unsafe extern "C" fn __sanitizer_cov_pcs_init(pcs_beg: *const usize, pcs_end: *const usize) {
// "The Unsafe Code Guidelines also notably defines that usize and isize are respectively compatible with uintptr_t and intptr_t defined in C."
assert!(
pcs_beg == PCS_BEG || PCS_BEG.is_null(),
"__sanitizer_cov_pcs_init can be called only once."
);
assert!(
pcs_end == PCS_END || PCS_END.is_null(),
"__sanitizer_cov_pcs_init can be called only once."
);
PCS_BEG = pcs_beg;
PCS_END = pcs_end;
}
/// An entry to the `sanitizer_cov` `pc_table`
#[repr(C, packed)]
#[derive(Debug, PartialEq, Eq)]
pub struct PcTableEntry {
addr: usize,
flags: usize,
}
impl PcTableEntry {
/// Returns whether the PC corresponds to a function entry point.
#[must_use]
pub fn is_function_entry(&self) -> bool {
self.flags == 0x1
}
/// Returns the address associated with this PC.
#[must_use]
pub fn addr(&self) -> usize {
self.addr
}
}
/// Returns a slice containing the PC table.
#[must_use]
pub fn sanitizer_cov_pc_table() -> Option<&'static [PcTableEntry]> {
// SAFETY: Once PCS_BEG and PCS_END have been initialized, will not be written to again. So
// there's no TOCTOU issue.
unsafe {
if PCS_BEG.is_null() || PCS_END.is_null() {
return None;
}
let len = PCS_END.offset_from(PCS_BEG);
assert!(
len > 0,
"Invalid PC Table bounds - start: {PCS_BEG:x?} end: {PCS_END:x?}"
);
assert_eq!(
len % 2,
0,
"PC Table size is not evens - start: {PCS_BEG:x?} end: {PCS_END:x?}"
);
assert_eq!(
(PCS_BEG as usize) % mem::align_of::<PcTableEntry>(),
0,
"Unaligned PC Table - start: {PCS_BEG:x?} end: {PCS_END:x?}"
);
Some(slice::from_raw_parts(
PCS_BEG as *const PcTableEntry,
(len / 2).try_into().unwrap(),
))
}
}