1 //! linux_raw syscalls supporting `rustix::runtime`.
2 //!
3 //! # Safety
4 //!
5 //! See the `rustix::backend` module documentation for details.
6 #![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7 
8 use crate::backend::c;
9 #[cfg(target_arch = "x86")]
10 use crate::backend::conv::by_mut;
11 #[cfg(target_arch = "x86_64")]
12 use crate::backend::conv::c_uint;
13 use crate::backend::conv::{
14     by_ref, c_int, ret, ret_c_int, ret_c_int_infallible, ret_error, ret_infallible, ret_void_star,
15     size_of, zero,
16 };
17 #[cfg(feature = "fs")]
18 use crate::fd::BorrowedFd;
19 use crate::ffi::CStr;
20 #[cfg(feature = "fs")]
21 use crate::fs::AtFlags;
22 use crate::io;
23 use crate::pid::{Pid, RawPid};
24 use crate::runtime::{Fork, How, Sigaction, Siginfo, Sigset, Stack};
25 use crate::signal::Signal;
26 use crate::timespec::Timespec;
27 use crate::utils::option_as_ptr;
28 use core::ffi::c_void;
29 use core::mem::MaybeUninit;
30 #[cfg(target_pointer_width = "32")]
31 use linux_raw_sys::general::__kernel_old_timespec;
32 use linux_raw_sys::general::kernel_sigset_t;
33 #[cfg(target_arch = "x86_64")]
34 use linux_raw_sys::general::ARCH_SET_FS;
35 
36 #[inline]
fork() -> io::Result<Fork>37 pub(crate) unsafe fn fork() -> io::Result<Fork> {
38     let mut child_pid = MaybeUninit::<RawPid>::uninit();
39 
40     // Unix `fork` only returns the child PID in the parent; we'd like it in
41     // the child too, so set `CLONE_CHILD_SETTID` and pass in the address of
42     // a memory location to store it to in the child.
43     //
44     // Architectures differ on the order of the parameters.
45     #[cfg(target_arch = "x86_64")]
46     let pid = ret_c_int(syscall_readonly!(
47         __NR_clone,
48         c_int(c::SIGCHLD | c::CLONE_CHILD_SETTID),
49         zero(),
50         zero(),
51         &mut child_pid,
52         zero()
53     ))?;
54     #[cfg(any(
55         target_arch = "aarch64",
56         target_arch = "arm",
57         target_arch = "mips",
58         target_arch = "mips32r6",
59         target_arch = "mips64",
60         target_arch = "mips64r6",
61         target_arch = "powerpc64",
62         target_arch = "riscv64",
63         target_arch = "x86"
64     ))]
65     let pid = ret_c_int(syscall_readonly!(
66         __NR_clone,
67         c_int(c::SIGCHLD | c::CLONE_CHILD_SETTID),
68         zero(),
69         zero(),
70         zero(),
71         &mut child_pid
72     ))?;
73 
74     Ok(if let Some(pid) = Pid::from_raw(pid) {
75         Fork::Parent(pid)
76     } else {
77         Fork::Child(Pid::from_raw_unchecked(child_pid.assume_init()))
78     })
79 }
80 
81 #[cfg(feature = "fs")]
execveat( dirfd: BorrowedFd<'_>, path: &CStr, args: *const *const u8, env_vars: *const *const u8, flags: AtFlags, ) -> io::Errno82 pub(crate) unsafe fn execveat(
83     dirfd: BorrowedFd<'_>,
84     path: &CStr,
85     args: *const *const u8,
86     env_vars: *const *const u8,
87     flags: AtFlags,
88 ) -> io::Errno {
89     ret_error(syscall_readonly!(
90         __NR_execveat,
91         dirfd,
92         path,
93         args,
94         env_vars,
95         flags
96     ))
97 }
98 
execve( path: &CStr, args: *const *const u8, env_vars: *const *const u8, ) -> io::Errno99 pub(crate) unsafe fn execve(
100     path: &CStr,
101     args: *const *const u8,
102     env_vars: *const *const u8,
103 ) -> io::Errno {
104     ret_error(syscall_readonly!(__NR_execve, path, args, env_vars))
105 }
106 
107 pub(crate) mod tls {
108     use super::*;
109     #[cfg(target_arch = "x86")]
110     use crate::backend::runtime::tls::UserDesc;
111 
112     #[cfg(target_arch = "x86")]
113     #[inline]
set_thread_area(u_info: &mut UserDesc) -> io::Result<()>114     pub(crate) unsafe fn set_thread_area(u_info: &mut UserDesc) -> io::Result<()> {
115         ret(syscall!(__NR_set_thread_area, by_mut(u_info)))
116     }
117 
118     #[cfg(target_arch = "arm")]
119     #[inline]
arm_set_tls(data: *mut c::c_void) -> io::Result<()>120     pub(crate) unsafe fn arm_set_tls(data: *mut c::c_void) -> io::Result<()> {
121         ret(syscall_readonly!(__ARM_NR_set_tls, data))
122     }
123 
124     #[cfg(target_arch = "x86_64")]
125     #[inline]
set_fs(data: *mut c::c_void)126     pub(crate) unsafe fn set_fs(data: *mut c::c_void) {
127         ret_infallible(syscall_readonly!(
128             __NR_arch_prctl,
129             c_uint(ARCH_SET_FS),
130             data,
131             zero(),
132             zero(),
133             zero()
134         ))
135     }
136 
137     #[inline]
set_tid_address(data: *mut c::c_void) -> Pid138     pub(crate) unsafe fn set_tid_address(data: *mut c::c_void) -> Pid {
139         let tid: i32 = ret_c_int_infallible(syscall_readonly!(__NR_set_tid_address, data));
140         Pid::from_raw_unchecked(tid)
141     }
142 
143     #[inline]
exit_thread(code: c::c_int) -> !144     pub(crate) fn exit_thread(code: c::c_int) -> ! {
145         unsafe { syscall_noreturn!(__NR_exit, c_int(code)) }
146     }
147 }
148 
149 #[inline]
sigaction(signal: Signal, new: Option<Sigaction>) -> io::Result<Sigaction>150 pub(crate) unsafe fn sigaction(signal: Signal, new: Option<Sigaction>) -> io::Result<Sigaction> {
151     let mut old = MaybeUninit::<Sigaction>::uninit();
152     let new = option_as_ptr(new.as_ref());
153     ret(syscall!(
154         __NR_rt_sigaction,
155         signal,
156         new,
157         &mut old,
158         size_of::<kernel_sigset_t, _>()
159     ))?;
160     Ok(old.assume_init())
161 }
162 
163 #[inline]
sigaltstack(new: Option<Stack>) -> io::Result<Stack>164 pub(crate) unsafe fn sigaltstack(new: Option<Stack>) -> io::Result<Stack> {
165     let mut old = MaybeUninit::<Stack>::uninit();
166     let new = option_as_ptr(new.as_ref());
167     ret(syscall!(__NR_sigaltstack, new, &mut old))?;
168     Ok(old.assume_init())
169 }
170 
171 #[inline]
tkill(tid: Pid, sig: Signal) -> io::Result<()>172 pub(crate) unsafe fn tkill(tid: Pid, sig: Signal) -> io::Result<()> {
173     ret(syscall_readonly!(__NR_tkill, tid, sig))
174 }
175 
176 #[inline]
sigprocmask(how: How, new: Option<&Sigset>) -> io::Result<Sigset>177 pub(crate) unsafe fn sigprocmask(how: How, new: Option<&Sigset>) -> io::Result<Sigset> {
178     let mut old = MaybeUninit::<Sigset>::uninit();
179     let new = option_as_ptr(new);
180     ret(syscall!(
181         __NR_rt_sigprocmask,
182         how,
183         new,
184         &mut old,
185         size_of::<kernel_sigset_t, _>()
186     ))?;
187     Ok(old.assume_init())
188 }
189 
190 #[inline]
sigpending() -> Sigset191 pub(crate) fn sigpending() -> Sigset {
192     let mut pending = MaybeUninit::<Sigset>::uninit();
193     unsafe {
194         ret_infallible(syscall!(
195             __NR_rt_sigpending,
196             &mut pending,
197             size_of::<kernel_sigset_t, _>()
198         ));
199         pending.assume_init()
200     }
201 }
202 
203 #[inline]
sigsuspend(set: &Sigset) -> io::Result<()>204 pub(crate) fn sigsuspend(set: &Sigset) -> io::Result<()> {
205     unsafe {
206         ret(syscall_readonly!(
207             __NR_rt_sigsuspend,
208             by_ref(set),
209             size_of::<kernel_sigset_t, _>()
210         ))
211     }
212 }
213 
214 #[inline]
sigwait(set: &Sigset) -> io::Result<Signal>215 pub(crate) fn sigwait(set: &Sigset) -> io::Result<Signal> {
216     unsafe {
217         match Signal::from_raw(ret_c_int(syscall_readonly!(
218             __NR_rt_sigtimedwait,
219             by_ref(set),
220             zero(),
221             zero(),
222             size_of::<kernel_sigset_t, _>()
223         ))?) {
224             Some(signum) => Ok(signum),
225             None => Err(io::Errno::NOTSUP),
226         }
227     }
228 }
229 
230 #[inline]
sigwaitinfo(set: &Sigset) -> io::Result<Siginfo>231 pub(crate) fn sigwaitinfo(set: &Sigset) -> io::Result<Siginfo> {
232     let mut info = MaybeUninit::<Siginfo>::uninit();
233     unsafe {
234         let _signum = ret_c_int(syscall!(
235             __NR_rt_sigtimedwait,
236             by_ref(set),
237             &mut info,
238             zero(),
239             size_of::<kernel_sigset_t, _>()
240         ))?;
241         Ok(info.assume_init())
242     }
243 }
244 
245 #[inline]
sigtimedwait(set: &Sigset, timeout: Option<Timespec>) -> io::Result<Siginfo>246 pub(crate) fn sigtimedwait(set: &Sigset, timeout: Option<Timespec>) -> io::Result<Siginfo> {
247     let mut info = MaybeUninit::<Siginfo>::uninit();
248     let timeout_ptr = option_as_ptr(timeout.as_ref());
249 
250     // `rt_sigtimedwait_time64` was introduced in Linux 5.1. The old
251     // `rt_sigtimedwait` syscall is not y2038-compatible on 32-bit
252     // architectures.
253     #[cfg(target_pointer_width = "32")]
254     unsafe {
255         match ret_c_int(syscall!(
256             __NR_rt_sigtimedwait_time64,
257             by_ref(set),
258             &mut info,
259             timeout_ptr,
260             size_of::<kernel_sigset_t, _>()
261         )) {
262             Ok(_signum) => (),
263             Err(io::Errno::NOSYS) => sigtimedwait_old(set, timeout, &mut info)?,
264             Err(err) => return Err(err),
265         }
266         Ok(info.assume_init())
267     }
268 
269     #[cfg(target_pointer_width = "64")]
270     unsafe {
271         let _signum = ret_c_int(syscall!(
272             __NR_rt_sigtimedwait,
273             by_ref(set),
274             &mut info,
275             timeout_ptr,
276             size_of::<kernel_sigset_t, _>()
277         ))?;
278         Ok(info.assume_init())
279     }
280 }
281 
282 #[cfg(target_pointer_width = "32")]
sigtimedwait_old( set: &Sigset, timeout: Option<Timespec>, info: &mut MaybeUninit<Siginfo>, ) -> io::Result<()>283 unsafe fn sigtimedwait_old(
284     set: &Sigset,
285     timeout: Option<Timespec>,
286     info: &mut MaybeUninit<Siginfo>,
287 ) -> io::Result<()> {
288     let old_timeout = match timeout {
289         Some(timeout) => Some(__kernel_old_timespec {
290             tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
291             tv_nsec: timeout.tv_nsec as _,
292         }),
293         None => None,
294     };
295 
296     let old_timeout_ptr = option_as_ptr(old_timeout.as_ref());
297 
298     let _signum = ret_c_int(syscall!(
299         __NR_rt_sigtimedwait,
300         by_ref(set),
301         info,
302         old_timeout_ptr,
303         size_of::<kernel_sigset_t, _>()
304     ))?;
305 
306     Ok(())
307 }
308 
309 #[inline]
exit_group(code: c::c_int) -> !310 pub(crate) fn exit_group(code: c::c_int) -> ! {
311     unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) }
312 }
313 
314 #[inline]
brk(addr: *mut c::c_void) -> io::Result<*mut c_void>315 pub(crate) unsafe fn brk(addr: *mut c::c_void) -> io::Result<*mut c_void> {
316     // This is non-`readonly`, to prevent loads from being reordered past it.
317     ret_void_star(syscall!(__NR_brk, addr))
318 }
319