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() { if memory.is_null() {
return null_mut(); return null_mut();
} }
memcpy(memory, s, len + 1); unsafe { memcpy(memory, s, len + 1) };
memory 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::{ use crate::{
heap::{ALLOCATOR, LinkedNode}, heap::{ALLOCATOR, LinkedNode},
@@ -12,10 +12,15 @@ pub fn sbrk(increment: i64) -> isize {
const MAX_SIZE: u64 = 18446744073709551615; const MAX_SIZE: u64 = 18446744073709551615;
const HEADER_MAGIC_ALLOC: u64 = 0xBADC0FFEE0DDF00D;
const HEADER_MAGIC_FREE: u64 = 0xFEE1DEADCAFEBABE;
#[repr(C, align(16))] #[repr(C, align(16))]
struct Header { struct Header {
size: usize, magic: u64,
_pad: usize, _pad: u64,
alloc_size: usize,
region_size: usize,
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@@ -34,7 +39,7 @@ pub extern "C" fn calloc(count: u64, size: u64) -> *mut u8 {
return null_mut(); return null_mut();
} }
memset(ptr, 0, total as usize); unsafe { memset(ptr, 0, total as usize) };
ptr ptr
} }
@@ -46,9 +51,18 @@ pub extern "C" fn free(ptr: *mut u8) {
unsafe { unsafe {
let header_ptr = (ptr as usize - mem::size_of::<Header>()) as *mut Header; 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(); 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 { unsafe {
let header_ptr = region.start as *mut Header; let header_ptr = region.start as *mut Header;
header_ptr.write(Header { header_ptr.write(Header {
size: region.end - region.start, magic: HEADER_MAGIC_ALLOC,
_pad: 0, _pad: 0,
alloc_size: (region.end - region.start).saturating_sub(hdr),
region_size: region.end - region.start,
}); });
return (region.start + hdr) as *mut u8; return (region.start + hdr) as *mut u8;
} }
@@ -111,30 +127,6 @@ pub extern "C" fn malloc(size: u64) -> *mut u8 {
malloc(size) 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)] #[unsafe(no_mangle)]
pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 { pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
if size == 0 { if size == 0 {
@@ -149,10 +141,14 @@ pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
unsafe { unsafe {
let hdr = mem::size_of::<Header>(); let hdr = mem::size_of::<Header>();
let header_ptr = (ptr as usize - hdr) as *mut 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; return ptr;
} }
@@ -161,8 +157,102 @@ pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
return null_mut(); return null_mut();
} }
core::ptr::copy_nonoverlapping(ptr, new_ptr, old_payload); core::ptr::copy_nonoverlapping(ptr, new_ptr, old_alloc_size);
free(ptr); free(ptr);
new_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", "int 0x80",
in("rax") num, in("rax") num,
lateout("rax") ret, lateout("rax") ret,
out("rdi") _, out("rcx") _, out("rdx") _, out("rsi") _, clobber_abi("sysv64"),
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
options(nostack) options(nostack)
); );
} }
@@ -50,8 +49,7 @@ pub unsafe fn syscall1(num: usize, arg0: isize) -> isize {
in("rax") num, in("rax") num,
in("rdi") arg0, in("rdi") arg0,
lateout("rax") ret, lateout("rax") ret,
out("rcx") _, out("rdx") _, out("rsi") _, clobber_abi("sysv64"),
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
options(nostack) options(nostack)
); );
} }
@@ -70,6 +68,7 @@ pub unsafe fn syscall3(num: usize, arg0: isize, arg1: isize, arg2: isize) -> isi
in("rsi") arg1, in("rsi") arg1,
in("rdx") arg2, in("rdx") arg2,
lateout("rax") ret, lateout("rax") ret,
clobber_abi("sysv64"),
options(nostack) options(nostack)
); );
} }