diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
commit | 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch) | |
tree | 3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /vendor/rustix/src/process/procctl.rs | |
parent | Releasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/rustix/src/process/procctl.rs')
-rw-r--r-- | vendor/rustix/src/process/procctl.rs | 380 |
1 files changed, 360 insertions, 20 deletions
diff --git a/vendor/rustix/src/process/procctl.rs b/vendor/rustix/src/process/procctl.rs index ff842513f..9e2b3c6e6 100644 --- a/vendor/rustix/src/process/procctl.rs +++ b/vendor/rustix/src/process/procctl.rs @@ -1,11 +1,14 @@ //! Bindings for the FreeBSD `procctl` system call. //! -//! There are similarities (but also differences) with Linux's `prctl` system call, whose interface -//! is located in the `prctl.rs` file. +//! There are similarities (but also differences) with Linux's `prctl` system +//! call, whose interface is located in the `prctl.rs` file. #![allow(unsafe_code)] use core::mem::MaybeUninit; +use core::ptr; + +use bitflags::bitflags; use crate::backend::c::{c_int, c_uint, c_void}; use crate::backend::process::syscalls; @@ -28,9 +31,10 @@ pub enum IdType { /// A process selector for use with the `procctl` interface. /// -/// `None` represents the current process. `Some((IdType::Pid, pid))` represents the process -/// with pid `pid`. `Some((IdType::Pgid, pgid))` represents the control processes belonging to -/// the process group with id `pgid`. +/// `None` represents the current process. `Some((IdType::Pid, pid))` +/// represents the process with pid `pid`. `Some((IdType::Pgid, pgid))` +/// represents the control processes belonging to the process group with id +/// `pgid`. pub type ProcSelector = Option<(IdType, Pid)>; fn proc_selector_to_raw(selector: ProcSelector) -> (IdType, RawPid) { match selector { @@ -77,8 +81,8 @@ const PROC_PDEATHSIG_STATUS: c_int = 12; /// Get the current value of the parent process death signal. /// /// # References -/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] -/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] +/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] +/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] /// /// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html /// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 @@ -92,8 +96,8 @@ const PROC_PDEATHSIG_CTL: c_int = 11; /// Set the parent-death signal of the calling process. /// /// # References -/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] -/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] +/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] +/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] /// /// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html /// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 @@ -125,16 +129,18 @@ pub enum DumpableBehavior { NotDumpableExecPreserved = PROC_TRACE_CTL_DISABLE_EXEC, } -/// Set the state of the `dumpable` attribute for the process indicated by `idtype` and `id`. -/// This determines whether the process can be traced and whether core dumps are produced for -/// the process upon delivery of a signal whose default behavior is to produce a core dump. +/// Set the state of the `dumpable` attribute for the process indicated by +/// `idtype` and `id`. This determines whether the process can be traced and +/// whether core dumps are produced for the process upon delivery of a signal +/// whose default behavior is to produce a core dump. /// -/// This is similar to `set_dumpable_behavior` on Linux, with the exception that on FreeBSD -/// there is an extra argument `process`. When `process` is set to `None`, the operation is -/// performed for the current process, like on Linux. +/// This is similar to `set_dumpable_behavior` on Linux, with the exception +/// that on FreeBSD there is an extra argument `process`. When `process` is set +/// to `None`, the operation is performed for the current process, like on +/// Linux. /// /// # References -/// - [`procctl(PROC_TRACE_CTL,...)`] +/// - [`procctl(PROC_TRACE_CTL,...)`] /// /// [`procctl(PROC_TRACE_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 #[inline] @@ -153,17 +159,18 @@ const PROC_TRACE_STATUS: c_int = 8; pub enum TracingStatus { /// Tracing is disabled for the process. NotTraceble, - /// Tracing is not disabled for the process, but not debugger/tracer is attached. + /// Tracing is not disabled for the process, but not debugger/tracer is + /// attached. Tracable, - /// The process is being traced by the process whose pid is stored in the first - /// component of this variant. + /// The process is being traced by the process whose pid is stored in the + /// first component of this variant. BeingTraced(Pid), } /// Get the tracing status of the process indicated by `idtype` and `id`. /// /// # References -/// - [`procctl(PROC_TRACE_STATUS,...)`] +/// - [`procctl(PROC_TRACE_STATUS,...)`] /// /// [`procctl(PROC_TRACE_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 #[inline] @@ -178,3 +185,336 @@ pub fn trace_status(process: ProcSelector) -> io::Result<TracingStatus> { } } } + +// +// PROC_REAP_* +// + +const PROC_REAP_ACQUIRE: c_int = 2; +const PROC_REAP_RELEASE: c_int = 3; + +/// Acquire or release the reaper status of the calling process. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_ACQUIRE/RELEASE,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_ACQUIRE/RELEASE,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_reaper_status(reaper: bool) -> io::Result<()> { + unsafe { + procctl( + if reaper { + PROC_REAP_ACQUIRE + } else { + PROC_REAP_RELEASE + }, + None, + ptr::null_mut(), + ) + } +} + +const PROC_REAP_STATUS: c_int = 4; + +bitflags! { + /// `REAPER_STATUS_*`. + pub struct ReaperStatusFlags: c_uint { + /// The process has acquired reaper status. + const OWNED = 1; + /// The process is the root of the reaper tree (pid 1). + const REALINIT = 2; + } +} + +#[repr(C)] +struct procctl_reaper_status { + rs_flags: c_uint, + rs_children: c_uint, + rs_descendants: c_uint, + rs_reaper: RawPid, + rs_pid: RawPid, + rs_pad0: [c_uint; 15], +} + +/// Reaper status as returned by [`get_reaper_status`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ReaperStatus { + /// The flags. + pub flags: ReaperStatusFlags, + /// The number of children of the reaper among the descendants. + pub children: usize, + /// The total number of descendants of the reaper(s), not counting + /// descendants of the reaper in the subtree. + pub descendants: usize, + /// The pid of the reaper for the specified process id. + pub reaper: Pid, + /// The pid of one reaper child if there are any descendants. + pub pid: Pid, +} + +/// Get information about the reaper of the specified process (or the process +/// itself if it is a reaper). +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_STATUS,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn get_reaper_status(process: ProcSelector) -> io::Result<ReaperStatus> { + let raw = unsafe { procctl_get_optional::<procctl_reaper_status>(PROC_REAP_STATUS, process) }?; + Ok(ReaperStatus { + flags: ReaperStatusFlags::from_bits_truncate(raw.rs_flags), + children: raw.rs_children as _, + descendants: raw.rs_descendants as _, + reaper: unsafe { Pid::from_raw(raw.rs_reaper) }.ok_or(io::Errno::RANGE)?, + pid: unsafe { Pid::from_raw(raw.rs_pid) }.ok_or(io::Errno::RANGE)?, + }) +} + +const PROC_REAP_GETPIDS: c_int = 5; + +bitflags! { + /// `REAPER_PIDINFO_*`. + pub struct PidInfoFlags: c_uint { + /// This structure was filled by the kernel. + const VALID = 1; + /// The pid field identifies a direct child of the reaper. + const CHILD = 2; + /// The reported process is itself a reaper. Descendants of a subordinate reaper are not reported. + const REAPER = 4; + } +} + +#[repr(C)] +#[derive(Default, Clone)] +struct procctl_reaper_pidinfo { + pi_pid: RawPid, + pi_subtree: RawPid, + pi_flags: c_uint, + pi_pad0: [c_uint; 15], +} + +#[repr(C)] +struct procctl_reaper_pids { + rp_count: c_uint, + rp_pad0: [c_uint; 15], + rp_pids: *mut procctl_reaper_pidinfo, +} + +/// A child process of a reaper. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct PidInfo { + /// The flags of the process. + pub flags: PidInfoFlags, + /// The pid of the process. + pub pid: Pid, + /// The pid of the child of the reaper which is the (grand-..)parent of the + /// process. + pub subtree: Pid, +} + +/// Get the list of descendants of the specified reaper process. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_GETPIDS,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_GETPIDS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +pub fn get_reaper_pids(process: ProcSelector) -> io::Result<Vec<PidInfo>> { + // Sadly no better way to guarantee that we get all the results than to + // allocate ~8MB of memory.. + const PID_MAX: usize = 99999; + let mut pids: Vec<procctl_reaper_pidinfo> = vec![Default::default(); PID_MAX]; + let mut pinfo = procctl_reaper_pids { + rp_count: PID_MAX as _, + rp_pad0: [0; 15], + rp_pids: pids.as_mut_slice().as_mut_ptr(), + }; + unsafe { + procctl( + PROC_REAP_GETPIDS, + process, + (&mut pinfo as *mut procctl_reaper_pids).cast(), + )? + }; + let mut result = Vec::new(); + for raw in pids.into_iter() { + let flags = PidInfoFlags::from_bits_truncate(raw.pi_flags); + if !flags.contains(PidInfoFlags::VALID) { + break; + } + result.push(PidInfo { + flags, + subtree: unsafe { Pid::from_raw(raw.pi_subtree) }.ok_or(io::Errno::RANGE)?, + pid: unsafe { Pid::from_raw(raw.pi_pid) }.ok_or(io::Errno::RANGE)?, + }); + } + Ok(result) +} + +const PROC_REAP_KILL: c_int = 6; + +bitflags! { + /// `REAPER_KILL_*`. + struct KillFlags: c_uint { + const CHILDREN = 1; + const SUBTREE = 2; + } +} + +#[repr(C)] +struct procctl_reaper_kill { + rk_sig: c_int, + rk_flags: c_uint, + rk_subtree: RawPid, + rk_killed: c_uint, + rk_fpid: RawPid, + rk_pad0: [c_uint; 15], +} + +/// Reaper status as returned by [`get_reaper_status`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct KillResult { + /// The number of processes that were signalled. + pub killed: usize, + /// The pid of the first process that wasn't successfully signalled. + pub first_failed: Option<Pid>, +} + +/// Deliver a signal to some subset of +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_KILL,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_KILL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +pub fn reaper_kill( + process: ProcSelector, + signal: Signal, + direct_children: bool, + subtree: Option<Pid>, +) -> io::Result<KillResult> { + let mut flags = KillFlags::empty(); + flags.set(KillFlags::CHILDREN, direct_children); + flags.set(KillFlags::SUBTREE, subtree.is_some()); + let mut req = procctl_reaper_kill { + rk_sig: signal as c_int, + rk_flags: flags.bits(), + rk_subtree: subtree.map(|p| p.as_raw_nonzero().into()).unwrap_or(0), + rk_killed: 0, + rk_fpid: 0, + rk_pad0: [0; 15], + }; + unsafe { + procctl( + PROC_REAP_KILL, + process, + (&mut req as *mut procctl_reaper_kill).cast(), + )? + }; + Ok(KillResult { + killed: req.rk_killed as _, + first_failed: if req.rk_fpid == -1 { + None + } else { + unsafe { Pid::from_raw(req.rk_fpid) } + }, + }) +} + +// +// PROC_TRAPCAP_STATUS/PROC_TRAPCAP_CTL +// + +const PROC_TRAPCAP_CTL: c_int = 9; + +const PROC_TRAPCAP_CTL_ENABLE: i32 = 1; +const PROC_TRAPCAP_CTL_DISABLE: i32 = 2; + +/// `PROC_TRAPCAP_CTL_*`. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum TrapCapBehavior { + /// Disable the SIGTRAP signal delivery on capability mode access + /// violations. + Disable = PROC_TRAPCAP_CTL_DISABLE, + /// Enable the SIGTRAP signal delivery on capability mode access + /// violations. + Enable = PROC_TRAPCAP_CTL_ENABLE, +} + +/// Set the current value of the capability mode violation trapping behavior. +/// If this behavior is enabled, the kernel would deliver a SIGTRAP signal on +/// any return from a system call that would result in a `ENOTCAPABLE` or +/// `ECAPMODE` error. +/// +/// This behavior is inherited by the children of the process and is kept +/// across `execve` calls. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_TRAPCAP_CTL,...)`] +/// +/// [FreeBSD: `procctl(PROC_TRAPCAP_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_trap_cap_behavior(process: ProcSelector, config: TrapCapBehavior) -> io::Result<()> { + let config = config as c_int; + unsafe { procctl_set::<c_int>(PROC_TRAPCAP_CTL, process, &config) } +} + +const PROC_TRAPCAP_STATUS: c_int = 10; + +/// Get the current value of the capability mode violation trapping behavior. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_TRAPCAP_STATUS,...)`] +/// +/// [FreeBSD: `procctl(PROC_TRAPCAP_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn trap_cap_behavior(process: ProcSelector) -> io::Result<TrapCapBehavior> { + let val = unsafe { procctl_get_optional::<c_int>(PROC_TRAPCAP_STATUS, process) }?; + match val { + PROC_TRAPCAP_CTL_DISABLE => Ok(TrapCapBehavior::Disable), + PROC_TRAPCAP_CTL_ENABLE => Ok(TrapCapBehavior::Enable), + _ => Err(io::Errno::RANGE), + } +} + +// +// PROC_NO_NEW_PRIVS_STATUS/PROC_NO_NEW_PRIVS_CTL +// + +const PROC_NO_NEW_PRIVS_CTL: c_int = 19; + +const PROC_NO_NEW_PRIVS_ENABLE: c_int = 1; + +/// Enable the `no_new_privs` mode that ignores SUID and SGID bits +/// on `execve` in the specified process and its future descendants. +/// +/// This is similar to `set_no_new_privs` on Linux, with the exception +/// that on FreeBSD there is no argument `no_new_privs` argument as it's +/// only possible to enable this mode and there's no going back. +/// +/// # References +/// - [Linux: `prctl(PR_SET_NO_NEW_PRIVS,...)`] +/// - [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_CTL,...)`] +/// +/// [Linux: `prctl(PR_SET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_no_new_privs(process: ProcSelector) -> io::Result<()> { + unsafe { procctl_set::<c_int>(PROC_NO_NEW_PRIVS_CTL, process, &PROC_NO_NEW_PRIVS_ENABLE) } +} + +const PROC_NO_NEW_PRIVS_STATUS: c_int = 20; + +/// Check the `no_new_privs` mode of the specified process. +/// +/// # References +/// - [Linux: `prctl(PR_GET_NO_NEW_PRIVS,...)`] +/// - [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_STATUS,...)`] +/// +/// [Linux: `prctl(PR_GET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn no_new_privs(process: ProcSelector) -> io::Result<bool> { + unsafe { procctl_get_optional::<c_int>(PROC_NO_NEW_PRIVS_STATUS, process) } + .map(|x| x == PROC_NO_NEW_PRIVS_ENABLE) +} |