1 //! linux_raw syscalls supporting `rustix::thread`.
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 use crate::backend::conv::{
10     by_mut, by_ref, c_int, c_uint, ret, ret_c_int, ret_c_int_infallible, ret_usize,
11     slice_just_addr, slice_just_addr_mut, zero,
12 };
13 use crate::fd::BorrowedFd;
14 use crate::io;
15 use crate::pid::Pid;
16 use crate::thread::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec};
17 use core::mem::MaybeUninit;
18 #[cfg(target_pointer_width = "32")]
19 use linux_raw_sys::general::timespec as __kernel_old_timespec;
20 use linux_raw_sys::general::{__kernel_timespec, TIMER_ABSTIME};
21 
22 #[inline]
clock_nanosleep_relative( id: ClockId, req: &__kernel_timespec, ) -> NanosleepRelativeResult23 pub(crate) fn clock_nanosleep_relative(
24     id: ClockId,
25     req: &__kernel_timespec,
26 ) -> NanosleepRelativeResult {
27     #[cfg(target_pointer_width = "32")]
28     unsafe {
29         let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
30         match ret(syscall!(
31             __NR_clock_nanosleep_time64,
32             id,
33             c_int(0),
34             by_ref(req),
35             &mut rem
36         ))
37         .or_else(|err| {
38             // See the comments in `rustix_clock_gettime_via_syscall` about
39             // emulation.
40             if err == io::Errno::NOSYS {
41                 clock_nanosleep_relative_old(id, req, &mut rem)
42             } else {
43                 Err(err)
44             }
45         }) {
46             Ok(()) => NanosleepRelativeResult::Ok,
47             Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
48             Err(err) => NanosleepRelativeResult::Err(err),
49         }
50     }
51     #[cfg(target_pointer_width = "64")]
52     unsafe {
53         let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
54         match ret(syscall!(
55             __NR_clock_nanosleep,
56             id,
57             c_int(0),
58             by_ref(req),
59             &mut rem
60         )) {
61             Ok(()) => NanosleepRelativeResult::Ok,
62             Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
63             Err(err) => NanosleepRelativeResult::Err(err),
64         }
65     }
66 }
67 
68 #[cfg(target_pointer_width = "32")]
clock_nanosleep_relative_old( id: ClockId, req: &__kernel_timespec, rem: &mut MaybeUninit<__kernel_timespec>, ) -> io::Result<()>69 unsafe fn clock_nanosleep_relative_old(
70     id: ClockId,
71     req: &__kernel_timespec,
72     rem: &mut MaybeUninit<__kernel_timespec>,
73 ) -> io::Result<()> {
74     let old_req = __kernel_old_timespec {
75         tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
76         tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
77     };
78     let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
79     ret(syscall!(
80         __NR_clock_nanosleep,
81         id,
82         c_int(0),
83         by_ref(&old_req),
84         &mut old_rem
85     ))?;
86     let old_rem = old_rem.assume_init();
87     rem.write(__kernel_timespec {
88         tv_sec: old_rem.tv_sec.into(),
89         tv_nsec: old_rem.tv_nsec.into(),
90     });
91     Ok(())
92 }
93 
94 #[inline]
clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()>95 pub(crate) fn clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
96     #[cfg(target_pointer_width = "32")]
97     unsafe {
98         ret(syscall_readonly!(
99             __NR_clock_nanosleep_time64,
100             id,
101             c_uint(TIMER_ABSTIME),
102             by_ref(req),
103             zero()
104         ))
105         .or_else(|err| {
106             // See the comments in `rustix_clock_gettime_via_syscall` about
107             // emulation.
108             if err == io::Errno::NOSYS {
109                 clock_nanosleep_absolute_old(id, req)
110             } else {
111                 Err(err)
112             }
113         })
114     }
115     #[cfg(target_pointer_width = "64")]
116     unsafe {
117         ret(syscall_readonly!(
118             __NR_clock_nanosleep,
119             id,
120             c_uint(TIMER_ABSTIME),
121             by_ref(req),
122             zero()
123         ))
124     }
125 }
126 
127 #[cfg(target_pointer_width = "32")]
clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()>128 unsafe fn clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
129     let old_req = __kernel_old_timespec {
130         tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
131         tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
132     };
133     ret(syscall_readonly!(
134         __NR_clock_nanosleep,
135         id,
136         c_int(0),
137         by_ref(&old_req),
138         zero()
139     ))
140 }
141 
142 #[inline]
nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult143 pub(crate) fn nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult {
144     #[cfg(target_pointer_width = "32")]
145     unsafe {
146         let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
147         match ret(syscall!(
148             __NR_clock_nanosleep_time64,
149             ClockId::Realtime,
150             c_int(0),
151             by_ref(req),
152             &mut rem
153         ))
154         .or_else(|err| {
155             // See the comments in `rustix_clock_gettime_via_syscall` about
156             // emulation.
157             if err == io::Errno::NOSYS {
158                 nanosleep_old(req, &mut rem)
159             } else {
160                 Err(err)
161             }
162         }) {
163             Ok(()) => NanosleepRelativeResult::Ok,
164             Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
165             Err(err) => NanosleepRelativeResult::Err(err),
166         }
167     }
168     #[cfg(target_pointer_width = "64")]
169     unsafe {
170         let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
171         match ret(syscall!(__NR_nanosleep, by_ref(req), &mut rem)) {
172             Ok(()) => NanosleepRelativeResult::Ok,
173             Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
174             Err(err) => NanosleepRelativeResult::Err(err),
175         }
176     }
177 }
178 
179 #[cfg(target_pointer_width = "32")]
nanosleep_old( req: &__kernel_timespec, rem: &mut MaybeUninit<__kernel_timespec>, ) -> io::Result<()>180 unsafe fn nanosleep_old(
181     req: &__kernel_timespec,
182     rem: &mut MaybeUninit<__kernel_timespec>,
183 ) -> io::Result<()> {
184     let old_req = __kernel_old_timespec {
185         tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
186         tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
187     };
188     let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
189     ret(syscall!(__NR_nanosleep, by_ref(&old_req), &mut old_rem))?;
190     let old_rem = old_rem.assume_init();
191     rem.write(__kernel_timespec {
192         tv_sec: old_rem.tv_sec.into(),
193         tv_nsec: old_rem.tv_nsec.into(),
194     });
195     Ok(())
196 }
197 
198 #[inline]
gettid() -> Pid199 pub(crate) fn gettid() -> Pid {
200     unsafe {
201         let tid = ret_c_int_infallible(syscall_readonly!(__NR_gettid));
202         Pid::from_raw_unchecked(tid)
203     }
204 }
205 
206 // TODO: This could be de-multiplexed.
207 #[inline]
futex( uaddr: *mut u32, op: FutexOperation, flags: FutexFlags, val: u32, utime: *const Timespec, uaddr2: *mut u32, val3: u32, ) -> io::Result<usize>208 pub(crate) unsafe fn futex(
209     uaddr: *mut u32,
210     op: FutexOperation,
211     flags: FutexFlags,
212     val: u32,
213     utime: *const Timespec,
214     uaddr2: *mut u32,
215     val3: u32,
216 ) -> io::Result<usize> {
217     #[cfg(target_pointer_width = "32")]
218     {
219         ret_usize(syscall!(
220             __NR_futex_time64,
221             uaddr,
222             (op, flags),
223             c_uint(val),
224             utime,
225             uaddr2,
226             c_uint(val3)
227         ))
228         .or_else(|err| {
229             // See the comments in `rustix_clock_gettime_via_syscall` about
230             // emulation.
231             if err == io::Errno::NOSYS {
232                 futex_old(uaddr, op, flags, val, utime, uaddr2, val3)
233             } else {
234                 Err(err)
235             }
236         })
237     }
238     #[cfg(target_pointer_width = "64")]
239     ret_usize(syscall!(
240         __NR_futex,
241         uaddr,
242         (op, flags),
243         c_uint(val),
244         utime,
245         uaddr2,
246         c_uint(val3)
247     ))
248 }
249 
250 #[cfg(target_pointer_width = "32")]
futex_old( uaddr: *mut u32, op: FutexOperation, flags: FutexFlags, val: u32, utime: *const Timespec, uaddr2: *mut u32, val3: u32, ) -> io::Result<usize>251 unsafe fn futex_old(
252     uaddr: *mut u32,
253     op: FutexOperation,
254     flags: FutexFlags,
255     val: u32,
256     utime: *const Timespec,
257     uaddr2: *mut u32,
258     val3: u32,
259 ) -> io::Result<usize> {
260     let old_utime = __kernel_old_timespec {
261         tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
262         tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
263     };
264     ret_usize(syscall!(
265         __NR_futex,
266         uaddr,
267         (op, flags),
268         c_uint(val),
269         by_ref(&old_utime),
270         uaddr2,
271         c_uint(val3)
272     ))
273 }
274 
275 #[inline]
setns(fd: BorrowedFd<'_>, nstype: c::c_int) -> io::Result<c::c_int>276 pub(crate) fn setns(fd: BorrowedFd<'_>, nstype: c::c_int) -> io::Result<c::c_int> {
277     unsafe { ret_c_int(syscall_readonly!(__NR_setns, fd, c_int(nstype))) }
278 }
279 
280 #[inline]
unshare(flags: crate::thread::UnshareFlags) -> io::Result<()>281 pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
282     unsafe { ret(syscall_readonly!(__NR_unshare, flags)) }
283 }
284 
285 #[inline]
capget( header: &mut linux_raw_sys::general::__user_cap_header_struct, data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>], ) -> io::Result<()>286 pub(crate) fn capget(
287     header: &mut linux_raw_sys::general::__user_cap_header_struct,
288     data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>],
289 ) -> io::Result<()> {
290     unsafe {
291         ret(syscall!(
292             __NR_capget,
293             by_mut(header),
294             slice_just_addr_mut(data)
295         ))
296     }
297 }
298 
299 #[inline]
capset( header: &mut linux_raw_sys::general::__user_cap_header_struct, data: &[linux_raw_sys::general::__user_cap_data_struct], ) -> io::Result<()>300 pub(crate) fn capset(
301     header: &mut linux_raw_sys::general::__user_cap_header_struct,
302     data: &[linux_raw_sys::general::__user_cap_data_struct],
303 ) -> io::Result<()> {
304     unsafe { ret(syscall!(__NR_capset, by_mut(header), slice_just_addr(data))) }
305 }
306 
307 #[inline]
setuid_thread(uid: crate::ugid::Uid) -> io::Result<()>308 pub(crate) fn setuid_thread(uid: crate::ugid::Uid) -> io::Result<()> {
309     unsafe { ret(syscall_readonly!(__NR_setuid, uid)) }
310 }
311 
312 #[inline]
setresuid_thread( ruid: crate::ugid::Uid, euid: crate::ugid::Uid, suid: crate::ugid::Uid, ) -> io::Result<()>313 pub(crate) fn setresuid_thread(
314     ruid: crate::ugid::Uid,
315     euid: crate::ugid::Uid,
316     suid: crate::ugid::Uid,
317 ) -> io::Result<()> {
318     #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
319     unsafe {
320         ret(syscall_readonly!(__NR_setresuid32, ruid, euid, suid))
321     }
322     #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
323     unsafe {
324         ret(syscall_readonly!(__NR_setresuid, ruid, euid, suid))
325     }
326 }
327 
328 #[inline]
setgid_thread(gid: crate::ugid::Gid) -> io::Result<()>329 pub(crate) fn setgid_thread(gid: crate::ugid::Gid) -> io::Result<()> {
330     unsafe { ret(syscall_readonly!(__NR_setgid, gid)) }
331 }
332 
333 #[inline]
setresgid_thread( rgid: crate::ugid::Gid, egid: crate::ugid::Gid, sgid: crate::ugid::Gid, ) -> io::Result<()>334 pub(crate) fn setresgid_thread(
335     rgid: crate::ugid::Gid,
336     egid: crate::ugid::Gid,
337     sgid: crate::ugid::Gid,
338 ) -> io::Result<()> {
339     #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
340     unsafe {
341         ret(syscall_readonly!(__NR_setresgid32, rgid, egid, sgid))
342     }
343     #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
344     unsafe {
345         ret(syscall_readonly!(__NR_setresgid, rgid, egid, sgid))
346     }
347 }
348