osmium
osmium copied to clipboard
Unsoundness in receive_data
Hello, thank you for your contribution in this project, I an testing our static analysis tool in github's Rust project and I notice the following code:
fn execve(
filename: u32,
filename_length: u32,
argv: u32,
envp: u32,
tf: &mut trap::TrapFrame,
k: &mut kernel::Kernel,
) -> Result<u32, SyscallError> {
let name: &str;
unsafe {
match str::from_utf8(
slice::from_raw_parts(filename as *const u8, filenamelength as usize),
) {
Ok(f) => name = f,
Err() => {
return Err(SyscallError::InvalidArguments);
}
};
}
let file = match files::search(name) {
Some(file) => file,
None => return Err(SyscallError::NotFound),
};
let e = match elf::Elf::new(file.bytes) {
Ok(e) => e,
Err(_) => return Err(SyscallError::IllegalFile),
};
match k.current_process.as_mut().unwrap().load_elf(&e, &mut k.allocator) {
Ok(()) => {}
Err(e) => return Err(SyscallError::IllegalFile),
};
dprintln!("set entry point: {:x}", e.elf.entry);
let new_tf = trap::TrapFrame::new(e.elf.entry, memlayout::USER_STACK_BOTTOMN);
*tf = new_tf;
Ok(0)
}
The unsoundness occurs in the execve function where:
It takes the filename parameter (which is just a u32) and casts it directly to a raw pointer It uses slice::from_raw_parts(filename as *const u8, filename_length as usize) without any validation If filename points to invalid memory or if filename_length is too large, it will attempt to read invalid memory before even checking if the data is valid UTF-8
While the function does check if the bytes are valid UTF-8 after creating the slice, this happens too late - the memory safety violation occurs during the from_raw_parts call itself when the memory is accessed. There are no guards, bounds checks, or validations before the unsafe operation, creating a direct path from user input to memory safety violation. A valid path to call this fn: pub fn syscall_dispatch -> fn execve
POC
fn main() {
// Create a syscall with an invalid memory address
let invalid_syscall = Syscall::Execve {
filename: 0xDEADBEEF, // Invalid memory address
filename_length: 10, // Attempt to read 10 bytes from invalid address
argv: 0,
envp: 0
};
// Create kernel and trap frame
let mut kernel = Kernel::new();
let mut trap_frame = TrapFrame::default();
// This will trigger undefined behavior
let result = syscall_dispatch(invalid_syscall, &mut kernel, &mut trap_frame);
}
another samilar case is: pub fn syscall_dispatch -> fn receive_data