Unverified Commit 91449b7b authored by jschwe's avatar jschwe Committed by GitHub
Browse files

Safety: Mark __sys_realloc and __sys_free as unsafe (#68)

# __sys_realloc, __sys_free and __sys_malloc
- Add Errors section to docs
- Check if parameters are valid and warn/return error

# __sys_realloc, __sys_free
- Mark as unsafe
- Add detailed Safety section

# uhyve::get_application_parameters()
- make internal block unsafe and add Todos and Fixmes since this still needs some work!
parent 353427d5
......@@ -37,25 +37,34 @@
#![allow(unused_macros)]
#![no_std]
#[cfg(test)]
#[macro_use]
extern crate std;
// EXTERNAL CRATES
#[macro_use]
extern crate alloc;
#[macro_use]
extern crate bitflags;
#[cfg(target_arch = "x86_64")]
extern crate multiboot;
#[cfg(target_arch = "x86_64")]
extern crate x86;
#[macro_use]
extern crate log;
#[cfg(target_arch = "x86_64")]
extern crate multiboot;
extern crate num;
#[macro_use]
extern crate num_derive;
extern crate num_traits;
#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(target_arch = "x86_64")]
extern crate x86;
use alloc::alloc::Layout;
use core::alloc::GlobalAlloc;
use arch::percore::*;
use mm::allocator::LockedHeap;
pub use crate::arch::*;
pub use crate::config::*;
pub use crate::syscalls::*;
#[macro_use]
mod macros;
......@@ -81,28 +90,28 @@ mod synch;
mod syscalls;
mod util;
pub use crate::arch::*;
pub use crate::config::*;
pub use crate::syscalls::*;
use alloc::alloc::Layout;
use arch::percore::*;
use core::alloc::GlobalAlloc;
use mm::allocator::LockedHeap;
#[cfg(not(test))]
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
/// Interface to allocate memory from system heap
///
/// # Errors
/// Returning a null pointer indicates that either memory is exhausted or
/// `size` and `align` do not meet this allocator's size or alignment constraints.
///
#[cfg(not(test))]
pub fn __sys_malloc(size: usize, align: usize) -> *mut u8 {
let layout: Layout = Layout::from_size_align(size, align).unwrap();
let ptr;
unsafe {
ptr = ALLOCATOR.alloc(layout);
let layout_res = Layout::from_size_align(size, align);
if layout_res.is_err() || size == 0 {
warn!(
"__sys_malloc called with size 0x{:x}, align 0x{:x} is an invalid layout!",
size, align
);
return core::ptr::null::<*mut u8>() as *mut u8;
}
let layout = layout_res.unwrap();
let ptr = unsafe { ALLOCATOR.alloc(layout) };
trace!(
"__sys_malloc: allocate memory at 0x{:x} (size 0x{:x}, align 0x{:x})",
......@@ -114,39 +123,82 @@ pub fn __sys_malloc(size: usize, align: usize) -> *mut u8 {
ptr
}
/// Interface to increase the size of a memory region
/// Shrink or grow a block of memory to the given `new_size`. The block is described by the given
/// ptr pointer and layout. If this returns a non-null pointer, then ownership of the memory block
/// referenced by ptr has been transferred to this allocator. The memory may or may not have been
/// deallocated, and should be considered unusable (unless of course it was transferred back to the
/// caller again via the return value of this method). The new memory block is allocated with
/// layout, but with the size updated to new_size.
/// If this method returns null, then ownership of the memory block has not been transferred to this
/// allocator, and the contents of the memory block are unaltered.
///
/// # Safety
/// This function is unsafe because undefined behavior can result if the caller does not ensure all
/// of the following:
/// - `ptr` must be currently allocated via this allocator,
/// - `size` and `align` must be the same layout that was used to allocate that block of memory.
/// ToDO: verify if the same values for size and align always lead to the same layout
///
/// # Errors
/// Returns null if the new layout does not meet the size and alignment constraints of the
/// allocator, or if reallocation otherwise fails.
#[cfg(not(test))]
pub fn __sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
let layout: Layout = Layout::from_size_align(size, align).unwrap();
let new_ptr;
unsafe {
new_ptr = ALLOCATOR.realloc(ptr, layout, new_size);
pub unsafe fn __sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
let layout_res = Layout::from_size_align(size, align);
if layout_res.is_err() || size == 0 || new_size == 0 {
warn!(
"__sys_realloc called with ptr 0x{:x}, size 0x{:x}, align 0x{:x}, new_size 0x{:x} is an invalid layout!",
ptr as usize, size, align, new_size
);
return core::ptr::null::<*mut u8>() as *mut u8;
}
let layout = layout_res.unwrap();
let new_ptr = unsafe { ALLOCATOR.realloc(ptr, layout, new_size) };
if new_ptr.is_null() {
debug!(
"__sys_realloc failed to resize ptr 0x{:x} with size 0x{:x}, align 0x{:x}, new_size 0x{:x} !",
ptr as usize, size, align, new_size
);
} else {
trace!(
"__sys_realloc: resized memory at 0x{:x}, new address 0x{:x}",
ptr as usize,
new_ptr as usize
);
}
trace!(
"__sys_realloc: resize memory at 0x{:x}, new address 0x{:x}",
ptr as usize,
new_ptr as usize
);
new_ptr
}
/// Interface to deallocate a memory region from the system heap
///
/// # Safety
/// This function is unsafe because undefined behavior can result if the caller does not ensure all of the following:
/// - ptr must denote a block of memory currently allocated via this allocator,
/// - `size` and `align` must be the same values that were used to allocate that block of memory
/// ToDO: verify if the same values for size and align always lead to the same layout
///
/// # Errors
/// May panic if debug assertions are enabled and invalid parameters `size` or `align` where passed.
#[cfg(not(test))]
pub fn __sys_free(ptr: *mut u8, size: usize, align: usize) {
let layout: Layout = Layout::from_size_align(size, align).unwrap();
trace!(
"sys_free: deallocate memory at 0x{:x} (size 0x{:x})",
ptr as usize,
size
);
unsafe {
ALLOCATOR.dealloc(ptr, layout);
pub unsafe fn __sys_free(ptr: *mut u8, size: usize, align: usize) {
let layout_res = Layout::from_size_align(size, align);
if layout_res.is_err() || size == 0 {
warn!(
"__sys_free called with size 0x{:x}, align 0x{:x} is an invalid layout!",
size, align
);
debug_assert!(layout_res.is_err(), "__sys_free error: Invalid layout");
debug_assert_ne!(size, 0, "__sys_free error: size cannot be 0");
} else {
trace!(
"sys_free: deallocate memory at 0x{:x} (size 0x{:x})",
ptr as usize,
size
);
}
let layout = layout_res.unwrap();
ALLOCATOR.dealloc(ptr, layout);
}
#[cfg(not(test))]
......
......@@ -5,6 +5,11 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use core::{mem, ptr, slice};
#[cfg(target_arch = "x86_64")]
use x86::io::*;
use crate::arch;
use crate::arch::mm::paging;
use crate::syscalls::interfaces::SyscallInterface;
......@@ -12,10 +17,6 @@ use crate::syscalls::interfaces::SyscallInterface;
use crate::syscalls::lwip::sys_lwip_get_errno;
#[cfg(feature = "newlib")]
use crate::syscalls::{LWIP_FD_BIT, LWIP_LOCK};
use core::{mem, ptr, slice};
#[cfg(target_arch = "x86_64")]
use x86::io::*;
const UHYVE_PORT_WRITE: u16 = 0x400;
const UHYVE_PORT_OPEN: u16 = 0x440;
......@@ -206,74 +207,83 @@ impl SyscallInterface for Uhyve {
sysclose.ret
}
/// ToDo: This function needs a description - also applies to trait in src/syscalls/interfaces/mod.rs
///
/// ToDo: Add Safety section under which circumctances this is safe/unsafe to use
/// ToDo: Add an Errors section - What happens when e.g. malloc fails, how is that handled (currently it isn't)
#[cfg(not(test))]
fn get_application_parameters(&self) -> (i32, *const *const u8, *const *const u8) {
// determine the number of arguments and environment variables
let mut syscmdsize = SysCmdsize::new();
uhyve_send(UHYVE_PORT_CMDSIZE, &mut syscmdsize);
// create array to receive all arguments
let argv_raw = crate::__sys_malloc(
syscmdsize.argc as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let argv_phy_raw = crate::__sys_malloc(
syscmdsize.argc as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let argv = unsafe { slice::from_raw_parts_mut(argv_raw, syscmdsize.argc as usize) };
let argv_phy = unsafe { slice::from_raw_parts_mut(argv_phy_raw, syscmdsize.argc as usize) };
for i in 0..syscmdsize.argc as usize {
argv[i] = crate::__sys_malloc(
syscmdsize.argsz[i] as usize * mem::size_of::<*const u8>(),
1,
);
argv_phy[i] = paging::virtual_to_physical(argv[i] as usize) as *const u8;
}
//FIXME: Determine how to make this safer, check return values of malloc etc
// and then remove the unsafe block and only wrap the parts where it is needed
unsafe {
// determine the number of arguments and environment variables
let mut syscmdsize = SysCmdsize::new();
uhyve_send(UHYVE_PORT_CMDSIZE, &mut syscmdsize);
// create array to receive all arguments
let argv_raw = crate::__sys_malloc(
syscmdsize.argc as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let argv_phy_raw = crate::__sys_malloc(
syscmdsize.argc as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let argv = unsafe { slice::from_raw_parts_mut(argv_raw, syscmdsize.argc as usize) };
let argv_phy =
unsafe { slice::from_raw_parts_mut(argv_phy_raw, syscmdsize.argc as usize) };
for i in 0..syscmdsize.argc as usize {
argv[i] = crate::__sys_malloc(
syscmdsize.argsz[i] as usize * mem::size_of::<*const u8>(),
1,
);
argv_phy[i] = paging::virtual_to_physical(argv[i] as usize) as *const u8;
}
// create array to receive the environment
let env_raw = crate::__sys_malloc(
(syscmdsize.envc + 1) as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let env_phy_raw = crate::__sys_malloc(
(syscmdsize.envc + 1) as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let env = unsafe { slice::from_raw_parts_mut(env_raw, (syscmdsize.envc + 1) as usize) };
let env_phy =
unsafe { slice::from_raw_parts_mut(env_phy_raw, (syscmdsize.envc + 1) as usize) };
for i in 0..syscmdsize.envc as usize {
env[i] = crate::__sys_malloc(
syscmdsize.envsz[i] as usize * mem::size_of::<*const u8>(),
1,
// create array to receive the environment
let env_raw = crate::__sys_malloc(
(syscmdsize.envc + 1) as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let env_phy_raw = crate::__sys_malloc(
(syscmdsize.envc + 1) as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
) as *mut *const u8;
let env = unsafe { slice::from_raw_parts_mut(env_raw, (syscmdsize.envc + 1) as usize) };
let env_phy =
unsafe { slice::from_raw_parts_mut(env_phy_raw, (syscmdsize.envc + 1) as usize) };
for i in 0..syscmdsize.envc as usize {
env[i] = crate::__sys_malloc(
syscmdsize.envsz[i] as usize * mem::size_of::<*const u8>(),
1,
);
env_phy[i] = paging::virtual_to_physical(env[i] as usize) as *const u8;
}
env[syscmdsize.envc as usize] = ptr::null_mut();
env_phy[syscmdsize.envc as usize] = ptr::null_mut();
// ask uhyve for the environment
let mut syscmdval = SysCmdval::new(argv_phy_raw as *const u8, env_phy_raw as *const u8);
uhyve_send(UHYVE_PORT_CMDVAL, &mut syscmdval);
// free temporary array
crate::__sys_free(
argv_phy_raw as *mut u8,
syscmdsize.argc as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
);
crate::__sys_free(
env_phy_raw as *mut u8,
(syscmdsize.envc + 1) as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
);
env_phy[i] = paging::virtual_to_physical(env[i] as usize) as *const u8;
(
syscmdsize.argc,
argv_raw as *const *const u8,
env_raw as *const *const u8,
)
}
env[syscmdsize.envc as usize] = ptr::null_mut();
env_phy[syscmdsize.envc as usize] = ptr::null_mut();
// ask uhyve for the environment
let mut syscmdval = SysCmdval::new(argv_phy_raw as *const u8, env_phy_raw as *const u8);
uhyve_send(UHYVE_PORT_CMDVAL, &mut syscmdval);
// free temporary array
crate::__sys_free(
argv_phy_raw as *mut u8,
syscmdsize.argc as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
);
crate::__sys_free(
env_phy_raw as *mut u8,
(syscmdsize.envc + 1) as usize * mem::size_of::<*const u8>(),
mem::size_of::<*const u8>(),
);
(
syscmdsize.argc,
argv_raw as *const *const u8,
env_raw as *const *const u8,
)
}
fn shutdown(&self, arg: i32) -> ! {
......
......@@ -6,19 +6,13 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
mod condvar;
pub mod fs;
mod interfaces;
use crate::drivers::net::*;
use crate::environment;
#[cfg(feature = "newlib")]
mod lwip;
mod processor;
mod random;
mod recmutex;
mod semaphore;
mod spinlock;
mod system;
mod tasks;
mod timer;
use crate::synch::spinlock::SpinlockIrqSave;
use crate::syscalls::interfaces::SyscallInterface;
#[cfg(not(test))]
use crate::{__sys_free, __sys_malloc, __sys_realloc};
pub use self::condvar::*;
pub use self::processor::*;
......@@ -29,14 +23,20 @@ pub use self::spinlock::*;
pub use self::system::*;
pub use self::tasks::*;
pub use self::timer::*;
#[cfg(not(test))]
use crate::{__sys_free, __sys_malloc, __sys_realloc};
use crate::drivers::net::*;
use crate::environment;
mod condvar;
pub mod fs;
mod interfaces;
#[cfg(feature = "newlib")]
use crate::synch::spinlock::SpinlockIrqSave;
use crate::syscalls::interfaces::SyscallInterface;
mod lwip;
mod processor;
mod random;
mod recmutex;
mod semaphore;
mod spinlock;
mod system;
mod tasks;
mod timer;
#[cfg(feature = "newlib")]
const LWIP_FD_BIT: i32 = 1 << 30;
......@@ -74,13 +74,13 @@ pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 {
#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8 {
__sys_realloc(ptr, size, align, new_size)
unsafe { __sys_realloc(ptr, size, align, new_size) }
}
#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) {
__sys_free(ptr, size, align)
unsafe { __sys_free(ptr, size, align) }
}
pub fn get_application_parameters() -> (i32, *const *const u8, *const *const u8) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment