@@ -14,31 +14,77 @@ extern "C" {
14
14
) -> c_types:: c_int ;
15
15
}
16
16
17
+ /// A reference to an area in userspace memory, which can be either
18
+ /// read-only or read-write.
19
+ ///
20
+ /// All methods on this struct are safe: invalid pointers return
21
+ /// `EFAULT`. Concurrent access, _including data races to/from userspace
22
+ /// memory_, is permitted, because fundamentally another userspace
23
+ /// thread / process could always be modifying memory at the same time
24
+ /// (in the same way that userspace Rust's std::io permits data races
25
+ /// with the contents of files on disk). In the presence of a race, the
26
+ /// exact byte values read/written are unspecified but the operation is
27
+ /// well-defined. Kernelspace code should validate its copy of data
28
+ /// after completing a read, and not expect that multiple reads of the
29
+ /// same address will return the same value.
30
+ ///
31
+ /// Constructing a `UserSlicePtr` only checks that the range is in valid
32
+ /// userspace memory, and does not depend on the current process (and
33
+ /// can safely be constructed inside a kernel thread with no current
34
+ /// userspace process). Reads and writes wrap the kernel APIs
35
+ /// `copy_from_user` and `copy_to_user`, and check the memory map of the
36
+ /// current process.
17
37
pub struct UserSlicePtr ( * mut c_types:: c_void , usize ) ;
18
38
19
39
impl UserSlicePtr {
40
+ /// Construct a user slice from a raw pointer and a length in bytes.
41
+ ///
42
+ /// Checks that the provided range is within the legal area for
43
+ /// userspace memory, using `access_ok` (e.g., on i386, the range
44
+ /// must be within the first 3 gigabytes), but does not check that
45
+ /// the actual pages are mapped in the current process with
46
+ /// appropriate permissions. Those checks are handled in the read
47
+ /// and write methods.
20
48
pub fn new ( ptr : * mut c_types:: c_void , length : usize ) -> error:: KernelResult < UserSlicePtr > {
49
+ // No current access_ok implementation actually distinguishes
50
+ // between VERIFY_READ and VERIFY_WRITE, so passing VERIFY_WRITE
51
+ // is fine in practice and fails safe if a future implementation
52
+ // bothers.
21
53
if unsafe { access_ok_helper ( bindings:: VERIFY_WRITE , ptr, length as c_types:: c_ulong ) } == 0
22
54
{
23
55
return Err ( error:: Error :: EFAULT ) ;
24
56
}
25
57
return Ok ( UserSlicePtr ( ptr, length) ) ;
26
58
}
27
59
60
+ /// Read the entirety of the user slice and return it in a `Vec`.
61
+ ///
62
+ /// Returns EFAULT if the address does not currently point to
63
+ /// mapped, readable memory.
28
64
pub fn read_all ( self ) -> error:: KernelResult < Vec < u8 > > {
29
65
let mut data = vec ! [ 0 ; self . 1 ] ;
30
66
self . reader ( ) . read ( & mut data) ?;
31
67
return Ok ( data) ;
32
68
}
33
69
70
+ /// Construct a `UserSlicePtrReader` that can incrementally read
71
+ /// from the user slice.
34
72
pub fn reader ( self ) -> UserSlicePtrReader {
35
73
return UserSlicePtrReader ( self . 0 , self . 1 ) ;
36
74
}
37
75
76
+ /// Write the provided slice into the user slice.
77
+ ///
78
+ /// Returns EFAULT if the address does not currently point to
79
+ /// mapped, writable memory (in which case some data from before the
80
+ /// fault may be written), or `data` is larger than the user slice
81
+ /// (in which case no data is written).
38
82
pub fn write_all ( self , data : & [ u8 ] ) -> error:: KernelResult < ( ) > {
39
83
return self . writer ( ) . write ( data) ;
40
84
}
41
85
86
+ /// Construct a `UserSlicePtrWrite` that can incrementally write
87
+ /// into the user slice.
42
88
pub fn writer ( self ) -> UserSlicePtrWriter {
43
89
return UserSlicePtrWriter ( self . 0 , self . 1 ) ;
44
90
}
@@ -66,7 +112,7 @@ impl UserSlicePtrReader {
66
112
// behavior.
67
113
self . 0 = self . 0 . wrapping_offset ( data. len ( ) ) ;
68
114
self . 1 -= data. len ( ) ;
69
- return Ok ( ( ) ) ;
115
+ Ok ( ( ) )
70
116
}
71
117
}
72
118
0 commit comments