From eee088c48f98afaf19bc41c84b41c5f35431e645 Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Tue, 7 Apr 2026 22:11:18 +0200 Subject: [PATCH] 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 --- user/apps/doomgeneric | 2 +- user/libxunil/src/lib.rs | 2 +- user/libxunil/src/mem.rs | 160 +++++++++++++++++++++++++++-------- user/libxunil/src/syscall.rs | 7 +- 4 files changed, 130 insertions(+), 41 deletions(-) diff --git a/user/apps/doomgeneric b/user/apps/doomgeneric index f67aed3..146c36b 160000 --- a/user/apps/doomgeneric +++ b/user/apps/doomgeneric @@ -1 +1 @@ -Subproject commit f67aed390445771897288d499bd46de93f28bb13 +Subproject commit 146c36bfda130001bf8818d28e58d7514a5ea47c diff --git a/user/libxunil/src/lib.rs b/user/libxunil/src/lib.rs index 308d150..a55ea5c 100644 --- a/user/libxunil/src/lib.rs +++ b/user/libxunil/src/lib.rs @@ -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 } diff --git a/user/libxunil/src/mem.rs b/user/libxunil/src/mem.rs index 6c0c113..9b4f3f0 100644 --- a/user/libxunil/src/mem.rs +++ b/user/libxunil/src/mem.rs @@ -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::
()) 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::
(); 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 +} diff --git a/user/libxunil/src/syscall.rs b/user/libxunil/src/syscall.rs index 9b5b576..8391b14 100644 --- a/user/libxunil/src/syscall.rs +++ b/user/libxunil/src/syscall.rs @@ -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) ); }