Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions kernel/arch/x86/src/raw_copy.s
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
.section .text

.global raw_copy
.global copy_fault
.global raw_zero
.global raw_fault

// The order of functions is important for bound checking in the exception handler

// TODO can be optimized
raw_copy:
push esi
push edi
Expand All @@ -41,7 +43,22 @@ raw_copy:
mov eax, 1
ret

copy_fault:
raw_zero:
push esi
push edi

mov edi, 12[esp]
mov ecx, 16[esp]

xor eax, eax
rep stosb

pop edi
pop esi
mov eax, 1
ret

raw_fault:
pop edi
pop esi
xor eax, eax
Expand Down
15 changes: 12 additions & 3 deletions kernel/arch/x86_64/src/raw_copy.s
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,24 @@
.section .text

.global raw_copy
.global copy_fault
.global raw_zero
.global raw_fault

// The order of functions is important for bound checking in the exception handler

// TODO can be optimized
raw_copy:
mov rcx, rdx
rep movsb
mov rax, 1
ret

copy_fault:
raw_zero:
mov rcx, rsi
xor rax, rax
rep stosb
mov rax, 1
ret

raw_fault:
xor rax, rax
ret
7 changes: 1 addition & 6 deletions kernel/src/device/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,7 @@ pub struct ZeroDeviceHandle;

impl FileOps for ZeroDeviceHandle {
fn read(&self, _file: &File, _: u64, buf: UserSlice<u8>) -> EResult<usize> {
let b: [u8; 128] = [0; 128];
let mut i = 0;
while i < buf.len() {
i += buf.copy_to_user(i, &b)?;
}
Ok(buf.len())
buf.zero(0, buf.len())
}

fn write(&self, _file: &File, _: u64, buf: UserSlice<u8>) -> EResult<usize> {
Expand Down
41 changes: 39 additions & 2 deletions kernel/src/memory/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ use utils::{
unsafe extern "C" {
/// Copy, with access check. On success, the function returns `true`.
pub fn raw_copy(dst: *mut u8, src: *const u8, n: usize) -> bool;
/// Function to be called back when a page fault occurs while using [`raw_copy`].
pub fn copy_fault();
/// Zero a range of memory, with page fault handling. On success, the function returns `true`.
pub fn raw_zero(dst: *mut u8, n: usize) -> bool;

/// Function called back when a page fault occurs while using [`raw_copy`] or [`raw_zero`].
pub fn raw_fault();
}

/// Low level function to copy data from userspace to kernelspace, with access check.
Expand All @@ -54,6 +57,22 @@ unsafe fn user_copy(src: *const u8, dst: *mut u8, n: usize) -> EResult<()> {
}
}

/// Low level function to zero a range of memory, with page fault handling.
///
/// If the access check fails, the function returns [`EFAULT`].
///
/// # Safety
///
/// The caller must ensure that `dst` points to valid memory that can be written to.
unsafe fn user_zero(dst: *mut u8, n: usize) -> EResult<()> {
let res = vmem::smap_disable(|| raw_zero(dst, n));
if likely(res) {
Ok(())
} else {
Err(errno!(EFAULT))
}
}

/// Wrapper for an userspace pointer.
#[derive(Clone, Copy)]
pub struct UserPtr<T: Sized + fmt::Debug>(pub Option<NonNull<T>>);
Expand Down Expand Up @@ -321,6 +340,24 @@ impl<'a, T: Sized + fmt::Debug> UserSlice<'a, T> {
pub fn copy_to_user(&self, off: usize, buf: &[T]) -> EResult<usize> {
unsafe { self.copy_to_user_raw(off, buf.as_ptr(), buf.len()) }
}

/// Zeros the portion of the slice starting at offset `off`, with length `len`.
///
/// The function returns the number of elements written.
///
/// If the pointer is null, the function does nothing and returns `0`.
///
/// If the slice is not accessible, the function returns an error.
pub fn zero(&self, off: usize, len: usize) -> EResult<usize> {
let Some(ptr) = self.ptr else {
return Ok(0);
};
let len = min(len, self.len.saturating_sub(off));
unsafe {
user_zero(ptr.as_ptr().add(off) as *mut _, size_of::<T>() * len)?;
}
Ok(len)
}
}

impl<T: fmt::Debug> fmt::Debug for UserSlice<'_, T> {
Expand Down
12 changes: 5 additions & 7 deletions kernel/src/process/exec/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
perm::{AccessProfile, can_execute_file},
vfs,
},
memory::{COMPAT_PROCESS_END, PROCESS_END, VirtAddr, vmem},
memory::{COMPAT_PROCESS_END, PROCESS_END, VirtAddr, user::UserSlice, vmem},
process::{
USER_STACK_SIZE,
exec::{ProgramImage, vdso::MappedVDSO},
Expand All @@ -40,7 +40,7 @@ use crate::{
},
},
};
use core::{cmp::max, hint::unlikely, num::NonZeroUsize, ops::Add, ptr, slice};
use core::{cmp::max, hint::unlikely, num::NonZeroUsize, ops::Add, ptr};
use utils::{
collections::{path::Path, string::String, vec::Vec},
errno,
Expand Down Expand Up @@ -277,11 +277,9 @@ fn map_segment(
// Zero the end of the last page if needed
let begin = load_base + seg.p_vaddr as usize + seg.p_filesz as usize;
let len = begin.next_multiple_of(PAGE_SIZE) - begin.0;
if len > 0 {
unsafe {
let slice = slice::from_raw_parts_mut(begin.as_ptr::<u8>(), len);
vmem::write_ro(|| vmem::smap_disable(|| slice.fill(0)));
}
unsafe {
let slice = UserSlice::from_user(begin.as_ptr::<u8>(), len)?;
vmem::write_ro(|| slice.zero(0, len))?;
}
}
// Add zero pages at the end if needed
Expand Down
8 changes: 4 additions & 4 deletions kernel/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,10 @@ pub(crate) fn init() -> EResult<()> {
Ok(true) => {}
Ok(false) => {
if ring < 3 {
// Check if the fault was caused by a user <-> kernel copy
if (user::raw_copy as usize..user::copy_fault as usize).contains(&pc) {
// Jump to `copy_fault`
frame.set_program_counter(user::copy_fault as usize);
// Check if the fault was caused by a user <-> kernel copy/zero
if (user::raw_copy as usize..user::raw_fault as usize).contains(&pc) {
// Jump to `raw_fault`
frame.set_program_counter(user::raw_fault as usize);
} else {
return CallbackResult::Panic;
}
Expand Down