summaryrefslogtreecommitdiff
path: root/rust/kernel/uaccess.rs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-08-03 13:49:10 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-08-03 13:49:10 -0700
commit352af6a011d586ff042db4b2d1f7421875eb8a14 (patch)
tree44f7ba337b3f49ae9454361967d0b0e13a792a73 /rust/kernel/uaccess.rs
parent186f3edfdd41f2ae87fc40a9ccba52a3bf930994 (diff)
parentdff64b072708ffef23c117fa1ee1ea59eb417807 (diff)
Merge tag 'rust-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Enable a set of Clippy lints: 'ptr_as_ptr', 'ptr_cast_constness', 'as_ptr_cast_mut', 'as_underscore', 'cast_lossless' and 'ref_as_ptr' These are intended to avoid type casts with the 'as' operator, which are quite powerful, into restricted variants that are less powerful and thus should help to avoid mistakes - Remove the 'author' key now that most instances were moved to the plural one in the previous cycle 'kernel' crate: - New 'bug' module: add 'warn_on!' macro which reuses the existing 'BUG'/'WARN' infrastructure, i.e. it respects the usual sysctls and kernel parameters: warn_on!(value == 42); To avoid duplicating the assembly code, the same strategy is followed as for the static branch code in order to share the assembly between both C and Rust This required a few rearrangements on C arch headers -- the existing C macros should still generate the same outputs, thus no functional change expected there - 'workqueue' module: add delayed work items, including a 'DelayedWork' struct, a 'impl_has_delayed_work!' macro and an 'enqueue_delayed' method, e.g.: /// Enqueue the struct for execution on the system workqueue, /// where its value will be printed 42 jiffies later. fn print_later(value: Arc<MyStruct>) { let _ = workqueue::system().enqueue_delayed(value, 42); } - New 'bits' module: add support for 'bit' and 'genmask' functions, with runtime- and compile-time variants, e.g.: static_assert!(0b00010000 == bit_u8(4)); static_assert!(0b00011110 == genmask_u8(1..=4)); assert!(checked_bit_u32(u32::BITS).is_none()); - 'uaccess' module: add 'UserSliceReader::strcpy_into_buf', which reads NUL-terminated strings from userspace into a '&CStr' Introduce 'UserPtr' newtype, similar in purpose to '__user' in C, to minimize mistakes handling userspace pointers, including mixing them up with integers and leaking them via the 'Debug' trait. Add it to the prelude, too - Start preparations for the replacement of our custom 'CStr' type with the analogous type in the 'core' standard library. This will take place across several cycles to make it easier. For this one, it includes a new 'fmt' module, using upstream method names and some other cleanups Replace 'fmt!' with a re-export, which helps Clippy lint properly, and clean up the found 'uninlined-format-args' instances - 'dma' module: - Clarify wording and be consistent in 'coherent' nomenclature - Convert the 'read!()' and 'write!()' macros to return a 'Result' - Add 'as_slice()', 'write()' methods in 'CoherentAllocation' - Expose 'count()' and 'size()' in 'CoherentAllocation' and add the corresponding type invariants - Implement 'CoherentAllocation::dma_handle_with_offset()' - 'time' module: - Make 'Instant' generic over clock source. This allows the compiler to assert that arithmetic expressions involving the 'Instant' use 'Instants' based on the same clock source - Make 'HrTimer' generic over the timer mode. 'HrTimer' timers take a 'Duration' or an 'Instant' when setting the expiry time, depending on the timer mode. With this change, the compiler can check the type matches the timer mode - Add an abstraction for 'fsleep'. 'fsleep' is a flexible sleep function that will select an appropriate sleep method depending on the requested sleep time - Avoid 64-bit divisions on 32-bit hardware when calculating timestamps - Seal the 'HrTimerMode' trait. This prevents users of the 'HrTimerMode' from implementing the trait on their own types - Pass the correct timer mode ID to 'hrtimer_start_range_ns()' - 'list' module: remove 'OFFSET' constants, allowing to remove pointer arithmetic; now 'impl_list_item!' invokes 'impl_has_list_links!' or 'impl_has_list_links_self_ptr!'. Other simplifications too - 'types' module: remove 'ForeignOwnable::PointedTo' in favor of a constant, which avoids exposing the type of the opaque pointer, and require 'into_foreign' to return non-null Remove the 'Either<L, R>' type as well. It is unused, and we want to encourage the use of custom enums for concrete use cases - 'sync' module: implement 'Borrow' and 'BorrowMut' for 'Arc' types to allow them to be used in generic APIs - 'alloc' module: implement 'Borrow' and 'BorrowMut' for 'Box<T, A>'; and 'Borrow', 'BorrowMut' and 'Default' for 'Vec<T, A>' - 'Opaque' type: add 'cast_from' method to perform a restricted cast that cannot change the inner type and use it in callers of 'container_of!'. Rename 'raw_get' to 'cast_into' to match it - 'rbtree' module: add 'is_empty' method - 'sync' module: new 'aref' submodule to hold 'AlwaysRefCounted' and 'ARef', which are moved from the too general 'types' module which we want to reduce or eventually remove. Also fix a safety comment in 'static_lock_class' 'pin-init' crate: - Add 'impl<T, E> [Pin]Init<T, E> for Result<T, E>', so results are now (pin-)initializers - Add 'Zeroable::init_zeroed()' that delegates to 'init_zeroed()' - New 'zeroed()', a safe version of 'mem::zeroed()' and also provide it via 'Zeroable::zeroed()' - Implement 'Zeroable' for 'Option<&T>', 'Option<&mut T>' and for 'Option<[unsafe] [extern "abi"] fn(...args...) -> ret>' for '"Rust"' and '"C"' ABIs and up to 20 arguments - Changed blanket impls of 'Init' and 'PinInit' from 'impl<T, E> [Pin]Init<T, E> for T' to 'impl<T> [Pin]Init<T> for T' - Renamed 'zeroed()' to 'init_zeroed()' - Upstream dev news: improve CI more to deny warnings, use '--all-targets'. Check the synchronization status of the two '-next' branches in upstream and the kernel MAINTAINERS: - Add Vlastimil Babka, Liam R. Howlett, Uladzislau Rezki and Lorenzo Stoakes as reviewers (thanks everyone) And a few other cleanups and improvements" * tag 'rust-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (76 commits) rust: Add warn_on macro arm64/bug: Add ARCH_WARN_ASM macro for BUG/WARN asm code sharing with Rust riscv/bug: Add ARCH_WARN_ASM macro for BUG/WARN asm code sharing with Rust x86/bug: Add ARCH_WARN_ASM macro for BUG/WARN asm code sharing with Rust rust: kernel: move ARef and AlwaysRefCounted to sync::aref rust: sync: fix safety comment for `static_lock_class` rust: types: remove `Either<L, R>` rust: kernel: use `core::ffi::CStr` method names rust: str: add `CStr` methods matching `core::ffi::CStr` rust: str: remove unnecessary qualification rust: use `kernel::{fmt,prelude::fmt!}` rust: kernel: add `fmt` module rust: kernel: remove `fmt!`, fix clippy::uninlined-format-args scripts: rust: emit path candidates in panic message scripts: rust: replace length checks with match rust: list: remove nonexistent generic parameter in link rust: bits: add support for bits/genmask macros rust: list: remove OFFSET constants rust: list: add `impl_list_item!` examples rust: list: use fully qualified path ...
Diffstat (limited to 'rust/kernel/uaccess.rs')
-rw-r--r--rust/kernel/uaccess.rs167
1 files changed, 153 insertions, 14 deletions
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 6d70edd8086a..a8fb4764185a 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -8,14 +8,57 @@ use crate::{
alloc::{Allocator, Flags},
bindings,
error::Result,
- ffi::c_void,
+ ffi::{c_char, c_void},
prelude::*,
transmute::{AsBytes, FromBytes},
};
use core::mem::{size_of, MaybeUninit};
-/// The type used for userspace addresses.
-pub type UserPtr = usize;
+/// A pointer into userspace.
+///
+/// This is the Rust equivalent to C pointers tagged with `__user`.
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+pub struct UserPtr(*mut c_void);
+
+impl UserPtr {
+ /// Create a `UserPtr` from an integer representing the userspace address.
+ #[inline]
+ pub fn from_addr(addr: usize) -> Self {
+ Self(addr as *mut c_void)
+ }
+
+ /// Create a `UserPtr` from a pointer representing the userspace address.
+ #[inline]
+ pub fn from_ptr(addr: *mut c_void) -> Self {
+ Self(addr)
+ }
+
+ /// Cast this userspace pointer to a raw const void pointer.
+ ///
+ /// It is up to the caller to use the returned pointer correctly.
+ #[inline]
+ pub fn as_const_ptr(self) -> *const c_void {
+ self.0
+ }
+
+ /// Cast this userspace pointer to a raw mutable void pointer.
+ ///
+ /// It is up to the caller to use the returned pointer correctly.
+ #[inline]
+ pub fn as_mut_ptr(self) -> *mut c_void {
+ self.0
+ }
+
+ /// Increment this user pointer by `add` bytes.
+ ///
+ /// This addition is wrapping, so wrapping around the address space does not result in a panic
+ /// even if `CONFIG_RUST_OVERFLOW_CHECKS` is enabled.
+ #[inline]
+ pub fn wrapping_byte_add(self, add: usize) -> UserPtr {
+ UserPtr(self.0.wrapping_byte_add(add))
+ }
+}
/// A pointer to an area in userspace memory, which can be either read-only or read-write.
///
@@ -177,7 +220,7 @@ impl UserSliceReader {
pub fn skip(&mut self, num_skip: usize) -> Result {
// Update `self.length` first since that's the fallible part of this operation.
self.length = self.length.checked_sub(num_skip).ok_or(EFAULT)?;
- self.ptr = self.ptr.wrapping_add(num_skip);
+ self.ptr = self.ptr.wrapping_byte_add(num_skip);
Ok(())
}
@@ -224,11 +267,11 @@ impl UserSliceReader {
}
// SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write
// that many bytes to it.
- let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) };
+ let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr.as_const_ptr(), len) };
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
Ok(())
}
@@ -240,7 +283,7 @@ impl UserSliceReader {
pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
// SAFETY: The types are compatible and `read_raw` doesn't write uninitialized bytes to
// `out`.
- let out = unsafe { &mut *(out as *mut [u8] as *mut [MaybeUninit<u8>]) };
+ let out = unsafe { &mut *(core::ptr::from_mut(out) as *mut [MaybeUninit<u8>]) };
self.read_raw(out)
}
@@ -262,14 +305,14 @@ impl UserSliceReader {
let res = unsafe {
bindings::_copy_from_user(
out.as_mut_ptr().cast::<c_void>(),
- self.ptr as *const c_void,
+ self.ptr.as_const_ptr(),
len,
)
};
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
// SAFETY: The read above has initialized all bytes in `out`, and since `T` implements
// `FromBytes`, any bit-pattern is a valid value for this type.
@@ -291,6 +334,65 @@ impl UserSliceReader {
unsafe { buf.inc_len(len) };
Ok(())
}
+
+ /// Read a NUL-terminated string from userspace and return it.
+ ///
+ /// The string is read into `buf` and a NUL-terminator is added if the end of `buf` is reached.
+ /// Since there must be space to add a NUL-terminator, the buffer must not be empty. The
+ /// returned `&CStr` points into `buf`.
+ ///
+ /// Fails with [`EFAULT`] if the read happens on a bad address (some data may have been
+ /// copied).
+ #[doc(alias = "strncpy_from_user")]
+ pub fn strcpy_into_buf<'buf>(self, buf: &'buf mut [u8]) -> Result<&'buf CStr> {
+ if buf.is_empty() {
+ return Err(EINVAL);
+ }
+
+ // SAFETY: The types are compatible and `strncpy_from_user` doesn't write uninitialized
+ // bytes to `buf`.
+ let mut dst = unsafe { &mut *(core::ptr::from_mut(buf) as *mut [MaybeUninit<u8>]) };
+
+ // We never read more than `self.length` bytes.
+ if dst.len() > self.length {
+ dst = &mut dst[..self.length];
+ }
+
+ let mut len = raw_strncpy_from_user(dst, self.ptr)?;
+ if len < dst.len() {
+ // Add one to include the NUL-terminator.
+ len += 1;
+ } else if len < buf.len() {
+ // This implies that `len == dst.len() < buf.len()`.
+ //
+ // This means that we could not fill the entire buffer, but we had to stop reading
+ // because we hit the `self.length` limit of this `UserSliceReader`. Since we did not
+ // fill the buffer, we treat this case as if we tried to read past the `self.length`
+ // limit and received a page fault, which is consistent with other `UserSliceReader`
+ // methods that also return page faults when you exceed `self.length`.
+ return Err(EFAULT);
+ } else {
+ // This implies that `len == buf.len()`.
+ //
+ // This means that we filled the buffer exactly. In this case, we add a NUL-terminator
+ // and return it. Unlike the `len < dst.len()` branch, don't modify `len` because it
+ // already represents the length including the NUL-terminator.
+ //
+ // SAFETY: Due to the check at the beginning, the buffer is not empty.
+ unsafe { *buf.last_mut().unwrap_unchecked() = 0 };
+ }
+
+ // This method consumes `self`, so it can only be called once, thus we do not need to
+ // update `self.length`. This sidesteps concerns such as whether `self.length` should be
+ // incremented by `len` or `len-1` in the `len == buf.len()` case.
+
+ // SAFETY: There are two cases:
+ // * If we hit the `len < dst.len()` case, then `raw_strncpy_from_user` guarantees that
+ // this slice contains exactly one NUL byte at the end of the string.
+ // * Otherwise, `raw_strncpy_from_user` guarantees that the string contained no NUL bytes,
+ // and we have since added a NUL byte at the end.
+ Ok(unsafe { CStr::from_bytes_with_nul_unchecked(&buf[..len]) })
+ }
}
/// A writer for [`UserSlice`].
@@ -327,11 +429,11 @@ impl UserSliceWriter {
}
// SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read
// that many bytes from it.
- let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) };
+ let res = unsafe { bindings::copy_to_user(self.ptr.as_mut_ptr(), data_ptr, len) };
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
Ok(())
}
@@ -354,16 +456,53 @@ impl UserSliceWriter {
// is a compile-time constant.
let res = unsafe {
bindings::_copy_to_user(
- self.ptr as *mut c_void,
- (value as *const T).cast::<c_void>(),
+ self.ptr.as_mut_ptr(),
+ core::ptr::from_ref(value).cast::<c_void>(),
len,
)
};
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
Ok(())
}
}
+
+/// Reads a nul-terminated string into `dst` and returns the length.
+///
+/// This reads from userspace until a NUL byte is encountered, or until `dst.len()` bytes have been
+/// read. Fails with [`EFAULT`] if a read happens on a bad address (some data may have been
+/// copied). When the end of the buffer is encountered, no NUL byte is added, so the string is
+/// *not* guaranteed to be NUL-terminated when `Ok(dst.len())` is returned.
+///
+/// # Guarantees
+///
+/// When this function returns `Ok(len)`, it is guaranteed that the first `len` bytes of `dst` are
+/// initialized and non-zero. Furthermore, if `len < dst.len()`, then `dst[len]` is a NUL byte.
+#[inline]
+fn raw_strncpy_from_user(dst: &mut [MaybeUninit<u8>], src: UserPtr) -> Result<usize> {
+ // CAST: Slice lengths are guaranteed to be `<= isize::MAX`.
+ let len = dst.len() as isize;
+
+ // SAFETY: `dst` is valid for writing `dst.len()` bytes.
+ let res = unsafe {
+ bindings::strncpy_from_user(
+ dst.as_mut_ptr().cast::<c_char>(),
+ src.as_const_ptr().cast::<c_char>(),
+ len,
+ )
+ };
+
+ if res < 0 {
+ return Err(Error::from_errno(res as i32));
+ }
+
+ #[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
+ assert!(res <= len);
+
+ // GUARANTEES: `strncpy_from_user` was successful, so `dst` has contents in accordance with the
+ // guarantees of this function.
+ Ok(res as usize)
+}