Add better register clobbering to syscall calling in libxunil, add header magic to verify each free/malloc/realloc/calloc statement, add our own memcpy, memcmp, memset, memmove

This commit is contained in:
csd4ni3l
2026-04-07 22:11:18 +02:00
parent 9e8090c736
commit eee088c48f
4 changed files with 130 additions and 41 deletions

View File

@@ -539,7 +539,7 @@ unsafe extern "C" fn strdup(s: *const u8) -> *mut u8 {
if memory.is_null() {
return null_mut();
}
memcpy(memory, s, len + 1);
unsafe { memcpy(memory, s, len + 1) };
memory
}

View File

@@ -1,4 +1,4 @@
use core::{mem, ptr::null_mut, usize};
use core::{ffi::c_int, mem, ptr::null_mut, usize};
use crate::{
heap::{ALLOCATOR, LinkedNode},
@@ -12,10 +12,15 @@ pub fn sbrk(increment: i64) -> isize {
const MAX_SIZE: u64 = 18446744073709551615;
const HEADER_MAGIC_ALLOC: u64 = 0xBADC0FFEE0DDF00D;
const HEADER_MAGIC_FREE: u64 = 0xFEE1DEADCAFEBABE;
#[repr(C, align(16))]
struct Header {
size: usize,
_pad: usize,
magic: u64,
_pad: u64,
alloc_size: usize,
region_size: usize,
}
#[unsafe(no_mangle)]
@@ -34,7 +39,7 @@ pub extern "C" fn calloc(count: u64, size: u64) -> *mut u8 {
return null_mut();
}
memset(ptr, 0, total as usize);
unsafe { memset(ptr, 0, total as usize) };
ptr
}
@@ -46,9 +51,18 @@ pub extern "C" fn free(ptr: *mut u8) {
unsafe {
let header_ptr = (ptr as usize - mem::size_of::<Header>()) as *mut Header;
let total = (*header_ptr).size;
if (header_ptr as usize) & 0xF != 0 {
core::hint::unreachable_unchecked();
}
if (*header_ptr).magic != HEADER_MAGIC_ALLOC {
return;
}
let region_size = (*header_ptr).region_size;
(*header_ptr).magic = HEADER_MAGIC_FREE;
let mut allocator = ALLOCATOR.lock();
allocator.add_free_memory_region(header_ptr as usize, total);
allocator.add_free_memory_region(header_ptr as usize, region_size);
}
}
@@ -71,8 +85,10 @@ pub extern "C" fn malloc(size: u64) -> *mut u8 {
unsafe {
let header_ptr = region.start as *mut Header;
header_ptr.write(Header {
size: region.end - region.start,
magic: HEADER_MAGIC_ALLOC,
_pad: 0,
alloc_size: (region.end - region.start).saturating_sub(hdr),
region_size: region.end - region.start,
});
return (region.start + hdr) as *mut u8;
}
@@ -111,30 +127,6 @@ pub extern "C" fn malloc(size: u64) -> *mut u8 {
malloc(size)
}
#[unsafe(no_mangle)]
pub extern "C" fn memcpy(dest_str: *mut u8, src_str: *const u8, n: usize) -> *mut u8 {
unsafe { core::ptr::copy(src_str, dest_str, n) };
dest_str
}
#[unsafe(no_mangle)]
pub extern "C" fn memset(dst: *mut u8, c: i64, n: usize) -> *mut u8 {
if dst.is_null() || n == 0 {
return dst;
}
unsafe {
let val = c as u8;
let mut i = 0usize;
while i < n {
*dst.add(i) = val;
i += 1;
}
}
dst
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
if size == 0 {
@@ -149,10 +141,14 @@ pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
unsafe {
let hdr = mem::size_of::<Header>();
let header_ptr = (ptr as usize - hdr) as *mut Header;
let total = (*header_ptr).size;
let old_payload = total.saturating_sub(hdr);
if size <= old_payload {
if (*header_ptr).magic != HEADER_MAGIC_ALLOC {
return null_mut();
}
let old_alloc_size = (*header_ptr).alloc_size;
if size <= old_alloc_size {
return ptr;
}
@@ -161,8 +157,102 @@ pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
return null_mut();
}
core::ptr::copy_nonoverlapping(ptr, new_ptr, old_payload);
core::ptr::copy_nonoverlapping(ptr, new_ptr, old_alloc_size);
free(ptr);
new_ptr
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, n: usize) -> *mut u8 {
if n == 0 {
return dest;
}
if dest.is_null() {
return null_mut();
}
let byte = c as u8;
let mut i = 0usize;
while i < n {
unsafe { core::ptr::write_volatile(dest.add(i), byte) };
i += 1;
}
dest
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
if n == 0 {
return dest;
}
if dest.is_null() || src.is_null() {
return null_mut();
}
let mut i = 0usize;
while i < n {
let v = unsafe { core::ptr::read_volatile(src.add(i)) };
unsafe { core::ptr::write_volatile(dest.add(i), v) };
i += 1;
}
dest
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
if n == 0 {
return dest;
}
if dest.is_null() || src.is_null() {
return null_mut();
}
let dest_addr = dest as usize;
let src_addr = src as usize;
if dest_addr == src_addr {
return dest;
}
if dest_addr < src_addr || dest_addr >= src_addr.saturating_add(n) {
let mut i = 0usize;
while i < n {
let v = unsafe { core::ptr::read_volatile(src.add(i)) };
unsafe { core::ptr::write_volatile(dest.add(i), v) };
i += 1;
}
} else {
let mut i = n;
while i != 0 {
i -= 1;
let v = unsafe { core::ptr::read_volatile(src.add(i)) };
unsafe { core::ptr::write_volatile(dest.add(i), v) };
}
}
dest
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memcmp(a: *const u8, b: *const u8, n: usize) -> i32 {
if n == 0 {
return 0;
}
if a.is_null() || b.is_null() {
return 0;
}
let mut i = 0usize;
while i < n {
let av = unsafe { core::ptr::read_volatile(a.add(i)) };
let bv = unsafe { core::ptr::read_volatile(b.add(i)) };
if av != bv {
return av as i32 - bv as i32;
}
i += 1;
}
0
}

View File

@@ -32,8 +32,7 @@ pub unsafe fn syscall0(num: usize) -> isize {
"int 0x80",
in("rax") num,
lateout("rax") ret,
out("rdi") _, out("rcx") _, out("rdx") _, out("rsi") _,
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
clobber_abi("sysv64"),
options(nostack)
);
}
@@ -50,8 +49,7 @@ pub unsafe fn syscall1(num: usize, arg0: isize) -> isize {
in("rax") num,
in("rdi") arg0,
lateout("rax") ret,
out("rcx") _, out("rdx") _, out("rsi") _,
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
clobber_abi("sysv64"),
options(nostack)
);
}
@@ -70,6 +68,7 @@ pub unsafe fn syscall3(num: usize, arg0: isize, arg1: isize, arg2: isize) -> isi
in("rsi") arg1,
in("rdx") arg2,
lateout("rax") ret,
clobber_abi("sysv64"),
options(nostack)
);
}