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