#![allow(unsafe_code)]
use core::mem::size_of;
use core::num::NonZeroI32;
use core::ptr::{null, null_mut, NonNull};
use bitflags::bitflags;
use crate::backend::prctl::syscalls;
use crate::fd::{AsRawFd as _, BorrowedFd, RawFd};
use crate::ffi::{c_int, c_uint, c_void, CStr};
use crate::io;
use crate::prctl::*;
use crate::process::{Pid, RawPid};
use crate::signal::Signal;
use crate::utils::{as_mut_ptr, as_ptr};
const PR_GET_PDEATHSIG: c_int = 2;
#[inline]
#[doc(alias = "PR_GET_PDEATHSIG")]
pub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
let raw = unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG)? };
if let Some(non_zero) = NonZeroI32::new(raw) {
Ok(Some(unsafe {
Signal::from_raw_nonzero_unchecked(non_zero)
}))
} else {
Ok(None)
}
}
const PR_SET_PDEATHSIG: c_int = 1;
#[inline]
#[doc(alias = "PR_SET_PDEATHSIG")]
pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
let signal = signal.map_or(0_usize, |signal| signal.as_raw() as usize);
unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ())
}
const PR_GET_DUMPABLE: c_int = 3;
const SUID_DUMP_DISABLE: i32 = 0;
const SUID_DUMP_USER: i32 = 1;
const SUID_DUMP_ROOT: i32 = 2;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(i32)]
pub enum DumpableBehavior {
#[doc(alias = "SUID_DUMP_DISABLE")]
NotDumpable = SUID_DUMP_DISABLE,
#[doc(alias = "SUID_DUMP_USER")]
Dumpable = SUID_DUMP_USER,
#[doc(alias = "SUID_DUMP_ROOT")]
DumpableReadableOnlyByRoot = SUID_DUMP_ROOT,
}
impl TryFrom<i32> for DumpableBehavior {
type Error = io::Errno;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
SUID_DUMP_DISABLE => Ok(Self::NotDumpable),
SUID_DUMP_USER => Ok(Self::Dumpable),
SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot),
_ => Err(io::Errno::RANGE),
}
}
}
#[inline]
#[doc(alias = "PR_GET_DUMPABLE")]
pub fn dumpable_behavior() -> io::Result<DumpableBehavior> {
unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into)
}
const PR_SET_DUMPABLE: c_int = 4;
#[inline]
#[doc(alias = "PR_SET_DUMPABLE")]
pub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r| ())
}
const PR_GET_UNALIGN: c_int = 5;
bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct UnalignedAccessControl: u32 {
#[doc(alias = "NOPRINT")]
#[doc(alias = "PR_UNALIGN_NOPRINT")]
const NO_PRINT = 1;
#[doc(alias = "PR_UNALIGN_SIGBUS")]
const SIGBUS = 2;
const _ = !0;
}
}
#[inline]
#[doc(alias = "PR_GET_UNALIGN")]
pub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> {
let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? };
UnalignedAccessControl::from_bits(r).ok_or(io::Errno::RANGE)
}
const PR_SET_UNALIGN: c_int = 6;
#[inline]
#[doc(alias = "PR_SET_UNALIGN")]
pub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r| ())
}
const PR_GET_FPEMU: c_int = 9;
bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct FloatingPointEmulationControl: u32 {
#[doc(alias = "PR_UNALIGN_NOPRINT")]
const NO_PRINT = 1;
#[doc(alias = "PR_UNALIGN_SIGFPE")]
const SIGFPE = 2;
}
}
#[inline]
#[doc(alias = "PR_GET_FPEMU")]
pub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> {
let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? };
FloatingPointEmulationControl::from_bits(r).ok_or(io::Errno::RANGE)
}
const PR_SET_FPEMU: c_int = 10;
#[inline]
#[doc(alias = "PR_SET_FPEMU")]
pub fn set_floating_point_emulation_control(
config: FloatingPointEmulationControl,
) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r| ())
}
const PR_GET_FPEXC: c_int = 11;
bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct FloatingPointExceptionMode: u32 {
const NONRECOV = 1;
const ASYNC = 2;
const PRECISE = 3;
const SW_ENABLE = 0x80;
const DIV = 0x01_0000;
const OVF = 0x02_0000;
const UND = 0x04_0000;
const RES = 0x08_0000;
const INV = 0x10_0000;
}
}
#[inline]
#[doc(alias = "PR_GET_FPEXEC")]
pub fn floating_point_exception_mode() -> io::Result<Option<FloatingPointExceptionMode>> {
unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEXC) }
.map(FloatingPointExceptionMode::from_bits)
}
const PR_SET_FPEXC: c_int = 12;
#[inline]
#[doc(alias = "PR_SET_FPEXEC")]
pub fn set_floating_point_exception_mode(
config: Option<FloatingPointExceptionMode>,
) -> io::Result<()> {
let config = config.as_ref().map_or(0, FloatingPointExceptionMode::bits);
unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r| ())
}
const PR_GET_TIMING: c_int = 13;
const PR_TIMING_STATISTICAL: i32 = 0;
const PR_TIMING_TIMESTAMP: i32 = 1;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(i32)]
pub enum TimingMethod {
Statistical = PR_TIMING_STATISTICAL,
TimeStamp = PR_TIMING_TIMESTAMP,
}
impl TryFrom<i32> for TimingMethod {
type Error = io::Errno;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
PR_TIMING_STATISTICAL => Ok(Self::Statistical),
PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp),
_ => Err(io::Errno::RANGE),
}
}
}
#[inline]
#[doc(alias = "PR_GET_TIMING")]
pub fn timing_method() -> io::Result<TimingMethod> {
unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into)
}
const PR_SET_TIMING: c_int = 14;
#[inline]
#[doc(alias = "PR_SET_TIMING")]
pub fn set_timing_method(method: TimingMethod) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r| ())
}
const PR_GET_ENDIAN: c_int = 19;
const PR_ENDIAN_BIG: u32 = 0;
const PR_ENDIAN_LITTLE: u32 = 1;
const PR_ENDIAN_PPC_LITTLE: u32 = 2;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum EndianMode {
Big = PR_ENDIAN_BIG,
Little = PR_ENDIAN_LITTLE,
PowerPCLittle = PR_ENDIAN_PPC_LITTLE,
}
impl TryFrom<u32> for EndianMode {
type Error = io::Errno;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
PR_ENDIAN_BIG => Ok(Self::Big),
PR_ENDIAN_LITTLE => Ok(Self::Little),
PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle),
_ => Err(io::Errno::RANGE),
}
}
}
#[inline]
#[doc(alias = "PR_GET_ENDIAN")]
pub fn endian_mode() -> io::Result<EndianMode> {
unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) }
}
const PR_SET_ENDIAN: c_int = 20;
#[inline]
#[doc(alias = "PR_SET_ENDIAN")]
pub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> {
prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r| ())
}
const PR_GET_TSC: c_int = 25;
const PR_TSC_ENABLE: u32 = 1;
const PR_TSC_SIGSEGV: u32 = 2;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum TimeStampCounterReadability {
Readable = PR_TSC_ENABLE,
RaiseSIGSEGV = PR_TSC_SIGSEGV,
}
impl TryFrom<u32> for TimeStampCounterReadability {
type Error = io::Errno;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
PR_TSC_ENABLE => Ok(Self::Readable),
PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV),
_ => Err(io::Errno::RANGE),
}
}
}
#[inline]
#[doc(alias = "PR_GET_TSC")]
pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> {
unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) }
}
const PR_SET_TSC: c_int = 26;
#[inline]
#[doc(alias = "PR_SET_TSC")]
pub fn set_time_stamp_counter_readability(
readability: TimeStampCounterReadability,
) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r| ())
}
const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31;
const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32;
#[inline]
#[doc(alias = "PR_TASK_PERF_EVENTS_ENABLE")]
#[doc(alias = "PR_TASK_PERF_EVENTS_DISABLE")]
pub fn configure_performance_counters(enable: bool) -> io::Result<()> {
let option = if enable {
PR_TASK_PERF_EVENTS_ENABLE
} else {
PR_TASK_PERF_EVENTS_DISABLE
};
unsafe { prctl_1arg(option) }.map(|_r| ())
}
const PR_MCE_KILL_GET: c_int = 34;
const PR_MCE_KILL_LATE: u32 = 0;
const PR_MCE_KILL_EARLY: u32 = 1;
const PR_MCE_KILL_DEFAULT: u32 = 2;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum MachineCheckMemoryCorruptionKillPolicy {
#[doc(alias = "PR_MCE_KILL_LATE")]
Late = PR_MCE_KILL_LATE,
#[doc(alias = "PR_MCE_KILL_EARLY")]
Early = PR_MCE_KILL_EARLY,
#[doc(alias = "PR_MCE_KILL_DEFAULT")]
Default = PR_MCE_KILL_DEFAULT,
}
impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy {
type Error = io::Errno;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
PR_MCE_KILL_LATE => Ok(Self::Late),
PR_MCE_KILL_EARLY => Ok(Self::Early),
PR_MCE_KILL_DEFAULT => Ok(Self::Default),
_ => Err(io::Errno::RANGE),
}
}
}
#[inline]
#[doc(alias = "PR_MCE_KILL_GET")]
pub fn machine_check_memory_corruption_kill_policy(
) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> {
let r = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint;
MachineCheckMemoryCorruptionKillPolicy::try_from(r)
}
const PR_MCE_KILL: c_int = 33;
const PR_MCE_KILL_CLEAR: usize = 0;
const PR_MCE_KILL_SET: usize = 1;
#[inline]
#[doc(alias = "PR_MCE_KILL")]
pub fn set_machine_check_memory_corruption_kill_policy(
policy: Option<MachineCheckMemoryCorruptionKillPolicy>,
) -> io::Result<()> {
let (sub_operation, policy) = if let Some(policy) = policy {
(PR_MCE_KILL_SET, policy as usize as *mut _)
} else {
(PR_MCE_KILL_CLEAR, null_mut())
};
unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r| ())
}
const PR_SET_MM: c_int = 35;
const PR_SET_MM_START_CODE: u32 = 1;
const PR_SET_MM_END_CODE: u32 = 2;
const PR_SET_MM_START_DATA: u32 = 3;
const PR_SET_MM_END_DATA: u32 = 4;
const PR_SET_MM_START_STACK: u32 = 5;
const PR_SET_MM_START_BRK: u32 = 6;
const PR_SET_MM_BRK: u32 = 7;
const PR_SET_MM_ARG_START: u32 = 8;
const PR_SET_MM_ARG_END: u32 = 9;
const PR_SET_MM_ENV_START: u32 = 10;
const PR_SET_MM_ENV_END: u32 = 11;
const PR_SET_MM_AUXV: usize = 12;
const PR_SET_MM_EXE_FILE: usize = 13;
const PR_SET_MM_MAP: usize = 14;
const PR_SET_MM_MAP_SIZE: usize = 15;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum VirtualMemoryMapAddress {
CodeStart = PR_SET_MM_START_CODE,
CodeEnd = PR_SET_MM_END_CODE,
DataStart = PR_SET_MM_START_DATA,
DataEnd = PR_SET_MM_END_DATA,
StackStart = PR_SET_MM_START_STACK,
BrkStart = PR_SET_MM_START_BRK,
BrkCurrent = PR_SET_MM_BRK,
ArgStart = PR_SET_MM_ARG_START,
ArgEnd = PR_SET_MM_ARG_END,
EnvironmentStart = PR_SET_MM_ENV_START,
EnvironmentEnd = PR_SET_MM_ENV_END,
}
#[inline]
#[doc(alias = "PR_SET_MM")]
pub unsafe fn set_virtual_memory_map_address(
option: VirtualMemoryMapAddress,
address: Option<NonNull<c_void>>,
) -> io::Result<()> {
let address = address.map_or_else(null_mut, NonNull::as_ptr);
prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r| ())
}
#[inline]
#[doc(alias = "PR_SET_MM")]
#[doc(alias = "PR_SET_MM_EXE_FILE")]
pub fn set_executable_file(fd: BorrowedFd<'_>) -> io::Result<()> {
let fd = usize::try_from(fd.as_raw_fd()).map_err(|_r| io::Errno::RANGE)?;
unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r| ())
}
#[inline]
#[doc(alias = "PR_SET_MM")]
#[doc(alias = "PR_SET_MM_AUXV")]
pub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> {
syscalls::prctl(
PR_SET_MM,
PR_SET_MM_AUXV as *mut _,
auxv.as_ptr() as *mut _,
auxv.len() as *mut _,
null_mut(),
)
.map(|_r| ())
}
#[inline]
#[doc(alias = "PR_SET_MM")]
#[doc(alias = "PR_SET_MM_MAP_SIZE")]
pub fn virtual_memory_map_config_struct_size() -> io::Result<usize> {
let mut value: c_uint = 0;
let value_ptr = as_mut_ptr(&mut value);
unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, value_ptr.cast())? };
Ok(value as usize)
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct PrctlMmMap {
pub start_code: u64,
pub end_code: u64,
pub start_data: u64,
pub end_data: u64,
pub start_brk: u64,
pub brk: u64,
pub start_stack: u64,
pub arg_start: u64,
pub arg_end: u64,
pub env_start: u64,
pub env_end: u64,
pub auxv: *mut u64,
pub auxv_size: u32,
pub exe_fd: RawFd,
}
#[inline]
#[doc(alias = "PR_SET_MM")]
#[doc(alias = "PR_SET_MM_MAP")]
pub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> {
syscalls::prctl(
PR_SET_MM,
PR_SET_MM_MAP as *mut _,
as_ptr(config) as *mut _,
size_of::<PrctlMmMap>() as *mut _,
null_mut(),
)
.map(|_r| ())
}
const PR_SET_PTRACER: c_int = 0x59_61_6d_61;
const PR_SET_PTRACER_ANY: usize = usize::MAX;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PTracer {
None,
Any,
ProcessID(Pid),
}
#[inline]
#[doc(alias = "PR_SET_PTRACER")]
pub fn set_ptracer(tracer: PTracer) -> io::Result<()> {
let pid = match tracer {
PTracer::None => null_mut(),
PTracer::Any => PR_SET_PTRACER_ANY as *mut _,
PTracer::ProcessID(pid) => pid.as_raw_nonzero().get() as usize as *mut _,
};
unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r| ())
}
const PR_GET_CHILD_SUBREAPER: c_int = 37;
#[inline]
#[doc(alias = "PR_GET_CHILD_SUBREAPER")]
pub fn child_subreaper() -> io::Result<Option<Pid>> {
unsafe {
let r = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?;
Ok(Pid::from_raw(r as RawPid))
}
}
const PR_SET_CHILD_SUBREAPER: c_int = 36;
#[inline]
#[doc(alias = "PR_SET_CHILD_SUBREAPER")]
pub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> {
let pid = pid.map_or(0_usize, |pid| pid.as_raw_nonzero().get() as usize);
unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r| ())
}
const PR_GET_FP_MODE: c_int = 46;
const PR_FP_MODE_FR: u32 = 1_u32 << 0;
const PR_FP_MODE_FRE: u32 = 1_u32 << 1;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum FloatingPointMode {
FloatingPointRegisters = PR_FP_MODE_FR,
FloatingPointEmulation = PR_FP_MODE_FRE,
}
impl TryFrom<u32> for FloatingPointMode {
type Error = io::Errno;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters),
PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation),
_ => Err(io::Errno::RANGE),
}
}
}
#[inline]
#[doc(alias = "PR_GET_FP_MODE")]
pub fn floating_point_mode() -> io::Result<FloatingPointMode> {
let r = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint;
FloatingPointMode::try_from(r)
}
const PR_SET_FP_MODE: c_int = 45;
#[inline]
#[doc(alias = "PR_SET_FP_MODE")]
pub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r| ())
}
const PR_GET_SPECULATION_CTRL: c_int = 52;
const PR_SPEC_STORE_BYPASS: u32 = 0;
const PR_SPEC_INDIRECT_BRANCH: u32 = 1;
const PR_SPEC_L1D_FLUSH: u32 = 2;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum SpeculationFeature {
SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS,
IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH,
FlushL1DCacheOnContextSwitchOutOfTask = PR_SPEC_L1D_FLUSH,
}
impl TryFrom<u32> for SpeculationFeature {
type Error = io::Errno;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass),
PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation),
PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask),
_ => Err(io::Errno::RANGE),
}
}
}
bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct SpeculationFeatureControl: u32 {
const ENABLE = 1_u32 << 1;
const DISABLE = 1_u32 << 2;
const FORCE_DISABLE = 1_u32 << 3;
const DISABLE_NOEXEC = 1_u32 << 4;
}
}
bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct SpeculationFeatureState: u32 {
const PRCTL = 1_u32 << 0;
const ENABLE = 1_u32 << 1;
const DISABLE = 1_u32 << 2;
const FORCE_DISABLE = 1_u32 << 3;
const DISABLE_NOEXEC = 1_u32 << 4;
}
}
#[inline]
#[doc(alias = "PR_GET_SPECULATION_CTRL")]
pub fn speculative_feature_state(
feature: SpeculationFeature,
) -> io::Result<Option<SpeculationFeatureState>> {
let r = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, feature as usize as *mut _)? } as c_uint;
Ok(SpeculationFeatureState::from_bits(r))
}
const PR_SET_SPECULATION_CTRL: c_int = 53;
#[inline]
#[doc(alias = "PR_SET_SPECULATION_CTRL")]
pub fn control_speculative_feature(
feature: SpeculationFeature,
config: SpeculationFeatureControl,
) -> io::Result<()> {
let feature = feature as usize as *mut _;
let config = config.bits() as usize as *mut _;
unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r| ())
}
const PR_GET_IO_FLUSHER: c_int = 58;
#[inline]
#[doc(alias = "PR_GET_IO_FLUSHER")]
pub fn is_io_flusher() -> io::Result<bool> {
unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0)
}
const PR_SET_IO_FLUSHER: c_int = 57;
#[inline]
#[doc(alias = "PR_SET_IO_FLUSHER")]
pub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> {
unsafe { prctl_2args(PR_SET_IO_FLUSHER, usize::from(enable) as *mut _) }.map(|_r| ())
}
const PR_PAC_GET_ENABLED_KEYS: c_int = 61;
#[inline]
#[doc(alias = "PR_PAC_GET_ENABLED_KEYS")]
#[cfg(linux_raw_dep)]
pub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> {
let r = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint;
PointerAuthenticationKeys::from_bits(r).ok_or(io::Errno::RANGE)
}
const PR_PAC_SET_ENABLED_KEYS: c_int = 60;
#[inline]
#[doc(alias = "PR_PAC_SET_ENABLED_KEYS")]
#[cfg(linux_raw_dep)]
pub unsafe fn configure_pointer_authentication_keys<
Config: Iterator<Item = (PointerAuthenticationKeys, bool)>,
>(
config: Config,
) -> io::Result<()> {
let mut affected_keys: u32 = 0;
let mut enabled_keys: u32 = 0;
for (key, enable) in config {
let key = key.bits();
affected_keys |= key;
if enable {
enabled_keys |= key;
} else {
enabled_keys &= !key;
}
}
if affected_keys == 0 {
return Ok(()); }
prctl_3args(
PR_PAC_SET_ENABLED_KEYS,
affected_keys as usize as *mut _,
enabled_keys as usize as *mut _,
)
.map(|_r| ())
}
const PR_SET_VMA: c_int = 0x53_56_4d_41;
const PR_SET_VMA_ANON_NAME: usize = 0;
#[inline]
#[doc(alias = "PR_SET_VMA")]
#[doc(alias = "PR_SET_VMA_ANON_NAME")]
pub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> {
unsafe {
syscalls::prctl(
PR_SET_VMA,
PR_SET_VMA_ANON_NAME as *mut _,
region.as_ptr() as *mut _,
region.len() as *mut _,
name.map_or_else(null, CStr::as_ptr) as *mut _,
)
.map(|_r| ())
}
}