Skip to content

Commit 187283f

Browse files
authored
Merge pull request #157 from wedsonaf/access_ok
`access_ok` is no longer needed.
2 parents a629f05 + 472181f commit 187283f

File tree

4 files changed

+18
-58
lines changed

4 files changed

+18
-58
lines changed

rust/helpers.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ void rust_helper_BUG(void)
1010
BUG();
1111
}
1212

13-
int rust_helper_access_ok(const void __user *addr, unsigned long n)
14-
{
15-
return access_ok(addr, n);
16-
}
17-
1813
unsigned long rust_helper_copy_from_user(void *to, const void __user *from, unsigned long n)
1914
{
2015
return copy_from_user(to, from, n);

rust/kernel/file_operations.rs

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
100100
offset: *mut bindings::loff_t,
101101
) -> c_types::c_ssize_t {
102102
from_kernel_result! {
103-
let mut data = UserSlicePtr::new(buf as *mut c_types::c_void, len)?.writer();
103+
let mut data = UserSlicePtr::new(buf as *mut c_types::c_void, len).writer();
104104
let f = &*((*file).private_data as *const T);
105105
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
106106
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
@@ -117,7 +117,7 @@ unsafe extern "C" fn write_callback<T: FileOperations>(
117117
offset: *mut bindings::loff_t,
118118
) -> c_types::c_ssize_t {
119119
from_kernel_result! {
120-
let mut data = UserSlicePtr::new(buf as *mut c_types::c_void, len)?.reader();
120+
let mut data = UserSlicePtr::new(buf as *mut c_types::c_void, len).reader();
121121
let f = &*((*file).private_data as *const T);
122122
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
123123
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
@@ -359,26 +359,12 @@ pub struct IoctlCommand {
359359

360360
impl IoctlCommand {
361361
/// Constructs a new [`IoctlCommand`].
362-
///
363-
/// # Safety
364-
///
365-
/// The caller must ensure that `fs` is compatible with `arg` and the original caller's
366-
/// context. For example, if the original caller is from userland (e.g., through the ioctl
367-
/// syscall), then `arg` is untrusted and `fs` should therefore be `USER_DS`.
368-
unsafe fn new(cmd: u32, arg: usize) -> Self {
369-
let user_slice = {
370-
let dir = (cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
371-
if dir == bindings::_IOC_NONE {
372-
None
373-
} else {
374-
let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
375-
376-
// SAFETY: We only create one instance of the user slice, so TOCTOU issues are not
377-
// possible. The `set_fs` requirements are imposed on the caller.
378-
UserSlicePtr::new(arg as _, size as _).ok()
379-
}
380-
};
362+
fn new(cmd: u32, arg: usize) -> Self {
363+
let size = (cmd >> bindings::_IOC_SIZESHIFT) & bindings::_IOC_SIZEMASK;
381364

365+
// SAFETY: We only create one instance of the user slice per ioctl call, so TOCTOU issues
366+
// are not possible.
367+
let user_slice = Some(unsafe { UserSlicePtr::new(arg as _, size as _) });
382368
Self {
383369
cmd,
384370
arg,
@@ -398,7 +384,7 @@ impl IoctlCommand {
398384
return T::pure(handler, file, self.cmd, self.arg);
399385
}
400386

401-
let data = self.user_slice.take().ok_or(Error::EFAULT)?;
387+
let data = self.user_slice.take().ok_or(Error::EINVAL)?;
402388
const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
403389
match dir {
404390
bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),

rust/kernel/sysctl.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,7 @@ unsafe extern "C" fn proc_handler<T: SysctlStorage>(
106106
return 0;
107107
}
108108

109-
let data = match UserSlicePtr::new(buffer, *len) {
110-
Ok(ptr) => ptr,
111-
Err(e) => return e.to_kernel_errno(),
112-
};
109+
let data = UserSlicePtr::new(buffer, *len);
113110
let storage = &*((*ctl).data as *const T);
114111
let (bytes_processed, result) = if write != 0 {
115112
let data = match data.read_all() {

rust/kernel/user_ptr.rs

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ use alloc::vec::Vec;
99
use core::mem::{size_of, MaybeUninit};
1010

1111
extern "C" {
12-
fn rust_helper_access_ok(addr: *const c_types::c_void, len: c_types::c_ulong)
13-
-> c_types::c_int;
14-
1512
fn rust_helper_copy_from_user(
1613
to: *mut c_types::c_void,
1714
from: *const c_types::c_void,
@@ -69,42 +66,27 @@ unsafe impl ReadableFromBytes for isize {}
6966
/// obtaining multiple readers on a given [`UserSlicePtr`], and the readers
7067
/// only permitting forward reads.
7168
///
72-
/// Constructing a [`UserSlicePtr`] only checks that the range is in valid
73-
/// userspace memory, and does not depend on the current process (and
74-
/// can safely be constructed inside a kernel thread with no current
75-
/// userspace process). Reads and writes wrap the kernel APIs
76-
/// `copy_from_user` and `copy_to_user`, and check the memory map of the
77-
/// current process.
69+
/// Constructing a [`UserSlicePtr`] performs no checks on the provided
70+
/// address and length, it can safely be constructed inside a kernel thread
71+
/// with no current userspace process. Reads and writes wrap the kernel APIs
72+
/// `copy_from_user` and `copy_to_user`, which check the memory map of the
73+
/// current process and enforce that the address range is within the user
74+
/// range (no additional calls to `access_ok` are needed).
7875
///
7976
/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html
8077
pub struct UserSlicePtr(*mut c_types::c_void, usize);
8178

8279
impl UserSlicePtr {
8380
/// Constructs a user slice from a raw pointer and a length in bytes.
8481
///
85-
/// Checks that the provided range is within the legal area for
86-
/// userspace memory, using `access_ok` (e.g., on i386, the range
87-
/// must be within the first 3 GiB), but does not check that
88-
/// the actual pages are mapped in the current process with
89-
/// appropriate permissions. Those checks are handled in the read
90-
/// and write methods.
91-
///
9282
/// # Safety
9383
///
94-
/// This is `unsafe` because if it is called within `set_fs(KERNEL_DS)`
95-
/// context then `access_ok` will not do anything. As a result the only
96-
/// place you can safely use this is with a `__user` pointer that was
97-
/// provided by the kernel.
98-
///
99-
/// Callers must also be careful to avoid time-of-check-time-of-use
84+
/// Callers must be careful to avoid time-of-check-time-of-use
10085
/// (TOCTOU) issues. The simplest way is to create a single instance of
10186
/// [`UserSlicePtr`] per user memory block as it reads each byte at
10287
/// most once.
103-
pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> KernelResult<UserSlicePtr> {
104-
if rust_helper_access_ok(ptr, length as c_types::c_ulong) == 0 {
105-
return Err(error::Error::EFAULT);
106-
}
107-
Ok(UserSlicePtr(ptr, length))
88+
pub unsafe fn new(ptr: *mut c_types::c_void, length: usize) -> Self {
89+
UserSlicePtr(ptr, length)
10890
}
10991

11092
/// Reads the entirety of the user slice.

0 commit comments

Comments
 (0)