refactor(kernel-hal): 移除全部对用户指针传入的字符串的拷贝

This commit is contained in:
YdrMaster 2022-03-25 09:15:20 +08:00
parent 8038eee630
commit 5783d60f9b
13 changed files with 105 additions and 102 deletions

View File

@ -1,12 +1,12 @@
//! Read/write user space pointer.
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::VirtAddr;
use alloc::{string::String, vec::Vec};
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
ops::{Deref, DerefMut},
};
/// Wapper of raw pointer from user space.
#[repr(C)]
@ -68,9 +68,9 @@ unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}
impl<T, P: Policy> From<usize> for UserPtr<T, P> {
fn from(x: usize) -> Self {
fn from(ptr: usize) -> Self {
UserPtr {
ptr: x as _,
ptr: ptr as _,
mark: PhantomData,
}
}
@ -96,7 +96,7 @@ impl<T, P: Policy> UserPtr<T, P> {
/// `count` is in units of `T`;
/// e.g., a count of 3 represents a pointer offset of `3 * size_of::<T>()` bytes.
pub fn add(&self, count: usize) -> Self {
UserPtr {
Self {
ptr: unsafe { self.ptr.add(count) },
mark: PhantomData,
}
@ -120,9 +120,9 @@ impl<T, P: Policy> UserPtr<T, P> {
}
impl<T, P: Read> UserPtr<T, P> {
/// Always returns a shared reference to the value wrapped in [`Ok`].
pub fn as_ref(&self) -> Result<&'static T> {
Ok(unsafe { &*self.ptr })
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &'static T {
unsafe { &*self.ptr }
}
/// Reads the value from self without moving it.
@ -142,56 +142,62 @@ impl<T, P: Read> UserPtr<T, P> {
}
}
/// Forms a slice from a user pointer and a `len`.
pub fn as_slice(&self, len: usize) -> Result<&'static [T]> {
if len == 0 {
Ok(&[])
} else {
self.check()?;
Ok(unsafe { core::slice::from_raw_parts(self.ptr, len) })
}
}
/// Copies elements into a new [`Vec`].
///
/// The `len` argument is the number of **elements**, not the number of bytes.
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
if len == 0 {
return Ok(Vec::default());
Ok(Vec::default())
} else {
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
}
Ok(ret)
}
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
}
Ok(ret)
}
}
impl<P: Read> UserPtr<u8, P> {
/// Copies chars into a new [`String`].
///
/// The `len` argument is the number of **bytes**, not the number of chars.
pub fn read_string(&self, len: usize) -> Result<String> {
self.check()?;
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) };
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?;
Ok(String::from(s))
/// Forms a utf-8 string slice from a user pointer and a `len`.
pub fn as_str(&self, len: usize) -> Result<&'static str> {
core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8)
}
/// Copies an zero-terminated string of c style to a new [`String`].
pub fn read_cstring(&self) -> Result<String> {
self.check()?;
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() };
self.read_string(len)
pub fn as_c_str(&self) -> Result<&'static str> {
self.as_str(unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() })
}
}
impl<P: Read> UserPtr<UserPtr<u8, P>, P> {
impl<P: 'static + Read> UserPtr<UserPtr<u8, P>, P> {
/// Copies a group of zero-terminated string into [`String`]s,
/// and collect them into a [`Vec`].
pub fn read_cstring_array(&self) -> Result<Vec<String>> {
self.check()?;
let len = unsafe {
(0usize..)
.find(|&i| self.ptr.add(i).read().is_null())
.unwrap()
};
self.read_array(len)?
.into_iter()
.map(|ptr| ptr.read_cstring())
.collect()
let mut result = Vec::new();
let mut pptr = self.ptr;
loop {
let sptr = unsafe { pptr.read() };
if sptr.is_null() {
break;
}
result.push(sptr.as_c_str()?.into());
pptr = unsafe { pptr.add(1) };
}
Ok(result)
}
}
@ -240,7 +246,7 @@ impl<P: Write> UserPtr<u8, P> {
#[derive(Debug)]
#[repr(C)]
pub struct IoVec<P: Policy> {
pub struct IoVec<P: 'static + Policy> {
/// Starting address
ptr: UserPtr<u8, P>,
/// Number of bytes to transfer
@ -252,7 +258,7 @@ pub type IoVecOut = IoVec<Out>;
/// A valid IoVecs request from user
#[derive(Debug)]
pub struct IoVecs<P: Policy> {
pub struct IoVecs<P: 'static + Policy> {
vec: Vec<IoVec<P>>,
}
@ -285,7 +291,7 @@ impl<P: Read> IoVecs<P> {
pub fn read_to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
for vec in self.vec.iter() {
buf.extend(vec.ptr.read_array(vec.len)?);
buf.extend_from_slice(vec.ptr.as_slice(vec.len)?);
}
Ok(buf)
}

View File

@ -95,7 +95,7 @@ mod tests {
use super::*;
/// A valid virtual address base to mmap.
const VBASE: VirtAddr = 0x2_00000000;
const VBASE: VirtAddr = 0x0002_0000_0000;
#[test]
fn map_unmap() {

View File

@ -1,4 +1,4 @@
//! Directory operations
//! Directory operations
//!
//! - getcwd
//! - chdir
@ -34,16 +34,16 @@ impl Syscall<'_> {
/// Change the current directory.
/// - `path` pointer to string with name of path
pub fn sys_chdir(&self, path: UserInPtr<u8>) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
info!("chdir: path={:?}", path);
let proc = self.linux_process();
let inode = proc.lookup_inode(&path)?;
let inode = proc.lookup_inode(path)?;
let info = inode.metadata()?;
if info.type_ != FileType::Dir {
return Err(LxError::ENOTDIR);
}
proc.change_directory(&path);
proc.change_directory(path);
Ok(0)
}
@ -56,14 +56,14 @@ impl Syscall<'_> {
/// create directory relative to directory file descriptor
pub fn sys_mkdirat(&self, dirfd: FileDesc, path: UserInPtr<u8>, mode: usize) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
// TODO: check pathname
info!(
"mkdirat: dirfd={:?}, path={:?}, mode={:#o}",
dirfd, path, mode
);
let (dir_path, file_name) = split_path(&path);
let (dir_path, file_name) = split_path(path);
let proc = self.linux_process();
let inode = proc.lookup_inode_at(dirfd, dir_path, true)?;
if inode.find(file_name).is_ok() {
@ -75,10 +75,10 @@ impl Syscall<'_> {
/// Remove a directory.
/// - path pointer to string with directory name
pub fn sys_rmdir(&self, path: UserInPtr<u8>) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
info!("rmdir: path={:?}", path);
let (dir_path, file_name) = split_path(&path);
let (dir_path, file_name) = split_path(path);
let proc = self.linux_process();
let dir_inode = proc.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?;
@ -141,8 +141,8 @@ impl Syscall<'_> {
newpath: UserInPtr<u8>,
flags: usize,
) -> SysResult {
let oldpath = oldpath.read_cstring()?;
let newpath = newpath.read_cstring()?;
let oldpath = oldpath.as_c_str()?;
let newpath = newpath.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags);
info!(
"linkat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}, flags={:?}",
@ -150,8 +150,8 @@ impl Syscall<'_> {
);
let proc = self.linux_process();
let (new_dir_path, new_file_name) = split_path(&newpath);
let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?;
let (new_dir_path, new_file_name) = split_path(newpath);
let inode = proc.lookup_inode_at(olddirfd, oldpath, true)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?;
new_dir_inode.link(new_file_name, &inode)?;
Ok(0)
@ -168,7 +168,7 @@ impl Syscall<'_> {
/// remove directory entry relative to directory file descriptor
/// The unlinkat() system call operates in exactly the same way as either unlink or rmdir.
pub fn sys_unlinkat(&self, dirfd: FileDesc, path: UserInPtr<u8>, flags: usize) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags);
info!(
"unlinkat: dirfd={:?}, path={:?}, flags={:?}",
@ -176,7 +176,7 @@ impl Syscall<'_> {
);
let proc = self.linux_process();
let (dir_path, file_name) = split_path(&path);
let (dir_path, file_name) = split_path(path);
let dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?;
let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir {
@ -199,16 +199,16 @@ impl Syscall<'_> {
newdirfd: FileDesc,
newpath: UserInPtr<u8>,
) -> SysResult {
let oldpath = oldpath.read_cstring()?;
let newpath = newpath.read_cstring()?;
let oldpath = oldpath.as_c_str()?;
let newpath = newpath.as_c_str()?;
info!(
"renameat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}",
olddirfd, oldpath, newdirfd, newpath
);
let proc = self.linux_process();
let (old_dir_path, old_file_name) = split_path(&oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let (old_dir_path, old_file_name) = split_path(oldpath);
let (new_dir_path, new_file_name) = split_path(newpath);
let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, false)?;
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
@ -230,14 +230,14 @@ impl Syscall<'_> {
mut base: UserOutPtr<u8>,
len: usize,
) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
info!(
"readlinkat: dirfd={:?}, path={:?}, base={:?}, len={}",
dirfd, path, base, len
);
let proc = self.linux_process();
let inode = proc.lookup_inode_at(dirfd, &path, false)?;
let inode = proc.lookup_inode_at(dirfd, path, false)?;
if inode.metadata()?.type_ != FileType::SymLink {
return Err(LxError::EINVAL);
}

View File

@ -23,7 +23,7 @@ impl Syscall<'_> {
mode: usize,
) -> SysResult {
let proc = self.linux_process();
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let flags = OpenFlags::from_bits_truncate(flags);
info!(
"openat: dir_fd={:?}, path={:?}, flags={:?}, mode={:#o}",
@ -31,7 +31,7 @@ impl Syscall<'_> {
);
let inode = if flags.contains(OpenFlags::CREATE) {
let (dir_path, file_name) = split_path(&path);
let (dir_path, file_name) = split_path(path);
// relative to cwd
let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?;
match dir_inode.find(file_name) {
@ -47,10 +47,10 @@ impl Syscall<'_> {
Err(e) => return Err(LxError::from(e)),
}
} else {
proc.lookup_inode_at(dir_fd, &path, true)?
proc.lookup_inode_at(dir_fd, path, true)?
};
let file = File::new(inode, flags, path);
let file = File::new(inode, flags, path.into());
let fd = proc.add_file(file)?;
Ok(fd.into())
}

View File

@ -147,10 +147,9 @@ impl Syscall<'_> {
/// cause the regular file named by path to be truncated to a size of precisely length bytes.
pub fn sys_truncate(&self, path: UserInPtr<u8>, len: usize) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
info!("truncate: path={:?}, len={}", path, len);
let proc = self.linux_process();
proc.lookup_inode(&path)?.resize(len)?;
self.linux_process().lookup_inode(path)?.resize(len)?;
Ok(0)
}
@ -356,7 +355,7 @@ impl Syscall<'_> {
flags: usize,
) -> SysResult {
// TODO: check permissions based on uid/gid
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags);
info!(
"faccessat: dirfd={:?}, path={:?}, mode={:#o}, flags={:?}",
@ -364,7 +363,7 @@ impl Syscall<'_> {
);
let proc = self.linux_process();
let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW);
let _inode = proc.lookup_inode_at(dirfd, &path, follow)?;
let _inode = proc.lookup_inode_at(dirfd, path, follow)?;
Ok(0)
}
@ -395,7 +394,7 @@ impl Syscall<'_> {
info!("futimens: fd: {:?}, times: {:?}", fd, times);
proc.get_file(fd)?.inode()
} else {
let pathname = pathname.read_cstring()?;
let pathname = pathname.as_c_str()?;
info!(
"utimensat: dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}",
dirfd, pathname, times, flags
@ -407,7 +406,7 @@ impl Syscall<'_> {
} else {
return Err(LxError::EINVAL);
};
proc.lookup_inode_at(dirfd, &pathname[..], follow)?
proc.lookup_inode_at(dirfd, pathname, follow)?
};
let mut metadata = inode.metadata()?;
if times[0].nsec != UTIME_OMIT {
@ -439,7 +438,7 @@ impl Syscall<'_> {
/// `path` is the pathname of **any file** within the mounted filesystem.
/// `buf` is a pointer to a `StatFs` structure.
pub fn sys_statfs(&self, path: UserInPtr<u8>, mut buf: UserOutPtr<StatFs>) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
info!("statfs: path={:?}, buf={:?}", path, buf);
// TODO

View File

@ -41,7 +41,7 @@ impl Syscall<'_> {
mut stat_ptr: UserOutPtr<Stat>,
flags: usize,
) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags);
info!(
"fstatat: dirfd={:?}, path={:?}, stat_ptr={:?}, flags={:?}",
@ -50,7 +50,7 @@ impl Syscall<'_> {
let proc = self.linux_process();
let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW);
let inode = proc.lookup_inode_at(dirfd, &path, follow)?;
let inode = proc.lookup_inode_at(dirfd, path, follow)?;
let stat = Stat::from(inode.metadata()?);
stat_ptr.write(stat)?;
Ok(0)

View File

@ -252,7 +252,7 @@ impl Syscall<'_> {
argv: UserInPtr<UserInPtr<u8>>,
envp: UserInPtr<UserInPtr<u8>>,
) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let args = argv.read_cstring_array()?;
let envs = envp.read_cstring_array()?;
info!(
@ -268,7 +268,7 @@ impl Syscall<'_> {
// Read program file
let proc = self.linux_process();
let inode = proc.lookup_inode(&path)?;
let inode = proc.lookup_inode(path)?;
let data = inode.read_as_vec()?;
proc.remove_cloexec_files();
@ -280,10 +280,10 @@ impl Syscall<'_> {
stack_pages: 8,
root_inode: proc.root_inode().clone(),
};
let (entry, sp) = loader.load(&vmar, &data, args, envs, path.clone())?;
let (entry, sp) = loader.load(&vmar, &data, args, envs, path.into())?;
// Modify exec path
proc.set_execute_path(&path);
proc.set_execute_path(path);
// TODO: use right signal
// self.zircon_process().signal_set(Signal::SIGNALED);

View File

@ -49,12 +49,12 @@ impl Syscall<'_> {
return Err(ZxError::INVALID_ARGS);
}
let datalen = len.min(224);
let data = buf.read_string(datalen as usize)?;
let data = buf.as_str(datalen as usize)?;
let proc = self.thread.proc();
let dlog = proc.get_object_with_rights::<DebugLog>(handle_value, Rights::WRITE)?;
dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data);
dlog.write(Severity::Info, options, self.thread.id(), proc.id(), data);
// print to kernel console
kernel_hal::console::console_write_str(&data);
kernel_hal::console::console_write_str(data);
if data.as_bytes().last() != Some(&b'\n') {
kernel_hal::console::console_write_str("\n");
}

View File

@ -22,7 +22,7 @@ impl Syscall<'_> {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let value = value_ptr.as_ref();
let proc = self.thread.proc();
let futex = proc.get_futex(value);
let new_owner = if new_futex_owner == INVALID_HANDLE {
@ -55,8 +55,8 @@ impl Syscall<'_> {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let requeue = requeue_ptr.as_ref()?;
let value = value_ptr.as_ref();
let requeue = requeue_ptr.as_ref();
if value_ptr.as_addr() == requeue_ptr.as_addr() {
return Err(ZxError::INVALID_ARGS);
}
@ -86,7 +86,7 @@ impl Syscall<'_> {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let value = value_ptr.as_ref();
let proc = self.thread.proc();
let futex = proc.get_futex(value);
futex.wake(count as usize);
@ -99,7 +99,7 @@ impl Syscall<'_> {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let value = value_ptr.as_ref();
let proc = self.thread.proc();
proc.get_futex(value).wake_single_owner();
Ok(())

View File

@ -308,7 +308,6 @@ impl Syscall<'_> {
// atomic_store_explicit(value_ptr, new_value, memory_order_release)
UserInPtr::<AtomicI32>::from(a0)
.as_ref()
.unwrap()
.store(a2 as i32, Ordering::Release);
let _ = self.sys_futex_wake(a0.into(), a1 as _);
let _ = self.sys_handle_close(a3 as _);

View File

@ -125,8 +125,7 @@ impl Syscall<'_> {
match property {
Property::Name => {
let length = buffer_size.min(MAX_NAME_LEN) as usize;
let s = UserInPtr::<u8>::from(buffer).read_string(length)?;
object.set_name(&s);
object.set_name(UserInPtr::<u8>::from(buffer).as_str(length)?);
Ok(())
}
Property::ProcessDebugAddr => {

View File

@ -2,7 +2,7 @@ use {super::*, core::convert::TryFrom, zircon_object::dev::*};
impl Syscall<'_> {
#[allow(clippy::too_many_arguments)]
/// Create a resource object for use with other DDK syscalls.
/// Create a resource object for use with other DDK syscalls.
pub fn sys_resource_create(
&self,
parent_rsrc: HandleValue,
@ -17,7 +17,7 @@ impl Syscall<'_> {
"resource.create: parent={:#x}, options={:#x}, base={:#X}, size={:#x}",
parent_rsrc, options, base, size
);
let name = name.read_string(name_size as usize)?;
let name = name.as_str(name_size as usize)?;
info!("name={:?}", name);
let proc = self.thread.proc();
let parent_rsrc = proc.get_object_with_rights::<Resource>(parent_rsrc, Rights::WRITE)?;
@ -25,7 +25,7 @@ impl Syscall<'_> {
let flags = ResourceFlags::from_bits(options & 0xFFFF_0000).ok_or(ZxError::INVALID_ARGS)?;
parent_rsrc.validate_ranged_resource(kind, base as usize, size as usize)?;
parent_rsrc.check_exclusive(flags)?;
let rsrc = Resource::create(&name, kind, base as usize, size as usize, flags);
let rsrc = Resource::create(name, kind, base as usize, size as usize, flags);
let handle = proc.add_handle(Handle::new(rsrc, Rights::DEFAULT_RESOURCE));
out.write(handle)?;
Ok(())

View File

@ -14,7 +14,7 @@ impl Syscall<'_> {
mut proc_handle: UserOutPtr<HandleValue>,
mut vmar_handle: UserOutPtr<HandleValue>,
) -> ZxResult {
let name = name.read_string(name_size)?;
let name = name.as_str(name_size)?;
info!(
"proc.create: job={:#x?}, name={:?}, options={:#x?}",
job, name, options,
@ -26,7 +26,7 @@ impl Syscall<'_> {
let job = proc
.get_object_with_rights::<Job>(job, Rights::MANAGE_PROCESS)
.or_else(|_| proc.get_object_with_rights::<Job>(job, Rights::WRITE))?;
let new_proc = Process::create(&job, &name)?;
let new_proc = Process::create(&job, name)?;
let new_vmar = new_proc.vmar();
let proc_handle_value = proc.add_handle(Handle::new(new_proc, Rights::DEFAULT_PROCESS));
let vmar_handle_value = proc.add_handle(Handle::new(
@ -57,7 +57,7 @@ impl Syscall<'_> {
options: u32,
mut thread_handle: UserOutPtr<HandleValue>,
) -> ZxResult {
let name = name.read_string(name_size)?;
let name = name.as_str(name_size)?;
info!(
"thread.create: proc={:#x?}, name={:?}, options={:#x?}",
proc_handle, name, options,
@ -67,7 +67,7 @@ impl Syscall<'_> {
}
let proc = self.thread.proc();
let process = proc.get_object_with_rights::<Process>(proc_handle, Rights::MANAGE_THREAD)?;
let thread = Thread::create(&process, &name)?;
let thread = Thread::create(&process, name)?;
let handle = proc.add_handle(Handle::new(thread, Rights::DEFAULT_THREAD));
thread_handle.write(handle)?;
Ok(())