/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustix-1.1.2/src/process/prctl.rs
Line | Count | Source |
1 | | //! Bindings for the Linux `prctl` system call. |
2 | | //! |
3 | | //! There are similarities (but also differences) with FreeBSD's `procctl` |
4 | | //! system call, whose interface is located in the `procctl.rs` file. |
5 | | |
6 | | #![allow(unsafe_code)] |
7 | | |
8 | | use core::mem::size_of; |
9 | | use core::num::NonZeroI32; |
10 | | use core::ptr::{null, null_mut, NonNull}; |
11 | | |
12 | | use bitflags::bitflags; |
13 | | |
14 | | use crate::backend::prctl::syscalls; |
15 | | use crate::fd::{AsRawFd as _, BorrowedFd, RawFd}; |
16 | | use crate::ffi::{c_int, c_uint, c_void, CStr}; |
17 | | use crate::io; |
18 | | use crate::prctl::*; |
19 | | use crate::process::{Pid, RawPid}; |
20 | | use crate::signal::Signal; |
21 | | use crate::utils::{as_mut_ptr, as_ptr}; |
22 | | |
23 | | // |
24 | | // PR_GET_PDEATHSIG/PR_SET_PDEATHSIG |
25 | | // |
26 | | |
27 | | const PR_GET_PDEATHSIG: c_int = 2; |
28 | | |
29 | | /// Get the current value of the parent process death signal. |
30 | | /// |
31 | | /// # References |
32 | | /// - [Linux: `prctl(PR_GET_PDEATHSIG,…)`] |
33 | | /// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,…)`] |
34 | | /// |
35 | | /// [Linux: `prctl(PR_GET_PDEATHSIG,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
36 | | /// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,…)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 |
37 | | #[inline] |
38 | | #[doc(alias = "PR_GET_PDEATHSIG")] |
39 | 0 | pub fn parent_process_death_signal() -> io::Result<Option<Signal>> { |
40 | 0 | let raw = unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG)? }; |
41 | 0 | if let Some(non_zero) = NonZeroI32::new(raw) { |
42 | | // SAFETY: The only way to get a libc-reserved signal number in |
43 | | // here would be to do something equivalent to |
44 | | // `set_parent_process_death_signal`, but that would have required |
45 | | // using a `Signal` with a libc-reserved value. |
46 | 0 | Ok(Some(unsafe { |
47 | 0 | Signal::from_raw_nonzero_unchecked(non_zero) |
48 | 0 | })) |
49 | | } else { |
50 | 0 | Ok(None) |
51 | | } |
52 | 0 | } |
53 | | |
54 | | const PR_SET_PDEATHSIG: c_int = 1; |
55 | | |
56 | | /// Set the parent-death signal of the calling process. |
57 | | /// |
58 | | /// # References |
59 | | /// - [Linux: `prctl(PR_SET_PDEATHSIG,…)`] |
60 | | /// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,…)`] |
61 | | /// |
62 | | /// [Linux: `prctl(PR_SET_PDEATHSIG,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
63 | | /// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,…)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 |
64 | | #[inline] |
65 | | #[doc(alias = "PR_SET_PDEATHSIG")] |
66 | 0 | pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> { |
67 | 0 | let signal = signal.map_or(0_usize, |signal| signal.as_raw() as usize); |
68 | 0 | unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ()) |
69 | 0 | } |
70 | | |
71 | | // |
72 | | // PR_GET_DUMPABLE/PR_SET_DUMPABLE |
73 | | // |
74 | | |
75 | | const PR_GET_DUMPABLE: c_int = 3; |
76 | | |
77 | | const SUID_DUMP_DISABLE: i32 = 0; |
78 | | const SUID_DUMP_USER: i32 = 1; |
79 | | const SUID_DUMP_ROOT: i32 = 2; |
80 | | |
81 | | /// `SUID_DUMP_*` values for use with [`dumpable_behavior`] and |
82 | | /// [`set_dumpable_behavior`]. |
83 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
84 | | #[repr(i32)] |
85 | | pub enum DumpableBehavior { |
86 | | /// Not dumpable. |
87 | | #[doc(alias = "SUID_DUMP_DISABLE")] |
88 | | NotDumpable = SUID_DUMP_DISABLE, |
89 | | /// Dumpable. |
90 | | #[doc(alias = "SUID_DUMP_USER")] |
91 | | Dumpable = SUID_DUMP_USER, |
92 | | /// Dumpable but only readable by root. |
93 | | #[doc(alias = "SUID_DUMP_ROOT")] |
94 | | DumpableReadableOnlyByRoot = SUID_DUMP_ROOT, |
95 | | } |
96 | | |
97 | | impl TryFrom<i32> for DumpableBehavior { |
98 | | type Error = io::Errno; |
99 | | |
100 | 0 | fn try_from(value: i32) -> Result<Self, Self::Error> { |
101 | 0 | match value { |
102 | 0 | SUID_DUMP_DISABLE => Ok(Self::NotDumpable), |
103 | 0 | SUID_DUMP_USER => Ok(Self::Dumpable), |
104 | 0 | SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot), |
105 | 0 | _ => Err(io::Errno::RANGE), |
106 | | } |
107 | 0 | } |
108 | | } |
109 | | |
110 | | /// Get the current state of the calling process' `dumpable` attribute. |
111 | | /// |
112 | | /// # References |
113 | | /// - [`prctl(PR_GET_DUMPABLE,…)`] |
114 | | /// |
115 | | /// [`prctl(PR_GET_DUMPABLE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
116 | | #[inline] |
117 | | #[doc(alias = "PR_GET_DUMPABLE")] |
118 | 0 | pub fn dumpable_behavior() -> io::Result<DumpableBehavior> { |
119 | 0 | unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into) |
120 | 0 | } |
121 | | |
122 | | const PR_SET_DUMPABLE: c_int = 4; |
123 | | |
124 | | /// Set the state of the `dumpable` attribute. |
125 | | /// |
126 | | /// This attribute determines whether the process can be traced and whether |
127 | | /// core dumps are produced for the calling process upon delivery of a signal |
128 | | /// whose default behavior is to produce a core dump. |
129 | | /// |
130 | | /// A similar function with the same name is available on FreeBSD (as part of |
131 | | /// the `procctl` interface), but it has an extra argument which allows to |
132 | | /// select a process other then the current process. |
133 | | /// |
134 | | /// # References |
135 | | /// - [`prctl(PR_SET_DUMPABLE,…)`] |
136 | | /// |
137 | | /// [`prctl(PR_SET_DUMPABLE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
138 | | #[inline] |
139 | | #[doc(alias = "PR_SET_DUMPABLE")] |
140 | 0 | pub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> { |
141 | 0 | unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r| ()) |
142 | 0 | } |
143 | | |
144 | | // |
145 | | // PR_GET_UNALIGN/PR_SET_UNALIGN |
146 | | // |
147 | | |
148 | | const PR_GET_UNALIGN: c_int = 5; |
149 | | |
150 | | bitflags! { |
151 | | /// `PR_UNALIGN_*` flags for use with [`unaligned_access_control`] and |
152 | | /// [`set_unaligned_access_control`]. |
153 | | #[repr(transparent)] |
154 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
155 | | pub struct UnalignedAccessControl: u32 { |
156 | | /// Silently fix up unaligned user accesses. |
157 | | #[doc(alias = "NOPRINT")] |
158 | | #[doc(alias = "PR_UNALIGN_NOPRINT")] |
159 | | const NO_PRINT = 1; |
160 | | /// Generate a [`Signal::Bus`] signal on unaligned user access. |
161 | | #[doc(alias = "PR_UNALIGN_SIGBUS")] |
162 | | const SIGBUS = 2; |
163 | | |
164 | | /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> |
165 | | const _ = !0; |
166 | | } |
167 | | } |
168 | | |
169 | | /// Get unaligned access control bits. |
170 | | /// |
171 | | /// # References |
172 | | /// - [`prctl(PR_GET_UNALIGN,…)`] |
173 | | /// |
174 | | /// [`prctl(PR_GET_UNALIGN,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
175 | | #[inline] |
176 | | #[doc(alias = "PR_GET_UNALIGN")] |
177 | 0 | pub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> { |
178 | 0 | let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? }; |
179 | 0 | UnalignedAccessControl::from_bits(r).ok_or(io::Errno::RANGE) |
180 | 0 | } |
181 | | |
182 | | const PR_SET_UNALIGN: c_int = 6; |
183 | | |
184 | | /// Set unaligned access control bits. |
185 | | /// |
186 | | /// # References |
187 | | /// - [`prctl(PR_SET_UNALIGN,…)`] |
188 | | /// |
189 | | /// [`prctl(PR_SET_UNALIGN,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
190 | | #[inline] |
191 | | #[doc(alias = "PR_SET_UNALIGN")] |
192 | 0 | pub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> { |
193 | 0 | unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r| ()) |
194 | 0 | } |
195 | | |
196 | | // |
197 | | // PR_GET_FPEMU/PR_SET_FPEMU |
198 | | // |
199 | | |
200 | | const PR_GET_FPEMU: c_int = 9; |
201 | | |
202 | | bitflags! { |
203 | | /// `PR_FPEMU_*` flags for use with [`floating_point_emulation_control`] |
204 | | /// and [`set_floating_point_emulation_control`]. |
205 | | #[repr(transparent)] |
206 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
207 | | pub struct FloatingPointEmulationControl: u32 { |
208 | | /// Silently emulate floating point operations accesses. |
209 | | #[doc(alias = "PR_UNALIGN_NOPRINT")] |
210 | | const NO_PRINT = 1; |
211 | | /// Don't emulate floating point operations, send a [`Signal::Fpe`] |
212 | | /// signal instead. |
213 | | #[doc(alias = "PR_UNALIGN_SIGFPE")] |
214 | | const SIGFPE = 2; |
215 | | } |
216 | | } |
217 | | |
218 | | /// Get floating point emulation control bits. |
219 | | /// |
220 | | /// # References |
221 | | /// - [`prctl(PR_GET_FPEMU,…)`] |
222 | | /// |
223 | | /// [`prctl(PR_GET_FPEMU,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
224 | | #[inline] |
225 | | #[doc(alias = "PR_GET_FPEMU")] |
226 | 0 | pub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> { |
227 | 0 | let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? }; |
228 | 0 | FloatingPointEmulationControl::from_bits(r).ok_or(io::Errno::RANGE) |
229 | 0 | } |
230 | | |
231 | | const PR_SET_FPEMU: c_int = 10; |
232 | | |
233 | | /// Set floating point emulation control bits. |
234 | | /// |
235 | | /// # References |
236 | | /// - [`prctl(PR_SET_FPEMU,…)`] |
237 | | /// |
238 | | /// [`prctl(PR_SET_FPEMU,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
239 | | #[inline] |
240 | | #[doc(alias = "PR_SET_FPEMU")] |
241 | 0 | pub fn set_floating_point_emulation_control( |
242 | 0 | config: FloatingPointEmulationControl, |
243 | 0 | ) -> io::Result<()> { |
244 | 0 | unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r| ()) |
245 | 0 | } |
246 | | |
247 | | // |
248 | | // PR_GET_FPEXC/PR_SET_FPEXC |
249 | | // |
250 | | |
251 | | const PR_GET_FPEXC: c_int = 11; |
252 | | |
253 | | bitflags! { |
254 | | /// Zero means floating point exceptions are disabled. |
255 | | #[repr(transparent)] |
256 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
257 | | pub struct FloatingPointExceptionMode: u32 { |
258 | | /// Async non-recoverable exception mode. |
259 | | const NONRECOV = 1; |
260 | | /// Async recoverable exception mode. |
261 | | const ASYNC = 2; |
262 | | /// Precise exception mode. |
263 | | const PRECISE = 3; |
264 | | |
265 | | /// Use FPEXC for floating point exception enables. |
266 | | const SW_ENABLE = 0x80; |
267 | | /// Floating point divide by zero. |
268 | | const DIV = 0x01_0000; |
269 | | /// Floating point overflow. |
270 | | const OVF = 0x02_0000; |
271 | | /// Floating point underflow. |
272 | | const UND = 0x04_0000; |
273 | | /// Floating point inexact result. |
274 | | const RES = 0x08_0000; |
275 | | /// Floating point invalid operation. |
276 | | const INV = 0x10_0000; |
277 | | } |
278 | | } |
279 | | |
280 | | /// Get floating point exception mode. |
281 | | /// |
282 | | /// # References |
283 | | /// - [`prctl(PR_GET_FPEXC,…)`] |
284 | | /// |
285 | | /// [`prctl(PR_GET_FPEXC,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
286 | | #[inline] |
287 | | #[doc(alias = "PR_GET_FPEXEC")] |
288 | 0 | pub fn floating_point_exception_mode() -> io::Result<Option<FloatingPointExceptionMode>> { |
289 | 0 | unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEXC) } |
290 | 0 | .map(FloatingPointExceptionMode::from_bits) |
291 | 0 | } |
292 | | |
293 | | const PR_SET_FPEXC: c_int = 12; |
294 | | |
295 | | /// Set floating point exception mode. |
296 | | /// |
297 | | /// # References |
298 | | /// - [`prctl(PR_SET_FPEXC,…)`] |
299 | | /// |
300 | | /// [`prctl(PR_SET_FPEXC,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
301 | | #[inline] |
302 | | #[doc(alias = "PR_SET_FPEXEC")] |
303 | 0 | pub fn set_floating_point_exception_mode( |
304 | 0 | config: Option<FloatingPointExceptionMode>, |
305 | 0 | ) -> io::Result<()> { |
306 | 0 | let config = config.as_ref().map_or(0, FloatingPointExceptionMode::bits); |
307 | 0 | unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r| ()) |
308 | 0 | } |
309 | | |
310 | | // |
311 | | // PR_GET_TIMING/PR_SET_TIMING |
312 | | // |
313 | | |
314 | | const PR_GET_TIMING: c_int = 13; |
315 | | |
316 | | const PR_TIMING_STATISTICAL: i32 = 0; |
317 | | const PR_TIMING_TIMESTAMP: i32 = 1; |
318 | | |
319 | | /// `PR_TIMING_*` values for use with [`timing_method`] and |
320 | | /// [`set_timing_method`]. |
321 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
322 | | #[repr(i32)] |
323 | | pub enum TimingMethod { |
324 | | /// Normal, traditional, statistical process timing. |
325 | | Statistical = PR_TIMING_STATISTICAL, |
326 | | /// Accurate timestamp based process timing. |
327 | | TimeStamp = PR_TIMING_TIMESTAMP, |
328 | | } |
329 | | |
330 | | impl TryFrom<i32> for TimingMethod { |
331 | | type Error = io::Errno; |
332 | | |
333 | 0 | fn try_from(value: i32) -> Result<Self, Self::Error> { |
334 | 0 | match value { |
335 | 0 | PR_TIMING_STATISTICAL => Ok(Self::Statistical), |
336 | 0 | PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp), |
337 | 0 | _ => Err(io::Errno::RANGE), |
338 | | } |
339 | 0 | } |
340 | | } |
341 | | |
342 | | /// Get which process timing method is currently in use. |
343 | | /// |
344 | | /// # References |
345 | | /// - [`prctl(PR_GET_TIMING,…)`] |
346 | | /// |
347 | | /// [`prctl(PR_GET_TIMING,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
348 | | #[inline] |
349 | | #[doc(alias = "PR_GET_TIMING")] |
350 | 0 | pub fn timing_method() -> io::Result<TimingMethod> { |
351 | 0 | unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into) |
352 | 0 | } |
353 | | |
354 | | const PR_SET_TIMING: c_int = 14; |
355 | | |
356 | | /// Set whether to use (normal, traditional) statistical process timing or |
357 | | /// accurate timestamp-based process timing. |
358 | | /// |
359 | | /// # References |
360 | | /// - [`prctl(PR_SET_TIMING,…)`] |
361 | | /// |
362 | | /// [`prctl(PR_SET_TIMING,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
363 | | #[inline] |
364 | | #[doc(alias = "PR_SET_TIMING")] |
365 | 0 | pub fn set_timing_method(method: TimingMethod) -> io::Result<()> { |
366 | 0 | unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r| ()) |
367 | 0 | } |
368 | | |
369 | | // |
370 | | // PR_GET_ENDIAN/PR_SET_ENDIAN |
371 | | // |
372 | | |
373 | | const PR_GET_ENDIAN: c_int = 19; |
374 | | |
375 | | const PR_ENDIAN_BIG: u32 = 0; |
376 | | const PR_ENDIAN_LITTLE: u32 = 1; |
377 | | const PR_ENDIAN_PPC_LITTLE: u32 = 2; |
378 | | |
379 | | /// `PR_ENDIAN_*` values for use with [`endian_mode`]. |
380 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
381 | | #[repr(u32)] |
382 | | pub enum EndianMode { |
383 | | /// Big endian mode. |
384 | | Big = PR_ENDIAN_BIG, |
385 | | /// True little endian mode. |
386 | | Little = PR_ENDIAN_LITTLE, |
387 | | /// `PowerPC` pseudo little endian. |
388 | | PowerPCLittle = PR_ENDIAN_PPC_LITTLE, |
389 | | } |
390 | | |
391 | | impl TryFrom<u32> for EndianMode { |
392 | | type Error = io::Errno; |
393 | | |
394 | 0 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
395 | 0 | match value { |
396 | 0 | PR_ENDIAN_BIG => Ok(Self::Big), |
397 | 0 | PR_ENDIAN_LITTLE => Ok(Self::Little), |
398 | 0 | PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle), |
399 | 0 | _ => Err(io::Errno::RANGE), |
400 | | } |
401 | 0 | } |
402 | | } |
403 | | |
404 | | /// Get the endianness of the calling process. |
405 | | /// |
406 | | /// # References |
407 | | /// - [`prctl(PR_GET_ENDIAN,…)`] |
408 | | /// |
409 | | /// [`prctl(PR_GET_ENDIAN,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
410 | | #[inline] |
411 | | #[doc(alias = "PR_GET_ENDIAN")] |
412 | 0 | pub fn endian_mode() -> io::Result<EndianMode> { |
413 | 0 | unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) } |
414 | 0 | } |
415 | | |
416 | | const PR_SET_ENDIAN: c_int = 20; |
417 | | |
418 | | /// Set the endianness of the calling process. |
419 | | /// |
420 | | /// # References |
421 | | /// - [`prctl(PR_SET_ENDIAN,…)`] |
422 | | /// |
423 | | /// # Safety |
424 | | /// |
425 | | /// Please ensure the conditions necessary to safely call this function, as |
426 | | /// detailed in the references above. |
427 | | /// |
428 | | /// [`prctl(PR_SET_ENDIAN,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
429 | | #[inline] |
430 | | #[doc(alias = "PR_SET_ENDIAN")] |
431 | 0 | pub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> { |
432 | 0 | prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r| ()) |
433 | 0 | } |
434 | | |
435 | | // |
436 | | // PR_GET_TSC/PR_SET_TSC |
437 | | // |
438 | | |
439 | | const PR_GET_TSC: c_int = 25; |
440 | | |
441 | | const PR_TSC_ENABLE: u32 = 1; |
442 | | const PR_TSC_SIGSEGV: u32 = 2; |
443 | | |
444 | | /// `PR_TSC_*` values for use with [`time_stamp_counter_readability`] and |
445 | | /// [`set_time_stamp_counter_readability`]. |
446 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
447 | | #[repr(u32)] |
448 | | pub enum TimeStampCounterReadability { |
449 | | /// Allow the use of the timestamp counter. |
450 | | Readable = PR_TSC_ENABLE, |
451 | | /// Throw a [`Signal::SEGV`] signal instead of reading the TSC. |
452 | | RaiseSIGSEGV = PR_TSC_SIGSEGV, |
453 | | } |
454 | | |
455 | | impl TryFrom<u32> for TimeStampCounterReadability { |
456 | | type Error = io::Errno; |
457 | | |
458 | 0 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
459 | 0 | match value { |
460 | 0 | PR_TSC_ENABLE => Ok(Self::Readable), |
461 | 0 | PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV), |
462 | 0 | _ => Err(io::Errno::RANGE), |
463 | | } |
464 | 0 | } |
465 | | } |
466 | | |
467 | | /// Get the state of the flag determining if the timestamp counter can be read. |
468 | | /// |
469 | | /// # References |
470 | | /// - [`prctl(PR_GET_TSC,…)`] |
471 | | /// |
472 | | /// [`prctl(PR_GET_TSC,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
473 | | #[inline] |
474 | | #[doc(alias = "PR_GET_TSC")] |
475 | 0 | pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> { |
476 | 0 | unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) } |
477 | 0 | } |
478 | | |
479 | | const PR_SET_TSC: c_int = 26; |
480 | | |
481 | | /// Set the state of the flag determining if the timestamp counter can be read |
482 | | /// by the process. |
483 | | /// |
484 | | /// # References |
485 | | /// - [`prctl(PR_SET_TSC,…)`] |
486 | | /// |
487 | | /// [`prctl(PR_SET_TSC,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
488 | | #[inline] |
489 | | #[doc(alias = "PR_SET_TSC")] |
490 | 0 | pub fn set_time_stamp_counter_readability( |
491 | 0 | readability: TimeStampCounterReadability, |
492 | 0 | ) -> io::Result<()> { |
493 | 0 | unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r| ()) |
494 | 0 | } |
495 | | |
496 | | // |
497 | | // PR_TASK_PERF_EVENTS_DISABLE/PR_TASK_PERF_EVENTS_ENABLE |
498 | | // |
499 | | |
500 | | const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31; |
501 | | const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32; |
502 | | |
503 | | /// Enable or disable all performance counters attached to the calling process. |
504 | | /// |
505 | | /// # References |
506 | | /// - [`prctl(PR_TASK_PERF_EVENTS_ENABLE,…)`] |
507 | | /// - [`prctl(PR_TASK_PERF_EVENTS_DISABLE,…)`] |
508 | | /// |
509 | | /// [`prctl(PR_TASK_PERF_EVENTS_ENABLE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
510 | | /// [`prctl(PR_TASK_PERF_EVENTS_DISABLE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
511 | | #[inline] |
512 | | #[doc(alias = "PR_TASK_PERF_EVENTS_ENABLE")] |
513 | | #[doc(alias = "PR_TASK_PERF_EVENTS_DISABLE")] |
514 | 0 | pub fn configure_performance_counters(enable: bool) -> io::Result<()> { |
515 | 0 | let option = if enable { |
516 | 0 | PR_TASK_PERF_EVENTS_ENABLE |
517 | | } else { |
518 | 0 | PR_TASK_PERF_EVENTS_DISABLE |
519 | | }; |
520 | | |
521 | 0 | unsafe { prctl_1arg(option) }.map(|_r| ()) |
522 | 0 | } |
523 | | |
524 | | // |
525 | | // PR_MCE_KILL_GET/PR_MCE_KILL |
526 | | // |
527 | | |
528 | | const PR_MCE_KILL_GET: c_int = 34; |
529 | | |
530 | | const PR_MCE_KILL_LATE: u32 = 0; |
531 | | const PR_MCE_KILL_EARLY: u32 = 1; |
532 | | const PR_MCE_KILL_DEFAULT: u32 = 2; |
533 | | |
534 | | /// `PR_MCE_KILL_*` values for use with |
535 | | /// [`machine_check_memory_corruption_kill_policy`] and |
536 | | /// [`set_machine_check_memory_corruption_kill_policy`]. |
537 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
538 | | #[repr(u32)] |
539 | | pub enum MachineCheckMemoryCorruptionKillPolicy { |
540 | | /// Late kill policy. |
541 | | #[doc(alias = "PR_MCE_KILL_LATE")] |
542 | | Late = PR_MCE_KILL_LATE, |
543 | | /// Early kill policy. |
544 | | #[doc(alias = "PR_MCE_KILL_EARLY")] |
545 | | Early = PR_MCE_KILL_EARLY, |
546 | | /// System-wide default policy. |
547 | | #[doc(alias = "PR_MCE_KILL_DEFAULT")] |
548 | | Default = PR_MCE_KILL_DEFAULT, |
549 | | } |
550 | | |
551 | | impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy { |
552 | | type Error = io::Errno; |
553 | | |
554 | 0 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
555 | 0 | match value { |
556 | 0 | PR_MCE_KILL_LATE => Ok(Self::Late), |
557 | 0 | PR_MCE_KILL_EARLY => Ok(Self::Early), |
558 | 0 | PR_MCE_KILL_DEFAULT => Ok(Self::Default), |
559 | 0 | _ => Err(io::Errno::RANGE), |
560 | | } |
561 | 0 | } |
562 | | } |
563 | | |
564 | | /// Get the current per-process machine check kill policy. |
565 | | /// |
566 | | /// # References |
567 | | /// - [`prctl(PR_MCE_KILL_GET,…)`] |
568 | | /// |
569 | | /// [`prctl(PR_MCE_KILL_GET,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
570 | | #[inline] |
571 | | #[doc(alias = "PR_MCE_KILL_GET")] |
572 | 0 | pub fn machine_check_memory_corruption_kill_policy( |
573 | 0 | ) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> { |
574 | 0 | let r = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint; |
575 | 0 | MachineCheckMemoryCorruptionKillPolicy::try_from(r) |
576 | 0 | } |
577 | | |
578 | | const PR_MCE_KILL: c_int = 33; |
579 | | |
580 | | const PR_MCE_KILL_CLEAR: usize = 0; |
581 | | const PR_MCE_KILL_SET: usize = 1; |
582 | | |
583 | | /// Set the machine check memory corruption kill policy for the calling thread. |
584 | | /// |
585 | | /// # References |
586 | | /// - [`prctl(PR_MCE_KILL,…)`] |
587 | | /// |
588 | | /// [`prctl(PR_MCE_KILL,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
589 | | #[inline] |
590 | | #[doc(alias = "PR_MCE_KILL")] |
591 | 0 | pub fn set_machine_check_memory_corruption_kill_policy( |
592 | 0 | policy: Option<MachineCheckMemoryCorruptionKillPolicy>, |
593 | 0 | ) -> io::Result<()> { |
594 | 0 | let (sub_operation, policy) = if let Some(policy) = policy { |
595 | 0 | (PR_MCE_KILL_SET, policy as usize as *mut _) |
596 | | } else { |
597 | 0 | (PR_MCE_KILL_CLEAR, null_mut()) |
598 | | }; |
599 | | |
600 | 0 | unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r| ()) |
601 | 0 | } |
602 | | |
603 | | // |
604 | | // PR_SET_MM |
605 | | // |
606 | | |
607 | | const PR_SET_MM: c_int = 35; |
608 | | |
609 | | const PR_SET_MM_START_CODE: u32 = 1; |
610 | | const PR_SET_MM_END_CODE: u32 = 2; |
611 | | const PR_SET_MM_START_DATA: u32 = 3; |
612 | | const PR_SET_MM_END_DATA: u32 = 4; |
613 | | const PR_SET_MM_START_STACK: u32 = 5; |
614 | | const PR_SET_MM_START_BRK: u32 = 6; |
615 | | const PR_SET_MM_BRK: u32 = 7; |
616 | | const PR_SET_MM_ARG_START: u32 = 8; |
617 | | const PR_SET_MM_ARG_END: u32 = 9; |
618 | | const PR_SET_MM_ENV_START: u32 = 10; |
619 | | const PR_SET_MM_ENV_END: u32 = 11; |
620 | | const PR_SET_MM_AUXV: usize = 12; |
621 | | const PR_SET_MM_EXE_FILE: usize = 13; |
622 | | const PR_SET_MM_MAP: usize = 14; |
623 | | const PR_SET_MM_MAP_SIZE: usize = 15; |
624 | | |
625 | | /// `PR_SET_MM_*` values for use with [`set_virtual_memory_map_address`]. |
626 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
627 | | #[repr(u32)] |
628 | | pub enum VirtualMemoryMapAddress { |
629 | | /// Set the address above which the program text can run. |
630 | | CodeStart = PR_SET_MM_START_CODE, |
631 | | /// Set the address below which the program text can run. |
632 | | CodeEnd = PR_SET_MM_END_CODE, |
633 | | /// Set the address above which initialized and uninitialized (bss) data |
634 | | /// are placed. |
635 | | DataStart = PR_SET_MM_START_DATA, |
636 | | /// Set the address below which initialized and uninitialized (bss) data |
637 | | /// are placed. |
638 | | DataEnd = PR_SET_MM_END_DATA, |
639 | | /// Set the start address of the stack. |
640 | | StackStart = PR_SET_MM_START_STACK, |
641 | | /// Set the address above which the program heap can be expanded with `brk` |
642 | | /// call. |
643 | | BrkStart = PR_SET_MM_START_BRK, |
644 | | /// Set the current `brk` value. |
645 | | BrkCurrent = PR_SET_MM_BRK, |
646 | | /// Set the address above which the program command line is placed. |
647 | | ArgStart = PR_SET_MM_ARG_START, |
648 | | /// Set the address below which the program command line is placed. |
649 | | ArgEnd = PR_SET_MM_ARG_END, |
650 | | /// Set the address above which the program environment is placed. |
651 | | EnvironmentStart = PR_SET_MM_ENV_START, |
652 | | /// Set the address below which the program environment is placed. |
653 | | EnvironmentEnd = PR_SET_MM_ENV_END, |
654 | | } |
655 | | |
656 | | /// Modify certain kernel memory map descriptor addresses of the calling |
657 | | /// process. |
658 | | /// |
659 | | /// # References |
660 | | /// - [`prctl(PR_SET_MM,…)`] |
661 | | /// |
662 | | /// # Safety |
663 | | /// |
664 | | /// Please ensure the conditions necessary to safely call this function, as |
665 | | /// detailed in the references above. |
666 | | /// |
667 | | /// [`prctl(PR_SET_MM,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
668 | | #[inline] |
669 | | #[doc(alias = "PR_SET_MM")] |
670 | 0 | pub unsafe fn set_virtual_memory_map_address( |
671 | 0 | option: VirtualMemoryMapAddress, |
672 | 0 | address: Option<NonNull<c_void>>, |
673 | 0 | ) -> io::Result<()> { |
674 | 0 | let address = address.map_or_else(null_mut, NonNull::as_ptr); |
675 | 0 | prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r| ()) |
676 | 0 | } |
677 | | |
678 | | /// Supersede the `/proc/pid/exe` symbolic link with a new one pointing to a |
679 | | /// new executable file. |
680 | | /// |
681 | | /// # References |
682 | | /// - [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,…)`] |
683 | | /// |
684 | | /// [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
685 | | #[inline] |
686 | | #[doc(alias = "PR_SET_MM")] |
687 | | #[doc(alias = "PR_SET_MM_EXE_FILE")] |
688 | 0 | pub fn set_executable_file(fd: BorrowedFd<'_>) -> io::Result<()> { |
689 | 0 | let fd = usize::try_from(fd.as_raw_fd()).map_err(|_r| io::Errno::RANGE)?; |
690 | 0 | unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r| ()) |
691 | 0 | } |
692 | | |
693 | | /// Set a new auxiliary vector. |
694 | | /// |
695 | | /// # References |
696 | | /// - [`prctl(PR_SET_MM,PR_SET_MM_AUXV,…)`] |
697 | | /// |
698 | | /// # Safety |
699 | | /// |
700 | | /// Please ensure the conditions necessary to safely call this function, as |
701 | | /// detailed in the references above. |
702 | | /// |
703 | | /// [`prctl(PR_SET_MM,PR_SET_MM_AUXV,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
704 | | #[inline] |
705 | | #[doc(alias = "PR_SET_MM")] |
706 | | #[doc(alias = "PR_SET_MM_AUXV")] |
707 | 0 | pub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> { |
708 | 0 | syscalls::prctl( |
709 | | PR_SET_MM, |
710 | 0 | PR_SET_MM_AUXV as *mut _, |
711 | 0 | auxv.as_ptr() as *mut _, |
712 | 0 | auxv.len() as *mut _, |
713 | 0 | null_mut(), |
714 | | ) |
715 | 0 | .map(|_r| ()) |
716 | 0 | } |
717 | | |
718 | | /// Get the size of the [`PrctlMmMap`] the kernel expects. |
719 | | /// |
720 | | /// # References |
721 | | /// - [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,…)`] |
722 | | /// |
723 | | /// [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
724 | | #[inline] |
725 | | #[doc(alias = "PR_SET_MM")] |
726 | | #[doc(alias = "PR_SET_MM_MAP_SIZE")] |
727 | 0 | pub fn virtual_memory_map_config_struct_size() -> io::Result<usize> { |
728 | 0 | let mut value: c_uint = 0; |
729 | 0 | let value_ptr = as_mut_ptr(&mut value); |
730 | 0 | unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, value_ptr.cast())? }; |
731 | 0 | Ok(value as usize) |
732 | 0 | } |
733 | | |
734 | | /// This structure provides new memory descriptor map which mostly modifies |
735 | | /// `/proc/pid/stat[m]` output for a task. |
736 | | /// This mostly done in a sake of checkpoint/restore functionality. |
737 | | #[repr(C)] |
738 | | #[derive(Debug, Clone)] |
739 | | pub struct PrctlMmMap { |
740 | | /// Code section start address. |
741 | | pub start_code: u64, |
742 | | /// Code section end address. |
743 | | pub end_code: u64, |
744 | | /// Data section start address. |
745 | | pub start_data: u64, |
746 | | /// Data section end address. |
747 | | pub end_data: u64, |
748 | | /// `brk` start address. |
749 | | pub start_brk: u64, |
750 | | /// `brk` current address. |
751 | | pub brk: u64, |
752 | | /// Stack start address. |
753 | | pub start_stack: u64, |
754 | | /// Program command line start address. |
755 | | pub arg_start: u64, |
756 | | /// Program command line end address. |
757 | | pub arg_end: u64, |
758 | | /// Program environment start address. |
759 | | pub env_start: u64, |
760 | | /// Program environment end address. |
761 | | pub env_end: u64, |
762 | | /// Auxiliary vector start address. |
763 | | pub auxv: *mut u64, |
764 | | /// Auxiliary vector size. |
765 | | pub auxv_size: u32, |
766 | | /// File descriptor of executable file that was used to create this |
767 | | /// process. |
768 | | pub exe_fd: RawFd, |
769 | | } |
770 | | |
771 | | /// Provides one-shot access to all the addresses by passing in a |
772 | | /// [`PrctlMmMap`]. |
773 | | /// |
774 | | /// # References |
775 | | /// - [`prctl(PR_SET_MM,PR_SET_MM_MAP,…)`] |
776 | | /// |
777 | | /// # Safety |
778 | | /// |
779 | | /// Please ensure the conditions necessary to safely call this function, as |
780 | | /// detailed in the references above. |
781 | | /// |
782 | | /// [`prctl(PR_SET_MM,PR_SET_MM_MAP,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
783 | | #[inline] |
784 | | #[doc(alias = "PR_SET_MM")] |
785 | | #[doc(alias = "PR_SET_MM_MAP")] |
786 | 0 | pub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> { |
787 | 0 | syscalls::prctl( |
788 | | PR_SET_MM, |
789 | 0 | PR_SET_MM_MAP as *mut _, |
790 | 0 | as_ptr(config) as *mut _, |
791 | 0 | size_of::<PrctlMmMap>() as *mut _, |
792 | 0 | null_mut(), |
793 | | ) |
794 | 0 | .map(|_r| ()) |
795 | 0 | } |
796 | | |
797 | | // |
798 | | // PR_SET_PTRACER |
799 | | // |
800 | | |
801 | | const PR_SET_PTRACER: c_int = 0x59_61_6d_61; |
802 | | |
803 | | const PR_SET_PTRACER_ANY: usize = usize::MAX; |
804 | | |
805 | | /// Process ptracer. |
806 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
807 | | pub enum PTracer { |
808 | | /// None. |
809 | | None, |
810 | | /// Disable `ptrace` restrictions for the calling process. |
811 | | Any, |
812 | | /// Specific process. |
813 | | ProcessID(Pid), |
814 | | } |
815 | | |
816 | | /// Declare that the ptracer process can `ptrace` the calling process as if it |
817 | | /// were a direct process ancestor. |
818 | | /// |
819 | | /// # References |
820 | | /// - [`prctl(PR_SET_PTRACER,…)`] |
821 | | /// |
822 | | /// [`prctl(PR_SET_PTRACER,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
823 | | #[inline] |
824 | | #[doc(alias = "PR_SET_PTRACER")] |
825 | 0 | pub fn set_ptracer(tracer: PTracer) -> io::Result<()> { |
826 | 0 | let pid = match tracer { |
827 | 0 | PTracer::None => null_mut(), |
828 | 0 | PTracer::Any => PR_SET_PTRACER_ANY as *mut _, |
829 | 0 | PTracer::ProcessID(pid) => pid.as_raw_nonzero().get() as usize as *mut _, |
830 | | }; |
831 | | |
832 | 0 | unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r| ()) |
833 | 0 | } |
834 | | |
835 | | // |
836 | | // PR_GET_CHILD_SUBREAPER/PR_SET_CHILD_SUBREAPER |
837 | | // |
838 | | |
839 | | const PR_GET_CHILD_SUBREAPER: c_int = 37; |
840 | | |
841 | | /// Get the `child subreaper` setting of the calling process. |
842 | | /// |
843 | | /// # References |
844 | | /// - [`prctl(PR_GET_CHILD_SUBREAPER,…)`] |
845 | | /// |
846 | | /// [`prctl(PR_GET_CHILD_SUBREAPER,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
847 | | #[inline] |
848 | | #[doc(alias = "PR_GET_CHILD_SUBREAPER")] |
849 | 0 | pub fn child_subreaper() -> io::Result<Option<Pid>> { |
850 | | unsafe { |
851 | 0 | let r = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?; |
852 | 0 | Ok(Pid::from_raw(r as RawPid)) |
853 | | } |
854 | 0 | } |
855 | | |
856 | | const PR_SET_CHILD_SUBREAPER: c_int = 36; |
857 | | |
858 | | /// Set the `child subreaper` attribute of the calling process. |
859 | | /// |
860 | | /// # References |
861 | | /// - [`prctl(PR_SET_CHILD_SUBREAPER,…)`] |
862 | | /// |
863 | | /// [`prctl(PR_SET_CHILD_SUBREAPER,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
864 | | #[inline] |
865 | | #[doc(alias = "PR_SET_CHILD_SUBREAPER")] |
866 | 0 | pub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> { |
867 | 0 | let pid = pid.map_or(0_usize, |pid| pid.as_raw_nonzero().get() as usize); |
868 | 0 | unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r| ()) |
869 | 0 | } |
870 | | |
871 | | // |
872 | | // PR_GET_FP_MODE/PR_SET_FP_MODE |
873 | | // |
874 | | |
875 | | const PR_GET_FP_MODE: c_int = 46; |
876 | | |
877 | | const PR_FP_MODE_FR: u32 = 1_u32 << 0; |
878 | | const PR_FP_MODE_FRE: u32 = 1_u32 << 1; |
879 | | |
880 | | /// `PR_FP_MODE_*` values for use with [`floating_point_mode`] and |
881 | | /// [`set_floating_point_mode`]. |
882 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
883 | | #[repr(u32)] |
884 | | pub enum FloatingPointMode { |
885 | | /// 64-bit floating point registers. |
886 | | FloatingPointRegisters = PR_FP_MODE_FR, |
887 | | /// Enable emulation of 32-bit floating-point mode. |
888 | | FloatingPointEmulation = PR_FP_MODE_FRE, |
889 | | } |
890 | | |
891 | | impl TryFrom<u32> for FloatingPointMode { |
892 | | type Error = io::Errno; |
893 | | |
894 | 0 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
895 | 0 | match value { |
896 | 0 | PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters), |
897 | 0 | PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation), |
898 | 0 | _ => Err(io::Errno::RANGE), |
899 | | } |
900 | 0 | } |
901 | | } |
902 | | |
903 | | /// Get the current floating point mode. |
904 | | /// |
905 | | /// # References |
906 | | /// - [`prctl(PR_GET_FP_MODE,…)`] |
907 | | /// |
908 | | /// [`prctl(PR_GET_FP_MODE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
909 | | #[inline] |
910 | | #[doc(alias = "PR_GET_FP_MODE")] |
911 | 0 | pub fn floating_point_mode() -> io::Result<FloatingPointMode> { |
912 | 0 | let r = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint; |
913 | 0 | FloatingPointMode::try_from(r) |
914 | 0 | } |
915 | | |
916 | | const PR_SET_FP_MODE: c_int = 45; |
917 | | |
918 | | /// Allow control of the floating point mode from user space. |
919 | | /// |
920 | | /// # References |
921 | | /// - [`prctl(PR_SET_FP_MODE,…)`] |
922 | | /// |
923 | | /// [`prctl(PR_SET_FP_MODE,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
924 | | #[inline] |
925 | | #[doc(alias = "PR_SET_FP_MODE")] |
926 | 0 | pub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> { |
927 | 0 | unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r| ()) |
928 | 0 | } |
929 | | |
930 | | // |
931 | | // PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL |
932 | | // |
933 | | |
934 | | const PR_GET_SPECULATION_CTRL: c_int = 52; |
935 | | |
936 | | const PR_SPEC_STORE_BYPASS: u32 = 0; |
937 | | const PR_SPEC_INDIRECT_BRANCH: u32 = 1; |
938 | | const PR_SPEC_L1D_FLUSH: u32 = 2; |
939 | | |
940 | | /// `PR_SPEC_*` values for use with [`speculative_feature_state`] and |
941 | | /// [`control_speculative_feature`]. |
942 | | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
943 | | #[repr(u32)] |
944 | | pub enum SpeculationFeature { |
945 | | /// Set the state of the speculative store bypass misfeature. |
946 | | SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS, |
947 | | /// Set the state of the indirect branch speculation misfeature. |
948 | | IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH, |
949 | | /// Flush L1D Cache on context switch out of the task. |
950 | | FlushL1DCacheOnContextSwitchOutOfTask = PR_SPEC_L1D_FLUSH, |
951 | | } |
952 | | |
953 | | impl TryFrom<u32> for SpeculationFeature { |
954 | | type Error = io::Errno; |
955 | | |
956 | 0 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
957 | 0 | match value { |
958 | 0 | PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass), |
959 | 0 | PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation), |
960 | 0 | PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask), |
961 | 0 | _ => Err(io::Errno::RANGE), |
962 | | } |
963 | 0 | } |
964 | | } |
965 | | |
966 | | bitflags! { |
967 | | /// `PR_SPEC_*` flags for use with [`control_speculative_feature`]. |
968 | | #[repr(transparent)] |
969 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
970 | | pub struct SpeculationFeatureControl: u32 { |
971 | | /// The speculation feature is enabled, mitigation is disabled. |
972 | | const ENABLE = 1_u32 << 1; |
973 | | /// The speculation feature is disabled, mitigation is enabled. |
974 | | const DISABLE = 1_u32 << 2; |
975 | | /// The speculation feature is disabled, mitigation is enabled, and it |
976 | | /// cannot be undone. |
977 | | const FORCE_DISABLE = 1_u32 << 3; |
978 | | /// The speculation feature is disabled, mitigation is enabled, and the |
979 | | /// state will be cleared on `execve`. |
980 | | const DISABLE_NOEXEC = 1_u32 << 4; |
981 | | } |
982 | | } |
983 | | |
984 | | bitflags! { |
985 | | /// Zero means the processors are not vulnerable. |
986 | | #[repr(transparent)] |
987 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
988 | | pub struct SpeculationFeatureState: u32 { |
989 | | /// Mitigation can be controlled per thread by |
990 | | /// [`control_speculative_feature`]. |
991 | | const PRCTL = 1_u32 << 0; |
992 | | /// The speculation feature is enabled, mitigation is disabled. |
993 | | const ENABLE = 1_u32 << 1; |
994 | | /// The speculation feature is disabled, mitigation is enabled. |
995 | | const DISABLE = 1_u32 << 2; |
996 | | /// The speculation feature is disabled, mitigation is enabled, and it |
997 | | /// cannot be undone. |
998 | | const FORCE_DISABLE = 1_u32 << 3; |
999 | | /// The speculation feature is disabled, mitigation is enabled, and the |
1000 | | /// state will be cleared on `execve`. |
1001 | | const DISABLE_NOEXEC = 1_u32 << 4; |
1002 | | } |
1003 | | } |
1004 | | |
1005 | | /// Get the state of the speculation misfeature. |
1006 | | /// |
1007 | | /// # References |
1008 | | /// - [`prctl(PR_GET_SPECULATION_CTRL,…)`] |
1009 | | /// |
1010 | | /// [`prctl(PR_GET_SPECULATION_CTRL,…)`]: https://www.kernel.org/doc/html/v6.13/userspace-api/spec_ctrl.html |
1011 | | #[inline] |
1012 | | #[doc(alias = "PR_GET_SPECULATION_CTRL")] |
1013 | 0 | pub fn speculative_feature_state( |
1014 | 0 | feature: SpeculationFeature, |
1015 | 0 | ) -> io::Result<Option<SpeculationFeatureState>> { |
1016 | 0 | let r = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, feature as usize as *mut _)? } as c_uint; |
1017 | 0 | Ok(SpeculationFeatureState::from_bits(r)) |
1018 | 0 | } |
1019 | | |
1020 | | const PR_SET_SPECULATION_CTRL: c_int = 53; |
1021 | | |
1022 | | /// Sets the state of the speculation misfeature. |
1023 | | /// |
1024 | | /// # References |
1025 | | /// - [`prctl(PR_SET_SPECULATION_CTRL,…)`] |
1026 | | /// |
1027 | | /// [`prctl(PR_SET_SPECULATION_CTRL,…)`]: https://www.kernel.org/doc/html/v6.13/userspace-api/spec_ctrl.html |
1028 | | #[inline] |
1029 | | #[doc(alias = "PR_SET_SPECULATION_CTRL")] |
1030 | 0 | pub fn control_speculative_feature( |
1031 | 0 | feature: SpeculationFeature, |
1032 | 0 | config: SpeculationFeatureControl, |
1033 | 0 | ) -> io::Result<()> { |
1034 | 0 | let feature = feature as usize as *mut _; |
1035 | 0 | let config = config.bits() as usize as *mut _; |
1036 | 0 | unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r| ()) |
1037 | 0 | } |
1038 | | |
1039 | | // |
1040 | | // PR_GET_IO_FLUSHER/PR_SET_IO_FLUSHER |
1041 | | // |
1042 | | |
1043 | | const PR_GET_IO_FLUSHER: c_int = 58; |
1044 | | |
1045 | | /// Get the `IO_FLUSHER` state of the caller. |
1046 | | /// |
1047 | | /// # References |
1048 | | /// - [`prctl(PR_GET_IO_FLUSHER,…)`] |
1049 | | /// |
1050 | | /// [`prctl(PR_GET_IO_FLUSHER,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
1051 | | #[inline] |
1052 | | #[doc(alias = "PR_GET_IO_FLUSHER")] |
1053 | 0 | pub fn is_io_flusher() -> io::Result<bool> { |
1054 | 0 | unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0) |
1055 | 0 | } |
1056 | | |
1057 | | const PR_SET_IO_FLUSHER: c_int = 57; |
1058 | | |
1059 | | /// Put the process in the `IO_FLUSHER` state, allowing it to make progress |
1060 | | /// when allocating memory. |
1061 | | /// |
1062 | | /// # References |
1063 | | /// - [`prctl(PR_SET_IO_FLUSHER,…)`] |
1064 | | /// |
1065 | | /// [`prctl(PR_SET_IO_FLUSHER,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
1066 | | #[inline] |
1067 | | #[doc(alias = "PR_SET_IO_FLUSHER")] |
1068 | 0 | pub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> { |
1069 | 0 | unsafe { prctl_2args(PR_SET_IO_FLUSHER, usize::from(enable) as *mut _) }.map(|_r| ()) |
1070 | 0 | } |
1071 | | |
1072 | | // |
1073 | | // PR_PAC_GET_ENABLED_KEYS/PR_PAC_SET_ENABLED_KEYS |
1074 | | // |
1075 | | |
1076 | | const PR_PAC_GET_ENABLED_KEYS: c_int = 61; |
1077 | | |
1078 | | /// Get enabled pointer authentication keys. |
1079 | | /// |
1080 | | /// # References |
1081 | | /// - [`prctl(PR_PAC_GET_ENABLED_KEYS,…)`] |
1082 | | /// |
1083 | | /// [`prctl(PR_PAC_GET_ENABLED_KEYS,…)`]: https://www.kernel.org/doc/html/v6.13/arch/arm64/pointer-authentication.html |
1084 | | #[inline] |
1085 | | #[doc(alias = "PR_PAC_GET_ENABLED_KEYS")] |
1086 | | #[cfg(linux_raw_dep)] |
1087 | 0 | pub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> { |
1088 | 0 | let r = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint; |
1089 | 0 | PointerAuthenticationKeys::from_bits(r).ok_or(io::Errno::RANGE) |
1090 | 0 | } |
1091 | | |
1092 | | const PR_PAC_SET_ENABLED_KEYS: c_int = 60; |
1093 | | |
1094 | | /// Set enabled pointer authentication keys. |
1095 | | /// |
1096 | | /// # References |
1097 | | /// - [`prctl(PR_PAC_SET_ENABLED_KEYS,…)`] |
1098 | | /// |
1099 | | /// # Safety |
1100 | | /// |
1101 | | /// Please ensure the conditions necessary to safely call this function, as |
1102 | | /// detailed in the references above. |
1103 | | /// |
1104 | | /// [`prctl(PR_PAC_SET_ENABLED_KEYS,…)`]: https://www.kernel.org/doc/html/v6.13/arch/arm64/pointer-authentication.html |
1105 | | #[inline] |
1106 | | #[doc(alias = "PR_PAC_SET_ENABLED_KEYS")] |
1107 | | #[cfg(linux_raw_dep)] |
1108 | 0 | pub unsafe fn configure_pointer_authentication_keys< |
1109 | 0 | Config: Iterator<Item = (PointerAuthenticationKeys, bool)>, |
1110 | 0 | >( |
1111 | 0 | config: Config, |
1112 | 0 | ) -> io::Result<()> { |
1113 | 0 | let mut affected_keys: u32 = 0; |
1114 | 0 | let mut enabled_keys: u32 = 0; |
1115 | | |
1116 | 0 | for (key, enable) in config { |
1117 | 0 | let key = key.bits(); |
1118 | 0 | affected_keys |= key; |
1119 | | |
1120 | 0 | if enable { |
1121 | 0 | enabled_keys |= key; |
1122 | 0 | } else { |
1123 | 0 | enabled_keys &= !key; |
1124 | 0 | } |
1125 | | } |
1126 | | |
1127 | 0 | if affected_keys == 0 { |
1128 | 0 | return Ok(()); // Nothing to do. |
1129 | 0 | } |
1130 | | |
1131 | 0 | prctl_3args( |
1132 | | PR_PAC_SET_ENABLED_KEYS, |
1133 | 0 | affected_keys as usize as *mut _, |
1134 | 0 | enabled_keys as usize as *mut _, |
1135 | | ) |
1136 | 0 | .map(|_r| ()) |
1137 | 0 | } |
1138 | | |
1139 | | // |
1140 | | // PR_SET_VMA |
1141 | | // |
1142 | | |
1143 | | const PR_SET_VMA: c_int = 0x53_56_4d_41; |
1144 | | |
1145 | | const PR_SET_VMA_ANON_NAME: usize = 0; |
1146 | | |
1147 | | /// Set the name for a virtual memory region. |
1148 | | /// |
1149 | | /// # References |
1150 | | /// - [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,…)`] |
1151 | | /// |
1152 | | /// [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,…)`]: https://lwn.net/Articles/867818/ |
1153 | | #[inline] |
1154 | | #[doc(alias = "PR_SET_VMA")] |
1155 | | #[doc(alias = "PR_SET_VMA_ANON_NAME")] |
1156 | 0 | pub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> { |
1157 | | unsafe { |
1158 | 0 | syscalls::prctl( |
1159 | | PR_SET_VMA, |
1160 | 0 | PR_SET_VMA_ANON_NAME as *mut _, |
1161 | 0 | region.as_ptr() as *mut _, |
1162 | 0 | region.len() as *mut _, |
1163 | 0 | name.map_or_else(null, CStr::as_ptr) as *mut _, |
1164 | | ) |
1165 | 0 | .map(|_r| ()) |
1166 | | } |
1167 | 0 | } |