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