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 } ;
88use alloc:: vec:: Vec ;
9+ use core:: mem:: { size_of, MaybeUninit } ;
910
1011extern "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