Skip to content

Commit bff6133

Browse files
committed
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.
1 parent e134ae0 commit bff6133

File tree

1 file changed

+66
-37
lines changed

1 file changed

+66
-37
lines changed

rust/kernel/user_ptr.rs

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
//!
55
//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
66
7-
use alloc::vec;
8-
use alloc::vec::Vec;
9-
use core::u32;
10-
11-
use crate::c_types;
12-
use crate::error;
7+
use crate::{c_types, error, KernelResult};
8+
use alloc::{vec, vec::Vec};
9+
use core::{
10+
clone::Clone,
11+
mem::{size_of, MaybeUninit},
12+
};
1313

1414
extern "C" {
1515
fn rust_helper_access_ok(addr: *const c_types::c_void, len: c_types::c_ulong)
@@ -68,14 +68,13 @@ impl UserSlicePtr {
6868
/// appropriate permissions. Those checks are handled in the read
6969
/// and write methods.
7070
///
71+
/// # Safety
72+
///
7173
/// This is `unsafe` because if it is called within `set_fs(KERNEL_DS)`
7274
/// context then `access_ok` will not do anything. As a result the only
7375
/// place you can safely use this is with a `__user` pointer that was
7476
/// provided by the kernel.
75-
pub(crate) unsafe fn new(
76-
ptr: *mut c_types::c_void,
77-
length: usize,
78-
) -> error::KernelResult<UserSlicePtr> {
77+
pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> KernelResult<UserSlicePtr> {
7978
if rust_helper_access_ok(ptr, length as c_types::c_ulong) == 0 {
8079
return Err(error::Error::EFAULT);
8180
}
@@ -86,7 +85,7 @@ impl UserSlicePtr {
8685
///
8786
/// Returns `EFAULT` if the address does not currently point to
8887
/// mapped, readable memory.
89-
pub fn read_all(self) -> error::KernelResult<Vec<u8>> {
88+
pub fn read_all(self) -> KernelResult<Vec<u8>> {
9089
self.reader().read_all()
9190
}
9291

@@ -101,8 +100,8 @@ impl UserSlicePtr {
101100
/// mapped, writable memory (in which case some data from before the
102101
/// fault may be written), or `data` is larger than the user slice
103102
/// (in which case no data is written).
104-
pub fn write_all(self, data: &[u8]) -> error::KernelResult<()> {
105-
self.writer().write(data)
103+
pub fn write_all(self, data: &[u8]) -> KernelResult<()> {
104+
self.writer().write_slice(data)
106105
}
107106

108107
/// Constructs a [`UserSlicePtrWriter`].
@@ -111,6 +110,12 @@ impl UserSlicePtr {
111110
}
112111
}
113112

113+
impl Clone for UserSlicePtr {
114+
fn clone(&self) -> Self {
115+
UserSlicePtr(self.0, self.1)
116+
}
117+
}
118+
114119
/// A reader for [`UserSlicePtr`].
115120
///
116121
/// Used to incrementally read from the user slice.
@@ -133,9 +138,10 @@ impl UserSlicePtrReader {
133138
///
134139
/// Returns `EFAULT` if the address does not currently point to
135140
/// mapped, readable memory.
136-
pub fn read_all(&mut self) -> error::KernelResult<Vec<u8>> {
141+
pub fn read_all(&mut self) -> KernelResult<Vec<u8>> {
137142
let mut data = vec![0; self.1];
138-
self.read(&mut data)?;
143+
// SAFETY: The output buffer is valid as we just allocated it.
144+
unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
139145
Ok(data)
140146
}
141147

@@ -144,27 +150,40 @@ impl UserSlicePtrReader {
144150
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
145151
/// of the user slice or if the address does not currently point to mapped,
146152
/// readable memory.
147-
pub fn read(&mut self, data: &mut [u8]) -> error::KernelResult<()> {
148-
if data.len() > self.1 || data.len() > u32::MAX as usize {
153+
pub fn read_slice(&mut self, data: &mut [u8]) -> KernelResult<()> {
154+
// SAFETY: The output buffer is valid as it's coming from a live reference.
155+
unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
156+
}
157+
158+
/// Reads raw data from the user slice into a raw kernel buffer.
159+
///
160+
/// # Safety
161+
///
162+
/// The output buffer must be valid.
163+
pub unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> KernelResult<()> {
164+
if len > self.1 || len > u32::MAX as usize {
149165
return Err(error::Error::EFAULT);
150166
}
151-
let res = unsafe {
152-
rust_helper_copy_from_user(
153-
data.as_mut_ptr() as *mut c_types::c_void,
154-
self.0,
155-
data.len() as _,
156-
)
157-
};
167+
let res = rust_helper_copy_from_user(out as _, self.0, len as _);
158168
if res != 0 {
159169
return Err(error::Error::EFAULT);
160170
}
161171
// Since this is not a pointer to a valid object in our program,
162172
// we cannot use `add`, which has C-style rules for defined
163173
// behavior.
164-
self.0 = self.0.wrapping_add(data.len());
165-
self.1 -= data.len();
174+
self.0 = self.0.wrapping_add(len);
175+
self.1 -= len;
166176
Ok(())
167177
}
178+
179+
/// Reads the contents of a plain old data (POD) type from the user slice.
180+
pub fn read<T: Copy>(&mut self) -> KernelResult<T> {
181+
let mut out = MaybeUninit::<T>::uninit();
182+
// SAFETY: The buffer is valid it was just allocated.
183+
unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>())? };
184+
// SAFETY: We just initialised the data.
185+
Ok(unsafe { out.assume_init() })
186+
}
168187
}
169188

170189
/// A writer for [`UserSlicePtr`].
@@ -190,25 +209,35 @@ impl UserSlicePtrWriter {
190209
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
191210
/// of the user slice or if the address does not currently point to mapped,
192211
/// writable memory.
193-
pub fn write(&mut self, data: &[u8]) -> error::KernelResult<()> {
194-
if data.len() > self.1 || data.len() > u32::MAX as usize {
212+
pub fn write_slice(&mut self, data: &[u8]) -> KernelResult<()> {
213+
// SAFETY: The input buffer is valid as it's coming from a live reference.
214+
unsafe { self.write_raw(data.as_ptr(), data.len()) }
215+
}
216+
217+
/// Writes raw data to the user slice from a raw kernel buffer.
218+
///
219+
/// # Safety
220+
///
221+
/// The input buffer must be valid.
222+
unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> KernelResult<()> {
223+
if len > self.1 || len > u32::MAX as usize {
195224
return Err(error::Error::EFAULT);
196225
}
197-
let res = unsafe {
198-
rust_helper_copy_to_user(
199-
self.0,
200-
data.as_ptr() as *const c_types::c_void,
201-
data.len() as _,
202-
)
203-
};
226+
let res = rust_helper_copy_to_user(self.0, data as _, len as _);
204227
if res != 0 {
205228
return Err(error::Error::EFAULT);
206229
}
207230
// Since this is not a pointer to a valid object in our program,
208231
// we cannot use `add`, which has C-style rules for defined
209232
// behavior.
210-
self.0 = self.0.wrapping_add(data.len());
211-
self.1 -= data.len();
233+
self.0 = self.0.wrapping_add(len);
234+
self.1 -= len;
212235
Ok(())
213236
}
237+
238+
/// Writes the contents of a plain old data (POD) type into the user slice.
239+
pub fn write<T: Copy>(&mut self, data: &T) -> KernelResult<()> {
240+
// SAFETY: The input buffer is valid as it's coming from a live reference.
241+
unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
242+
}
214243
}

0 commit comments

Comments
 (0)