Skip to content

Commit 832575d

Browse files
authored
Merge pull request #117 from Rust-for-Linux/user_ptr
Add functions to read/write plain old data (POD) types.
2 parents 72904b1 + 176ba9e commit 832575d

File tree

2 files changed

+87
-32
lines changed

2 files changed

+87
-32
lines changed

rust/kernel/sysctl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl SysctlStorage for atomic::AtomicBool {
7676
} else {
7777
b"0\n"
7878
};
79-
(value.len(), data.write(value))
79+
(value.len(), data.write_slice(value))
8080
}
8181
}
8282

rust/kernel/user_ptr.rs

+86-31
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
//!
55
//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
66
7-
use crate::{c_types, error};
7+
use crate::{c_types, error, KernelResult};
88
use alloc::vec::Vec;
9+
use core::mem::{size_of, MaybeUninit};
910

1011
extern "C" {
1112
fn rust_helper_access_ok(addr: *const c_types::c_void, len: c_types::c_ulong)
@@ -24,6 +25,30 @@ extern "C" {
2425
) -> c_types::c_ulong;
2526
}
2627

28+
/// Specifies that a type is safely readable from byte slices.
29+
///
30+
/// Not all types can be safely read from byte slices; examples from
31+
/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
32+
/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
33+
///
34+
/// # Safety
35+
///
36+
/// Implementers must ensure that the type is made up only of types that can be safely read from
37+
/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
38+
pub unsafe trait ReadableFromBytes {}
39+
40+
// SAFETY: All bit patterns are acceptable values of the types below.
41+
unsafe impl ReadableFromBytes for u8 {}
42+
unsafe impl ReadableFromBytes for u16 {}
43+
unsafe impl ReadableFromBytes for u32 {}
44+
unsafe impl ReadableFromBytes for u64 {}
45+
unsafe impl ReadableFromBytes for usize {}
46+
unsafe impl ReadableFromBytes for i8 {}
47+
unsafe impl ReadableFromBytes for i16 {}
48+
unsafe impl ReadableFromBytes for i32 {}
49+
unsafe impl ReadableFromBytes for i64 {}
50+
unsafe impl ReadableFromBytes for isize {}
51+
2752
/// A reference to an area in userspace memory, which can be either
2853
/// read-only or read-write.
2954
///
@@ -64,14 +89,18 @@ impl UserSlicePtr {
6489
/// appropriate permissions. Those checks are handled in the read
6590
/// and write methods.
6691
///
92+
/// # Safety
93+
///
6794
/// This is `unsafe` because if it is called within `set_fs(KERNEL_DS)`
6895
/// context then `access_ok` will not do anything. As a result the only
6996
/// place you can safely use this is with a `__user` pointer that was
7097
/// provided by the kernel.
71-
pub(crate) unsafe fn new(
72-
ptr: *mut c_types::c_void,
73-
length: usize,
74-
) -> error::KernelResult<UserSlicePtr> {
98+
///
99+
/// Callers must also be careful to avoid time-of-check-time-of-use
100+
/// (TOCTOU) issues. The simplest way is to create a single instance of
101+
/// [`UserSlicePtr`] per user memory block as it reads each byte at
102+
/// most once.
103+
pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> KernelResult<UserSlicePtr> {
75104
if rust_helper_access_ok(ptr, length as c_types::c_ulong) == 0 {
76105
return Err(error::Error::EFAULT);
77106
}
@@ -82,7 +111,7 @@ impl UserSlicePtr {
82111
///
83112
/// Returns `EFAULT` if the address does not currently point to
84113
/// mapped, readable memory.
85-
pub fn read_all(self) -> error::KernelResult<Vec<u8>> {
114+
pub fn read_all(self) -> KernelResult<Vec<u8>> {
86115
self.reader().read_all()
87116
}
88117

@@ -97,14 +126,22 @@ impl UserSlicePtr {
97126
/// mapped, writable memory (in which case some data from before the
98127
/// fault may be written), or `data` is larger than the user slice
99128
/// (in which case no data is written).
100-
pub fn write_all(self, data: &[u8]) -> error::KernelResult<()> {
101-
self.writer().write(data)
129+
pub fn write_all(self, data: &[u8]) -> KernelResult<()> {
130+
self.writer().write_slice(data)
102131
}
103132

104133
/// Constructs a [`UserSlicePtrWriter`].
105134
pub fn writer(self) -> UserSlicePtrWriter {
106135
UserSlicePtrWriter(self.0, self.1)
107136
}
137+
138+
/// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
139+
pub fn reader_writer(self) -> (UserSlicePtrReader, UserSlicePtrWriter) {
140+
(
141+
UserSlicePtrReader(self.0, self.1),
142+
UserSlicePtrWriter(self.0, self.1),
143+
)
144+
}
108145
}
109146

110147
/// A reader for [`UserSlicePtr`].
@@ -133,7 +170,8 @@ impl UserSlicePtrReader {
133170
let mut data = Vec::<u8>::new();
134171
data.try_reserve_exact(self.1)?;
135172
data.resize(self.1, 0);
136-
self.read(&mut data)?;
173+
// SAFETY: The output buffer is valid as we just allocated it.
174+
unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
137175
Ok(data)
138176
}
139177

@@ -142,27 +180,40 @@ impl UserSlicePtrReader {
142180
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
143181
/// of the user slice or if the address does not currently point to mapped,
144182
/// readable memory.
145-
pub fn read(&mut self, data: &mut [u8]) -> error::KernelResult<()> {
146-
if data.len() > self.1 || data.len() > u32::MAX as usize {
183+
pub fn read_slice(&mut self, data: &mut [u8]) -> KernelResult<()> {
184+
// SAFETY: The output buffer is valid as it's coming from a live reference.
185+
unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
186+
}
187+
188+
/// Reads raw data from the user slice into a raw kernel buffer.
189+
///
190+
/// # Safety
191+
///
192+
/// The output buffer must be valid.
193+
pub unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> KernelResult<()> {
194+
if len > self.1 || len > u32::MAX as usize {
147195
return Err(error::Error::EFAULT);
148196
}
149-
let res = unsafe {
150-
rust_helper_copy_from_user(
151-
data.as_mut_ptr() as *mut c_types::c_void,
152-
self.0,
153-
data.len() as _,
154-
)
155-
};
197+
let res = rust_helper_copy_from_user(out as _, self.0, len as _);
156198
if res != 0 {
157199
return Err(error::Error::EFAULT);
158200
}
159201
// Since this is not a pointer to a valid object in our program,
160202
// we cannot use `add`, which has C-style rules for defined
161203
// behavior.
162-
self.0 = self.0.wrapping_add(data.len());
163-
self.1 -= data.len();
204+
self.0 = self.0.wrapping_add(len);
205+
self.1 -= len;
164206
Ok(())
165207
}
208+
209+
/// Reads the contents of a plain old data (POD) type from the user slice.
210+
pub fn read<T: ReadableFromBytes>(&mut self) -> KernelResult<T> {
211+
let mut out = MaybeUninit::<T>::uninit();
212+
// SAFETY: The buffer is valid as it was just allocated.
213+
unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
214+
// SAFETY: We just initialised the data.
215+
Ok(unsafe { out.assume_init() })
216+
}
166217
}
167218

168219
/// A writer for [`UserSlicePtr`].
@@ -188,25 +239,29 @@ impl UserSlicePtrWriter {
188239
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
189240
/// of the user slice or if the address does not currently point to mapped,
190241
/// writable memory.
191-
pub fn write(&mut self, data: &[u8]) -> error::KernelResult<()> {
192-
if data.len() > self.1 || data.len() > u32::MAX as usize {
242+
pub fn write_slice(&mut self, data: &[u8]) -> KernelResult<()> {
243+
// SAFETY: The input buffer is valid as it's coming from a live reference.
244+
unsafe { self.write_raw(data.as_ptr(), data.len()) }
245+
}
246+
247+
/// Writes raw data to the user slice from a raw kernel buffer.
248+
///
249+
/// # Safety
250+
///
251+
/// The input buffer must be valid.
252+
unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> KernelResult<()> {
253+
if len > self.1 || len > u32::MAX as usize {
193254
return Err(error::Error::EFAULT);
194255
}
195-
let res = unsafe {
196-
rust_helper_copy_to_user(
197-
self.0,
198-
data.as_ptr() as *const c_types::c_void,
199-
data.len() as _,
200-
)
201-
};
256+
let res = rust_helper_copy_to_user(self.0, data as _, len as _);
202257
if res != 0 {
203258
return Err(error::Error::EFAULT);
204259
}
205260
// Since this is not a pointer to a valid object in our program,
206261
// we cannot use `add`, which has C-style rules for defined
207262
// behavior.
208-
self.0 = self.0.wrapping_add(data.len());
209-
self.1 -= data.len();
263+
self.0 = self.0.wrapping_add(len);
264+
self.1 -= len;
210265
Ok(())
211266
}
212267
}

0 commit comments

Comments
 (0)