1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: Apache-2.0
use super::syscall::types::SockaddrOutput;
use crate::libc::{iovec, EINVAL};
use core::ffi::c_int;
use core::slice;
/// Platform-specific functionality.
pub trait Platform {
/// Validates that the memory pointed to by `ptr` of the type `T` is:
/// * in valid address space and writable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * ptr is non-null and aligned
/// * not borrowed already
/// and registers the memory as borrowed mutably.
///
/// Returns a mutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
///
/// [the ptr module documentation]: core::ptr#safety
fn validate_mut<T>(&self, ptr: usize) -> Result<&mut T, c_int>;
/// Validates that the memory pointed to by `ptr` of the type `T` is:
/// * in valid address space and readable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * ptr is non-null and aligned
/// * not borrowed already
/// and registers the memory as borrowed.
///
/// Returns an immutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
///
/// [the ptr module documentation]: core::ptr#safety
fn validate<T>(&self, ptr: usize) -> Result<&T, c_int>;
/// Validates that a region for `count` elements of type `T` is:
/// * in valid address space and writable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * ptr is non-null and aligned
/// * not borrowed already
/// and registers the memory as borrowed mutably.
///
/// Returns a mutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
///
/// [the ptr module documentation]: core::ptr#safety
fn validate_slice_mut<T: Sized>(&self, ptr: usize, count: usize) -> Result<&mut [T], c_int>;
/// Validates that a region of memory is valid for read-only access for `count` elements of type `T`.
/// * in valid address space and writable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * ptr is non-null and aligned
/// * not borrowed already
/// and registers the memory as borrowed.
///
/// Returns an immutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
///
/// [the ptr module documentation]: core::ptr#safety
fn validate_slice<T: Sized>(&self, ptr: usize, count: usize) -> Result<&[T], c_int>;
/// Validates that pointer `iov` points to represents a slice of `iovcnt` pointers to [`libc::iovec`] structures
/// valid for read-write access.
///
/// Also checks, that memory is:
/// * in valid address space and writable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * not borrowed already
/// * and pointers are non-null and aligned
/// and registers the memory as borrowed mutably.
///
/// Returns a mutable borrow of the [`libc::iovec`] structs as a 2-dimensional slice
/// of mutable byte buffer borrows if valid, otherwise [`EINVAL`](libc::EINVAL).
#[inline]
fn validate_iovec_slice_mut(
&self,
iov: usize,
iovcnt: usize,
) -> Result<&mut [&mut [u8]], c_int> {
let iovec_slice = self.validate_slice::<iovec>(iov, iovcnt)?;
for iovec in iovec_slice {
self.validate_slice_mut::<u8>(iovec.iov_base as _, iovec.iov_len)?;
}
// Safety: checked all slices before
Ok(unsafe { slice::from_raw_parts_mut(iov as _, iovcnt) })
}
/// Validates that pointer `iov` points to represents a slice of `iovcnt` pointers to [`libc::iovec`] structures
/// valid for read-only access.
///
/// Also checks, that the memory is:
/// * in valid address space and readable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * not borrowed already
/// * and pointers are non-null and aligned
/// and registers the memory as borrowed.
///
/// Returns an immutable borrow of the [`libc::iovec`] structs as a 2-dimensional slice
/// of immutable byte buffer borrows if valid, otherwise [`EINVAL`](libc::EINVAL).
#[inline]
fn validate_iovec_slice(&self, iov: usize, iovcnt: usize) -> Result<&[&[u8]], c_int> {
let iovec_slice = self.validate_slice::<iovec>(iov, iovcnt)?;
for iovec in iovec_slice {
self.validate_slice::<u8>(iovec.iov_base as _, iovec.iov_len)?;
}
// Safety: checked all slices before
Ok(unsafe { slice::from_raw_parts(iov as _, iovcnt) })
}
/// Validates that a region of memory represents a C string and is valid for read-only access.
///
/// Also checks, that the memory is:
/// * in valid address space and readable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * ptr is non-null and aligned
/// * not borrowed already
/// and registers the memory as borrowed.
///
/// Returns an immutable borrow of bytes of the string with the nul terminator byte if valid,
/// otherwise [`EINVAL`](libc::EINVAL).
#[inline]
fn validate_str(&self, ptr: usize) -> Result<&[u8], c_int> {
let mut p = ptr;
loop {
let byte = self.validate::<u8>(p)?;
p += 1;
if *byte == 0 {
break;
}
}
let len = p.checked_sub(ptr).ok_or(EINVAL)?;
// Safety: checked all bytes before
Ok(unsafe { slice::from_raw_parts(ptr as *const u8, len) })
}
/// Validates that pointer `addrlen` points to `socklen_t` and `addr` points to
/// a byte array of size `*addrlen` and is valid for read-write access.
///
/// Also checks that the memory is:
/// * in valid address space and writable for the lifetime of `self`.
/// * "dereferenceable" in the sense defined in [the ptr module documentation].
/// * not borrowed already
/// * and pointers are non-null and aligned
/// and registers the memory as borrowed.
///
/// Returns a `SockaddrOutput`, otherwise [`EINVAL`](libc::EINVAL).
#[inline]
fn validate_sockaddr_output(
&self,
addr: usize,
addrlen: usize,
) -> Result<SockaddrOutput, c_int> {
let addrlen = self.validate_mut(addrlen)?;
let addr = self.validate_slice_mut(addr, *addrlen as _)?;
Ok(SockaddrOutput::new(addr, addrlen))
}
}