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
8use core::convert::{TryFrom, TryInto};
9use core::mem::MaybeUninit;
10use core::ptr::NonNull;
11use core::{mem, ptr};
12
13use bitflags::bitflags;
14
15use crate::backend::c::{c_int, c_uint, c_void};
16use crate::backend::process::syscalls;
17use crate::backend::process::types::Signal;
18use crate::fd::{AsRawFd, BorrowedFd};
19use crate::ffi::CStr;
20use crate::io;
21use crate::process::{Pid, RawPid};
22
23//
24// Helper functions.
25//
26
27#[inline]
28pub(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]
34pub(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]
40pub(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]
49pub(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]
56pub(crate) unsafe fn prctl_get_at_arg2<P, T>(option: i32) -> io::Result<T>
57where
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
70const 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]
81pub 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
85const 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]
96pub 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
105const PR_GET_DUMPABLE: c_int = 3;
106
107const SUID_DUMP_DISABLE: i32 = 0;
108const SUID_DUMP_USER: i32 = 1;
109const SUID_DUMP_ROOT: i32 = 2;
110
111/// `SUID_DUMP_*`.
112#[derive(Copy, Clone, Debug, Eq, PartialEq)]
113#[repr(i32)]
114pub 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
123impl TryFrom<i32> for DumpableBehavior {
124    type Error = io::Errno;
125
126    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]
143pub fn dumpable_behavior() -> io::Result<DumpableBehavior> {
144    unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into)
145}
146
147const 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]
162pub 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
170const PR_GET_UNALIGN: c_int = 5;
171
172bitflags! {
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]
189pub 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
194const 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]
203pub 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
211const PR_GET_FPEMU: c_int = 9;
212
213bitflags! {
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]
230pub 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
235const 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]
244pub 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
254const PR_GET_FPEXC: c_int = 11;
255
256bitflags! {
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]
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]
302pub 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
313const PR_GET_TIMING: c_int = 13;
314
315const PR_TIMING_STATISTICAL: i32 = 0;
316const PR_TIMING_TIMESTAMP: i32 = 1;
317
318/// `PR_TIMING_*`.
319#[derive(Copy, Clone, Debug, Eq, PartialEq)]
320#[repr(i32)]
321pub 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
328impl TryFrom<i32> for TimingMethod {
329    type Error = io::Errno;
330
331    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]
347pub fn timing_method() -> io::Result<TimingMethod> {
348    unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into)
349}
350
351const 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]
361pub 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
369const PR_GET_ENDIAN: c_int = 19;
370
371const PR_ENDIAN_BIG: u32 = 0;
372const PR_ENDIAN_LITTLE: u32 = 1;
373const PR_ENDIAN_PPC_LITTLE: u32 = 2;
374
375/// `PR_ENDIAN_*`.
376#[derive(Copy, Clone, Debug, Eq, PartialEq)]
377#[repr(u32)]
378pub 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
387impl TryFrom<u32> for EndianMode {
388    type Error = io::Errno;
389
390    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]
407pub fn endian_mode() -> io::Result<EndianMode> {
408    unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) }
409}
410
411const 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]
425pub 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
433const PR_GET_TSC: c_int = 25;
434
435const PR_TSC_ENABLE: u32 = 1;
436const PR_TSC_SIGSEGV: u32 = 2;
437
438/// `PR_TSC_*`.
439#[derive(Copy, Clone, Debug, Eq, PartialEq)]
440#[repr(u32)]
441pub 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
448impl TryFrom<u32> for TimeStampCounterReadability {
449    type Error = io::Errno;
450
451    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]
467pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> {
468    unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) }
469}
470
471const 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]
480pub 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
490const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31;
491const 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]
502pub 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
516const PR_MCE_KILL_GET: c_int = 34;
517
518const PR_MCE_KILL_LATE: u32 = 0;
519const PR_MCE_KILL_EARLY: u32 = 1;
520const PR_MCE_KILL_DEFAULT: u32 = 2;
521
522/// `PR_MCE_KILL_*`.
523#[derive(Copy, Clone, Debug, Eq, PartialEq)]
524#[repr(u32)]
525pub 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
534impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy {
535    type Error = io::Errno;
536
537    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]
554pub 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
560const PR_MCE_KILL: c_int = 33;
561
562const PR_MCE_KILL_CLEAR: usize = 0;
563const 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]
572pub 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
588const PR_SET_MM: c_int = 35;
589
590const PR_SET_MM_START_CODE: u32 = 1;
591const PR_SET_MM_END_CODE: u32 = 2;
592const PR_SET_MM_START_DATA: u32 = 3;
593const PR_SET_MM_END_DATA: u32 = 4;
594const PR_SET_MM_START_STACK: u32 = 5;
595const PR_SET_MM_START_BRK: u32 = 6;
596const PR_SET_MM_BRK: u32 = 7;
597const PR_SET_MM_ARG_START: u32 = 8;
598const PR_SET_MM_ARG_END: u32 = 9;
599const PR_SET_MM_ENV_START: u32 = 10;
600const PR_SET_MM_ENV_END: u32 = 11;
601const PR_SET_MM_AUXV: usize = 12;
602const PR_SET_MM_EXE_FILE: usize = 13;
603const PR_SET_MM_MAP: usize = 14;
604const PR_SET_MM_MAP_SIZE: usize = 15;
605
606/// `PR_SET_MM_*`.
607#[derive(Copy, Clone, Debug, Eq, PartialEq)]
608#[repr(u32)]
609pub 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]
646pub 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]
661pub 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]
678pub 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]
696pub 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)]
708pub 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]
751pub 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
766const PR_SET_PTRACER: c_int = 0x59_61_6d_61;
767
768const PR_SET_PTRACER_ANY: usize = usize::MAX;
769
770/// Process ptracer.
771#[derive(Copy, Clone, Debug, Eq, PartialEq)]
772pub 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]
789pub 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
803const 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]
812pub 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
819const 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]
828pub 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
837const PR_GET_FP_MODE: c_int = 46;
838
839const PR_FP_MODE_FR: u32 = 1_u32 << 0;
840const PR_FP_MODE_FRE: u32 = 1_u32 << 1;
841
842/// `PR_FP_MODE_*`.
843#[derive(Copy, Clone, Debug, Eq, PartialEq)]
844#[repr(u32)]
845pub 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
852impl TryFrom<u32> for FloatingPointMode {
853    type Error = io::Errno;
854
855    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]
871pub 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
876const 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]
885pub 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
893const PR_GET_SPECULATION_CTRL: c_int = 52;
894
895const PR_SPEC_STORE_BYPASS: u32 = 0;
896const PR_SPEC_INDIRECT_BRANCH: u32 = 1;
897const PR_SPEC_L1D_FLUSH: u32 = 2;
898
899/// `PR_SPEC_*`.
900#[derive(Copy, Clone, Debug, Eq, PartialEq)]
901#[repr(u32)]
902pub 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
911impl TryFrom<u32> for SpeculationFeature {
912    type Error = io::Errno;
913
914    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
924bitflags! {
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
938bitflags! {
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]
961pub 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
968const 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]
977pub 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
990const 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]
999pub fn is_io_flusher() -> io::Result<bool> {
1000    unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0)
1001}
1002
1003const 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]
1013pub 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
1021const PR_PAC_GET_ENABLED_KEYS: c_int = 61;
1022
1023bitflags! {
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]
1046pub 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
1051const 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]
1065pub 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
1098const PR_SET_VMA: c_int = 0x53_56_4d_41;
1099
1100const 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]
1109pub 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