4
4
//!
5
5
//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
6
6
7
- use crate :: { c_types, error} ;
7
+ use crate :: { c_types, error, KernelResult } ;
8
8
use alloc:: vec:: Vec ;
9
+ use core:: mem:: { size_of, MaybeUninit } ;
9
10
10
11
extern "C" {
11
12
fn rust_helper_access_ok ( addr : * const c_types:: c_void , len : c_types:: c_ulong )
@@ -24,6 +25,30 @@ extern "C" {
24
25
) -> c_types:: c_ulong ;
25
26
}
26
27
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
+
27
52
/// A reference to an area in userspace memory, which can be either
28
53
/// read-only or read-write.
29
54
///
@@ -64,14 +89,18 @@ impl UserSlicePtr {
64
89
/// appropriate permissions. Those checks are handled in the read
65
90
/// and write methods.
66
91
///
92
+ /// # Safety
93
+ ///
67
94
/// This is `unsafe` because if it is called within `set_fs(KERNEL_DS)`
68
95
/// context then `access_ok` will not do anything. As a result the only
69
96
/// place you can safely use this is with a `__user` pointer that was
70
97
/// 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 > {
75
104
if rust_helper_access_ok ( ptr, length as c_types:: c_ulong ) == 0 {
76
105
return Err ( error:: Error :: EFAULT ) ;
77
106
}
@@ -82,7 +111,7 @@ impl UserSlicePtr {
82
111
///
83
112
/// Returns `EFAULT` if the address does not currently point to
84
113
/// mapped, readable memory.
85
- pub fn read_all ( self ) -> error :: KernelResult < Vec < u8 > > {
114
+ pub fn read_all ( self ) -> KernelResult < Vec < u8 > > {
86
115
self . reader ( ) . read_all ( )
87
116
}
88
117
@@ -97,14 +126,22 @@ impl UserSlicePtr {
97
126
/// mapped, writable memory (in which case some data from before the
98
127
/// fault may be written), or `data` is larger than the user slice
99
128
/// (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)
102
131
}
103
132
104
133
/// Constructs a [`UserSlicePtrWriter`].
105
134
pub fn writer ( self ) -> UserSlicePtrWriter {
106
135
UserSlicePtrWriter ( self . 0 , self . 1 )
107
136
}
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
+ }
108
145
}
109
146
110
147
/// A reader for [`UserSlicePtr`].
@@ -133,7 +170,8 @@ impl UserSlicePtrReader {
133
170
let mut data = Vec :: < u8 > :: new ( ) ;
134
171
data. try_reserve_exact ( self . 1 ) ?;
135
172
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 ( ) ) ? } ;
137
175
Ok ( data)
138
176
}
139
177
@@ -142,27 +180,40 @@ impl UserSlicePtrReader {
142
180
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
143
181
/// of the user slice or if the address does not currently point to mapped,
144
182
/// 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 {
147
195
return Err ( error:: Error :: EFAULT ) ;
148
196
}
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 _ ) ;
156
198
if res != 0 {
157
199
return Err ( error:: Error :: EFAULT ) ;
158
200
}
159
201
// Since this is not a pointer to a valid object in our program,
160
202
// we cannot use `add`, which has C-style rules for defined
161
203
// 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;
164
206
Ok ( ( ) )
165
207
}
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
+ }
166
217
}
167
218
168
219
/// A writer for [`UserSlicePtr`].
@@ -188,25 +239,29 @@ impl UserSlicePtrWriter {
188
239
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
189
240
/// of the user slice or if the address does not currently point to mapped,
190
241
/// 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 {
193
254
return Err ( error:: Error :: EFAULT ) ;
194
255
}
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 _ ) ;
202
257
if res != 0 {
203
258
return Err ( error:: Error :: EFAULT ) ;
204
259
}
205
260
// Since this is not a pointer to a valid object in our program,
206
261
// we cannot use `add`, which has C-style rules for defined
207
262
// 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;
210
265
Ok ( ( ) )
211
266
}
212
267
}
0 commit comments