rustix/process/
prctl.rs

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
8use core::mem::size_of;
9use core::num::NonZeroI32;
10use core::ptr::{null, null_mut, NonNull};
11
12use bitflags::bitflags;
13
14use crate::backend::prctl::syscalls;
15use crate::fd::{AsRawFd as _, BorrowedFd, RawFd};
16use crate::ffi::{c_int, c_uint, c_void, CStr};
17use crate::io;
18use crate::prctl::*;
19use crate::process::{Pid, RawPid};
20use crate::signal::Signal;
21use crate::utils::{as_mut_ptr, as_ptr};
22
23//
24// PR_GET_PDEATHSIG/PR_SET_PDEATHSIG
25//
26
27const 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")]
39pub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
40    let raw = unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG)? };
41    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        Ok(Some(unsafe {
47            Signal::from_raw_nonzero_unchecked(non_zero)
48        }))
49    } else {
50        Ok(None)
51    }
52}
53
54const 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")]
66pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
67    let signal = signal.map_or(0_usize, |signal| signal.as_raw() as usize);
68    unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ())
69}
70
71//
72// PR_GET_DUMPABLE/PR_SET_DUMPABLE
73//
74
75const PR_GET_DUMPABLE: c_int = 3;
76
77const SUID_DUMP_DISABLE: i32 = 0;
78const SUID_DUMP_USER: i32 = 1;
79const 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)]
85pub 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
97impl TryFrom<i32> for DumpableBehavior {
98    type Error = io::Errno;
99
100    fn try_from(value: i32) -> Result<Self, Self::Error> {
101        match value {
102            SUID_DUMP_DISABLE => Ok(Self::NotDumpable),
103            SUID_DUMP_USER => Ok(Self::Dumpable),
104            SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot),
105            _ => Err(io::Errno::RANGE),
106        }
107    }
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")]
118pub fn dumpable_behavior() -> io::Result<DumpableBehavior> {
119    unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into)
120}
121
122const 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")]
140pub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> {
141    unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r| ())
142}
143
144//
145// PR_GET_UNALIGN/PR_SET_UNALIGN
146//
147
148const PR_GET_UNALIGN: c_int = 5;
149
150bitflags! {
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")]
177pub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> {
178    let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? };
179    UnalignedAccessControl::from_bits(r).ok_or(io::Errno::RANGE)
180}
181
182const 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")]
192pub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> {
193    unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r| ())
194}
195
196//
197// PR_GET_FPEMU/PR_SET_FPEMU
198//
199
200const PR_GET_FPEMU: c_int = 9;
201
202bitflags! {
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")]
226pub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> {
227    let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? };
228    FloatingPointEmulationControl::from_bits(r).ok_or(io::Errno::RANGE)
229}
230
231const 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")]
241pub fn set_floating_point_emulation_control(
242    config: FloatingPointEmulationControl,
243) -> io::Result<()> {
244    unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r| ())
245}
246
247//
248// PR_GET_FPEXC/PR_SET_FPEXC
249//
250
251const PR_GET_FPEXC: c_int = 11;
252
253bitflags! {
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")]
288pub 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
293const 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")]
303pub fn set_floating_point_exception_mode(
304    config: Option<FloatingPointExceptionMode>,
305) -> io::Result<()> {
306    let config = config.as_ref().map_or(0, FloatingPointExceptionMode::bits);
307    unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r| ())
308}
309
310//
311// PR_GET_TIMING/PR_SET_TIMING
312//
313
314const PR_GET_TIMING: c_int = 13;
315
316const PR_TIMING_STATISTICAL: i32 = 0;
317const 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)]
323pub 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
330impl TryFrom<i32> for TimingMethod {
331    type Error = io::Errno;
332
333    fn try_from(value: i32) -> Result<Self, Self::Error> {
334        match value {
335            PR_TIMING_STATISTICAL => Ok(Self::Statistical),
336            PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp),
337            _ => Err(io::Errno::RANGE),
338        }
339    }
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")]
350pub fn timing_method() -> io::Result<TimingMethod> {
351    unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into)
352}
353
354const 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")]
365pub fn set_timing_method(method: TimingMethod) -> io::Result<()> {
366    unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r| ())
367}
368
369//
370// PR_GET_ENDIAN/PR_SET_ENDIAN
371//
372
373const PR_GET_ENDIAN: c_int = 19;
374
375const PR_ENDIAN_BIG: u32 = 0;
376const PR_ENDIAN_LITTLE: u32 = 1;
377const 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)]
382pub 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
391impl TryFrom<u32> for EndianMode {
392    type Error = io::Errno;
393
394    fn try_from(value: u32) -> Result<Self, Self::Error> {
395        match value {
396            PR_ENDIAN_BIG => Ok(Self::Big),
397            PR_ENDIAN_LITTLE => Ok(Self::Little),
398            PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle),
399            _ => Err(io::Errno::RANGE),
400        }
401    }
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")]
412pub fn endian_mode() -> io::Result<EndianMode> {
413    unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) }
414}
415
416const 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")]
431pub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> {
432    prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r| ())
433}
434
435//
436// PR_GET_TSC/PR_SET_TSC
437//
438
439const PR_GET_TSC: c_int = 25;
440
441const PR_TSC_ENABLE: u32 = 1;
442const 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)]
448pub 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
455impl TryFrom<u32> for TimeStampCounterReadability {
456    type Error = io::Errno;
457
458    fn try_from(value: u32) -> Result<Self, Self::Error> {
459        match value {
460            PR_TSC_ENABLE => Ok(Self::Readable),
461            PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV),
462            _ => Err(io::Errno::RANGE),
463        }
464    }
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")]
475pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> {
476    unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) }
477}
478
479const 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")]
490pub fn set_time_stamp_counter_readability(
491    readability: TimeStampCounterReadability,
492) -> io::Result<()> {
493    unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r| ())
494}
495
496//
497// PR_TASK_PERF_EVENTS_DISABLE/PR_TASK_PERF_EVENTS_ENABLE
498//
499
500const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31;
501const 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")]
514pub fn configure_performance_counters(enable: bool) -> io::Result<()> {
515    let option = if enable {
516        PR_TASK_PERF_EVENTS_ENABLE
517    } else {
518        PR_TASK_PERF_EVENTS_DISABLE
519    };
520
521    unsafe { prctl_1arg(option) }.map(|_r| ())
522}
523
524//
525// PR_MCE_KILL_GET/PR_MCE_KILL
526//
527
528const PR_MCE_KILL_GET: c_int = 34;
529
530const PR_MCE_KILL_LATE: u32 = 0;
531const PR_MCE_KILL_EARLY: u32 = 1;
532const 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)]
539pub 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
551impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy {
552    type Error = io::Errno;
553
554    fn try_from(value: u32) -> Result<Self, Self::Error> {
555        match value {
556            PR_MCE_KILL_LATE => Ok(Self::Late),
557            PR_MCE_KILL_EARLY => Ok(Self::Early),
558            PR_MCE_KILL_DEFAULT => Ok(Self::Default),
559            _ => Err(io::Errno::RANGE),
560        }
561    }
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")]
572pub fn machine_check_memory_corruption_kill_policy(
573) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> {
574    let r = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint;
575    MachineCheckMemoryCorruptionKillPolicy::try_from(r)
576}
577
578const PR_MCE_KILL: c_int = 33;
579
580const PR_MCE_KILL_CLEAR: usize = 0;
581const 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")]
591pub fn set_machine_check_memory_corruption_kill_policy(
592    policy: Option<MachineCheckMemoryCorruptionKillPolicy>,
593) -> io::Result<()> {
594    let (sub_operation, policy) = if let Some(policy) = policy {
595        (PR_MCE_KILL_SET, policy as usize as *mut _)
596    } else {
597        (PR_MCE_KILL_CLEAR, null_mut())
598    };
599
600    unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r| ())
601}
602
603//
604// PR_SET_MM
605//
606
607const PR_SET_MM: c_int = 35;
608
609const PR_SET_MM_START_CODE: u32 = 1;
610const PR_SET_MM_END_CODE: u32 = 2;
611const PR_SET_MM_START_DATA: u32 = 3;
612const PR_SET_MM_END_DATA: u32 = 4;
613const PR_SET_MM_START_STACK: u32 = 5;
614const PR_SET_MM_START_BRK: u32 = 6;
615const PR_SET_MM_BRK: u32 = 7;
616const PR_SET_MM_ARG_START: u32 = 8;
617const PR_SET_MM_ARG_END: u32 = 9;
618const PR_SET_MM_ENV_START: u32 = 10;
619const PR_SET_MM_ENV_END: u32 = 11;
620const PR_SET_MM_AUXV: usize = 12;
621const PR_SET_MM_EXE_FILE: usize = 13;
622const PR_SET_MM_MAP: usize = 14;
623const 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)]
628pub 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")]
670pub unsafe fn set_virtual_memory_map_address(
671    option: VirtualMemoryMapAddress,
672    address: Option<NonNull<c_void>>,
673) -> io::Result<()> {
674    let address = address.map_or_else(null_mut, NonNull::as_ptr);
675    prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r| ())
676}
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")]
688pub fn set_executable_file(fd: BorrowedFd<'_>) -> io::Result<()> {
689    let fd = usize::try_from(fd.as_raw_fd()).map_err(|_r| io::Errno::RANGE)?;
690    unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r| ())
691}
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")]
707pub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> {
708    syscalls::prctl(
709        PR_SET_MM,
710        PR_SET_MM_AUXV as *mut _,
711        auxv.as_ptr() as *mut _,
712        auxv.len() as *mut _,
713        null_mut(),
714    )
715    .map(|_r| ())
716}
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")]
727pub fn virtual_memory_map_config_struct_size() -> io::Result<usize> {
728    let mut value: c_uint = 0;
729    let value_ptr = as_mut_ptr(&mut value);
730    unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, value_ptr.cast())? };
731    Ok(value as usize)
732}
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)]
739pub 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")]
786pub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> {
787    syscalls::prctl(
788        PR_SET_MM,
789        PR_SET_MM_MAP as *mut _,
790        as_ptr(config) as *mut _,
791        size_of::<PrctlMmMap>() as *mut _,
792        null_mut(),
793    )
794    .map(|_r| ())
795}
796
797//
798// PR_SET_PTRACER
799//
800
801const PR_SET_PTRACER: c_int = 0x59_61_6d_61;
802
803const PR_SET_PTRACER_ANY: usize = usize::MAX;
804
805/// Process ptracer.
806#[derive(Copy, Clone, Debug, Eq, PartialEq)]
807pub 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")]
825pub fn set_ptracer(tracer: PTracer) -> io::Result<()> {
826    let pid = match tracer {
827        PTracer::None => null_mut(),
828        PTracer::Any => PR_SET_PTRACER_ANY as *mut _,
829        PTracer::ProcessID(pid) => pid.as_raw_nonzero().get() as usize as *mut _,
830    };
831
832    unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r| ())
833}
834
835//
836// PR_GET_CHILD_SUBREAPER/PR_SET_CHILD_SUBREAPER
837//
838
839const 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")]
849pub fn child_subreaper() -> io::Result<Option<Pid>> {
850    unsafe {
851        let r = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?;
852        Ok(Pid::from_raw(r as RawPid))
853    }
854}
855
856const 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")]
866pub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> {
867    let pid = pid.map_or(0_usize, |pid| pid.as_raw_nonzero().get() as usize);
868    unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r| ())
869}
870
871//
872// PR_GET_FP_MODE/PR_SET_FP_MODE
873//
874
875const PR_GET_FP_MODE: c_int = 46;
876
877const PR_FP_MODE_FR: u32 = 1_u32 << 0;
878const 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)]
884pub 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
891impl TryFrom<u32> for FloatingPointMode {
892    type Error = io::Errno;
893
894    fn try_from(value: u32) -> Result<Self, Self::Error> {
895        match value {
896            PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters),
897            PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation),
898            _ => Err(io::Errno::RANGE),
899        }
900    }
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")]
911pub fn floating_point_mode() -> io::Result<FloatingPointMode> {
912    let r = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint;
913    FloatingPointMode::try_from(r)
914}
915
916const 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")]
926pub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> {
927    unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r| ())
928}
929
930//
931// PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL
932//
933
934const PR_GET_SPECULATION_CTRL: c_int = 52;
935
936const PR_SPEC_STORE_BYPASS: u32 = 0;
937const PR_SPEC_INDIRECT_BRANCH: u32 = 1;
938const 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)]
944pub 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
953impl TryFrom<u32> for SpeculationFeature {
954    type Error = io::Errno;
955
956    fn try_from(value: u32) -> Result<Self, Self::Error> {
957        match value {
958            PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass),
959            PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation),
960            PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask),
961            _ => Err(io::Errno::RANGE),
962        }
963    }
964}
965
966bitflags! {
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
984bitflags! {
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")]
1013pub fn speculative_feature_state(
1014    feature: SpeculationFeature,
1015) -> io::Result<Option<SpeculationFeatureState>> {
1016    let r = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, feature as usize as *mut _)? } as c_uint;
1017    Ok(SpeculationFeatureState::from_bits(r))
1018}
1019
1020const 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")]
1030pub fn control_speculative_feature(
1031    feature: SpeculationFeature,
1032    config: SpeculationFeatureControl,
1033) -> io::Result<()> {
1034    let feature = feature as usize as *mut _;
1035    let config = config.bits() as usize as *mut _;
1036    unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r| ())
1037}
1038
1039//
1040// PR_GET_IO_FLUSHER/PR_SET_IO_FLUSHER
1041//
1042
1043const 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")]
1053pub fn is_io_flusher() -> io::Result<bool> {
1054    unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0)
1055}
1056
1057const 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")]
1068pub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> {
1069    unsafe { prctl_2args(PR_SET_IO_FLUSHER, usize::from(enable) as *mut _) }.map(|_r| ())
1070}
1071
1072//
1073// PR_PAC_GET_ENABLED_KEYS/PR_PAC_SET_ENABLED_KEYS
1074//
1075
1076const 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")]
1086pub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> {
1087    let r = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint;
1088    PointerAuthenticationKeys::from_bits(r).ok_or(io::Errno::RANGE)
1089}
1090
1091const PR_PAC_SET_ENABLED_KEYS: c_int = 60;
1092
1093/// Set enabled pointer authentication keys.
1094///
1095/// # References
1096///  - [`prctl(PR_PAC_SET_ENABLED_KEYS,…)`]
1097///
1098/// # Safety
1099///
1100/// Please ensure the conditions necessary to safely call this function, as
1101/// detailed in the references above.
1102///
1103/// [`prctl(PR_PAC_SET_ENABLED_KEYS,…)`]: https://www.kernel.org/doc/html/v6.13/arch/arm64/pointer-authentication.html
1104#[inline]
1105#[doc(alias = "PR_PAC_SET_ENABLED_KEYS")]
1106pub unsafe fn configure_pointer_authentication_keys<
1107    Config: Iterator<Item = (PointerAuthenticationKeys, bool)>,
1108>(
1109    config: Config,
1110) -> io::Result<()> {
1111    let mut affected_keys: u32 = 0;
1112    let mut enabled_keys: u32 = 0;
1113
1114    for (key, enable) in config {
1115        let key = key.bits();
1116        affected_keys |= key;
1117
1118        if enable {
1119            enabled_keys |= key;
1120        } else {
1121            enabled_keys &= !key;
1122        }
1123    }
1124
1125    if affected_keys == 0 {
1126        return Ok(()); // Nothing to do.
1127    }
1128
1129    prctl_3args(
1130        PR_PAC_SET_ENABLED_KEYS,
1131        affected_keys as usize as *mut _,
1132        enabled_keys as usize as *mut _,
1133    )
1134    .map(|_r| ())
1135}
1136
1137//
1138// PR_SET_VMA
1139//
1140
1141const PR_SET_VMA: c_int = 0x53_56_4d_41;
1142
1143const PR_SET_VMA_ANON_NAME: usize = 0;
1144
1145/// Set the name for a virtual memory region.
1146///
1147/// # References
1148///  - [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,…)`]
1149///
1150/// [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,…)`]: https://lwn.net/Articles/867818/
1151#[inline]
1152#[doc(alias = "PR_SET_VMA")]
1153#[doc(alias = "PR_SET_VMA_ANON_NAME")]
1154pub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> {
1155    unsafe {
1156        syscalls::prctl(
1157            PR_SET_VMA,
1158            PR_SET_VMA_ANON_NAME as *mut _,
1159            region.as_ptr() as *mut _,
1160            region.len() as *mut _,
1161            name.map_or_else(null, CStr::as_ptr) as *mut _,
1162        )
1163        .map(|_r| ())
1164    }
1165}