From bff61338d39c064795e0d3c7fff089e06a312000 Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Wed, 17 Mar 2021 23:13:53 +0000 Subject: [PATCH] Add functions to read/write plain old data (POD) types. Other minor changes: * Made UserSlicePtr::new public. This is to allow drivers to access user buffers that don't come directly from file operations. * Ability to clone UserSlicePtr. This is for cases when we need to read then write; so we clone before creating a reader/writer. --- rust/kernel/user_ptr.rs | 103 +++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 37 deletions(-) diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs index fdab26d2f4bb25..35a7f6b8c0a985 100644 --- a/rust/kernel/user_ptr.rs +++ b/rust/kernel/user_ptr.rs @@ -4,12 +4,12 @@ //! //! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h) -use alloc::vec; -use alloc::vec::Vec; -use core::u32; - -use crate::c_types; -use crate::error; +use crate::{c_types, error, KernelResult}; +use alloc::{vec, vec::Vec}; +use core::{ + clone::Clone, + mem::{size_of, MaybeUninit}, +}; extern "C" { fn rust_helper_access_ok(addr: *const c_types::c_void, len: c_types::c_ulong) @@ -68,14 +68,13 @@ impl UserSlicePtr { /// appropriate permissions. Those checks are handled in the read /// and write methods. /// + /// # Safety + /// /// This is `unsafe` because if it is called within `set_fs(KERNEL_DS)` /// context then `access_ok` will not do anything. As a result the only /// place you can safely use this is with a `__user` pointer that was /// provided by the kernel. - pub(crate) unsafe fn new( - ptr: *mut c_types::c_void, - length: usize, - ) -> error::KernelResult { + pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> KernelResult { if rust_helper_access_ok(ptr, length as c_types::c_ulong) == 0 { return Err(error::Error::EFAULT); } @@ -86,7 +85,7 @@ impl UserSlicePtr { /// /// Returns `EFAULT` if the address does not currently point to /// mapped, readable memory. - pub fn read_all(self) -> error::KernelResult> { + pub fn read_all(self) -> KernelResult> { self.reader().read_all() } @@ -101,8 +100,8 @@ impl UserSlicePtr { /// mapped, writable memory (in which case some data from before the /// fault may be written), or `data` is larger than the user slice /// (in which case no data is written). - pub fn write_all(self, data: &[u8]) -> error::KernelResult<()> { - self.writer().write(data) + pub fn write_all(self, data: &[u8]) -> KernelResult<()> { + self.writer().write_slice(data) } /// Constructs a [`UserSlicePtrWriter`]. @@ -111,6 +110,12 @@ impl UserSlicePtr { } } +impl Clone for UserSlicePtr { + fn clone(&self) -> Self { + UserSlicePtr(self.0, self.1) + } +} + /// A reader for [`UserSlicePtr`]. /// /// Used to incrementally read from the user slice. @@ -133,9 +138,10 @@ impl UserSlicePtrReader { /// /// Returns `EFAULT` if the address does not currently point to /// mapped, readable memory. - pub fn read_all(&mut self) -> error::KernelResult> { + pub fn read_all(&mut self) -> KernelResult> { let mut data = vec![0; self.1]; - self.read(&mut data)?; + // SAFETY: The output buffer is valid as we just allocated it. + unsafe { self.read_raw(data.as_mut_ptr(), data.len())? }; Ok(data) } @@ -144,27 +150,40 @@ impl UserSlicePtrReader { /// Returns `EFAULT` if the byte slice is bigger than the remaining size /// of the user slice or if the address does not currently point to mapped, /// readable memory. - pub fn read(&mut self, data: &mut [u8]) -> error::KernelResult<()> { - if data.len() > self.1 || data.len() > u32::MAX as usize { + pub fn read_slice(&mut self, data: &mut [u8]) -> KernelResult<()> { + // SAFETY: The output buffer is valid as it's coming from a live reference. + unsafe { self.read_raw(data.as_mut_ptr(), data.len()) } + } + + /// Reads raw data from the user slice into a raw kernel buffer. + /// + /// # Safety + /// + /// The output buffer must be valid. + pub unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> KernelResult<()> { + if len > self.1 || len > u32::MAX as usize { return Err(error::Error::EFAULT); } - let res = unsafe { - rust_helper_copy_from_user( - data.as_mut_ptr() as *mut c_types::c_void, - self.0, - data.len() as _, - ) - }; + let res = rust_helper_copy_from_user(out as _, self.0, len as _); if res != 0 { return Err(error::Error::EFAULT); } // Since this is not a pointer to a valid object in our program, // we cannot use `add`, which has C-style rules for defined // behavior. - self.0 = self.0.wrapping_add(data.len()); - self.1 -= data.len(); + self.0 = self.0.wrapping_add(len); + self.1 -= len; Ok(()) } + + /// Reads the contents of a plain old data (POD) type from the user slice. + pub fn read(&mut self) -> KernelResult { + let mut out = MaybeUninit::::uninit(); + // SAFETY: The buffer is valid it was just allocated. + unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::())? }; + // SAFETY: We just initialised the data. + Ok(unsafe { out.assume_init() }) + } } /// A writer for [`UserSlicePtr`]. @@ -190,25 +209,35 @@ impl UserSlicePtrWriter { /// Returns `EFAULT` if the byte slice is bigger than the remaining size /// of the user slice or if the address does not currently point to mapped, /// writable memory. - pub fn write(&mut self, data: &[u8]) -> error::KernelResult<()> { - if data.len() > self.1 || data.len() > u32::MAX as usize { + pub fn write_slice(&mut self, data: &[u8]) -> KernelResult<()> { + // SAFETY: The input buffer is valid as it's coming from a live reference. + unsafe { self.write_raw(data.as_ptr(), data.len()) } + } + + /// Writes raw data to the user slice from a raw kernel buffer. + /// + /// # Safety + /// + /// The input buffer must be valid. + unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> KernelResult<()> { + if len > self.1 || len > u32::MAX as usize { return Err(error::Error::EFAULT); } - let res = unsafe { - rust_helper_copy_to_user( - self.0, - data.as_ptr() as *const c_types::c_void, - data.len() as _, - ) - }; + let res = rust_helper_copy_to_user(self.0, data as _, len as _); if res != 0 { return Err(error::Error::EFAULT); } // Since this is not a pointer to a valid object in our program, // we cannot use `add`, which has C-style rules for defined // behavior. - self.0 = self.0.wrapping_add(data.len()); - self.1 -= data.len(); + self.0 = self.0.wrapping_add(len); + self.1 -= len; Ok(()) } + + /// Writes the contents of a plain old data (POD) type into the user slice. + pub fn write(&mut self, data: &T) -> KernelResult<()> { + // SAFETY: The input buffer is valid as it's coming from a live reference. + unsafe { self.write_raw(data as *const T as _, size_of::()) } + } }