• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Encapsulation for system call arguments and return values.
2 //!
3 //! The inline-asm and outline-asm code paths do some amount of reordering
4 //! of arguments; to ensure that we don't accidentally misroute an argument
5 //! or return value, we use distinct types for each argument index and
6 //! return value.
7 //!
8 //! # Safety
9 //!
10 //! The `ToAsm` and `FromAsm` traits are unsafe to use; they should only be
11 //! used by the syscall code which executes actual syscall machine
12 //! instructions.
13 
14 #![allow(unsafe_code)]
15 
16 use super::c;
17 use super::fd::RawFd;
18 use core::marker::PhantomData;
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
27     /// the 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
39     /// the 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 pub(super) struct Opaque(c::c_void);
49 
50 // Argument numbers.
51 pub(super) struct A0(());
52 pub(super) struct A1(());
53 pub(super) struct A2(());
54 pub(super) struct A3(());
55 pub(super) struct A4(());
56 pub(super) struct A5(());
57 #[cfg(target_arch = "mips")]
58 pub(super) struct A6(());
59 #[cfg(target_arch = "x86")]
60 pub(super) struct SocketArg;
61 
62 pub(super) trait ArgNumber: private::Sealed {}
63 impl ArgNumber for A0 {}
64 impl ArgNumber for A1 {}
65 impl ArgNumber for A2 {}
66 impl ArgNumber for A3 {}
67 impl ArgNumber for A4 {}
68 impl ArgNumber for A5 {}
69 #[cfg(target_arch = "mips")]
70 impl ArgNumber for A6 {}
71 #[cfg(target_arch = "x86")]
72 impl ArgNumber for SocketArg {}
73 
74 // Return value numbers.
75 pub(super) struct R0(());
76 
77 pub(super) trait RetNumber: private::Sealed {}
78 impl RetNumber for R0 {}
79 
80 /// Syscall arguments use register-sized types. We use a newtype to
81 /// discourage accidental misuse of the raw integer values.
82 ///
83 /// This type doesn't implement `Clone` or `Copy`; it should be used exactly
84 /// once. And it has a lifetime to ensure that it doesn't outlive any resources
85 /// it might be pointing to.
86 #[repr(transparent)]
87 #[must_use]
88 pub(super) struct ArgReg<'a, Num: ArgNumber> {
89     raw: *mut Opaque,
90     _phantom: PhantomData<(&'a (), Num)>,
91 }
92 
93 impl<'a, Num: ArgNumber> ToAsm for ArgReg<'a, Num> {
94     #[inline]
to_asm(self) -> *mut Opaque95     unsafe fn to_asm(self) -> *mut Opaque {
96         self.raw
97     }
98 }
99 
100 /// Syscall return values use register-sized types. We use a newtype to
101 /// discourage accidental misuse of the raw integer values.
102 ///
103 /// This type doesn't implement `Clone` or `Copy`; it should be used exactly
104 /// once.
105 #[repr(transparent)]
106 #[must_use]
107 pub(super) struct RetReg<Num: RetNumber> {
108     raw: *mut Opaque,
109     _phantom: PhantomData<Num>,
110 }
111 
112 impl<Num: RetNumber> RetReg<Num> {
113     #[inline]
decode_usize(self) -> usize114     pub(super) fn decode_usize(self) -> usize {
115         debug_assert!(!(-4095..0).contains(&(self.raw as isize)));
116         self.raw as usize
117     }
118 
119     #[inline]
decode_raw_fd(self) -> RawFd120     pub(super) fn decode_raw_fd(self) -> RawFd {
121         let bits = self.decode_usize();
122         let raw_fd = bits as RawFd;
123 
124         // Converting `raw` to `RawFd` should be lossless.
125         debug_assert_eq!(raw_fd as usize, bits);
126 
127         raw_fd
128     }
129 
130     #[inline]
decode_c_int(self) -> c::c_int131     pub(super) fn decode_c_int(self) -> c::c_int {
132         let bits = self.decode_usize();
133         let c_int_ = bits as c::c_int;
134 
135         // Converting `raw` to `c_int` should be lossless.
136         debug_assert_eq!(c_int_ as usize, bits);
137 
138         c_int_
139     }
140 
141     #[inline]
decode_c_uint(self) -> c::c_uint142     pub(super) fn decode_c_uint(self) -> c::c_uint {
143         let bits = self.decode_usize();
144         let c_uint_ = bits as c::c_uint;
145 
146         // Converting `raw` to `c_uint` should be lossless.
147         debug_assert_eq!(c_uint_ as usize, bits);
148 
149         c_uint_
150     }
151 
152     #[inline]
decode_void_star(self) -> *mut c::c_void153     pub(super) fn decode_void_star(self) -> *mut c::c_void {
154         self.raw.cast()
155     }
156 
157     #[cfg(target_pointer_width = "64")]
158     #[inline]
decode_u64(self) -> u64159     pub(super) fn decode_u64(self) -> u64 {
160         self.decode_usize() as u64
161     }
162 
163     #[inline]
decode_void(self)164     pub(super) fn decode_void(self) {
165         let ignore = self.decode_usize();
166         debug_assert_eq!(ignore, 0);
167     }
168 
169     #[inline]
decode_error_code(self) -> u16170     pub(super) fn decode_error_code(self) -> u16 {
171         let bits = self.raw as usize;
172 
173         // `raw` must be in `-4095..0`. Linux always returns errors in
174         // `-4095..0`, and we double-check it here.
175         debug_assert!((-4095..0).contains(&(bits as isize)));
176 
177         bits as u16
178     }
179 
180     #[inline]
is_nonzero(&self) -> bool181     pub(super) fn is_nonzero(&self) -> bool {
182         !self.raw.is_null()
183     }
184 
185     #[inline]
is_negative(&self) -> bool186     pub(super) fn is_negative(&self) -> bool {
187         (self.raw as isize) < 0
188     }
189 
190     #[inline]
is_in_range(&self, range: core::ops::Range<isize>) -> bool191     pub(super) fn is_in_range(&self, range: core::ops::Range<isize>) -> bool {
192         range.contains(&(self.raw as isize))
193     }
194 }
195 
196 impl<Num: RetNumber> FromAsm for RetReg<Num> {
197     #[inline]
from_asm(raw: *mut Opaque) -> Self198     unsafe fn from_asm(raw: *mut Opaque) -> Self {
199         Self {
200             raw,
201             _phantom: PhantomData,
202         }
203     }
204 }
205 
206 #[repr(transparent)]
207 pub(super) struct SyscallNumber<'a> {
208     nr: usize,
209     _phantom: PhantomData<&'a ()>,
210 }
211 
212 impl<'a> ToAsm for SyscallNumber<'a> {
213     #[inline]
to_asm(self) -> *mut Opaque214     unsafe fn to_asm(self) -> *mut Opaque {
215         self.nr as usize as *mut Opaque
216     }
217 }
218 
219 /// Encode a system call argument as an `ArgReg`.
220 #[inline]
raw_arg<'a, Num: ArgNumber>(raw: *mut Opaque) -> ArgReg<'a, Num>221 pub(super) fn raw_arg<'a, Num: ArgNumber>(raw: *mut Opaque) -> ArgReg<'a, Num> {
222     ArgReg {
223         raw,
224         _phantom: PhantomData,
225     }
226 }
227 
228 /// Encode a system call number (a `__NR_*` constant) as a `SyscallNumber`.
229 #[inline]
nr<'a>(nr: u32) -> SyscallNumber<'a>230 pub(super) const fn nr<'a>(nr: u32) -> SyscallNumber<'a> {
231     SyscallNumber {
232         nr: nr as usize,
233         _phantom: PhantomData,
234     }
235 }
236 
237 /// Seal our various traits using the technique documented [here].
238 ///
239 /// [here]: https://rust-lang.github.io/api-guidelines/future-proofing.html
240 mod private {
241     pub trait Sealed {}
242 
243     // Implement for those same types, but no others.
244     impl<'a, Num: super::ArgNumber> Sealed for super::ArgReg<'a, Num> {}
245     impl<Num: super::RetNumber> Sealed for super::RetReg<Num> {}
246     impl<'a> Sealed for super::SyscallNumber<'a> {}
247     impl Sealed for super::A0 {}
248     impl Sealed for super::A1 {}
249     impl Sealed for super::A2 {}
250     impl Sealed for super::A3 {}
251     impl Sealed for super::A4 {}
252     impl Sealed for super::A5 {}
253     #[cfg(target_arch = "mips")]
254     impl Sealed for super::A6 {}
255     #[cfg(target_arch = "x86")]
256     impl Sealed for super::SocketArg {}
257     impl Sealed for super::R0 {}
258 }
259