4
4
//!
5
5
//! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h)
6
6
7
- use alloc:: vec;
8
- use alloc:: vec:: Vec ;
9
- use core:: u32;
10
-
11
- use crate :: c_types;
12
- use crate :: error;
7
+ use crate :: { c_types, error, KernelResult } ;
8
+ use alloc:: { vec, vec:: Vec } ;
9
+ use core:: mem:: { size_of, MaybeUninit } ;
13
10
14
11
extern "C" {
15
12
fn rust_helper_access_ok ( addr : * const c_types:: c_void , len : c_types:: c_ulong )
@@ -68,14 +65,18 @@ impl UserSlicePtr {
68
65
/// appropriate permissions. Those checks are handled in the read
69
66
/// and write methods.
70
67
///
68
+ /// # Safety
69
+ ///
71
70
/// This is `unsafe` because if it is called within `set_fs(KERNEL_DS)`
72
71
/// context then `access_ok` will not do anything. As a result the only
73
72
/// place you can safely use this is with a `__user` pointer that was
74
73
/// provided by the kernel.
75
- pub ( crate ) unsafe fn new (
76
- ptr : * mut c_types:: c_void ,
77
- length : usize ,
78
- ) -> error:: KernelResult < UserSlicePtr > {
74
+ ///
75
+ /// Callers must also be careful to avoid time-of-check-time-of-use
76
+ /// (TOCTOU) issues. The simplest way is to create a single instance of
77
+ /// [`UserSlicePtr`] per user memory block as it reads each byte at
78
+ /// most once.
79
+ pub unsafe fn new ( ptr : * mut c_types:: c_void , length : usize ) -> KernelResult < UserSlicePtr > {
79
80
if rust_helper_access_ok ( ptr, length as c_types:: c_ulong ) == 0 {
80
81
return Err ( error:: Error :: EFAULT ) ;
81
82
}
@@ -86,7 +87,7 @@ impl UserSlicePtr {
86
87
///
87
88
/// Returns `EFAULT` if the address does not currently point to
88
89
/// mapped, readable memory.
89
- pub fn read_all ( self ) -> error :: KernelResult < Vec < u8 > > {
90
+ pub fn read_all ( self ) -> KernelResult < Vec < u8 > > {
90
91
self . reader ( ) . read_all ( )
91
92
}
92
93
@@ -101,14 +102,22 @@ impl UserSlicePtr {
101
102
/// mapped, writable memory (in which case some data from before the
102
103
/// fault may be written), or `data` is larger than the user slice
103
104
/// (in which case no data is written).
104
- pub fn write_all ( self , data : & [ u8 ] ) -> error :: KernelResult < ( ) > {
105
- self . writer ( ) . write ( data)
105
+ pub fn write_all ( self , data : & [ u8 ] ) -> KernelResult < ( ) > {
106
+ self . writer ( ) . write_slice ( data)
106
107
}
107
108
108
109
/// Constructs a [`UserSlicePtrWriter`].
109
110
pub fn writer ( self ) -> UserSlicePtrWriter {
110
111
UserSlicePtrWriter ( self . 0 , self . 1 )
111
112
}
113
+
114
+ /// Constructs both a [`UserSlicePtrReader`] and a [`UserSlicePtrWriter`].
115
+ pub fn reader_writer ( self ) -> ( UserSlicePtrReader , UserSlicePtrWriter ) {
116
+ (
117
+ UserSlicePtrReader ( self . 0 , self . 1 ) ,
118
+ UserSlicePtrWriter ( self . 0 , self . 1 ) ,
119
+ )
120
+ }
112
121
}
113
122
114
123
/// A reader for [`UserSlicePtr`].
@@ -133,9 +142,10 @@ impl UserSlicePtrReader {
133
142
///
134
143
/// Returns `EFAULT` if the address does not currently point to
135
144
/// mapped, readable memory.
136
- pub fn read_all ( & mut self ) -> error :: KernelResult < Vec < u8 > > {
145
+ pub fn read_all ( & mut self ) -> KernelResult < Vec < u8 > > {
137
146
let mut data = vec ! [ 0 ; self . 1 ] ;
138
- self . read ( & mut data) ?;
147
+ // SAFETY: The output buffer is valid as we just allocated it.
148
+ unsafe { self . read_raw ( data. as_mut_ptr ( ) , data. len ( ) ) ? } ;
139
149
Ok ( data)
140
150
}
141
151
@@ -144,27 +154,40 @@ impl UserSlicePtrReader {
144
154
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
145
155
/// of the user slice or if the address does not currently point to mapped,
146
156
/// readable memory.
147
- pub fn read ( & mut self , data : & mut [ u8 ] ) -> error:: KernelResult < ( ) > {
148
- if data. len ( ) > self . 1 || data. len ( ) > u32:: MAX as usize {
157
+ pub fn read_slice ( & mut self , data : & mut [ u8 ] ) -> KernelResult < ( ) > {
158
+ // SAFETY: The output buffer is valid as it's coming from a live reference.
159
+ unsafe { self . read_raw ( data. as_mut_ptr ( ) , data. len ( ) ) }
160
+ }
161
+
162
+ /// Reads raw data from the user slice into a raw kernel buffer.
163
+ ///
164
+ /// # Safety
165
+ ///
166
+ /// The output buffer must be valid.
167
+ pub unsafe fn read_raw ( & mut self , out : * mut u8 , len : usize ) -> KernelResult < ( ) > {
168
+ if len > self . 1 || len > u32:: MAX as usize {
149
169
return Err ( error:: Error :: EFAULT ) ;
150
170
}
151
- let res = unsafe {
152
- rust_helper_copy_from_user (
153
- data. as_mut_ptr ( ) as * mut c_types:: c_void ,
154
- self . 0 ,
155
- data. len ( ) as _ ,
156
- )
157
- } ;
171
+ let res = rust_helper_copy_from_user ( out as _ , self . 0 , len as _ ) ;
158
172
if res != 0 {
159
173
return Err ( error:: Error :: EFAULT ) ;
160
174
}
161
175
// Since this is not a pointer to a valid object in our program,
162
176
// we cannot use `add`, which has C-style rules for defined
163
177
// behavior.
164
- self . 0 = self . 0 . wrapping_add ( data . len ( ) ) ;
165
- self . 1 -= data . len ( ) ;
178
+ self . 0 = self . 0 . wrapping_add ( len) ;
179
+ self . 1 -= len;
166
180
Ok ( ( ) )
167
181
}
182
+
183
+ /// Reads the contents of a plain old data (POD) type from the user slice.
184
+ pub fn read < T : Copy > ( & mut self ) -> KernelResult < T > {
185
+ let mut out = MaybeUninit :: < T > :: uninit ( ) ;
186
+ // SAFETY: The buffer is valid it was just allocated.
187
+ unsafe { self . read_raw ( out. as_mut_ptr ( ) as _ , size_of :: < T > ( ) ) ? } ;
188
+ // SAFETY: We just initialised the data.
189
+ Ok ( unsafe { out. assume_init ( ) } )
190
+ }
168
191
}
169
192
170
193
/// A writer for [`UserSlicePtr`].
@@ -190,25 +213,35 @@ impl UserSlicePtrWriter {
190
213
/// Returns `EFAULT` if the byte slice is bigger than the remaining size
191
214
/// of the user slice or if the address does not currently point to mapped,
192
215
/// writable memory.
193
- pub fn write ( & mut self , data : & [ u8 ] ) -> error:: KernelResult < ( ) > {
194
- if data. len ( ) > self . 1 || data. len ( ) > u32:: MAX as usize {
216
+ pub fn write_slice ( & mut self , data : & [ u8 ] ) -> KernelResult < ( ) > {
217
+ // SAFETY: The input buffer is valid as it's coming from a live reference.
218
+ unsafe { self . write_raw ( data. as_ptr ( ) , data. len ( ) ) }
219
+ }
220
+
221
+ /// Writes raw data to the user slice from a raw kernel buffer.
222
+ ///
223
+ /// # Safety
224
+ ///
225
+ /// The input buffer must be valid.
226
+ unsafe fn write_raw ( & mut self , data : * const u8 , len : usize ) -> KernelResult < ( ) > {
227
+ if len > self . 1 || len > u32:: MAX as usize {
195
228
return Err ( error:: Error :: EFAULT ) ;
196
229
}
197
- let res = unsafe {
198
- rust_helper_copy_to_user (
199
- self . 0 ,
200
- data. as_ptr ( ) as * const c_types:: c_void ,
201
- data. len ( ) as _ ,
202
- )
203
- } ;
230
+ let res = rust_helper_copy_to_user ( self . 0 , data as _ , len as _ ) ;
204
231
if res != 0 {
205
232
return Err ( error:: Error :: EFAULT ) ;
206
233
}
207
234
// Since this is not a pointer to a valid object in our program,
208
235
// we cannot use `add`, which has C-style rules for defined
209
236
// behavior.
210
- self . 0 = self . 0 . wrapping_add ( data . len ( ) ) ;
211
- self . 1 -= data . len ( ) ;
237
+ self . 0 = self . 0 . wrapping_add ( len) ;
238
+ self . 1 -= len;
212
239
Ok ( ( ) )
213
240
}
241
+
242
+ /// Writes the contents of a plain old data (POD) type into the user slice.
243
+ pub fn write < T : Copy > ( & mut self , data : & T ) -> KernelResult < ( ) > {
244
+ // SAFETY: The input buffer is valid as it's coming from a live reference.
245
+ unsafe { self . write_raw ( data as * const T as _ , size_of :: < T > ( ) ) }
246
+ }
214
247
}
0 commit comments