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