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