Skip to main content

starnix_core/signals/
syscalls.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub use super::signal_handling::sys_restart_syscall;
6use super::signalfd::SignalFd;
7use crate::mm::MemoryAccessorExt;
8use crate::security;
9use crate::signals::{
10    IntoSignalInfoOptions, RunState, SI_MAX_SIZE_AS_USIZE, SignalDetail, SignalInfo,
11    UncheckedSignalInfo, restore_from_signal_handler, send_signal,
12};
13use crate::task::{
14    CurrentTask, PidTable, ProcessEntryRef, ProcessSelector, Task, TaskMutableState, ThreadGroup,
15    ThreadGroupLifecycleWaitValue, WaitResult, WaitableChildResult, Waiter,
16};
17use crate::vfs::{FdFlags, FdNumber};
18use starnix_sync::{LockBefore, RwLockReadGuard, ThreadGroupLimits};
19use starnix_uapi::user_address::{ArchSpecific, MultiArchUserRef};
20use starnix_uapi::{tid_t, uapi};
21
22use starnix_logging::track_stub;
23use starnix_sync::{InterruptibleEvent, Locked, Unlocked, WakeReason};
24use starnix_syscalls::SyscallResult;
25use starnix_types::time::{duration_from_timespec, timeval_from_duration};
26use starnix_uapi::errors::{EINTR, ETIMEDOUT, Errno, ErrnoResultExt};
27use starnix_uapi::open_flags::OpenFlags;
28use starnix_uapi::signals::{SigSet, Signal, UNBLOCKABLE_SIGNALS, UncheckedSignal};
29use starnix_uapi::user_address::{UserAddress, UserRef};
30use starnix_uapi::{
31    __WALL, __WCLONE, __WNOTHREAD, P_ALL, P_PGID, P_PID, P_PIDFD, SFD_CLOEXEC, SFD_NONBLOCK,
32    SI_TKILL, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK, SS_AUTODISARM, SS_DISABLE, SS_ONSTACK,
33    WCONTINUED, WEXITED, WNOHANG, WNOWAIT, WSTOPPED, WUNTRACED, errno, error, pid_t, rusage,
34    sigaltstack,
35};
36use static_assertions::const_assert_eq;
37use zerocopy::{FromBytes, Immutable, IntoBytes};
38
39pub type RUsagePtr = MultiArchUserRef<uapi::rusage, uapi::arch32::rusage>;
40type SigAction64Ptr = MultiArchUserRef<uapi::sigaction_t, uapi::arch32::sigaction64_t>;
41type SigActionPtr = MultiArchUserRef<uapi::sigaction_t, uapi::arch32::sigaction_t>;
42
43/// The `rt_sigaction` syscall allows the calling process to examine and change the action
44/// associated with a specific signal.
45///
46/// # Args
47/// * `signum`: The signal number to examine or change. It can be any valid signal except
48///   `SIGKILL` and `SIGSTOP`.
49/// * `user_action`: A pointer to a `sigaction` structure. If it is not null, the new action
50///   for signal `signum` is installed from it.
51/// * `user_old_action`: A pointer to a `sigaction` structure. If it is not null, the previous
52///   action is saved in it.
53/// * `sigset_size`: The size in bytes of the signal sets in `user_action` and `user_old_action`.
54///
55/// # Returns
56/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
57pub fn sys_rt_sigaction(
58    _locked: &mut Locked<Unlocked>,
59    current_task: &CurrentTask,
60    signum: UncheckedSignal,
61    user_action: SigAction64Ptr,
62    user_old_action: SigAction64Ptr,
63    sigset_size: usize,
64) -> Result<(), Errno> {
65    if user_action.is_arch32() && sigset_size == std::mem::size_of::<uapi::arch32::sigset_t>() {
66        let user_action = SigActionPtr::from_32(user_action.addr().into());
67        let user_old_action = SigActionPtr::from_32(user_old_action.addr().into());
68        return rt_sigaction(current_task, signum, user_action, user_old_action);
69    }
70
71    if sigset_size != std::mem::size_of::<uapi::sigset_t>() {
72        return error!(EINVAL);
73    }
74    rt_sigaction(current_task, signum, user_action, user_old_action)
75}
76
77fn rt_sigaction<Arch32SigAction>(
78    current_task: &CurrentTask,
79    signum: UncheckedSignal,
80    user_action: MultiArchUserRef<uapi::sigaction_t, Arch32SigAction>,
81    user_old_action: MultiArchUserRef<uapi::sigaction_t, Arch32SigAction>,
82) -> Result<(), Errno>
83where
84    Arch32SigAction:
85        IntoBytes + FromBytes + Immutable + TryFrom<uapi::sigaction_t> + TryInto<uapi::sigaction_t>,
86{
87    let signal = Signal::try_from(signum)?;
88
89    let new_signal_action = if !user_action.is_null() {
90        // Actions can't be set for SIGKILL and SIGSTOP, but the actions for these signals can
91        // still be returned in `user_old_action`, so only return early if the intention is to
92        // set an action (i.e., the user_action is non-null).
93        if signal.is_unblockable() {
94            return error!(EINVAL);
95        }
96
97        let signal_action = current_task.read_multi_arch_object(user_action)?;
98        Some(signal_action)
99    } else {
100        None
101    };
102
103    let signal_actions = &current_task.thread_group().signal_actions;
104    let old_action = if let Some(new_signal_action) = new_signal_action {
105        signal_actions.set(signal, new_signal_action)
106    } else {
107        signal_actions.get(signal)
108    };
109
110    if !user_old_action.is_null() {
111        current_task.write_multi_arch_object(user_old_action, old_action)?;
112    }
113
114    Ok(())
115}
116
117/// The `rt_sigpending` syscall returns the set of signals that are pending for delivery to the
118/// calling thread.
119///
120/// # Args
121/// * `set`: A pointer to a `sigset_t` where the set of pending signals is stored.
122/// * `sigset_size`: The size of the signal set, in bytes.
123///
124/// # Returns
125/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
126pub fn sys_rt_sigpending(
127    _locked: &mut Locked<Unlocked>,
128    current_task: &CurrentTask,
129    set: UserRef<SigSet>,
130    sigset_size: usize,
131) -> Result<(), Errno> {
132    if sigset_size != std::mem::size_of::<SigSet>() {
133        return error!(EINVAL);
134    }
135
136    let signals = current_task.read().pending_signals();
137    current_task.write_object(set, &signals)?;
138    Ok(())
139}
140
141/// The `rt_sigprocmask` syscall is used to fetch and/or change the signal mask of the calling
142/// thread.
143///
144/// # Args
145/// * `how`: Specifies how the signal mask should be changed. Can be `SIG_BLOCK`, `SIG_UNBLOCK`,
146///   or `SIG_SETMASK`.
147/// * `user_set`: A pointer to a signal set. The interpretation of this set depends on `how`.
148/// * `user_old_set`: If not null, the previous signal mask is stored here.
149/// * `sigset_size`: The size of the signal set, in bytes.
150///
151/// # Returns
152/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
153pub fn sys_rt_sigprocmask(
154    _locked: &mut Locked<Unlocked>,
155    current_task: &CurrentTask,
156    how: u32,
157    user_set: UserRef<SigSet>,
158    user_old_set: UserRef<SigSet>,
159    sigset_size: usize,
160) -> Result<(), Errno> {
161    if sigset_size != std::mem::size_of::<SigSet>() {
162        return error!(EINVAL);
163    }
164    match how {
165        SIG_BLOCK | SIG_UNBLOCK | SIG_SETMASK => (),
166        _ => return error!(EINVAL),
167    };
168
169    // Read the new mask. This must be done before the old mask is written to `user_old_set`
170    // since it might point to the same location as `user_set`.
171    let mut new_mask = SigSet::default();
172    if !user_set.is_null() {
173        new_mask = current_task.read_object(user_set)?;
174    }
175
176    let mut state = current_task.write();
177    let signal_mask = state.signal_mask();
178    // If old_set is not null, store the previous value in old_set.
179    if !user_old_set.is_null() {
180        current_task.write_object(user_old_set, &signal_mask)?;
181    }
182
183    // If set is null, how is ignored and the mask is not updated.
184    if user_set.is_null() {
185        return Ok(());
186    }
187
188    let signal_mask = match how {
189        SIG_BLOCK => signal_mask | new_mask,
190        SIG_UNBLOCK => signal_mask & !new_mask,
191        SIG_SETMASK => new_mask,
192        // Arguments have already been verified, this should never match.
193        _ => return error!(EINVAL),
194    };
195    state.set_signal_mask(signal_mask);
196
197    Ok(())
198}
199
200type SigAltStackPtr = MultiArchUserRef<uapi::sigaltstack, uapi::arch32::sigaltstack>;
201
202/// The `sigaltstack` syscall allows a process to define an alternate signal stack.
203///
204/// # Args
205/// * `user_ss`: A pointer to a `sigaltstack` structure specifying the new alternate signal stack.
206/// * `user_old_ss`: If not null, the previous alternate signal stack is stored here.
207///
208/// # Returns
209/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
210pub fn sys_sigaltstack(
211    _locked: &mut Locked<Unlocked>,
212    current_task: &CurrentTask,
213    user_ss: SigAltStackPtr,
214    user_old_ss: SigAltStackPtr,
215) -> Result<(), Errno> {
216    let stack_pointer_register = current_task.thread_state.registers.stack_pointer_register();
217    let mut state = current_task.write();
218    let on_signal_stack = state.on_signal_stack(stack_pointer_register);
219
220    let mut ss = sigaltstack::default();
221    if !user_ss.is_null() {
222        if on_signal_stack {
223            return error!(EPERM);
224        }
225        ss = current_task.read_multi_arch_object(user_ss)?;
226        if (ss.ss_flags & !((SS_AUTODISARM | SS_DISABLE) as i32)) != 0 {
227            return error!(EINVAL);
228        }
229        let min_stack_size =
230            if current_task.is_arch32() { uapi::arch32::MINSIGSTKSZ } else { uapi::MINSIGSTKSZ };
231        if ss.ss_flags & (SS_DISABLE as i32) == 0 && ss.ss_size < min_stack_size as u64 {
232            return error!(ENOMEM);
233        }
234    }
235
236    if !user_old_ss.is_null() {
237        let mut old_ss = match state.sigaltstack() {
238            Some(old_ss) => old_ss,
239            None => sigaltstack { ss_flags: SS_DISABLE as i32, ..sigaltstack::default() },
240        };
241        if on_signal_stack {
242            old_ss.ss_flags = SS_ONSTACK as i32;
243        }
244        current_task.write_multi_arch_object(user_old_ss, old_ss)?;
245    }
246
247    if !user_ss.is_null() {
248        if ss.ss_flags & (SS_DISABLE as i32) != 0 {
249            state.set_sigaltstack(None);
250        } else {
251            state.set_sigaltstack(Some(ss));
252        }
253    }
254
255    Ok(())
256}
257
258/// The `rt_sigsuspend` syscall temporarily replaces the signal mask of the calling thread with
259/// the mask given by `user_mask` and then suspends the thread until delivery of a signal whose
260/// action is to invoke a signal handler or to terminate a process.
261///
262/// # Args
263/// * `user_mask`: A pointer to a signal set that will temporarily replace the thread's signal mask.
264/// * `sigset_size`: The size of the signal set, in bytes.
265///
266/// # Returns
267/// This function never returns `Ok(())`. It always returns an `Errno`, typically `EINTR` (or a
268/// restart equivalent).
269pub fn sys_rt_sigsuspend(
270    locked: &mut Locked<Unlocked>,
271    current_task: &mut CurrentTask,
272    user_mask: UserRef<SigSet>,
273    sigset_size: usize,
274) -> Result<(), Errno> {
275    if sigset_size != std::mem::size_of::<SigSet>() {
276        return error!(EINVAL);
277    }
278    let mask = current_task.read_object(user_mask)?;
279
280    let waiter = Waiter::new();
281    // ERESTARTNOHAND indicates that the error should be EINTR if
282    // interrupted by a signal delivered to a user handler, and the syscall
283    // should be restarted otherwise.
284    current_task
285        .wait_with_temporary_mask(locked, mask, |locked, current_task| {
286            waiter.wait(locked, current_task)
287        })
288        .map_eintr(|| errno!(ERESTARTNOHAND))
289}
290
291/// The `rt_sigtimedwait` syscall waits for one of the signals in `set_addr` to become pending
292/// for the calling thread. The call will block until a signal is pending or the timeout expires.
293///
294/// # Args
295/// * `set_addr`: A pointer to a signal set specifying the signals to wait for.
296/// * `siginfo_addr`: If not null, a `siginfo_t` structure for the received signal is stored here.
297/// * `timeout_addr`: If not null, specifies a timeout for the wait.
298/// * `sigset_size`: The size of the signal set, in bytes.
299///
300/// # Returns
301/// On success, returns `Ok(Signal)` containing the signal that was caught. On failure, returns
302/// an `Errno`.
303pub fn sys_rt_sigtimedwait(
304    locked: &mut Locked<Unlocked>,
305    current_task: &mut CurrentTask,
306    set_addr: UserRef<SigSet>,
307    siginfo_addr: MultiArchUserRef<uapi::siginfo_t, uapi::arch32::siginfo_t>,
308    timeout_addr: MultiArchUserRef<uapi::timespec, uapi::arch32::timespec>,
309    sigset_size: usize,
310) -> Result<Signal, Errno> {
311    if sigset_size != std::mem::size_of::<SigSet>() {
312        return error!(EINVAL);
313    }
314
315    // Signals in `set_addr` are what we are waiting for.
316    let set = current_task.read_object(set_addr)?;
317    // Attempts to wait for `UNBLOCKABLE_SIGNALS` will be ignored.
318    let unblock = set & !UNBLOCKABLE_SIGNALS;
319    let deadline = if timeout_addr.is_null() {
320        zx::MonotonicInstant::INFINITE
321    } else {
322        let timeout = current_task.read_multi_arch_object(timeout_addr)?;
323        zx::MonotonicInstant::after(duration_from_timespec(timeout)?)
324    };
325
326    let signal_info = loop {
327        let waiter;
328
329        {
330            let mut task_state = current_task.write();
331            // If one of the signals in set is already pending for the calling thread,
332            // sigwaitinfo() will return immediately.
333            if let Some(signal) = task_state.take_signal_with_mask(!unblock) {
334                break signal;
335            }
336
337            waiter = Waiter::new();
338            task_state.wait_on_signal(&waiter);
339        }
340
341        // A new signal is enqueued when it's masked in the SignalState. So we need to invert
342        // the SigSet to block them.
343        let tmp_mask = current_task.read().signal_mask() & !unblock;
344
345        // Wait for a timeout or a new signal.
346        let waiter_result =
347            current_task.wait_with_temporary_mask(locked, tmp_mask, |locked, current_task| {
348                waiter.wait_until(locked, current_task, deadline)
349            });
350
351        // Restore mask after timeout or get a new signal.
352        current_task.write().restore_signal_mask();
353
354        if let Err(e) = waiter_result {
355            if e == EINTR {
356                // Check if EINTR was returned for a signal we were waiting for.
357                if let Some(signal) = current_task.write().take_signal_with_mask(!unblock) {
358                    break signal;
359                }
360            } else if e == ETIMEDOUT {
361                return error!(EAGAIN);
362            }
363
364            return Err(e);
365        }
366    };
367
368    if !siginfo_addr.is_null() {
369        signal_info.write(current_task, siginfo_addr)?;
370    }
371
372    Ok(signal_info.signal)
373}
374
375/// The `signalfd4` syscall creates a file descriptor that can be used to accept signals targeted
376/// at the caller.
377///
378/// # Args
379/// * `fd`: A file descriptor. If -1, a new file descriptor is created. Otherwise, the mask of the
380///   existing signalfd is modified.
381/// * `mask_addr`: A pointer to a signal set specifying the signals to handle with this signalfd.
382/// * `mask_size`: The size of the signal set, in bytes.
383/// * `flags`: Flags to control the behavior of the file descriptor.
384///
385/// # Returns
386/// On success, returns `Ok(FdNumber)` containing the file descriptor number. On failure, returns
387/// an `Errno`.
388pub fn sys_signalfd4(
389    locked: &mut Locked<Unlocked>,
390    current_task: &CurrentTask,
391    fd: FdNumber,
392    mask_addr: UserRef<SigSet>,
393    mask_size: usize,
394    flags: u32,
395) -> Result<FdNumber, Errno> {
396    if flags & !(SFD_CLOEXEC | SFD_NONBLOCK) != 0 {
397        return error!(EINVAL);
398    }
399    if mask_size != std::mem::size_of::<SigSet>() {
400        return error!(EINVAL);
401    }
402    let mask = current_task.read_object(mask_addr)?;
403
404    if fd.raw() != -1 {
405        let file = current_task.get_file(fd)?;
406        let file = file.downcast_file::<SignalFd>().ok_or_else(|| errno!(EINVAL))?;
407        file.set_mask(mask);
408        Ok(fd)
409    } else {
410        let signalfd = SignalFd::new_file(locked, current_task, mask, flags);
411        let flags = if flags & SFD_CLOEXEC != 0 { FdFlags::CLOEXEC } else { FdFlags::empty() };
412        let fd = current_task.add_file(locked, signalfd, flags)?;
413        Ok(fd)
414    }
415}
416
417#[track_caller]
418fn send_unchecked_signal<L>(
419    locked: &mut Locked<L>,
420    current_task: &CurrentTask,
421    target: &Task,
422    unchecked_signal: UncheckedSignal,
423    si_code: i32,
424) -> Result<(), Errno>
425where
426    L: LockBefore<ThreadGroupLimits>,
427{
428    current_task.can_signal(&target, unchecked_signal)?;
429
430    // 0 is a sentinel value used to do permission checks.
431    if unchecked_signal.is_zero() {
432        return Ok(());
433    }
434
435    let signal = Signal::try_from(unchecked_signal)?;
436    security::check_signal_access(current_task, &target, signal)?;
437
438    send_signal(
439        locked,
440        target,
441        SignalInfo::with_sender(
442            signal,
443            si_code,
444            SignalDetail::Kill {
445                pid: current_task.thread_group().leader,
446                uid: current_task.current_creds().uid,
447            },
448            Some(current_task.weak_self.clone()),
449        ),
450    )
451}
452
453#[track_caller]
454fn send_unchecked_signal_info<L>(
455    locked: &mut Locked<L>,
456    current_task: &CurrentTask,
457    target: &Task,
458    unchecked_signal: UncheckedSignal,
459    siginfo_ref: UserAddress,
460) -> Result<(), Errno>
461where
462    L: LockBefore<ThreadGroupLimits>,
463{
464    current_task.can_signal(&target, unchecked_signal)?;
465
466    // 0 is a sentinel value used to do permission checks.
467    if unchecked_signal.is_zero() {
468        // Check we can read siginfo.
469        current_task.read_memory_to_array::<SI_MAX_SIZE_AS_USIZE>(siginfo_ref)?;
470        return Ok(());
471    }
472
473    let signal = Signal::try_from(unchecked_signal)?;
474    security::check_signal_access(current_task, &target, signal)?;
475
476    let siginfo = UncheckedSignalInfo::read_from_siginfo(current_task, siginfo_ref)?;
477    if target.get_pid() != current_task.get_pid()
478        && (siginfo.code() >= 0 || siginfo.code() == SI_TKILL)
479    {
480        return error!(EINVAL);
481    }
482
483    send_signal(locked, &target, siginfo.into_signal_info(signal, IntoSignalInfoOptions::None)?)
484}
485
486/// The `kill` syscall can be used to send any signal to any process group or process.
487///
488/// # Args
489/// * `pid`: Specifies the target process or process group. See `kill(2)` for details.
490/// * `unchecked_signal`: The signal to send.
491///
492/// # Returns
493/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
494pub fn sys_kill(
495    locked: &mut Locked<Unlocked>,
496    current_task: &CurrentTask,
497    pid: pid_t,
498    unchecked_signal: UncheckedSignal,
499) -> Result<(), Errno> {
500    let pids = current_task.kernel().pids.read();
501    match pid {
502        pid if pid > 0 => {
503            // "If pid is positive, then signal sig is sent to the process with
504            // the ID specified by pid."
505            let target_thread_group = {
506                match pids.get_process(pid) {
507                    Some(ProcessEntryRef::Process(process)) => process,
508
509                    // Zombies cannot receive signals. Just ignore it.
510                    Some(ProcessEntryRef::Zombie(_zombie)) => return Ok(()),
511
512                    // If we don't have process with `pid` then check if there is a task with
513                    // the `pid`.
514                    None => {
515                        let task = pids.get_task(pid)?;
516                        task.thread_group().clone()
517                    }
518                }
519            };
520
521            target_thread_group.send_signal_unchecked(current_task, unchecked_signal)?;
522        }
523        pid if pid == -1 => {
524            // "If pid equals -1, then sig is sent to every process for which
525            // the calling process has permission to send signals, except for
526            // process 1 (init), but ... POSIX.1-2001 requires that kill(-1,sig)
527            // send sig to all processes that the calling process may send
528            // signals to, except possibly for some implementation-defined
529            // system processes. Linux allows a process to signal itself, but on
530            // Linux the call kill(-1,sig) does not signal the calling process."
531
532            let thread_groups: Vec<_> = pids
533                .get_thread_groups()
534                .into_iter()
535                .filter(|thread_group| {
536                    if *current_task.thread_group() == *thread_group {
537                        return false;
538                    }
539                    if thread_group.leader == 1 {
540                        return false;
541                    }
542                    true
543                })
544                .collect();
545            signal_thread_groups(current_task, unchecked_signal, thread_groups)?;
546        }
547        _ => {
548            // "If pid equals 0, then sig is sent to every process in the
549            // process group of the calling process."
550            //
551            // "If pid is less than -1, then sig is sent to every process in the
552            // process group whose ID is -pid."
553            let process_group_id = match pid {
554                0 => current_task.thread_group().read().process_group.leader,
555                _ => negate_pid(pid)?,
556            };
557
558            let process_group = pids.get_process_group(process_group_id);
559            let thread_groups = process_group
560                .iter()
561                .flat_map(|pg| pg.read(locked).thread_groups().collect::<Vec<_>>());
562            signal_thread_groups(current_task, unchecked_signal, thread_groups)?;
563        }
564    };
565
566    Ok(())
567}
568
569fn verify_tgid_for_task(
570    task: &Task,
571    tgid: pid_t,
572    pids: &RwLockReadGuard<'_, PidTable>,
573) -> Result<(), Errno> {
574    let thread_group = match pids.get_process(tgid) {
575        Some(ProcessEntryRef::Process(proc)) => proc,
576        Some(ProcessEntryRef::Zombie(_)) => return error!(EINVAL),
577        None => return error!(ESRCH),
578    };
579    if *task.thread_group() != thread_group {
580        return error!(EINVAL);
581    } else {
582        Ok(())
583    }
584}
585
586/// The `tkill` syscall sends the signal `unchecked_signal` to the thread with the thread ID
587/// `tid`.
588///
589/// This is an obsolete and non-standard syscall that is replaced by `tgkill`.
590///
591/// # Args
592/// * `tid`: The thread ID of the thread to send the signal to.
593/// * `unchecked_signal`: The signal to send.
594///
595/// # Returns
596/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
597pub fn sys_tkill(
598    locked: &mut Locked<Unlocked>,
599    current_task: &CurrentTask,
600    tid: tid_t,
601    unchecked_signal: UncheckedSignal,
602) -> Result<(), Errno> {
603    // Linux returns EINVAL when the tgid or tid <= 0.
604    if tid <= 0 {
605        return error!(EINVAL);
606    }
607    let thread = current_task.get_task(tid)?;
608    send_unchecked_signal(locked, current_task, &thread, unchecked_signal, SI_TKILL)
609}
610
611/// The `tgkill` syscall sends the signal `unchecked_signal` to the thread with thread ID `tid`
612/// in the thread group `tgid`.
613///
614/// # Args
615/// * `tgid`: The thread group ID of the target thread.
616/// * `tid`: The thread ID of the target thread.
617/// * `unchecked_signal`: The signal to send.
618///
619/// # Returns
620/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
621pub fn sys_tgkill(
622    locked: &mut Locked<Unlocked>,
623    current_task: &CurrentTask,
624    tgid: pid_t,
625    tid: tid_t,
626    unchecked_signal: UncheckedSignal,
627) -> Result<(), Errno> {
628    // Linux returns EINVAL when the tgid or tid <= 0.
629    if tgid <= 0 || tid <= 0 {
630        return error!(EINVAL);
631    }
632    let pids = current_task.kernel().pids.read();
633
634    let thread = pids.get_task(tid)?;
635    verify_tgid_for_task(&thread, tgid, &pids)?;
636    send_unchecked_signal(locked, current_task, &thread, unchecked_signal, SI_TKILL)
637}
638
639/// The `rt_sigreturn` syscall returns from a signal handler and restores the process's context.
640///
641/// This function is not intended to be called directly by user code, but is instead part of the
642/// signal handling trampoline that is set up by the kernel.
643///
644/// # Returns
645/// A `SyscallResult` with the value that should be returned to userspace. This function
646/// does not return to the caller in the kernel on success.
647pub fn sys_rt_sigreturn(
648    _locked: &mut Locked<Unlocked>,
649    current_task: &mut CurrentTask,
650) -> Result<SyscallResult, Errno> {
651    restore_from_signal_handler(current_task)?;
652    Ok(current_task.thread_state.registers.return_register().into())
653}
654
655/// The `rt_sigqueueinfo` syscall sends a signal with a payload to a process.
656///
657/// # Args
658/// * `tgid`: The thread group ID of the process to send the signal to.
659/// * `unchecked_signal`: The signal to send.
660/// * `siginfo_ref`: A pointer to a `siginfo_t` structure that contains the signal payload.
661///
662/// # Returns
663/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
664pub fn sys_rt_sigqueueinfo(
665    _locked: &mut Locked<Unlocked>,
666    current_task: &CurrentTask,
667    tgid: pid_t,
668    unchecked_signal: UncheckedSignal,
669    siginfo_ref: UserAddress,
670) -> Result<(), Errno> {
671    let task = current_task.kernel().pids.read().get_task(tgid)?;
672    task.thread_group().send_signal_unchecked_with_info(
673        current_task,
674        unchecked_signal,
675        siginfo_ref,
676        IntoSignalInfoOptions::None,
677    )
678}
679
680/// The `rt_tgsigqueueinfo` syscall sends a signal with a payload to a specific thread.
681///
682/// # Args
683/// * `tgid`: The thread group ID of the process to send the signal to.
684/// * `tid`: The thread ID of the thread to send the signal to.
685/// * `unchecked_signal`: The signal to send.
686/// * `siginfo_ref`: A pointer to a `siginfo_t` structure that contains the signal payload.
687///
688/// # Returns
689/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
690pub fn sys_rt_tgsigqueueinfo(
691    locked: &mut Locked<Unlocked>,
692    current_task: &CurrentTask,
693    tgid: pid_t,
694    tid: tid_t,
695    unchecked_signal: UncheckedSignal,
696    siginfo_ref: UserAddress,
697) -> Result<(), Errno> {
698    let pids = current_task.kernel().pids.read();
699
700    let task = pids.get_task(tid)?;
701    verify_tgid_for_task(&task, tgid, &pids)?;
702    send_unchecked_signal_info(locked, current_task, &task, unchecked_signal, siginfo_ref)
703}
704
705/// The `pause` syscall causes the calling process sleep until it receives a signal or terminates.
706///
707/// # Returns
708/// This function never returns `Ok(())` under normal circumstances. It always returns `Err(EINTR)`.
709pub fn sys_pause(_locked: &mut Locked<Unlocked>, current_task: &CurrentTask) -> Result<(), Errno> {
710    let event = InterruptibleEvent::new();
711    let guard = event.begin_wait();
712    let result = current_task.run_in_state(RunState::Event(event.clone()), || {
713        match guard.block_until(None, zx::MonotonicInstant::INFINITE) {
714            Err(WakeReason::Interrupted) => error!(ERESTARTNOHAND),
715            Err(WakeReason::DeadlineExpired) => panic!("blocking forever cannot time out"),
716            Ok(()) => Ok(()),
717        }
718    });
719    // ERESTARTNOHAND is mapped to EINTR if interrupted by signal delivery.
720    result.map_eintr(|| errno!(ERESTARTNOHAND))
721}
722
723/// The `pidfd_send_signal` syscall sends a signal to a process specified by a PID file
724/// descriptor.
725///
726/// # Args
727/// * `pidfd`: The PID file descriptor of the process to send the signal to.
728/// * `unchecked_signal`: The signal to send.
729/// * `siginfo_ref`: An optional pointer to a `siginfo_t` structure that contains the signal
730///   payload.
731/// * `flags`: Must be 0.
732///
733/// # Returns
734/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
735pub fn sys_pidfd_send_signal(
736    _locked: &mut Locked<Unlocked>,
737    current_task: &CurrentTask,
738    pidfd: FdNumber,
739    unchecked_signal: UncheckedSignal,
740    siginfo_ref: UserAddress,
741    flags: u32,
742) -> Result<(), Errno> {
743    if flags != 0 {
744        return error!(EINVAL);
745    }
746
747    let file = current_task.get_file(pidfd)?;
748    let target = file.as_thread_group_key()?;
749    let target = target.upgrade().ok_or_else(|| errno!(ESRCH))?;
750
751    if siginfo_ref.is_null() {
752        target.send_signal_unchecked(current_task, unchecked_signal)
753    } else {
754        target.send_signal_unchecked_with_info(
755            current_task,
756            unchecked_signal,
757            siginfo_ref,
758            IntoSignalInfoOptions::CheckSigno,
759        )
760    }
761}
762
763/// Sends a signal to all thread groups in `thread_groups`.
764///
765/// # Parameters
766/// - `task`: The task that is sending the signal.
767/// - `unchecked_signal`: The signal that is to be sent. Unchecked, since `0` is a sentinel value
768/// where rights are to be checked but no signal is actually sent.
769/// - `thread_groups`: The thread groups to signal.
770///
771/// # Returns
772/// Returns Ok(()) if at least one signal was sent, otherwise the last error that was encountered.
773#[track_caller]
774fn signal_thread_groups<F>(
775    current_task: &CurrentTask,
776    unchecked_signal: UncheckedSignal,
777    thread_groups: F,
778) -> Result<(), Errno>
779where
780    F: IntoIterator<Item: AsRef<ThreadGroup>>,
781{
782    let mut last_error = None;
783    let mut sent_signal = false;
784
785    // This loop keeps track of whether a signal was sent, so that "on
786    // success (at least one signal was sent), zero is returned."
787    for thread_group in thread_groups.into_iter() {
788        match thread_group.as_ref().send_signal_unchecked(current_task, unchecked_signal) {
789            Ok(_) => sent_signal = true,
790            Err(errno) => last_error = Some(errno),
791        }
792    }
793
794    if sent_signal { Ok(()) } else { Err(last_error.unwrap_or_else(|| errno!(ESRCH))) }
795}
796
797/// The generic options for both waitid and wait4.
798#[derive(Debug)]
799pub struct WaitingOptions {
800    /// Wait for a process that has exited.
801    pub wait_for_exited: bool,
802    /// Wait for a process in the stop state.
803    pub wait_for_stopped: bool,
804    /// Wait for a process that was continued.
805    pub wait_for_continued: bool,
806    /// Block the wait until a process matches.
807    pub block: bool,
808    /// Do not clear the waitable state.
809    pub keep_waitable_state: bool,
810    /// Wait for all children processes.
811    pub wait_for_all: bool,
812    /// Wait for children who deliver no signal or a signal other than SIGCHLD, ignored if wait_for_all is true
813    pub wait_for_clone: bool,
814}
815
816impl WaitingOptions {
817    fn new(options: u32) -> Self {
818        const_assert_eq!(WUNTRACED, WSTOPPED);
819        if options & __WNOTHREAD != 0 {
820            track_stub!(TODO("https://fxbug.dev/509926462"), "wait options wnothread");
821        }
822        Self {
823            wait_for_exited: options & WEXITED > 0,
824            wait_for_stopped: options & WSTOPPED > 0,
825            wait_for_continued: options & WCONTINUED > 0,
826            block: options & WNOHANG == 0,
827            keep_waitable_state: options & WNOWAIT > 0,
828            wait_for_all: options & __WALL > 0,
829            wait_for_clone: options & __WCLONE > 0,
830        }
831    }
832
833    /// Build a `WaitingOptions` from the waiting flags of waitid.
834    pub fn new_for_waitid(options: u32) -> Result<Self, Errno> {
835        if options & !(__WCLONE | __WALL | WNOHANG | WNOWAIT | WSTOPPED | WEXITED | WCONTINUED) != 0
836        {
837            track_stub!(TODO("https://fxbug.dev/322874788"), "waitid options", options);
838            return error!(EINVAL);
839        }
840        if options & (WEXITED | WSTOPPED | WCONTINUED) == 0 {
841            return error!(EINVAL);
842        }
843        Ok(Self::new(options))
844    }
845
846    /// Build a `WaitingOptions` from the waiting flags of wait4.
847    pub fn new_for_wait4(options: u32) -> Result<Self, Errno> {
848        if options & !(__WCLONE | __WNOTHREAD | __WALL | WNOHANG | WUNTRACED | WCONTINUED) != 0 {
849            track_stub!(TODO("https://fxbug.dev/322874017"), "wait4 options", options);
850            return error!(EINVAL);
851        }
852        Ok(Self::new(options | WEXITED))
853    }
854}
855
856/// Waits on the task with `pid` to exit or change state.
857///
858/// - `current_task`: The current task.
859/// - `pid`: The id of the task to wait on.
860/// - `options`: The options passed to the wait syscall.
861fn wait_on_pid(
862    locked: &mut Locked<Unlocked>,
863    current_task: &CurrentTask,
864    selector: &ProcessSelector,
865    options: &WaitingOptions,
866) -> Result<Option<WaitResult>, Errno> {
867    let waiter = Waiter::new();
868    loop {
869        {
870            let mut pids = current_task.kernel().pids.write();
871            // Waits and notifies on a given task need to be done atomically
872            // with respect to changes to the task's waitable state; otherwise,
873            // we see missing notifications. We do that by holding the task lock.
874            // This next line checks for waitable traces without holding the
875            // task lock, because constructing WaitResult objects requires
876            // holding all sorts of locks that are incompatible with holding the
877            // task lock.  We therefore have to check to see if a tracee has
878            // become waitable again, after we acquire the lock.
879            if let Some(tracee) =
880                current_task.thread_group().get_waitable_ptracee(selector, options, &mut pids)
881            {
882                return Ok(Some(tracee));
883            }
884            {
885                let mut thread_group = current_task.thread_group().write();
886
887                // Per the above, see if traced tasks have become waitable. If they have, release
888                // the lock and retry getting waitable tracees.
889                let mut has_waitable_tracee = false;
890                let mut has_any_tracee = false;
891                current_task.thread_group().get_ptracees_and(
892                    selector,
893                    &pids,
894                    &mut |task: &Task, task_state: &TaskMutableState| {
895                        if let Some(ptrace) = &task_state.ptrace {
896                            has_any_tracee = true;
897                            ptrace.tracer_waiters().wait_async(&waiter);
898                            if ptrace.is_waitable(task.load_stopped(), options) {
899                                has_waitable_tracee = true;
900                            }
901                        }
902                    },
903                );
904                if has_waitable_tracee
905                    || thread_group.zombie_ptracees.has_zombie_matching(&selector)
906                {
907                    continue;
908                }
909                match thread_group.get_waitable_child(selector, options, &mut pids) {
910                    WaitableChildResult::ReadyNow(child) => {
911                        return Ok(Some(*child));
912                    }
913                    WaitableChildResult::ShouldWait => (),
914                    WaitableChildResult::NoneFound => {
915                        if !has_any_tracee {
916                            return error!(ECHILD);
917                        }
918                    }
919                }
920                thread_group
921                    .lifecycle_waiters
922                    .wait_async_value(&waiter, ThreadGroupLifecycleWaitValue::ChildStatus);
923            }
924        }
925
926        if !options.block {
927            return Ok(None);
928        }
929        waiter.wait(locked, current_task).map_eintr(|| errno!(ERESTARTSYS))?;
930    }
931}
932
933/// The `waitid` syscall waits for a child process to change state.
934///
935/// # Args
936/// * `id_type`: The type of ID to wait for.
937/// * `id`: The ID to wait for.
938/// * `user_info`: A pointer to a `siginfo_t` structure that will be filled with information
939///   about the state change.
940/// * `options`: A bitmask of flags that control the behavior of the syscall.
941/// * `user_rusage`: An optional pointer to a `rusage` structure that will be filled with
942///   resource usage information.
943///
944/// # Returns
945/// `Ok(())` on success. Otherwise, returns an `Errno` with the error code.
946pub fn sys_waitid(
947    locked: &mut Locked<Unlocked>,
948    current_task: &CurrentTask,
949    id_type: u32,
950    id: i32,
951    user_info: MultiArchUserRef<uapi::siginfo_t, uapi::arch32::siginfo_t>,
952    options: u32,
953    user_rusage: RUsagePtr,
954) -> Result<(), Errno> {
955    let mut waiting_options = WaitingOptions::new_for_waitid(options)?;
956
957    let task_selector = match id_type {
958        P_PID => ProcessSelector::Pid(id),
959        P_ALL => ProcessSelector::Any,
960        P_PGID => ProcessSelector::Pgid(if id == 0 {
961            current_task.thread_group().read().process_group.leader
962        } else {
963            id
964        }),
965        P_PIDFD => {
966            let fd = FdNumber::from_raw(id);
967            let file = current_task.get_file(fd)?;
968            if file.flags().contains(OpenFlags::NONBLOCK) {
969                waiting_options.block = false;
970            }
971            ProcessSelector::Process(file.as_thread_group_key()?)
972        }
973        _ => return error!(EINVAL),
974    };
975
976    // wait_on_pid returns None if the task was not waited on. In that case, we don't write out a
977    // siginfo. This seems weird but is the correct behavior according to the waitid(2) man page.
978    if let Some(waitable_process) =
979        wait_on_pid(locked, current_task, &task_selector, &waiting_options)?
980    {
981        if !user_rusage.is_null() {
982            let usage = rusage {
983                ru_utime: timeval_from_duration(waitable_process.time_stats.user_time),
984                ru_stime: timeval_from_duration(waitable_process.time_stats.system_time),
985                ..Default::default()
986            };
987
988            track_stub!(TODO("https://fxbug.dev/322874712"), "real rusage from waitid");
989            current_task.write_multi_arch_object(user_rusage, usage)?;
990        }
991
992        if !user_info.is_null() {
993            let siginfo = waitable_process.as_signal_info();
994            siginfo.write(current_task, user_info)?;
995        }
996    } else if id_type == P_PIDFD {
997        // From <https://man7.org/linux/man-pages/man2/pidfd_open.2.html>:
998        //
999        //   PIDFD_NONBLOCK
1000        //     Return a nonblocking file descriptor.  If the process
1001        //     referred to by the file descriptor has not yet terminated,
1002        //     then an attempt to wait on the file descriptor using
1003        //     waitid(2) will immediately return the error EAGAIN rather
1004        //     than blocking.
1005        return error!(EAGAIN);
1006    }
1007
1008    Ok(())
1009}
1010
1011/// The `wait4` syscall waits for a child process to change state.
1012///
1013/// # Args
1014/// * `raw_selector`: The PID of the process to wait for. See `wait4(2)` for more details.
1015/// * `user_wstatus`: A pointer to an integer that will be filled with the exit status of the
1016///   process.
1017/// * `options`: A bitmask of flags that control the behavior of the syscall.
1018/// * `user_rusage`: An optional pointer to a `rusage` structure that will be filled with
1019///   resource usage information.
1020///
1021/// # Returns
1022/// On success, returns the PID of the process that changed state, or 0 if `WNOHANG` was
1023/// specified and no child has changed state. On error, returns an `Errno`.
1024pub fn sys_wait4(
1025    locked: &mut Locked<Unlocked>,
1026    current_task: &CurrentTask,
1027    raw_selector: pid_t,
1028    user_wstatus: UserRef<i32>,
1029    options: u32,
1030    user_rusage: RUsagePtr,
1031) -> Result<pid_t, Errno> {
1032    let waiting_options = WaitingOptions::new_for_wait4(options)?;
1033
1034    let selector = if raw_selector == 0 {
1035        ProcessSelector::Pgid(current_task.thread_group().read().process_group.leader)
1036    } else if raw_selector == -1 {
1037        ProcessSelector::Any
1038    } else if raw_selector > 0 {
1039        ProcessSelector::Pid(raw_selector)
1040    } else if raw_selector < -1 {
1041        ProcessSelector::Pgid(negate_pid(raw_selector)?)
1042    } else {
1043        track_stub!(
1044            TODO("https://fxbug.dev/322874213"),
1045            "wait4 with selector",
1046            raw_selector as u64
1047        );
1048        return error!(ENOSYS);
1049    };
1050
1051    if let Some(waitable_process) = wait_on_pid(locked, current_task, &selector, &waiting_options)?
1052    {
1053        let status = waitable_process.exit_info.status.wait_status();
1054
1055        if !user_rusage.is_null() {
1056            track_stub!(TODO("https://fxbug.dev/322874768"), "real rusage from wait4");
1057            let usage = rusage {
1058                ru_utime: timeval_from_duration(waitable_process.time_stats.user_time),
1059                ru_stime: timeval_from_duration(waitable_process.time_stats.system_time),
1060                ..Default::default()
1061            };
1062            current_task.write_multi_arch_object(user_rusage, usage)?;
1063        }
1064
1065        if !user_wstatus.is_null() {
1066            current_task.write_object(user_wstatus, &status)?;
1067        }
1068
1069        Ok(waitable_process.pid)
1070    } else {
1071        Ok(0)
1072    }
1073}
1074
1075// Negates the `pid` safely or fails with `ESRCH` (negation operation panics for `i32::MIN`).
1076fn negate_pid(pid: pid_t) -> Result<pid_t, Errno> {
1077    pid.checked_neg().ok_or_else(|| errno!(ESRCH))
1078}
1079
1080// Syscalls for arch32 usage
1081#[cfg(target_arch = "aarch64")]
1082mod arch32 {
1083    use crate::task::CurrentTask;
1084    use crate::vfs::FdNumber;
1085    use starnix_sync::{Locked, Unlocked};
1086    use starnix_uapi::errors::Errno;
1087    use starnix_uapi::signals::SigSet;
1088    use starnix_uapi::user_address::UserRef;
1089
1090    /// The `signalfd` syscall creates a file descriptor that can be used to accept signals targeted
1091    /// at the caller.
1092    ///
1093    /// This is the 32-bit compatibility version of `signalfd4`.
1094    ///
1095    /// # Args
1096    /// * `fd`: A file descriptor. If -1, a new file descriptor is created. Otherwise, the mask of the
1097    ///   existing signalfd is modified.
1098    /// * `mask_addr`: A pointer to a signal set specifying the signals to handle with this signalfd.
1099    /// * `mask_size`: The size of the signal set, in bytes.
1100    ///
1101    /// # Returns
1102    /// On success, returns `Ok(FdNumber)` containing the file descriptor number. On failure, returns
1103    /// an `Errno`.
1104    pub fn sys_arch32_signalfd(
1105        locked: &mut Locked<Unlocked>,
1106        current_task: &CurrentTask,
1107        fd: FdNumber,
1108        mask_addr: UserRef<SigSet>,
1109        mask_size: usize,
1110    ) -> Result<FdNumber, Errno> {
1111        super::sys_signalfd4(locked, current_task, fd, mask_addr, mask_size, 0)
1112    }
1113
1114    pub use super::{
1115        sys_pidfd_send_signal as sys_arch32_pidfd_send_signal,
1116        sys_rt_sigaction as sys_arch32_rt_sigaction,
1117        sys_rt_sigqueueinfo as sys_arch32_rt_sigqueueinfo,
1118        sys_rt_sigtimedwait as sys_arch32_rt_sigtimedwait,
1119        sys_rt_tgsigqueueinfo as sys_arch32_rt_tgsigqueueinfo,
1120        sys_sigaltstack as sys_arch32_sigaltstack, sys_signalfd4 as sys_arch32_signalfd4,
1121        sys_waitid as sys_arch32_waitid,
1122    };
1123}
1124
1125#[cfg(target_arch = "aarch64")]
1126pub use arch32::*;
1127
1128#[cfg(test)]
1129mod tests {
1130    use super::*;
1131    use crate::mm::{MemoryAccessor, PAGE_SIZE};
1132    use crate::signals::testing::dequeue_signal_for_test;
1133    use crate::signals::{SI_HEADER_SIZE, SignalInfoHeader, send_standard_signal};
1134    use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
1135    use crate::task::{EventHandler, ExitStatus, ProcessExitInfo};
1136    use crate::testing::*;
1137    use starnix_sync::Mutex;
1138    use starnix_types::math::round_up_to_system_page_size;
1139    use starnix_uapi::auth::Credentials;
1140    use starnix_uapi::errors::ERESTARTSYS;
1141    use starnix_uapi::signals::{
1142        SIGCHLD, SIGHUP, SIGINT, SIGIO, SIGKILL, SIGRTMIN, SIGSEGV, SIGSTOP, SIGTERM, SIGTRAP,
1143        SIGUSR1,
1144    };
1145    use starnix_uapi::vfs::FdEvents;
1146    use starnix_uapi::{SI_QUEUE, sigaction_t, uaddr, uid_t};
1147    use std::collections::VecDeque;
1148    use std::sync::Arc;
1149    use zerocopy::IntoBytes;
1150
1151    #[cfg(target_arch = "x86_64")]
1152    #[::fuchsia::test]
1153    async fn test_sigaltstack() {
1154        spawn_kernel_and_run(async |locked, current_task| {
1155            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1156
1157            let user_ss = UserRef::<sigaltstack>::new(addr);
1158            let nullptr = UserRef::<sigaltstack>::default();
1159
1160            // Check that the initial state is disabled.
1161            sys_sigaltstack(locked, &current_task, nullptr.into(), user_ss.into())
1162                .expect("failed to call sigaltstack");
1163            let mut ss = current_task.read_object(user_ss).expect("failed to read struct");
1164            assert!(ss.ss_flags & (SS_DISABLE as i32) != 0);
1165
1166            // Install a sigaltstack and read it back out.
1167            ss.ss_sp = uaddr { addr: 0x7FFFF };
1168            ss.ss_size = 0x1000;
1169            ss.ss_flags = SS_AUTODISARM as i32;
1170            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1171            sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into())
1172                .expect("failed to call sigaltstack");
1173            current_task
1174                .write_memory(addr, &[0u8; std::mem::size_of::<sigaltstack>()])
1175                .expect("failed to clear struct");
1176            sys_sigaltstack(locked, &current_task, nullptr.into(), user_ss.into())
1177                .expect("failed to call sigaltstack");
1178            let another_ss = current_task.read_object(user_ss).expect("failed to read struct");
1179            assert_eq!(ss.as_bytes(), another_ss.as_bytes());
1180
1181            // Disable the sigaltstack and read it back out.
1182            let ss = sigaltstack { ss_flags: SS_DISABLE as i32, ..sigaltstack::default() };
1183            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1184            sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into())
1185                .expect("failed to call sigaltstack");
1186            current_task
1187                .write_memory(addr, &[0u8; std::mem::size_of::<sigaltstack>()])
1188                .expect("failed to clear struct");
1189            sys_sigaltstack(locked, &current_task, nullptr.into(), user_ss.into())
1190                .expect("failed to call sigaltstack");
1191            let ss = current_task.read_object(user_ss).expect("failed to read struct");
1192            assert!(ss.ss_flags & (SS_DISABLE as i32) != 0);
1193        })
1194        .await;
1195    }
1196
1197    #[::fuchsia::test]
1198    async fn test_sigaltstack_invalid_size() {
1199        spawn_kernel_and_run(async |locked, current_task| {
1200            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1201
1202            let user_ss = UserRef::<sigaltstack>::new(addr);
1203            let nullptr = UserRef::<sigaltstack>::default();
1204
1205            // Check that the initial state is disabled.
1206            sys_sigaltstack(locked, &current_task, nullptr.into(), user_ss.into())
1207                .expect("failed to call sigaltstack");
1208            let mut ss = current_task.read_object(user_ss).expect("failed to read struct");
1209            assert!(ss.ss_flags & (SS_DISABLE as i32) != 0);
1210
1211            // Try to install a sigaltstack with an invalid size.
1212            let sigaltstack_addr_size = round_up_to_system_page_size(uapi::MINSIGSTKSZ as usize)
1213                .expect("failed to round up");
1214            let sigaltstack_addr = map_memory(
1215                locked,
1216                &current_task,
1217                UserAddress::default(),
1218                sigaltstack_addr_size as u64,
1219            );
1220            ss.ss_sp = sigaltstack_addr.into();
1221            ss.ss_flags = 0;
1222            ss.ss_size = uapi::MINSIGSTKSZ as u64 - 1;
1223            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1224            assert_eq!(
1225                sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into()),
1226                error!(ENOMEM)
1227            );
1228        })
1229        .await;
1230    }
1231
1232    #[cfg(target_arch = "x86_64")]
1233    #[::fuchsia::test]
1234    async fn test_sigaltstack_active_stack() {
1235        spawn_kernel_and_run(async |locked, current_task| {
1236            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1237
1238            let user_ss = UserRef::<sigaltstack>::new(addr);
1239            let nullptr = UserRef::<sigaltstack>::default();
1240
1241            // Check that the initial state is disabled.
1242            sys_sigaltstack(locked, &current_task, nullptr.into(), user_ss.into())
1243                .expect("failed to call sigaltstack");
1244            let mut ss = current_task.read_object(user_ss).expect("failed to read struct");
1245            assert!(ss.ss_flags & (SS_DISABLE as i32) != 0);
1246
1247            // Try to install a sigaltstack.
1248            let sigaltstack_addr_size = round_up_to_system_page_size(uapi::MINSIGSTKSZ as usize)
1249                .expect("failed to round up");
1250            let sigaltstack_addr = map_memory(
1251                locked,
1252                &current_task,
1253                UserAddress::default(),
1254                sigaltstack_addr_size as u64,
1255            );
1256            ss.ss_sp = sigaltstack_addr.into();
1257            ss.ss_flags = 0;
1258            ss.ss_size = sigaltstack_addr_size as u64;
1259            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1260            sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into())
1261                .expect("failed to call sigaltstack");
1262
1263            // Changing the sigaltstack while we are there should be an error.
1264            let next_addr = (sigaltstack_addr + sigaltstack_addr_size).unwrap();
1265            current_task.thread_state.registers.rsp = next_addr.ptr() as u64;
1266            ss.ss_flags = SS_DISABLE as i32;
1267            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1268            assert_eq!(
1269                sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into()),
1270                error!(EPERM)
1271            );
1272
1273            // However, setting the rsp to a different value outside the alt stack should allow us to
1274            // disable it.
1275            let next_ss_addr = sigaltstack_addr
1276                .checked_add(sigaltstack_addr_size)
1277                .unwrap()
1278                .checked_add(0x1000usize)
1279                .unwrap();
1280            current_task.thread_state.registers.rsp = next_ss_addr.ptr() as u64;
1281            let ss = sigaltstack { ss_flags: SS_DISABLE as i32, ..sigaltstack::default() };
1282            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1283            sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into())
1284                .expect("failed to call sigaltstack");
1285        })
1286        .await;
1287    }
1288
1289    #[cfg(target_arch = "x86_64")]
1290    #[::fuchsia::test]
1291    async fn test_sigaltstack_active_stack_saturates() {
1292        spawn_kernel_and_run(async |locked, current_task| {
1293            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1294
1295            let user_ss = UserRef::<sigaltstack>::new(addr);
1296            let nullptr = UserRef::<sigaltstack>::default();
1297
1298            // Check that the initial state is disabled.
1299            sys_sigaltstack(locked, &current_task, nullptr.into(), user_ss.into())
1300                .expect("failed to call sigaltstack");
1301            let mut ss = current_task.read_object(user_ss).expect("failed to read struct");
1302            assert!(ss.ss_flags & (SS_DISABLE as i32) != 0);
1303
1304            // Try to install a sigaltstack that takes the whole memory.
1305            let sigaltstack_addr_size = round_up_to_system_page_size(uapi::MINSIGSTKSZ as usize)
1306                .expect("failed to round up");
1307            let sigaltstack_addr = map_memory(
1308                locked,
1309                &current_task,
1310                UserAddress::default(),
1311                sigaltstack_addr_size as u64,
1312            );
1313            ss.ss_sp = sigaltstack_addr.into();
1314            ss.ss_flags = 0;
1315            ss.ss_size = u64::MAX;
1316            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1317            sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into())
1318                .expect("failed to call sigaltstack");
1319
1320            // Changing the sigaltstack while we are there should be an error.
1321            current_task.thread_state.registers.rsp =
1322                (sigaltstack_addr + sigaltstack_addr_size).unwrap().ptr() as u64;
1323            ss.ss_flags = SS_DISABLE as i32;
1324            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1325            assert_eq!(
1326                sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into()),
1327                error!(EPERM)
1328            );
1329
1330            // However, setting the rsp to a low value should work (it doesn't wrap-around).
1331            current_task.thread_state.registers.rsp = 0u64;
1332            let ss = sigaltstack { ss_flags: SS_DISABLE as i32, ..sigaltstack::default() };
1333            current_task.write_object(user_ss, &ss).expect("failed to write struct");
1334            sys_sigaltstack(locked, &current_task, user_ss.into(), nullptr.into())
1335                .expect("failed to call sigaltstack");
1336        })
1337        .await;
1338    }
1339
1340    /// It is invalid to call rt_sigprocmask with a sigsetsize that does not match the size of
1341    /// SigSet.
1342    #[::fuchsia::test]
1343    async fn test_sigprocmask_invalid_size() {
1344        spawn_kernel_and_run(async |locked, current_task| {
1345            let set = UserRef::<SigSet>::default();
1346            let old_set = UserRef::<SigSet>::default();
1347            let how = 0;
1348
1349            assert_eq!(
1350                sys_rt_sigprocmask(
1351                    locked,
1352                    &current_task,
1353                    how,
1354                    set,
1355                    old_set,
1356                    std::mem::size_of::<SigSet>() * 2
1357                ),
1358                error!(EINVAL)
1359            );
1360            assert_eq!(
1361                sys_rt_sigprocmask(
1362                    locked,
1363                    &current_task,
1364                    how,
1365                    set,
1366                    old_set,
1367                    std::mem::size_of::<SigSet>() / 2
1368                ),
1369                error!(EINVAL)
1370            );
1371        })
1372        .await;
1373    }
1374
1375    /// It is invalid to call rt_sigprocmask with a bad `how`.
1376    #[::fuchsia::test]
1377    async fn test_sigprocmask_invalid_how() {
1378        spawn_kernel_and_run(async |locked, current_task| {
1379            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1380
1381            let set = UserRef::<SigSet>::new(addr);
1382            let old_set = UserRef::<SigSet>::default();
1383            let how = SIG_SETMASK | SIG_UNBLOCK | SIG_BLOCK;
1384
1385            assert_eq!(
1386                sys_rt_sigprocmask(
1387                    locked,
1388                    &current_task,
1389                    how,
1390                    set,
1391                    old_set,
1392                    std::mem::size_of::<SigSet>()
1393                ),
1394                error!(EINVAL)
1395            );
1396        })
1397        .await;
1398    }
1399
1400    /// It is valid to call rt_sigprocmask with a null value for set. In that case, old_set should
1401    /// contain the current signal mask.
1402    #[::fuchsia::test]
1403    async fn test_sigprocmask_null_set() {
1404        spawn_kernel_and_run(async |locked, current_task| {
1405            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1406            let original_mask = SigSet::from(SIGTRAP);
1407            {
1408                current_task.write().set_signal_mask(original_mask);
1409            }
1410
1411            let set = UserRef::<SigSet>::default();
1412            let old_set = UserRef::<SigSet>::new(addr);
1413            let how = SIG_SETMASK;
1414
1415            current_task
1416                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>()])
1417                .expect("failed to clear struct");
1418
1419            assert_eq!(
1420                sys_rt_sigprocmask(
1421                    locked,
1422                    &current_task,
1423                    how,
1424                    set,
1425                    old_set,
1426                    std::mem::size_of::<SigSet>()
1427                ),
1428                Ok(())
1429            );
1430
1431            let old_mask = current_task.read_object(old_set).expect("failed to read mask");
1432            assert_eq!(old_mask, original_mask);
1433        })
1434        .await;
1435    }
1436
1437    /// It is valid to call rt_sigprocmask with null values for both set and old_set.
1438    /// In this case, how should be ignored and the set remains the same.
1439    #[::fuchsia::test]
1440    async fn test_sigprocmask_null_set_and_old_set() {
1441        spawn_kernel_and_run(async |locked, current_task| {
1442            let original_mask = SigSet::from(SIGTRAP);
1443            {
1444                current_task.write().set_signal_mask(original_mask);
1445            }
1446
1447            let set = UserRef::<SigSet>::default();
1448            let old_set = UserRef::<SigSet>::default();
1449            let how = SIG_SETMASK;
1450
1451            assert_eq!(
1452                sys_rt_sigprocmask(
1453                    locked,
1454                    &current_task,
1455                    how,
1456                    set,
1457                    old_set,
1458                    std::mem::size_of::<SigSet>()
1459                ),
1460                Ok(())
1461            );
1462            assert_eq!(current_task.read().signal_mask(), original_mask);
1463        })
1464        .await;
1465    }
1466
1467    /// Calling rt_sigprocmask with SIG_SETMASK should set the mask to the provided set.
1468    #[::fuchsia::test]
1469    async fn test_sigprocmask_setmask() {
1470        spawn_kernel_and_run(async |locked, current_task| {
1471            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1472            current_task
1473                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1474                .expect("failed to clear struct");
1475
1476            let original_mask = SigSet::from(SIGTRAP);
1477            {
1478                current_task.write().set_signal_mask(original_mask);
1479            }
1480
1481            let new_mask = SigSet::from(SIGIO);
1482            let set = UserRef::<SigSet>::new(addr);
1483            current_task.write_object(set, &new_mask).expect("failed to set mask");
1484
1485            let old_addr_range = (addr + std::mem::size_of::<SigSet>()).unwrap();
1486            let old_set = UserRef::<SigSet>::new(old_addr_range);
1487            let how = SIG_SETMASK;
1488
1489            assert_eq!(
1490                sys_rt_sigprocmask(
1491                    locked,
1492                    &current_task,
1493                    how,
1494                    set,
1495                    old_set,
1496                    std::mem::size_of::<SigSet>()
1497                ),
1498                Ok(())
1499            );
1500
1501            let old_mask = current_task.read_object(old_set).expect("failed to read mask");
1502            assert_eq!(old_mask, original_mask);
1503            assert_eq!(current_task.read().signal_mask(), new_mask);
1504        })
1505        .await;
1506    }
1507
1508    /// Calling st_sigprocmask with a how of SIG_BLOCK should add to the existing set.
1509    #[::fuchsia::test]
1510    async fn test_sigprocmask_block() {
1511        spawn_kernel_and_run(async |locked, current_task| {
1512            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1513            current_task
1514                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1515                .expect("failed to clear struct");
1516
1517            let original_mask = SigSet::from(SIGTRAP);
1518            {
1519                current_task.write().set_signal_mask(original_mask);
1520            }
1521
1522            let new_mask = SigSet::from(SIGIO);
1523            let set = UserRef::<SigSet>::new(addr);
1524            current_task.write_object(set, &new_mask).expect("failed to set mask");
1525
1526            let old_addr_range = (addr + std::mem::size_of::<SigSet>()).unwrap();
1527            let old_set = UserRef::<SigSet>::new(old_addr_range);
1528            let how = SIG_BLOCK;
1529
1530            assert_eq!(
1531                sys_rt_sigprocmask(
1532                    locked,
1533                    &current_task,
1534                    how,
1535                    set,
1536                    old_set,
1537                    std::mem::size_of::<SigSet>()
1538                ),
1539                Ok(())
1540            );
1541
1542            let old_mask = current_task.read_object(old_set).expect("failed to read mask");
1543            assert_eq!(old_mask, original_mask);
1544            assert_eq!(current_task.read().signal_mask(), new_mask | original_mask);
1545        })
1546        .await;
1547    }
1548
1549    /// Calling st_sigprocmask with a how of SIG_UNBLOCK should remove from the existing set.
1550    #[::fuchsia::test]
1551    async fn test_sigprocmask_unblock() {
1552        spawn_kernel_and_run(async |locked, current_task| {
1553            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1554            current_task
1555                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1556                .expect("failed to clear struct");
1557
1558            let original_mask = SigSet::from(SIGTRAP) | SigSet::from(SIGIO);
1559            {
1560                current_task.write().set_signal_mask(original_mask);
1561            }
1562
1563            let new_mask = SigSet::from(SIGTRAP);
1564            let set = UserRef::<SigSet>::new(addr);
1565            current_task.write_object(set, &new_mask).expect("failed to set mask");
1566
1567            let old_addr_range = (addr + std::mem::size_of::<SigSet>()).unwrap();
1568            let old_set = UserRef::<SigSet>::new(old_addr_range);
1569            let how = SIG_UNBLOCK;
1570
1571            assert_eq!(
1572                sys_rt_sigprocmask(
1573                    locked,
1574                    &current_task,
1575                    how,
1576                    set,
1577                    old_set,
1578                    std::mem::size_of::<SigSet>()
1579                ),
1580                Ok(())
1581            );
1582
1583            let old_mask = current_task.read_object(old_set).expect("failed to read mask");
1584            assert_eq!(old_mask, original_mask);
1585            assert_eq!(current_task.read().signal_mask(), SIGIO.into());
1586        })
1587        .await;
1588    }
1589
1590    /// It's ok to call sigprocmask to unblock a signal that is not set.
1591    #[::fuchsia::test]
1592    async fn test_sigprocmask_unblock_not_set() {
1593        spawn_kernel_and_run(async |locked, current_task| {
1594            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1595            current_task
1596                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1597                .expect("failed to clear struct");
1598
1599            let original_mask = SigSet::from(SIGIO);
1600            {
1601                current_task.write().set_signal_mask(original_mask);
1602            }
1603
1604            let new_mask = SigSet::from(SIGTRAP);
1605            let set = UserRef::<SigSet>::new(addr);
1606            current_task.write_object(set, &new_mask).expect("failed to set mask");
1607
1608            let old_addr_range = (addr + std::mem::size_of::<SigSet>()).unwrap();
1609            let old_set = UserRef::<SigSet>::new(old_addr_range);
1610            let how = SIG_UNBLOCK;
1611
1612            assert_eq!(
1613                sys_rt_sigprocmask(
1614                    locked,
1615                    &current_task,
1616                    how,
1617                    set,
1618                    old_set,
1619                    std::mem::size_of::<SigSet>()
1620                ),
1621                Ok(())
1622            );
1623
1624            let old_mask = current_task.read_object(old_set).expect("failed to read mask");
1625            assert_eq!(old_mask, original_mask);
1626            assert_eq!(current_task.read().signal_mask(), original_mask);
1627        })
1628        .await;
1629    }
1630
1631    /// It's not possible to block SIGKILL or SIGSTOP.
1632    #[::fuchsia::test]
1633    async fn test_sigprocmask_kill_stop() {
1634        spawn_kernel_and_run(async |locked, current_task| {
1635            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1636            current_task
1637                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1638                .expect("failed to clear struct");
1639
1640            let original_mask = SigSet::from(SIGIO);
1641            {
1642                current_task.write().set_signal_mask(original_mask);
1643            }
1644
1645            let new_mask = UNBLOCKABLE_SIGNALS;
1646            let set = UserRef::<SigSet>::new(addr);
1647            current_task.write_object(set, &new_mask).expect("failed to set mask");
1648
1649            let old_addr_range = (addr + std::mem::size_of::<SigSet>()).unwrap();
1650            let old_set = UserRef::<SigSet>::new(old_addr_range);
1651            let how = SIG_BLOCK;
1652
1653            assert_eq!(
1654                sys_rt_sigprocmask(
1655                    locked,
1656                    &current_task,
1657                    how,
1658                    set,
1659                    old_set,
1660                    std::mem::size_of::<SigSet>()
1661                ),
1662                Ok(())
1663            );
1664
1665            let old_mask = current_task.read_object(old_set).expect("failed to read mask");
1666            assert_eq!(old_mask, original_mask);
1667            assert_eq!(current_task.read().signal_mask(), original_mask);
1668        })
1669        .await;
1670    }
1671
1672    #[::fuchsia::test]
1673    async fn test_sigaction_invalid_signal() {
1674        spawn_kernel_and_run(async |locked, current_task| {
1675            assert_eq!(
1676                sys_rt_sigaction(
1677                    locked,
1678                    &current_task,
1679                    UncheckedSignal::from(SIGKILL),
1680                    // The signal is only checked when the action is set (i.e., action is non-null).
1681                    UserRef::<sigaction_t>::new(UserAddress::from(10)).into(),
1682                    UserRef::<sigaction_t>::default().into(),
1683                    std::mem::size_of::<SigSet>(),
1684                ),
1685                error!(EINVAL)
1686            );
1687            assert_eq!(
1688                sys_rt_sigaction(
1689                    locked,
1690                    &current_task,
1691                    UncheckedSignal::from(SIGSTOP),
1692                    // The signal is only checked when the action is set (i.e., action is non-null).
1693                    UserRef::<sigaction_t>::new(UserAddress::from(10)).into(),
1694                    UserRef::<sigaction_t>::default().into(),
1695                    std::mem::size_of::<SigSet>(),
1696                ),
1697                error!(EINVAL)
1698            );
1699            assert_eq!(
1700                sys_rt_sigaction(
1701                    locked,
1702                    &current_task,
1703                    UncheckedSignal::from(Signal::NUM_SIGNALS + 1),
1704                    // The signal is only checked when the action is set (i.e., action is non-null).
1705                    UserRef::<sigaction_t>::new(UserAddress::from(10)).into(),
1706                    UserRef::<sigaction_t>::default().into(),
1707                    std::mem::size_of::<SigSet>(),
1708                ),
1709                error!(EINVAL)
1710            );
1711        })
1712        .await;
1713    }
1714
1715    #[::fuchsia::test]
1716    async fn test_sigaction_old_value_set() {
1717        spawn_kernel_and_run(async |locked, current_task| {
1718            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1719            current_task
1720                .write_memory(addr, &[0u8; std::mem::size_of::<sigaction_t>()])
1721                .expect("failed to clear struct");
1722
1723            let org_mask = SigSet::from(SIGHUP) | SigSet::from(SIGINT);
1724            let original_action =
1725                sigaction_t { sa_mask: org_mask.into(), ..sigaction_t::default() };
1726
1727            {
1728                current_task.thread_group().signal_actions.set(SIGHUP, original_action);
1729            }
1730
1731            let old_action_ref = UserRef::<sigaction_t>::new(addr);
1732            assert_eq!(
1733                sys_rt_sigaction(
1734                    locked,
1735                    &current_task,
1736                    UncheckedSignal::from(SIGHUP),
1737                    UserRef::<sigaction_t>::default().into(),
1738                    old_action_ref.into(),
1739                    std::mem::size_of::<SigSet>()
1740                ),
1741                Ok(())
1742            );
1743
1744            let old_action =
1745                current_task.read_object(old_action_ref).expect("failed to read action");
1746            assert_eq!(old_action.as_bytes(), original_action.as_bytes());
1747        })
1748        .await;
1749    }
1750
1751    #[::fuchsia::test]
1752    async fn test_sigaction_new_value_set() {
1753        spawn_kernel_and_run(async |locked, current_task| {
1754            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1755            current_task
1756                .write_memory(addr, &[0u8; std::mem::size_of::<sigaction_t>()])
1757                .expect("failed to clear struct");
1758
1759            let org_mask = SigSet::from(SIGHUP) | SigSet::from(SIGINT);
1760            let original_action =
1761                sigaction_t { sa_mask: org_mask.into(), ..sigaction_t::default() };
1762            let set_action_ref = UserRef::<sigaction_t>::new(addr);
1763            current_task
1764                .write_object(set_action_ref, &original_action)
1765                .expect("failed to set action");
1766
1767            assert_eq!(
1768                sys_rt_sigaction(
1769                    locked,
1770                    &current_task,
1771                    UncheckedSignal::from(SIGINT),
1772                    set_action_ref.into(),
1773                    UserRef::<sigaction_t>::default().into(),
1774                    std::mem::size_of::<SigSet>(),
1775                ),
1776                Ok(())
1777            );
1778
1779            assert_eq!(
1780                current_task.thread_group().signal_actions.get(SIGINT).as_bytes(),
1781                original_action.as_bytes()
1782            );
1783        })
1784        .await;
1785    }
1786
1787    /// A task should be able to signal itself.
1788    #[::fuchsia::test]
1789    async fn test_kill_same_task() {
1790        spawn_kernel_and_run(async |locked, current_task| {
1791            assert_eq!(sys_kill(locked, &current_task, current_task.tid, SIGINT.into()), Ok(()));
1792        })
1793        .await;
1794    }
1795
1796    /// A task should be able to signal its own thread group.
1797    #[::fuchsia::test]
1798    async fn test_kill_own_thread_group() {
1799        spawn_kernel_and_run(async |locked, init_task| {
1800            let task1 = init_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
1801            task1.thread_group().setsid(locked).expect("setsid");
1802            let task2 = task1.clone_task_for_test(locked, 0, Some(SIGCHLD));
1803
1804            assert_eq!(sys_kill(locked, &task1, 0, SIGINT.into()), Ok(()));
1805            assert_eq!(task1.read().queued_signal_count(SIGINT), 1);
1806            assert_eq!(task2.read().queued_signal_count(SIGINT), 1);
1807            assert_eq!(init_task.read().queued_signal_count(SIGINT), 0);
1808        })
1809        .await;
1810    }
1811
1812    /// A task should be able to signal a thread group.
1813    #[::fuchsia::test]
1814    async fn test_kill_thread_group() {
1815        spawn_kernel_and_run(async |locked, init_task| {
1816            let task1 = init_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
1817            task1.thread_group().setsid(locked).expect("setsid");
1818            let task2 = task1.clone_task_for_test(locked, 0, Some(SIGCHLD));
1819
1820            assert_eq!(sys_kill(locked, &task1, -task1.tid, SIGINT.into()), Ok(()));
1821            assert_eq!(task1.read().queued_signal_count(SIGINT), 1);
1822            assert_eq!(task2.read().queued_signal_count(SIGINT), 1);
1823            assert_eq!(init_task.read().queued_signal_count(SIGINT), 0);
1824        })
1825        .await;
1826    }
1827
1828    /// A task should be able to signal everything but init and itself.
1829    #[::fuchsia::test]
1830    async fn test_kill_all() {
1831        spawn_kernel_and_run(async |locked, init_task| {
1832            let task1 = init_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
1833            task1.thread_group().setsid(locked).expect("setsid");
1834            let task2 = task1.clone_task_for_test(locked, 0, Some(SIGCHLD));
1835
1836            assert_eq!(sys_kill(locked, &task1, -1, SIGINT.into()), Ok(()));
1837            assert_eq!(task1.read().queued_signal_count(SIGINT), 0);
1838            assert_eq!(task2.read().queued_signal_count(SIGINT), 1);
1839            assert_eq!(init_task.read().queued_signal_count(SIGINT), 0);
1840        })
1841        .await;
1842    }
1843
1844    /// A task should not be able to signal a nonexistent task.
1845    #[::fuchsia::test]
1846    async fn test_kill_inexistant_task() {
1847        spawn_kernel_and_run(async |locked, current_task| {
1848            assert_eq!(sys_kill(locked, &current_task, 9, SIGINT.into()), error!(ESRCH));
1849        })
1850        .await;
1851    }
1852
1853    /// A task should not be able to signal a task owned by another uid.
1854    #[::fuchsia::test]
1855    async fn test_kill_invalid_task() {
1856        spawn_kernel_and_run(async |locked, task1| {
1857            // Task must not have the kill capability.
1858            task1.set_creds(Credentials::with_ids(1, 1));
1859            let task2 = task1.clone_task_for_test(locked, 0, Some(SIGCHLD));
1860            task2.set_creds(Credentials::with_ids(2, 2));
1861
1862            assert!(task1.can_signal(&task2, SIGINT.into()).is_err());
1863            assert_eq!(sys_kill(locked, &task2, task1.tid, SIGINT.into()), error!(EPERM));
1864            assert_eq!(task1.read().queued_signal_count(SIGINT), 0);
1865        })
1866        .await;
1867    }
1868
1869    /// A task should not be able to signal a task owned by another uid in a thead group.
1870    #[::fuchsia::test]
1871    async fn test_kill_invalid_task_in_thread_group() {
1872        spawn_kernel_and_run(async |locked, init_task| {
1873            let task1 = init_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
1874            task1.thread_group().setsid(locked).expect("setsid");
1875            let task2 = task1.clone_task_for_test(locked, 0, Some(SIGCHLD));
1876            task2.thread_group().setsid(locked).expect("setsid");
1877            task2.set_creds(Credentials::with_ids(2, 2));
1878
1879            assert!(task2.can_signal(&task1, SIGINT.into()).is_err());
1880            assert_eq!(sys_kill(locked, &task2, -task1.tid, SIGINT.into()), error!(EPERM));
1881            assert_eq!(task1.read().queued_signal_count(SIGINT), 0);
1882        })
1883        .await;
1884    }
1885
1886    /// A task should not be able to send an invalid signal.
1887    #[::fuchsia::test]
1888    async fn test_kill_invalid_signal() {
1889        spawn_kernel_and_run(async |locked, current_task| {
1890            assert_eq!(
1891                sys_kill(locked, &current_task, current_task.tid, UncheckedSignal::from(75)),
1892                error!(EINVAL)
1893            );
1894        })
1895        .await;
1896    }
1897
1898    /// Sending a blocked signal should result in a pending signal.
1899    #[::fuchsia::test]
1900    async fn test_blocked_signal_pending() {
1901        spawn_kernel_and_run(async |locked, current_task| {
1902            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1903            current_task
1904                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1905                .expect("failed to clear struct");
1906
1907            let new_mask = SigSet::from(SIGIO);
1908            let set = UserRef::<SigSet>::new(addr);
1909            current_task.write_object(set, &new_mask).expect("failed to set mask");
1910
1911            assert_eq!(
1912                sys_rt_sigprocmask(
1913                    locked,
1914                    &current_task,
1915                    SIG_BLOCK,
1916                    set,
1917                    UserRef::default(),
1918                    std::mem::size_of::<SigSet>()
1919                ),
1920                Ok(())
1921            );
1922            assert_eq!(sys_kill(locked, &current_task, current_task.tid, SIGIO.into()), Ok(()));
1923            assert_eq!(current_task.read().queued_signal_count(SIGIO), 1);
1924
1925            // A second signal should not increment the number of pending signals.
1926            assert_eq!(sys_kill(locked, &current_task, current_task.tid, SIGIO.into()), Ok(()));
1927            assert_eq!(current_task.read().queued_signal_count(SIGIO), 1);
1928        })
1929        .await;
1930    }
1931
1932    /// More than one instance of a real-time signal can be blocked.
1933    #[::fuchsia::test]
1934    async fn test_blocked_real_time_signal_pending() {
1935        spawn_kernel_and_run(async |locked, current_task| {
1936            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1937            current_task
1938                .write_memory(addr, &[0u8; std::mem::size_of::<SigSet>() * 2])
1939                .expect("failed to clear struct");
1940
1941            let new_mask = SigSet::from(starnix_uapi::signals::SIGRTMIN);
1942            let set = UserRef::<SigSet>::new(addr);
1943            current_task.write_object(set, &new_mask).expect("failed to set mask");
1944
1945            assert_eq!(
1946                sys_rt_sigprocmask(
1947                    locked,
1948                    &current_task,
1949                    SIG_BLOCK,
1950                    set,
1951                    UserRef::default(),
1952                    std::mem::size_of::<SigSet>()
1953                ),
1954                Ok(())
1955            );
1956            assert_eq!(sys_kill(locked, &current_task, current_task.tid, SIGRTMIN.into()), Ok(()));
1957            assert_eq!(current_task.read().queued_signal_count(starnix_uapi::signals::SIGRTMIN), 1);
1958
1959            // A second signal should increment the number of pending signals.
1960            assert_eq!(sys_kill(locked, &current_task, current_task.tid, SIGRTMIN.into()), Ok(()));
1961            assert_eq!(current_task.read().queued_signal_count(starnix_uapi::signals::SIGRTMIN), 2);
1962        })
1963        .await;
1964    }
1965
1966    #[::fuchsia::test]
1967    async fn test_suspend() {
1968        spawn_kernel_and_run(async |locked, current_task| {
1969            let init_task_weak = current_task.weak_task();
1970            let (tx, rx) = std::sync::mpsc::sync_channel::<()>(0);
1971
1972            let closure = move |locked: &mut Locked<Unlocked>, current_task: &CurrentTask| {
1973                let init_task_temp = init_task_weak.upgrade().expect("Task must be alive");
1974
1975                // Wait for the init task to be suspended.
1976                let mut suspended = false;
1977                while !suspended {
1978                    suspended = init_task_temp.read().is_blocked();
1979                    std::thread::sleep(std::time::Duration::from_millis(10));
1980                }
1981
1982                // Signal the suspended task with a signal that is not blocked (only SIGHUP in this test).
1983                let _ = sys_kill(
1984                    locked,
1985                    current_task,
1986                    init_task_temp.tid,
1987                    UncheckedSignal::from(SIGHUP),
1988                );
1989
1990                // Wait for the sigsuspend to complete.
1991                rx.recv().expect("receive");
1992                assert!(!init_task_temp.read().is_blocked());
1993            };
1994            let (thread, req) =
1995                SpawnRequestBuilder::new().with_sync_closure(closure).build_with_async_result();
1996            current_task.kernel().kthreads.spawner().spawn_from_request(req);
1997
1998            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
1999            let user_ref = UserRef::<SigSet>::new(addr);
2000
2001            let sigset = !SigSet::from(SIGHUP);
2002            current_task.write_object(user_ref, &sigset).expect("failed to set action");
2003
2004            assert_eq!(
2005                sys_rt_sigsuspend(locked, current_task, user_ref, std::mem::size_of::<SigSet>()),
2006                error!(ERESTARTNOHAND)
2007            );
2008            tx.send(()).expect("send");
2009            futures::executor::block_on(thread).expect("join");
2010        })
2011        .await;
2012    }
2013
2014    /// Waitid does not support all options.
2015    #[::fuchsia::test]
2016    async fn test_waitid_options() {
2017        spawn_kernel_and_run(async |locked, current_task| {
2018            let id = 1;
2019            assert_eq!(
2020                sys_waitid(
2021                    locked,
2022                    &current_task,
2023                    P_PID,
2024                    id,
2025                    MultiArchUserRef::null(current_task),
2026                    0,
2027                    UserRef::default().into()
2028                ),
2029                error!(EINVAL)
2030            );
2031            assert_eq!(
2032                sys_waitid(
2033                    locked,
2034                    &current_task,
2035                    P_PID,
2036                    id,
2037                    MultiArchUserRef::null(current_task),
2038                    0xffff,
2039                    UserRef::default().into()
2040                ),
2041                error!(EINVAL)
2042            );
2043        })
2044        .await;
2045    }
2046
2047    /// Wait4 does not support all options.
2048    #[::fuchsia::test]
2049    async fn test_wait4_options() {
2050        spawn_kernel_and_run(async |locked, current_task| {
2051            let id = 1;
2052            assert_eq!(
2053                sys_wait4(
2054                    locked,
2055                    &current_task,
2056                    id,
2057                    UserRef::default(),
2058                    WEXITED,
2059                    RUsagePtr::null(current_task)
2060                ),
2061                error!(EINVAL)
2062            );
2063            assert_eq!(
2064                sys_wait4(
2065                    locked,
2066                    &current_task,
2067                    id,
2068                    UserRef::default(),
2069                    WNOWAIT,
2070                    RUsagePtr::null(current_task)
2071                ),
2072                error!(EINVAL)
2073            );
2074            assert_eq!(
2075                sys_wait4(
2076                    locked,
2077                    &current_task,
2078                    id,
2079                    UserRef::default(),
2080                    0xffff,
2081                    RUsagePtr::null(current_task)
2082                ),
2083                error!(EINVAL)
2084            );
2085        })
2086        .await;
2087    }
2088
2089    #[::fuchsia::test]
2090    async fn test_echild_when_no_zombie() {
2091        spawn_kernel_and_run(async |locked, current_task| {
2092            // Send the signal to the task.
2093            assert!(
2094                sys_kill(
2095                    locked,
2096                    &current_task,
2097                    current_task.get_pid(),
2098                    UncheckedSignal::from(SIGCHLD)
2099                )
2100                .is_ok()
2101            );
2102            // Verify that ECHILD is returned because there is no zombie process and no children to
2103            // block waiting for.
2104            assert_eq!(
2105                wait_on_pid(
2106                    locked,
2107                    &current_task,
2108                    &ProcessSelector::Any,
2109                    &WaitingOptions::new_for_wait4(0).expect("WaitingOptions")
2110                ),
2111                error!(ECHILD)
2112            );
2113        })
2114        .await;
2115    }
2116
2117    #[::fuchsia::test]
2118    async fn test_no_error_when_zombie() {
2119        spawn_kernel_and_run(async |locked, current_task| {
2120            let child = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2121            let expected_result = WaitResult {
2122                pid: child.tid,
2123                uid: 0,
2124                exit_info: ProcessExitInfo {
2125                    status: ExitStatus::Exit(1),
2126                    exit_signal: Some(SIGCHLD),
2127                },
2128                time_stats: Default::default(),
2129            };
2130            child.thread_group().exit(locked, ExitStatus::Exit(1), None);
2131            std::mem::drop(child);
2132
2133            assert_eq!(
2134                wait_on_pid(
2135                    locked,
2136                    &current_task,
2137                    &ProcessSelector::Any,
2138                    &WaitingOptions::new_for_wait4(0).expect("WaitingOptions")
2139                ),
2140                Ok(Some(expected_result))
2141            );
2142        })
2143        .await;
2144    }
2145
2146    #[::fuchsia::test]
2147    async fn test_waiting_for_child() {
2148        spawn_kernel_and_run(async |locked, task| {
2149            let child = task.clone_task_builder_for_test(locked, 0, Some(SIGCHLD));
2150
2151            // No child is currently terminated.
2152            assert_eq!(
2153                wait_on_pid(
2154                    locked,
2155                    &task,
2156                    &ProcessSelector::Any,
2157                    &WaitingOptions::new_for_wait4(WNOHANG).expect("WaitingOptions")
2158                ),
2159                Ok(None)
2160            );
2161
2162            let thread = std::thread::spawn({
2163                let task = task.weak_task();
2164                move || {
2165                    // Create child
2166                    #[allow(
2167                        clippy::undocumented_unsafe_blocks,
2168                        reason = "Force documented unsafe blocks in Starnix"
2169                    )]
2170                    let locked = unsafe { Unlocked::new() };
2171                    let task = task.upgrade().expect("task must be alive");
2172                    let child: AutoReleasableTask = child.into();
2173                    // Wait for the main thread to be blocked on waiting for a child.
2174                    while !task.read().is_blocked() {
2175                        std::thread::sleep(std::time::Duration::from_millis(10));
2176                    }
2177                    child.thread_group().exit(locked, ExitStatus::Exit(0), None);
2178                    child.tid
2179                }
2180            });
2181
2182            // Block until child is terminated.
2183            let waited_child = wait_on_pid(
2184                locked,
2185                &task,
2186                &ProcessSelector::Any,
2187                &WaitingOptions::new_for_wait4(0).expect("WaitingOptions"),
2188            )
2189            .expect("wait_on_pid")
2190            .unwrap();
2191
2192            // Child is deleted, the thread must be able to terminate.
2193            let child_id = thread.join().expect("join");
2194            assert_eq!(waited_child.pid, child_id);
2195        })
2196        .await;
2197    }
2198
2199    #[::fuchsia::test]
2200    async fn test_waiting_for_child_with_signal_pending() {
2201        spawn_kernel_and_run(async |locked, task| {
2202            // Register a signal action to ensure that the `SIGUSR1` signal interrupts the task.
2203            task.thread_group().signal_actions.set(
2204                SIGUSR1,
2205                sigaction_t { sa_handler: uaddr { addr: 0xDEADBEEF }, ..sigaction_t::default() },
2206            );
2207
2208            // Start a child task. This will ensure that `wait_on_pid` tries to wait for the child.
2209            let _child = task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2210
2211            // Send a signal to the task. `wait_on_pid` should realize there is a signal pending when
2212            // entering a wait and return with `EINTR`.
2213            send_standard_signal(locked, &task, SignalInfo::kernel(SIGUSR1));
2214
2215            let errno = wait_on_pid(
2216                locked,
2217                &task,
2218                &ProcessSelector::Any,
2219                &WaitingOptions::new_for_wait4(0).expect("WaitingOptions"),
2220            )
2221            .expect_err("wait_on_pid");
2222            assert_eq!(errno, ERESTARTSYS);
2223        })
2224        .await;
2225    }
2226
2227    #[::fuchsia::test]
2228    async fn test_sigkill() {
2229        spawn_kernel_and_run(async |locked, current_task| {
2230            let mut child = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2231
2232            // Send SIGKILL to the child. As kill is handled immediately, no need to dequeue signals.
2233            send_standard_signal(locked, &child, SignalInfo::kernel(SIGKILL));
2234            dequeue_signal_for_test(locked, &mut child);
2235            std::mem::drop(child);
2236
2237            // Retrieve the exit status.
2238            let address = map_memory(
2239                locked,
2240                &current_task,
2241                UserAddress::default(),
2242                std::mem::size_of::<i32>() as u64,
2243            );
2244            let address_ref = UserRef::<i32>::new(address);
2245            sys_wait4(locked, &current_task, -1, address_ref, 0, RUsagePtr::null(current_task))
2246                .expect("wait4");
2247            let wstatus = current_task.read_object(address_ref).expect("read memory");
2248            assert_eq!(wstatus, SIGKILL.number() as i32);
2249        })
2250        .await;
2251    }
2252
2253    async fn test_exit_status_for_signal(
2254        sig: Signal,
2255        wait_status: i32,
2256        exit_signal: Option<Signal>,
2257    ) {
2258        spawn_kernel_and_run(async move |locked, current_task| {
2259            let mut child = current_task.clone_task_for_test(locked, 0, exit_signal);
2260
2261            // Send the signal to the child.
2262            send_standard_signal(locked, &child, SignalInfo::kernel(sig));
2263            dequeue_signal_for_test(locked, &mut child);
2264            std::mem::drop(child);
2265
2266            // Retrieve the exit status.
2267            let address = map_memory(
2268                locked,
2269                &current_task,
2270                UserAddress::default(),
2271                std::mem::size_of::<i32>() as u64,
2272            );
2273            let address_ref = UserRef::<i32>::new(address);
2274            sys_wait4(locked, &current_task, -1, address_ref, 0, RUsagePtr::null(current_task))
2275                .expect("wait4");
2276            let wstatus = current_task.read_object(address_ref).expect("read memory");
2277            assert_eq!(wstatus, wait_status);
2278        })
2279        .await;
2280    }
2281
2282    #[::fuchsia::test]
2283    async fn test_exit_status() {
2284        // Default action is Terminate
2285        test_exit_status_for_signal(SIGTERM, SIGTERM.number() as i32, Some(SIGCHLD)).await;
2286        // Default action is CoreDump
2287        test_exit_status_for_signal(SIGSEGV, (SIGSEGV.number() as i32) | 0x80, Some(SIGCHLD)).await;
2288    }
2289
2290    #[::fuchsia::test]
2291    async fn test_wait4_by_pgid() {
2292        spawn_kernel_and_run(async |locked, current_task| {
2293            let child1 = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2294            let child1_pid = child1.tid;
2295            child1.thread_group().exit(locked, ExitStatus::Exit(42), None);
2296            std::mem::drop(child1);
2297            let child2 = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2298            child2.thread_group().setsid(locked).expect("setsid");
2299            let child2_pid = child2.tid;
2300            child2.thread_group().exit(locked, ExitStatus::Exit(42), None);
2301            std::mem::drop(child2);
2302
2303            assert_eq!(
2304                sys_wait4(
2305                    locked,
2306                    &current_task,
2307                    -child2_pid,
2308                    UserRef::default(),
2309                    0,
2310                    RUsagePtr::null(current_task)
2311                ),
2312                Ok(child2_pid)
2313            );
2314            assert_eq!(
2315                sys_wait4(
2316                    locked,
2317                    &current_task,
2318                    0,
2319                    UserRef::default(),
2320                    0,
2321                    RUsagePtr::null(current_task)
2322                ),
2323                Ok(child1_pid)
2324            );
2325        })
2326        .await;
2327    }
2328
2329    #[::fuchsia::test]
2330    async fn test_waitid_by_pgid() {
2331        spawn_kernel_and_run(async |locked, current_task| {
2332            let child1 = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2333            let child1_pid = child1.tid;
2334            child1.thread_group().exit(locked, ExitStatus::Exit(42), None);
2335            std::mem::drop(child1);
2336            let child2 = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2337            child2.thread_group().setsid(locked).expect("setsid");
2338            let child2_pid = child2.tid;
2339            child2.thread_group().exit(locked, ExitStatus::Exit(42), None);
2340            std::mem::drop(child2);
2341
2342            let address: UserRef<uapi::siginfo_t> =
2343                map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE).into();
2344            assert_eq!(
2345                sys_waitid(
2346                    locked,
2347                    &current_task,
2348                    P_PGID,
2349                    child2_pid,
2350                    address.into(),
2351                    WEXITED,
2352                    UserRef::default().into()
2353                ),
2354                Ok(())
2355            );
2356            // The previous wait matched child2, only child1 should be in the available zombies.
2357            assert_eq!(current_task.thread_group().read().zombie_children[0].pid(), child1_pid);
2358
2359            assert_eq!(
2360                sys_waitid(
2361                    locked,
2362                    &current_task,
2363                    P_PGID,
2364                    0,
2365                    address.into(),
2366                    WEXITED,
2367                    UserRef::default().into()
2368                ),
2369                Ok(())
2370            );
2371        })
2372        .await;
2373    }
2374
2375    #[::fuchsia::test]
2376    async fn test_sigqueue() {
2377        spawn_kernel_and_run(async |locked, current_task| {
2378            let current_uid = current_task.current_creds().uid;
2379            let current_pid = current_task.get_pid();
2380
2381            const TEST_VALUE: u64 = 101;
2382
2383            // Add the padding int for arch64
2384            const ARCH64_SI_HEADER_SIZE: usize = SI_HEADER_SIZE + 4;
2385            // Taken from gVisor of SignalInfo in  //pkg/abi/linux/signal.go
2386            const PID_DATA_OFFSET: usize = ARCH64_SI_HEADER_SIZE;
2387            const UID_DATA_OFFSET: usize = ARCH64_SI_HEADER_SIZE + 4;
2388            const VALUE_DATA_OFFSET: usize = ARCH64_SI_HEADER_SIZE + 8;
2389
2390            let mut data = vec![0u8; SI_MAX_SIZE_AS_USIZE];
2391            let header = SignalInfoHeader {
2392                signo: SIGIO.number(),
2393                code: SI_QUEUE,
2394                ..SignalInfoHeader::default()
2395            };
2396            let _ = header.write_to(&mut data[..SI_HEADER_SIZE]);
2397            data[PID_DATA_OFFSET..PID_DATA_OFFSET + 4].copy_from_slice(&current_pid.to_ne_bytes());
2398            data[UID_DATA_OFFSET..UID_DATA_OFFSET + 4].copy_from_slice(&current_uid.to_ne_bytes());
2399            data[VALUE_DATA_OFFSET..VALUE_DATA_OFFSET + 8]
2400                .copy_from_slice(&TEST_VALUE.to_ne_bytes());
2401
2402            let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
2403            current_task.write_memory(addr, &data).unwrap();
2404            let second_current = create_task(locked, current_task.kernel(), "second task");
2405            let second_pid = second_current.get_pid();
2406            let second_tid = second_current.get_tid();
2407            assert_eq!(second_current.read().queued_signal_count(SIGIO), 0);
2408
2409            assert_eq!(
2410                sys_rt_tgsigqueueinfo(
2411                    locked,
2412                    &current_task,
2413                    second_pid,
2414                    second_tid,
2415                    UncheckedSignal::from(SIGIO),
2416                    addr
2417                ),
2418                Ok(())
2419            );
2420            assert_eq!(second_current.read().queued_signal_count(SIGIO), 1);
2421
2422            let signal = SignalInfo::with_detail(
2423                SIGIO,
2424                SI_QUEUE,
2425                SignalDetail::Kill {
2426                    pid: current_task.thread_group().leader,
2427                    uid: current_task.current_creds().uid,
2428                },
2429            );
2430            let queued_signal = second_current.write().take_specific_signal(signal);
2431            if let Some(sig) = queued_signal {
2432                assert_eq!(sig.signal, SIGIO);
2433                assert_eq!(sig.errno, 0);
2434                assert_eq!(sig.code, SI_QUEUE);
2435                if let SignalDetail::Raw { data } = sig.detail {
2436                    // offsets into the raw portion of the signal info
2437                    let offset_pid = PID_DATA_OFFSET - SI_HEADER_SIZE;
2438                    let offset_uid = UID_DATA_OFFSET - SI_HEADER_SIZE;
2439                    let offset_value = VALUE_DATA_OFFSET - SI_HEADER_SIZE;
2440                    let pid =
2441                        pid_t::from_ne_bytes(data[offset_pid..offset_pid + 4].try_into().unwrap());
2442                    let uid =
2443                        uid_t::from_ne_bytes(data[offset_uid..offset_uid + 4].try_into().unwrap());
2444                    let value = u64::from_ne_bytes(
2445                        data[offset_value..offset_value + 8].try_into().unwrap(),
2446                    );
2447                    assert_eq!(pid, current_pid);
2448                    assert_eq!(uid, current_uid);
2449                    assert_eq!(value, TEST_VALUE);
2450                } else {
2451                    panic!("incorrect signal detail");
2452                }
2453            } else {
2454                panic!("expected a queued signal");
2455            }
2456        })
2457        .await;
2458    }
2459
2460    #[::fuchsia::test]
2461    async fn test_signalfd_filters_signals() {
2462        spawn_kernel_and_run(async |locked, current_task| {
2463            let memory_for_masks =
2464                map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
2465
2466            // Create a signalfd for SIGTERM and SIGINT.
2467            let term_int_mask = SigSet::from(SIGTERM) | SigSet::from(SIGINT);
2468            let term_int_mask_addr = UserRef::<SigSet>::new(memory_for_masks);
2469            current_task
2470                .write_object(term_int_mask_addr, &term_int_mask)
2471                .expect("failed to write mask");
2472            let sfd_term_int = sys_signalfd4(
2473                locked,
2474                &current_task,
2475                FdNumber::from_raw(-1),
2476                term_int_mask_addr,
2477                std::mem::size_of::<SigSet>(),
2478                0,
2479            )
2480            .expect("failed to create SIGTERM/SIGINT signalfd");
2481
2482            // Create a signalfd for SIGCHLD.
2483            let sigchld_mask = SigSet::from(SIGCHLD);
2484            let sigchld_mask_addr =
2485                UserRef::<SigSet>::new((memory_for_masks + std::mem::size_of::<SigSet>()).unwrap());
2486            current_task
2487                .write_object(sigchld_mask_addr, &sigchld_mask)
2488                .expect("failed to write mask");
2489            let sfd_chld = sys_signalfd4(
2490                locked,
2491                &current_task,
2492                FdNumber::from_raw(-1),
2493                sigchld_mask_addr,
2494                std::mem::size_of::<SigSet>(),
2495                0,
2496            )
2497            .expect("failed to create SIGCHLD signalfd");
2498
2499            // Create and exit a child process, which should generate a SIGCHLD.
2500            let child = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2501            child.thread_group().exit(locked, ExitStatus::Exit(1), None);
2502            std::mem::drop(child);
2503
2504            // Check which signalfds are readable.
2505            let sfd_term_int_file = current_task
2506                .live()
2507                .files
2508                .get(sfd_term_int)
2509                .expect("failed to get sfd_term_int file");
2510            let sfd_chld_file =
2511                current_task.get_file(sfd_chld).expect("failed to get sfd_chld file");
2512
2513            let term_int_events = sfd_term_int_file
2514                .query_events(locked, &current_task)
2515                .expect("failed to query sfd_term_int events");
2516            let chld_events = sfd_chld_file
2517                .query_events(locked, &current_task)
2518                .expect("failed to query sfd_chld events");
2519
2520            assert!(!term_int_events.contains(FdEvents::POLLIN));
2521            assert!(chld_events.contains(FdEvents::POLLIN));
2522        })
2523        .await;
2524    }
2525
2526    #[::fuchsia::test]
2527    async fn test_signalfd_filters_signals_async() {
2528        spawn_kernel_and_run(async |locked, current_task| {
2529            let memory_for_masks =
2530                map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
2531
2532            // Create a signalfd for SIGTERM and SIGINT.
2533            let term_int_mask = SigSet::from(SIGTERM) | SigSet::from(SIGINT);
2534            let term_int_mask_addr = UserRef::<SigSet>::new(memory_for_masks);
2535            current_task
2536                .write_object(term_int_mask_addr, &term_int_mask)
2537                .expect("failed to write mask");
2538            let sfd_term_int = sys_signalfd4(
2539                locked,
2540                &current_task,
2541                FdNumber::from_raw(-1),
2542                term_int_mask_addr,
2543                std::mem::size_of::<SigSet>(),
2544                0,
2545            )
2546            .expect("failed to create SIGTERM/SIGINT signalfd");
2547
2548            // Create a signalfd for SIGCHLD.
2549            let sigchld_mask = SigSet::from(SIGCHLD);
2550            let sigchld_mask_addr =
2551                UserRef::<SigSet>::new((memory_for_masks + std::mem::size_of::<SigSet>()).unwrap());
2552            current_task
2553                .write_object(sigchld_mask_addr, &sigchld_mask)
2554                .expect("failed to write mask");
2555            let sfd_chld = sys_signalfd4(
2556                locked,
2557                &current_task,
2558                FdNumber::from_raw(-1),
2559                sigchld_mask_addr,
2560                std::mem::size_of::<SigSet>(),
2561                0,
2562            )
2563            .expect("failed to create SIGCHLD signalfd");
2564
2565            // Set up the async wait.
2566            let waiter = Waiter::new();
2567            let ready_items = Arc::new(Mutex::new(VecDeque::new()));
2568
2569            let sfd_term_int_file = current_task
2570                .live()
2571                .files
2572                .get(sfd_term_int)
2573                .expect("failed to get sfd_term_int file");
2574            let sfd_chld_file =
2575                current_task.get_file(sfd_chld).expect("failed to get sfd_chld file");
2576
2577            sfd_term_int_file
2578                .wait_async(
2579                    locked,
2580                    &current_task,
2581                    &waiter,
2582                    FdEvents::POLLIN,
2583                    EventHandler::Enqueue {
2584                        key: sfd_term_int.into(),
2585                        queue: ready_items.clone(),
2586                        sought_events: FdEvents::POLLIN,
2587                    },
2588                )
2589                .expect("failed to wait on sfd_term_int");
2590
2591            sfd_chld_file
2592                .wait_async(
2593                    locked,
2594                    &current_task,
2595                    &waiter,
2596                    FdEvents::POLLIN,
2597                    EventHandler::Enqueue {
2598                        key: sfd_chld.into(),
2599                        queue: ready_items.clone(),
2600                        sought_events: FdEvents::POLLIN,
2601                    },
2602                )
2603                .expect("failed to wait on sfd_chld");
2604
2605            // Block SIGCHLD so it can be received by the signalfd.
2606            let sigchld_mask_ref = UserRef::<SigSet>::new(memory_for_masks);
2607            current_task
2608                .write_object(sigchld_mask_ref, &sigchld_mask)
2609                .expect("failed to write mask");
2610            sys_rt_sigprocmask(
2611                locked,
2612                &current_task,
2613                SIG_BLOCK,
2614                sigchld_mask_ref,
2615                UserRef::default(),
2616                std::mem::size_of::<SigSet>(),
2617            )
2618            .expect("failed to block SIGCHLD");
2619
2620            // Create and exit a child process, which should generate a SIGCHLD.
2621            let child = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2622            child.thread_group().exit(locked, ExitStatus::Exit(1), None);
2623            std::mem::drop(child);
2624
2625            // Wait for the signal to be processed.
2626            waiter.wait(locked, &current_task).expect("failed to wait");
2627
2628            // Check that only the correct signalfd was woken up.
2629            let ready_items = ready_items.lock();
2630            assert_eq!(ready_items.len(), 1);
2631            assert_eq!(ready_items[0].key, sfd_chld.into());
2632        })
2633        .await;
2634    }
2635}