linux_api/
sched.rs

1use linux_syscall::{Result as LinuxSyscallResult, Result64};
2
3use crate::errno::Errno;
4use crate::ldt::linux_user_desc;
5use crate::posix_types::{Pid, kernel_pid_t};
6use crate::signal::Signal;
7use crate::{bindings, const_conversions};
8
9bitflags::bitflags! {
10    /// The flags passed to the `clone` and `clone3` syscalls.
11    /// While `clone` is documented as taking an i32 parameter for flags,
12    /// in `clone3` its a u64. Promote to u64 throughout.
13    #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
14    pub struct CloneFlags: u64 {
15        const CLONE_CLEAR_SIGHAND = bindings::LINUX_CLONE_CLEAR_SIGHAND;
16        const CLONE_INTO_CGROUP = bindings::LINUX_CLONE_INTO_CGROUP;
17        const CLONE_NEWTIME = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWTIME);
18        const CLONE_VM = const_conversions::u64_from_u32(bindings::LINUX_CLONE_VM);
19        const CLONE_FS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_FS);
20        const CLONE_FILES = const_conversions::u64_from_u32(bindings::LINUX_CLONE_FILES);
21        const CLONE_SIGHAND = const_conversions::u64_from_u32(bindings::LINUX_CLONE_SIGHAND);
22        const CLONE_PIDFD = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PIDFD);
23        const CLONE_PTRACE = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PTRACE);
24        const CLONE_VFORK = const_conversions::u64_from_u32(bindings::LINUX_CLONE_VFORK);
25        const CLONE_PARENT = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PARENT);
26        const CLONE_THREAD = const_conversions::u64_from_u32(bindings::LINUX_CLONE_THREAD);
27        const CLONE_NEWNS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWNS);
28        const CLONE_SYSVSEM = const_conversions::u64_from_u32(bindings::LINUX_CLONE_SYSVSEM);
29        const CLONE_SETTLS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_SETTLS);
30        const CLONE_PARENT_SETTID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PARENT_SETTID);
31        const CLONE_CHILD_CLEARTID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_CHILD_CLEARTID);
32        const CLONE_DETACHED = const_conversions::u64_from_u32(bindings::LINUX_CLONE_DETACHED);
33        const CLONE_UNTRACED = const_conversions::u64_from_u32(bindings::LINUX_CLONE_UNTRACED);
34        const CLONE_CHILD_SETTID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_CHILD_SETTID);
35        const CLONE_NEWCGROUP = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWCGROUP);
36        const CLONE_NEWUTS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWUTS);
37        const CLONE_NEWIPC = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWIPC);
38        const CLONE_NEWUSER = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWUSER);
39        const CLONE_NEWPID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWPID);
40        const CLONE_NEWNET = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWNET);
41        const CLONE_IO = const_conversions::u64_from_u32(bindings::LINUX_CLONE_IO);
42    }
43}
44
45pub use bindings::linux_clone_args;
46#[allow(non_camel_case_types)]
47pub type clone_args = linux_clone_args;
48
49#[allow(clippy::derivable_impls)]
50impl Default for clone_args {
51    fn default() -> Self {
52        Self {
53            flags: Default::default(),
54            pidfd: Default::default(),
55            child_tid: Default::default(),
56            parent_tid: Default::default(),
57            exit_signal: Default::default(),
58            stack: Default::default(),
59            stack_size: Default::default(),
60            tls: Default::default(),
61            set_tid: Default::default(),
62            set_tid_size: Default::default(),
63            cgroup: Default::default(),
64        }
65    }
66}
67
68impl clone_args {
69    #[inline]
70    pub fn with_flags(mut self, flags: CloneFlags) -> Self {
71        self.flags = flags.bits();
72        self
73    }
74
75    #[inline]
76    pub fn with_exit_signal(mut self, exit_signal: Option<Signal>) -> Self {
77        self.exit_signal = u64::try_from(Signal::as_raw(exit_signal)).unwrap();
78        self
79    }
80}
81
82unsafe impl shadow_pod::Pod for clone_args {}
83
84/// The "dumpable" state, as manipulated via the prctl operations `PR_SET_DUMPABLE` and
85/// `PR_GET_DUMPABLE`.
86#[derive(Copy, Clone, PartialEq, Eq)]
87pub struct SuidDump(i32);
88
89impl SuidDump {
90    pub const SUID_DUMP_DISABLE: Self = Self(const_conversions::i32_from_u32(
91        bindings::LINUX_SUID_DUMP_DISABLE,
92    ));
93    pub const SUID_DUMP_USER: Self = Self(const_conversions::i32_from_u32(
94        bindings::LINUX_SUID_DUMP_USER,
95    ));
96    pub const SUID_DUMP_ROOT: Self = Self(const_conversions::i32_from_u32(
97        bindings::LINUX_SUID_DUMP_ROOT,
98    ));
99    // NOTE: add new entries to `to_str` below
100
101    pub const fn new(val: i32) -> Self {
102        Self(val)
103    }
104
105    pub const fn val(&self) -> i32 {
106        self.0
107    }
108
109    pub const fn to_str(&self) -> Option<&'static str> {
110        match *self {
111            Self::SUID_DUMP_DISABLE => Some("SUID_DUMP_DISABLE"),
112            Self::SUID_DUMP_USER => Some("SUID_DUMP_USER"),
113            Self::SUID_DUMP_ROOT => Some("SUID_DUMP_ROOT"),
114            _ => None,
115        }
116    }
117}
118
119impl core::fmt::Display for SuidDump {
120    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
121        match self.to_str() {
122            Some(s) => formatter.write_str(s),
123            None => write!(formatter, "(unknown dumpable option {})", self.0),
124        }
125    }
126}
127
128impl core::fmt::Debug for SuidDump {
129    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
130        match self.to_str() {
131            Some(s) => write!(formatter, "SuidDump::{s}"),
132            None => write!(formatter, "SuidDump::<{}>", self.0),
133        }
134    }
135}
136
137pub fn sched_yield() -> Result<(), Errno> {
138    unsafe { linux_syscall::syscall!(linux_syscall::SYS_sched_yield) }
139        .check()
140        .map_err(Errno::from)
141}
142
143/// # Safety
144///
145/// Too many requirements to list here. See `clone(2)`.
146pub unsafe fn clone_raw(
147    flags: core::ffi::c_ulong,
148    stack: core::ffi::c_ulong,
149    parent_tid: *mut core::ffi::c_int,
150    child_tid: *mut core::ffi::c_int,
151    tls: core::ffi::c_ulong,
152) -> Result<core::ffi::c_long, Errno> {
153    unsafe {
154        linux_syscall::syscall!(
155            linux_syscall::SYS_clone,
156            flags,
157            stack,
158            parent_tid,
159            child_tid,
160            tls
161        )
162    }
163    .try_i64()
164    .map_err(Errno::from)
165}
166
167/// # Safety
168///
169/// Too many requirements to list here. See `clone(2)`.
170pub unsafe fn clone3_raw(args: *const clone_args, size: usize) -> Result<core::ffi::c_long, Errno> {
171    unsafe { linux_syscall::syscall!(linux_syscall::SYS_clone3, args, size,) }
172        .try_i64()
173        .map_err(Errno::from)
174}
175
176pub enum CloneResult {
177    CallerIsChild,
178    // Caller is the parent; child has the given pid
179    CallerIsParent(Pid),
180}
181
182/// # Safety
183///
184/// Too many requirements to list here. See `clone(2)`.
185pub unsafe fn clone(
186    flags: CloneFlags,
187    exit_signal: Option<Signal>,
188    stack: *mut core::ffi::c_void,
189    parent_tid: *mut kernel_pid_t,
190    child_tid: *mut kernel_pid_t,
191    tls: *mut linux_user_desc,
192) -> Result<CloneResult, Errno> {
193    unsafe {
194        clone_raw(
195            flags.bits() | u64::try_from(Signal::as_raw(exit_signal)).unwrap(),
196            stack as core::ffi::c_ulong,
197            parent_tid,
198            child_tid,
199            tls as core::ffi::c_ulong,
200        )
201    }
202    .map(|res| match res.cmp(&0) {
203        core::cmp::Ordering::Equal => CloneResult::CallerIsChild,
204        core::cmp::Ordering::Greater => {
205            CloneResult::CallerIsParent(Pid::from_raw(res.try_into().unwrap()).unwrap())
206        }
207        core::cmp::Ordering::Less => unreachable!(),
208    })
209}
210
211/// # Safety
212///
213/// Too many requirements to list here. See `clone(2)`.
214pub unsafe fn clone3(args: &clone_args) -> Result<CloneResult, Errno> {
215    unsafe { clone3_raw(args, core::mem::size_of::<clone_args>()) }.map(|res| match res.cmp(&0) {
216        core::cmp::Ordering::Equal => CloneResult::CallerIsChild,
217        core::cmp::Ordering::Greater => {
218            CloneResult::CallerIsParent(Pid::from_raw(res.try_into().unwrap()).unwrap())
219        }
220        core::cmp::Ordering::Less => unreachable!(),
221    })
222}
223
224/// See `fork(2)`.
225///
226/// # Safety
227///
228/// *Mostly* safe, since most memory will be copy-on-write in the child process.
229/// Non-private mutable mappings *are* shared in the child, though, which may
230/// break soundness. (Such mappings aren't common in practice)
231///
232/// Additionally some OS resources are shared with the parent, and others are
233/// dropped, which may /// break assumptions by code that uses or wraps such
234/// resources. See `fork(2)` for a full list, but some notable examples include:
235///
236/// * The child shares file descriptors (and underlying file descriptions) with the parent.
237/// * The child is the only thread in the new process.
238pub unsafe fn fork_raw() -> Result<core::ffi::c_long, Errno> {
239    unsafe { linux_syscall::syscall!(linux_syscall::SYS_fork) }
240        .try_i64()
241        .map_err(Errno::from)
242}
243
244/// # Safety
245///
246/// See `fork_raw`
247pub unsafe fn fork() -> Result<CloneResult, Errno> {
248    unsafe { fork_raw() }.map(|res| match res.cmp(&0) {
249        core::cmp::Ordering::Equal => CloneResult::CallerIsChild,
250        core::cmp::Ordering::Greater => {
251            CloneResult::CallerIsParent(Pid::from_raw(res.try_into().unwrap()).unwrap())
252        }
253        core::cmp::Ordering::Less => unreachable!(),
254    })
255}