refactor: improve system call ABI

This commit is contained in:
2021-11-04 14:14:31 +02:00
parent eb3c14db5f
commit ee5daf32b9
11 changed files with 179 additions and 154 deletions
+113
View File
@@ -0,0 +1,113 @@
//! System call argument ABI helpers
use crate::mem;
use core::mem::size_of;
use error::Errno;
fn translate(virt: usize) -> Option<usize> {
let mut res: usize;
unsafe {
asm!("at s1e1r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
}
if res & 1 == 0 {
Some(res & !(0xFFF | (0xFF << 56)))
} else {
None
}
}
/// Unwraps a slim structure pointer
pub fn validate_user_ptr_struct<'a, T>(base: usize) -> Result<&'a mut T, Errno> {
let bytes = validate_user_ptr(base, size_of::<T>())?;
Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
}
/// Unwraps an user buffer reference
pub fn validate_user_ptr<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Errno> {
if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET {
warnln!(
"User region refers to kernel memory: base={:#x}, len={:#x}",
base,
len
);
return Err(Errno::InvalidArgument);
}
for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) {
if translate(i * mem::PAGE_SIZE).is_none() {
warnln!(
"User region refers to unmapped memory: base={:#x}, len={:#x} (page {:#x})",
base,
len,
i * mem::PAGE_SIZE
);
return Err(Errno::InvalidArgument);
}
}
Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) })
}
/// Unwraps a nullable user buffer reference
pub fn validate_user_ptr_null<'a>(base: usize, len: usize) -> Result<Option<&'a mut [u8]>, Errno> {
if base == 0 {
Ok(None)
} else {
validate_user_ptr(base, len).map(Some)
}
}
/// Unwraps user string argument
pub fn validate_user_str<'a>(base: usize, len: usize) -> Result<&'a str, Errno> {
let bytes = validate_user_ptr(base, len)?;
core::str::from_utf8(bytes).map_err(|_| {
warnln!("User string contains invalid UTF-8 characters: base={:#x}, len={:#x}", base, len);
Errno::InvalidArgument
})
}
// if base > mem::KERNEL_OFFSET {
// warnln!("User string refers to kernel memory: base={:#x}", base);
// return Err(Errno::InvalidArgument);
// }
//
// let base_ptr = base as *const u8;
// let mut len = 0;
// let mut page_valid = false;
// loop {
// if len == limit {
// warnln!("User string exceeded limit: base={:#x}", base);
// return Err(Errno::InvalidArgument);
// }
//
// if (base + len) % mem::PAGE_SIZE == 0 {
// page_valid = false;
// }
//
// if !page_valid && translate((base + len) & !0xFFF).is_none() {
// warnln!(
// "User string refers to unmapped memory: base={:#x}, off={:#x}",
// base,
// len
// );
// return Err(Errno::InvalidArgument);
// }
//
// page_valid = true;
//
// let byte = unsafe { *base_ptr.add(len) };
// if byte == 0 {
// break;
// }
//
// len += 1;
// }
//
// let slice = unsafe { core::slice::from_raw_parts(base_ptr, len) };
// core::str::from_utf8(slice).map_err(|_| {
// warnln!(
// "User string contains invalid UTF-8 characters: base={:#x}",
// base
// );
// Errno::InvalidArgument
// })
// }
@@ -1,113 +1,17 @@
//! System call implementation
use crate::arch::platform::exception::ExceptionFrame;
use crate::debug::Level;
use crate::mem;
use crate::proc::{wait, Process, Pid};
use crate::proc::{wait, Pid, Process};
use core::mem::size_of;
use core::time::Duration;
use error::Errno;
use libcommon::{Read, Write};
use syscall::{abi, stat::AT_FDCWD};
use vfs::{FileMode, OpenFlags, Stat};
use crate::arch::platform::exception::ExceptionFrame;
fn translate(virt: usize) -> Option<usize> {
let mut res: usize;
unsafe {
asm!("at s1e1r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
}
if res & 1 == 0 {
Some(res & !(0xFFF | (0xFF << 56)))
} else {
None
}
}
fn validate_user_ptr_struct<'a, T>(base: usize) -> Result<&'a mut T, Errno> {
let bytes = validate_user_ptr(base, size_of::<T>())?;
Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
}
fn validate_user_ptr<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Errno> {
if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET {
warnln!(
"User region refers to kernel memory: base={:#x}, len={:#x}",
base,
len
);
return Err(Errno::InvalidArgument);
}
for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) {
if translate(i * mem::PAGE_SIZE).is_none() {
warnln!(
"User region refers to unmapped memory: base={:#x}, len={:#x} (page {:#x})",
base,
len,
i * mem::PAGE_SIZE
);
return Err(Errno::InvalidArgument);
}
}
Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) })
}
fn validate_user_ptr_null<'a>(base: usize, len: usize) -> Result<Option<&'a mut [u8]>, Errno> {
if base == 0 {
Ok(None)
} else {
validate_user_ptr(base, len).map(Some)
}
}
fn validate_user_str<'a>(base: usize, limit: usize) -> Result<&'a str, Errno> {
if base > mem::KERNEL_OFFSET {
warnln!("User string refers to kernel memory: base={:#x}", base);
return Err(Errno::InvalidArgument);
}
let base_ptr = base as *const u8;
let mut len = 0;
let mut page_valid = false;
loop {
if len == limit {
warnln!("User string exceeded limit: base={:#x}", base);
return Err(Errno::InvalidArgument);
}
if (base + len) % mem::PAGE_SIZE == 0 {
page_valid = false;
}
if !page_valid && translate((base + len) & !0xFFF).is_none() {
warnln!(
"User string refers to unmapped memory: base={:#x}, off={:#x}",
base,
len
);
return Err(Errno::InvalidArgument);
}
page_valid = true;
let byte = unsafe { *base_ptr.add(len) };
if byte == 0 {
break;
}
len += 1;
}
let slice = unsafe { core::slice::from_raw_parts(base_ptr, len) };
core::str::from_utf8(slice).map_err(|_| {
warnln!(
"User string contains invalid UTF-8 characters: base={:#x}",
base
);
Errno::InvalidArgument
})
}
mod arg;
use arg::*;
/// Creates a "fork" process from current one using its register frame.
/// See [Process::fork()].
@@ -132,9 +36,9 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
// I/O system calls
abi::SYS_OPENAT => {
let at_fd = args[0];
let path = validate_user_str(args[1], 256)?;
let mode = FileMode::from_bits(args[2] as u32).ok_or(Errno::InvalidArgument)?;
let opts = OpenFlags::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
let path = validate_user_str(args[1], args[2])?;
let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
let opts = OpenFlags::from_bits(args[4] as u32).ok_or(Errno::InvalidArgument)?;
let at = if at_fd as i32 == AT_FDCWD {
None
@@ -166,8 +70,8 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
let proc = Process::current();
let mut io = proc.io.lock();
let fd = args[0];
let filename = validate_user_str(args[1], 256)?;
let buf = validate_user_ptr_struct::<Stat>(args[2])?;
let filename = validate_user_str(args[1], args[2])?;
let buf = validate_user_ptr_struct::<Stat>(args[3])?;
// TODO "self" flag
let at = if fd as i32 != AT_FDCWD {