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