1#![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
23const PR_GET_PDEATHSIG: c_int = 2;
28
29#[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#[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
60const 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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
73#[repr(i32)]
74pub enum DumpableBehavior {
75 #[doc(alias = "SUID_DUMP_DISABLE")]
77 NotDumpable = SUID_DUMP_DISABLE,
78 #[doc(alias = "SUID_DUMP_USER")]
80 Dumpable = SUID_DUMP_USER,
81 #[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#[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#[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
133const PR_GET_UNALIGN: c_int = 5;
138
139bitflags! {
140 #[repr(transparent)]
143 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
144 pub struct UnalignedAccessControl: u32 {
145 #[doc(alias = "NOPRINT")]
147 #[doc(alias = "PR_UNALIGN_NOPRINT")]
148 const NO_PRINT = 1;
149 #[doc(alias = "PR_UNALIGN_SIGBUS")]
151 const SIGBUS = 2;
152
153 const _ = !0;
155 }
156}
157
158#[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#[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
185const PR_GET_FPEMU: c_int = 9;
190
191bitflags! {
192 #[repr(transparent)]
195 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
196 pub struct FloatingPointEmulationControl: u32 {
197 #[doc(alias = "PR_UNALIGN_NOPRINT")]
199 const NO_PRINT = 1;
200 #[doc(alias = "PR_UNALIGN_SIGFPE")]
203 const SIGFPE = 2;
204 }
205}
206
207#[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#[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
236const PR_GET_FPEXC: c_int = 11;
241
242bitflags! {
243 #[repr(transparent)]
245 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
246 pub struct FloatingPointExceptionMode: u32 {
247 const NONRECOV = 1;
249 const ASYNC = 2;
251 const PRECISE = 3;
253
254 const SW_ENABLE = 0x80;
256 const DIV = 0x01_0000;
258 const OVF = 0x02_0000;
260 const UND = 0x04_0000;
262 const RES = 0x08_0000;
264 const INV = 0x10_0000;
266 }
267}
268
269#[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#[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
299const PR_GET_TIMING: c_int = 13;
304
305const PR_TIMING_STATISTICAL: i32 = 0;
306const PR_TIMING_TIMESTAMP: i32 = 1;
307
308#[derive(Copy, Clone, Debug, Eq, PartialEq)]
311#[repr(i32)]
312pub enum TimingMethod {
313 Statistical = PR_TIMING_STATISTICAL,
315 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#[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#[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
358const 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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
370#[repr(u32)]
371pub enum EndianMode {
372 Big = PR_ENDIAN_BIG,
374 Little = PR_ENDIAN_LITTLE,
376 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#[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#[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
424const PR_GET_TSC: c_int = 25;
429
430const PR_TSC_ENABLE: u32 = 1;
431const PR_TSC_SIGSEGV: u32 = 2;
432
433#[derive(Copy, Clone, Debug, Eq, PartialEq)]
436#[repr(u32)]
437pub enum TimeStampCounterReadability {
438 Readable = PR_TSC_ENABLE,
440 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#[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#[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
485const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31;
490const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32;
491
492#[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
513const 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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
527#[repr(u32)]
528pub enum MachineCheckMemoryCorruptionKillPolicy {
529 #[doc(alias = "PR_MCE_KILL_LATE")]
531 Late = PR_MCE_KILL_LATE,
532 #[doc(alias = "PR_MCE_KILL_EARLY")]
534 Early = PR_MCE_KILL_EARLY,
535 #[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#[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#[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
592const 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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
616#[repr(u32)]
617pub enum VirtualMemoryMapAddress {
618 CodeStart = PR_SET_MM_START_CODE,
620 CodeEnd = PR_SET_MM_END_CODE,
622 DataStart = PR_SET_MM_START_DATA,
625 DataEnd = PR_SET_MM_END_DATA,
628 StackStart = PR_SET_MM_START_STACK,
630 BrkStart = PR_SET_MM_START_BRK,
633 BrkCurrent = PR_SET_MM_BRK,
635 ArgStart = PR_SET_MM_ARG_START,
637 ArgEnd = PR_SET_MM_ARG_END,
639 EnvironmentStart = PR_SET_MM_ENV_START,
641 EnvironmentEnd = PR_SET_MM_ENV_END,
643}
644
645#[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#[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#[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#[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#[repr(C)]
727#[derive(Debug, Clone)]
728pub struct PrctlMmMap {
729 pub start_code: u64,
731 pub end_code: u64,
733 pub start_data: u64,
735 pub end_data: u64,
737 pub start_brk: u64,
739 pub brk: u64,
741 pub start_stack: u64,
743 pub arg_start: u64,
745 pub arg_end: u64,
747 pub env_start: u64,
749 pub env_end: u64,
751 pub auxv: *mut u64,
753 pub auxv_size: u32,
755 pub exe_fd: u32,
758}
759
760#[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
786const PR_SET_PTRACER: c_int = 0x59_61_6d_61;
791
792const PR_SET_PTRACER_ANY: usize = usize::MAX;
793
794#[derive(Copy, Clone, Debug, Eq, PartialEq)]
796pub enum PTracer {
797 None,
799 Any,
801 ProcessID(Pid),
803}
804
805#[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
824const PR_GET_CHILD_SUBREAPER: c_int = 37;
829
830#[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#[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
860const 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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
872#[repr(u32)]
873pub enum FloatingPointMode {
874 FloatingPointRegisters = PR_FP_MODE_FR,
876 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#[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#[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
919const 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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
932#[repr(u32)]
933pub enum SpeculationFeature {
934 SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS,
936 IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH,
938 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 #[repr(transparent)]
958 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
959 pub struct SpeculationFeatureControl: u32 {
960 const ENABLE = 1_u32 << 1;
962 const DISABLE = 1_u32 << 2;
964 const FORCE_DISABLE = 1_u32 << 3;
967 const DISABLE_NOEXEC = 1_u32 << 4;
970 }
971}
972
973bitflags! {
974 #[repr(transparent)]
976 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
977 pub struct SpeculationFeatureState: u32 {
978 const PRCTL = 1_u32 << 0;
981 const ENABLE = 1_u32 << 1;
983 const DISABLE = 1_u32 << 2;
985 const FORCE_DISABLE = 1_u32 << 3;
988 const DISABLE_NOEXEC = 1_u32 << 4;
991 }
992}
993
994#[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#[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
1028const PR_GET_IO_FLUSHER: c_int = 58;
1033
1034#[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#[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
1061const PR_PAC_GET_ENABLED_KEYS: c_int = 61;
1066
1067#[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#[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(()); }
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
1124const PR_SET_VMA: c_int = 0x53_56_4d_41;
1129
1130const PR_SET_VMA_ANON_NAME: usize = 0;
1131
1132#[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}