1 //! Encapsulation for system call arguments and return values.
2 //!
3 //! The inline-asm code paths do some amount of reordering of arguments; to
4 //! ensure that we don't accidentally misroute an argument or return value, we
5 //! use distinct types for each argument index and return value.
6 //!
7 //! # Safety
8 //!
9 //! The `ToAsm` and `FromAsm` traits are unsafe to use; they should only be
10 //! used by the syscall code which executes actual syscall machine
11 //! instructions.
12 
13 #![allow(unsafe_code)]
14 
15 use super::c;
16 use super::fd::RawFd;
17 use core::marker::PhantomData;
18 use core::ops::Range;
19 
20 pub(super) trait ToAsm: private::Sealed {
21     /// Convert `self` to a `usize` ready to be passed to a syscall
22     /// machine instruction.
23     ///
24     /// # Safety
25     ///
26     /// This should be used immediately before the syscall instruction, and the
27     /// returned value shouldn't be used for any other purpose.
28     #[must_use]
to_asm(self) -> *mut Opaque29     unsafe fn to_asm(self) -> *mut Opaque;
30 }
31 
32 pub(super) trait FromAsm: private::Sealed {
33     /// Convert `raw` from a value produced by a syscall machine instruction
34     /// into a `Self`.
35     ///
36     /// # Safety
37     ///
38     /// This should be used immediately after the syscall instruction, and the
39     /// operand value shouldn't be used for any other purpose.
40     #[must_use]
from_asm(raw: *mut Opaque) -> Self41     unsafe fn from_asm(raw: *mut Opaque) -> Self;
42 }
43 
44 /// To preserve provenance, syscall arguments and return values are passed as
45 /// pointer types. They need a type to point to, so we define a custom private
46 /// type, to prevent it from being used for anything else.
47 #[repr(transparent)]
48 #[allow(dead_code)]
49 pub(super) struct Opaque(c::c_void);
50 
51 // Argument numbers.
52 pub(super) struct A0(());
53 pub(super) struct A1(());
54 pub(super) struct A2(());
55 pub(super) struct A3(());
56 pub(super) struct A4(());
57 pub(super) struct A5(());
58 #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
59 pub(super) struct A6(());
60 #[cfg(target_arch = "x86")]
61 pub(super) struct SocketArg;
62 
63 pub(super) trait ArgNumber: private::Sealed {}
64 impl ArgNumber for A0 {}
65 impl ArgNumber for A1 {}
66 impl ArgNumber for A2 {}
67 impl ArgNumber for A3 {}
68 impl ArgNumber for A4 {}
69 impl ArgNumber for A5 {}
70 #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
71 impl ArgNumber for A6 {}
72 #[cfg(target_arch = "x86")]
73 impl ArgNumber for SocketArg {}
74 
75 // Return value numbers.
76 pub(super) struct R0(());
77 
78 pub(super) trait RetNumber: private::Sealed {}
79 impl RetNumber for R0 {}
80 
81 /// Syscall arguments use register-sized types. We use a newtype to
82 /// discourage accidental misuse of the raw integer values.
83 ///
84 /// This type doesn't implement `Clone` or `Copy`; it should be used exactly
85 /// once. And it has a lifetime to ensure that it doesn't outlive any resources
86 /// it might be pointing to.
87 #[repr(transparent)]
88 #[must_use]
89 pub(super) struct ArgReg<'a, Num: ArgNumber> {
90     raw: *mut Opaque,
91     _phantom: PhantomData<(&'a (), Num)>,
92 }
93 
94 impl<'a, Num: ArgNumber> ToAsm for ArgReg<'a, Num> {
95     #[inline]
to_asm(self) -> *mut Opaque96     unsafe fn to_asm(self) -> *mut Opaque {
97         self.raw
98     }
99 }
100 
101 /// Syscall return values use register-sized types. We use a newtype to
102 /// discourage accidental misuse of the raw integer values.
103 ///
104 /// This type doesn't implement `Clone` or `Copy`; it should be used exactly
105 /// once.
106 #[repr(transparent)]
107 #[must_use]
108 pub(super) struct RetReg<Num: RetNumber> {
109     raw: *mut Opaque,
110     _phantom: PhantomData<Num>,
111 }
112 
113 impl<Num: RetNumber> RetReg<Num> {
114     #[inline]
decode_usize(self) -> usize115     pub(super) fn decode_usize(self) -> usize {
116         debug_assert!(!(-4095..0).contains(&(self.raw as isize)));
117         self.raw as usize
118     }
119 
120     #[inline]
decode_raw_fd(self) -> RawFd121     pub(super) fn decode_raw_fd(self) -> RawFd {
122         let bits = self.decode_usize();
123         let raw_fd = bits as RawFd;
124 
125         // Converting `raw` to `RawFd` should be lossless.
126         debug_assert_eq!(raw_fd as usize, bits);
127 
128         raw_fd
129     }
130 
131     #[inline]
decode_c_int(self) -> c::c_int132     pub(super) fn decode_c_int(self) -> c::c_int {
133         let bits = self.decode_usize();
134         let c_int_ = bits as c::c_int;
135 
136         // Converting `raw` to `c_int` should be lossless.
137         debug_assert_eq!(c_int_ as usize, bits);
138 
139         c_int_
140     }
141 
142     #[inline]
decode_c_uint(self) -> c::c_uint143     pub(super) fn decode_c_uint(self) -> c::c_uint {
144         let bits = self.decode_usize();
145         let c_uint_ = bits as c::c_uint;
146 
147         // Converting `raw` to `c_uint` should be lossless.
148         debug_assert_eq!(c_uint_ as usize, bits);
149 
150         c_uint_
151     }
152 
153     #[inline]
decode_void_star(self) -> *mut c::c_void154     pub(super) fn decode_void_star(self) -> *mut c::c_void {
155         self.raw.cast()
156     }
157 
158     #[cfg(target_pointer_width = "64")]
159     #[inline]
decode_u64(self) -> u64160     pub(super) fn decode_u64(self) -> u64 {
161         self.decode_usize() as u64
162     }
163 
164     #[inline]
decode_void(self)165     pub(super) fn decode_void(self) {
166         let ignore = self.decode_usize();
167         debug_assert_eq!(ignore, 0);
168     }
169 
170     #[inline]
decode_error_code(self) -> u16171     pub(super) fn decode_error_code(self) -> u16 {
172         let bits = self.raw as usize;
173 
174         // `raw` must be in `-4095..0`. Linux always returns errors in
175         // `-4095..0`, and we double-check it here.
176         debug_assert!((-4095..0).contains(&(bits as isize)));
177 
178         bits as u16
179     }
180 
181     #[inline]
is_nonzero(&self) -> bool182     pub(super) fn is_nonzero(&self) -> bool {
183         !self.raw.is_null()
184     }
185 
186     #[inline]
is_negative(&self) -> bool187     pub(super) fn is_negative(&self) -> bool {
188         (self.raw as isize) < 0
189     }
190 
191     #[inline]
is_in_range(&self, range: Range<isize>) -> bool192     pub(super) fn is_in_range(&self, range: Range<isize>) -> bool {
193         range.contains(&(self.raw as isize))
194     }
195 }
196 
197 impl<Num: RetNumber> FromAsm for RetReg<Num> {
198     #[inline]
from_asm(raw: *mut Opaque) -> Self199     unsafe fn from_asm(raw: *mut Opaque) -> Self {
200         Self {
201             raw,
202             _phantom: PhantomData,
203         }
204     }
205 }
206 
207 #[repr(transparent)]
208 pub(super) struct SyscallNumber<'a> {
209     nr: usize,
210     _phantom: PhantomData<&'a ()>,
211 }
212 
213 impl<'a> ToAsm for SyscallNumber<'a> {
214     #[inline]
to_asm(self) -> *mut Opaque215     unsafe fn to_asm(self) -> *mut Opaque {
216         self.nr as usize as *mut Opaque
217     }
218 }
219 
220 /// Encode a system call argument as an `ArgReg`.
221 #[inline]
raw_arg<'a, Num: ArgNumber>(raw: *mut Opaque) -> ArgReg<'a, Num>222 pub(super) fn raw_arg<'a, Num: ArgNumber>(raw: *mut Opaque) -> ArgReg<'a, Num> {
223     ArgReg {
224         raw,
225         _phantom: PhantomData,
226     }
227 }
228 
229 /// Encode a system call number (a `__NR_*` constant) as a `SyscallNumber`.
230 #[inline]
nr<'a>(nr: u32) -> SyscallNumber<'a>231 pub(super) const fn nr<'a>(nr: u32) -> SyscallNumber<'a> {
232     SyscallNumber {
233         nr: nr as usize,
234         _phantom: PhantomData,
235     }
236 }
237 
238 /// Seal our various traits using the technique documented [here].
239 ///
240 /// [here]: https://rust-lang.github.io/api-guidelines/future-proofing.html
241 mod private {
242     pub trait Sealed {}
243 
244     // Implement for those same types, but no others.
245     impl<'a, Num: super::ArgNumber> Sealed for super::ArgReg<'a, Num> {}
246     impl<Num: super::RetNumber> Sealed for super::RetReg<Num> {}
247     impl<'a> Sealed for super::SyscallNumber<'a> {}
248     impl Sealed for super::A0 {}
249     impl Sealed for super::A1 {}
250     impl Sealed for super::A2 {}
251     impl Sealed for super::A3 {}
252     impl Sealed for super::A4 {}
253     impl Sealed for super::A5 {}
254     #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
255     impl Sealed for super::A6 {}
256     #[cfg(target_arch = "x86")]
257     impl Sealed for super::SocketArg {}
258     impl Sealed for super::R0 {}
259 }
260