starnix_core/signals/
signal_handling.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
5use crate::arch::signal_handling::{
6    RED_ZONE_SIZE, SIG_STACK_SIZE, SignalStackFrame, align_stack_pointer, restore_registers,
7};
8use crate::mm::{MemoryAccessor, MemoryAccessorExt};
9use crate::ptrace::StopState;
10use crate::signals::{KernelSignal, KernelSignalInfo, SignalDetail, SignalInfo, SignalState};
11use crate::task::{CurrentTask, ExitStatus, Task, TaskFlags, TaskWriteGuard, ThreadState, Waiter};
12use extended_pstate::ExtendedPstateState;
13use starnix_logging::{log_info, log_trace, log_warn};
14use starnix_registers::{RegisterState, RegisterStorageEnum};
15use starnix_sync::{LockBefore, Locked, ThreadGroupLimits, Unlocked};
16use starnix_syscalls::SyscallResult;
17use starnix_types::arch::ArchWidth;
18use starnix_uapi::errors::{EINTR, ERESTART_RESTARTBLOCK, Errno};
19use starnix_uapi::resource_limits::Resource;
20use starnix_uapi::signals::{
21    SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGIO, SIGKILL,
22    SIGPIPE, SIGPROF, SIGPWR, SIGQUIT, SIGSEGV, SIGSTKFLT, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP,
23    SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ,
24    SigSet, sigaltstack_contains_pointer,
25};
26use starnix_uapi::user_address::UserAddress;
27use starnix_uapi::{
28    SA_NODEFER, SA_ONSTACK, SA_RESETHAND, SA_SIGINFO, SIG_DFL, SIG_IGN, errno, error, sigaction_t,
29};
30
31/// Indicates where in the signal queue a signal should go.  Signals
32/// can jump the queue when being injected by tools like ptrace.
33#[derive(PartialEq)]
34enum SignalPriority {
35    First,
36    Last,
37}
38
39// `send_signal*()` calls below may fail only for real-time signals (with EAGAIN). They are
40// expected to succeed for all other signals.
41pub fn send_signal_first<L>(
42    locked: &mut Locked<L>,
43    task: &Task,
44    task_state: TaskWriteGuard<'_>,
45    siginfo: SignalInfo,
46) where
47    L: LockBefore<ThreadGroupLimits>,
48{
49    send_signal_prio(locked, task, task_state, siginfo.into(), SignalPriority::First, true)
50        .expect("send_signal(SignalPriority::First) is not expected to fail")
51}
52
53// Sends `signal` to `task`. The signal must be a standard (i.e. not real-time) signal.
54pub fn send_standard_signal<L>(locked: &mut Locked<L>, task: &Task, siginfo: SignalInfo)
55where
56    L: LockBefore<ThreadGroupLimits>,
57{
58    debug_assert!(!siginfo.signal.is_real_time());
59    let state = task.write();
60    send_signal_prio(locked, task, state, siginfo.into(), SignalPriority::Last, false)
61        .expect("send_signal(SignalPriority::Last) is not expected to fail for standard signals.")
62}
63
64pub fn send_signal<L>(locked: &mut Locked<L>, task: &Task, siginfo: SignalInfo) -> Result<(), Errno>
65where
66    L: LockBefore<ThreadGroupLimits>,
67{
68    let state = task.write();
69    send_signal_prio(locked, task, state, siginfo.into(), SignalPriority::Last, false)
70}
71
72pub fn send_freeze_signal<L>(
73    locked: &mut Locked<L>,
74    task: &Task,
75    waiter: Waiter,
76) -> Result<(), Errno>
77where
78    L: LockBefore<ThreadGroupLimits>,
79{
80    let state = task.write();
81    send_signal_prio(
82        locked,
83        task,
84        state,
85        KernelSignalInfo::Freeze(waiter),
86        SignalPriority::First,
87        true,
88    )
89}
90
91fn send_signal_prio<L>(
92    locked: &mut Locked<L>,
93    task: &Task,
94    mut task_state: TaskWriteGuard<'_>,
95    kernel_siginfo: KernelSignalInfo,
96    prio: SignalPriority,
97    force_wake: bool,
98) -> Result<(), Errno>
99where
100    L: LockBefore<ThreadGroupLimits>,
101{
102    let (siginfo, signal, is_masked, was_masked, is_real_time, sigaction, action) =
103        match kernel_siginfo {
104            KernelSignalInfo::User(ref user_siginfo) => {
105                let signal = user_siginfo.signal;
106                let is_masked = task_state.is_signal_masked(signal);
107                let was_masked = task_state.is_signal_masked_by_saved_mask(signal);
108                let sigaction = task.get_signal_action(signal);
109                let action = action_for_signal(&user_siginfo, sigaction);
110                (
111                    Some(user_siginfo.clone()),
112                    Some(signal),
113                    is_masked,
114                    was_masked,
115                    signal.is_real_time(),
116                    Some(sigaction),
117                    Some(action),
118                )
119            }
120            KernelSignalInfo::Freeze(_) => (None, None, false, false, false, None, None),
121        };
122
123    if is_real_time && prio != SignalPriority::First {
124        if task_state.pending_signal_count()
125            >= task.thread_group().get_rlimit(locked, Resource::SIGPENDING) as usize
126        {
127            return error!(EAGAIN);
128        }
129    }
130
131    // If the signal is ignored then it doesn't need to be queued, except the following 2 cases:
132    //  1. The signal is blocked by the current or the original mask. The signal may be unmasked
133    //     later, see `SigtimedwaitTest.IgnoredUnmaskedSignal` gvisor test.
134    //  2. The task is ptraced. In this case we want to queue the signal for signal-delivery-stop.
135    let is_queued = action.is_none()
136        || action != Some(DeliveryAction::Ignore)
137        || is_masked
138        || was_masked
139        || task_state.is_ptraced();
140    if is_queued {
141        match kernel_siginfo {
142            KernelSignalInfo::User(ref siginfo) => {
143                if prio == SignalPriority::First {
144                    task_state.enqueue_signal_front(siginfo.clone());
145                } else {
146                    task_state.enqueue_signal(siginfo.clone());
147                }
148                task_state.set_flags(TaskFlags::SIGNALS_AVAILABLE, true);
149            }
150            KernelSignalInfo::Freeze(waiter) => {
151                task_state.enqueue_kernel_signal(KernelSignal::Freeze(waiter))
152            }
153        }
154    }
155
156    if action == Some(DeliveryAction::CoreDump) && !task_state.is_ptraced() {
157        // If the signal is a core dump, request a backtrace to get information about the sender.
158        // TODO(https://fxbug.dev/356732164) collect a backtrace ourselves.
159        log_info!(
160            "Sending a core dump signal {signal:?} to task {}. Take a backtrace of the sender for debugging",
161            task.tid
162        );
163        debug::backtrace_request_current_thread();
164    }
165
166    drop(task_state);
167    if is_queued
168        && !is_masked
169        && action.map_or_else(|| true, |action| action.must_interrupt(sigaction))
170    {
171        // Wake the task. Note that any potential signal handler will be executed before
172        // the task returns from the suspend (from the perspective of user space).
173        task.interrupt();
174    }
175
176    // Unstop the process for SIGCONT. Also unstop for SIGKILL, the only signal that can interrupt
177    // a stopped process.
178    if signal == Some(SIGKILL) {
179        task.write().thaw();
180        task.thread_group().set_stopped(StopState::ForceWaking, siginfo, false);
181        task.write().set_stopped(StopState::ForceWaking, None, None, None);
182    } else if signal == Some(SIGCONT) || force_wake {
183        task.thread_group().set_stopped(StopState::Waking, siginfo, false);
184        task.write().set_stopped(StopState::Waking, None, None, None);
185    }
186
187    Ok(())
188}
189
190/// Represents the action to take when signal is delivered.
191///
192/// See https://man7.org/linux/man-pages/man7/signal.7.html.
193#[derive(Debug, PartialEq)]
194pub enum DeliveryAction {
195    Ignore,
196    CallHandler,
197    Terminate,
198    CoreDump,
199    Stop,
200    Continue,
201}
202
203impl DeliveryAction {
204    /// Returns whether the target task must be interrupted to execute the action.
205    ///
206    /// The task will not be interrupted if the signal is the action is the Continue action, or if
207    /// the action is Ignore and the user specifically requested to ignore the signal.
208    pub fn must_interrupt(&self, sigaction: Option<sigaction_t>) -> bool {
209        match *self {
210            Self::Continue => false,
211            Self::Ignore => sigaction.map_or(false, |sa| sa.sa_handler == SIG_IGN),
212            _ => true,
213        }
214    }
215}
216
217pub fn action_for_signal(siginfo: &SignalInfo, sigaction: sigaction_t) -> DeliveryAction {
218    let handler = if siginfo.force && sigaction.sa_handler == SIG_IGN {
219        SIG_DFL
220    } else {
221        sigaction.sa_handler
222    };
223    match handler {
224        SIG_DFL => match siginfo.signal {
225            SIGCHLD | SIGURG | SIGWINCH => DeliveryAction::Ignore,
226            sig if sig.is_real_time() => DeliveryAction::Ignore,
227            SIGHUP | SIGINT | SIGKILL | SIGPIPE | SIGALRM | SIGTERM | SIGUSR1 | SIGUSR2
228            | SIGPROF | SIGVTALRM | SIGSTKFLT | SIGIO | SIGPWR => DeliveryAction::Terminate,
229            SIGQUIT | SIGILL | SIGABRT | SIGFPE | SIGSEGV | SIGBUS | SIGSYS | SIGTRAP | SIGXCPU
230            | SIGXFSZ => DeliveryAction::CoreDump,
231            SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => DeliveryAction::Stop,
232            SIGCONT => DeliveryAction::Continue,
233            _ => panic!("Unknown signal"),
234        },
235        SIG_IGN => DeliveryAction::Ignore,
236        _ => DeliveryAction::CallHandler,
237    }
238}
239
240/// Dequeues and handles a pending signal for `current_task`.
241pub fn dequeue_signal(locked: &mut Locked<Unlocked>, current_task: &mut CurrentTask) {
242    let &mut CurrentTask { ref task, ref mut thread_state, .. } = current_task;
243    if !task.should_check_for_pending_signals() {
244        return;
245    }
246
247    let mut task_state = task.write();
248    // This code is occasionally executed as the task is stopping. Stopping /
249    // stopped threads should not get signals.
250    if task.load_stopped().is_stopping_or_stopped() {
251        return;
252    }
253
254    // If there is a kernel signal needs to handle, deliver the signal right away.
255    let kernel_signal = task_state.take_kernel_signal();
256    let siginfo = if kernel_signal.is_some() { None } else { task_state.take_any_signal() };
257    prepare_to_restart_syscall(
258        thread_state,
259        siginfo.as_ref().map(|siginfo| task.thread_group().signal_actions.get(siginfo.signal)),
260    );
261
262    if let Some(ref siginfo) = siginfo {
263        if task_state.ptrace_on_signal_consume() && siginfo.signal != SIGKILL {
264            // Indicate we will be stopping for ptrace at the next opportunity.
265            // Whether you actually deliver the signal is now up to ptrace, so
266            // we can return.
267            task_state.set_stopped(
268                StopState::SignalDeliveryStopping,
269                Some(siginfo.clone()),
270                None,
271                None,
272            );
273            return;
274        }
275    }
276
277    // A syscall may have been waiting with a temporary mask which should be used to dequeue the
278    // signal, but after the signal has been dequeued the old mask should be restored.
279    task_state.restore_signal_mask();
280    {
281        let (clear, set) = if task_state.pending_signal_count() == 0 {
282            (TaskFlags::SIGNALS_AVAILABLE, TaskFlags::empty())
283        } else {
284            (TaskFlags::empty(), TaskFlags::SIGNALS_AVAILABLE)
285        };
286        task_state.update_flags(clear | TaskFlags::TEMPORARY_SIGNAL_MASK, set);
287    };
288
289    if let Some(kernel_signal) = kernel_signal {
290        let KernelSignal::Freeze(waiter) = kernel_signal;
291        drop(task_state);
292
293        waiter.freeze(locked, current_task);
294    } else if let Some(ref siginfo) = siginfo {
295        if let SignalDetail::Timer { timer } = &siginfo.detail {
296            timer.on_signal_delivered();
297        }
298        if let Some(status) = deliver_signal(
299            &task,
300            current_task.thread_state.arch_width,
301            task_state,
302            siginfo.clone(),
303            &mut current_task.thread_state.registers,
304            &current_task.thread_state.extended_pstate,
305            None,
306        ) {
307            current_task.thread_group_exit(locked, status);
308        }
309    };
310}
311
312pub fn deliver_signal(
313    task: &Task,
314    arch_width: ArchWidth,
315    mut task_state: TaskWriteGuard<'_>,
316    mut siginfo: SignalInfo,
317    registers: &mut RegisterState<RegisterStorageEnum>,
318    extended_pstate: &ExtendedPstateState,
319    restricted_exception: Option<zx::ExceptionReport>,
320) -> Option<ExitStatus> {
321    loop {
322        let sigaction = task.thread_group().signal_actions.get(siginfo.signal);
323        let action = action_for_signal(&siginfo, sigaction);
324        log_trace!("handling signal {:?} with action {:?}", siginfo, action);
325        match action {
326            DeliveryAction::Ignore => {}
327            DeliveryAction::CallHandler => {
328                let sigaction = task.thread_group().signal_actions.get(siginfo.signal);
329                let signal = siginfo.signal;
330                match dispatch_signal_handler(
331                    task,
332                    arch_width,
333                    registers,
334                    extended_pstate,
335                    task_state.signals_mut(),
336                    siginfo,
337                    sigaction,
338                ) {
339                    Ok(_) => {
340                        // Reset the signal handler if `SA_RESETHAND` was set.
341                        if sigaction.sa_flags & (SA_RESETHAND as u64) != 0 {
342                            let new_sigaction = sigaction_t {
343                                sa_handler: SIG_DFL,
344                                sa_flags: sigaction.sa_flags & !(SA_RESETHAND as u64),
345                                ..sigaction
346                            };
347                            task.thread_group().signal_actions.set(signal, new_sigaction);
348                        }
349                    }
350                    Err(err) => {
351                        log_warn!("failed to deliver signal {:?}: {:?}", signal, err);
352
353                        siginfo = SignalInfo::default(SIGSEGV);
354                        // The behavior that we want is:
355                        //  1. If we failed to send a SIGSEGV, or SIGSEGV is masked, or SIGSEGV is
356                        //  ignored, we reset the signal disposition and unmask SIGSEGV.
357                        //  2. Send a SIGSEGV to the program, with the (possibly) updated signal
358                        //  disposition and mask.
359                        let sigaction = task.thread_group().signal_actions.get(siginfo.signal);
360                        let action = action_for_signal(&siginfo, sigaction);
361                        let masked_signals = task_state.signal_mask();
362                        if signal == SIGSEGV
363                            || masked_signals.has_signal(SIGSEGV)
364                            || action == DeliveryAction::Ignore
365                        {
366                            task_state.set_signal_mask(masked_signals & !SigSet::from(SIGSEGV));
367                            task.thread_group().signal_actions.set(SIGSEGV, sigaction_t::default());
368                        }
369
370                        // Try to deliver the SIGSEGV.
371                        // We already checked whether we needed to unmask or reset the signal
372                        // disposition.
373                        // This could not lead to an infinite loop, because if we had a SIGSEGV
374                        // handler, and we failed to send a SIGSEGV, we remove the handler and resend
375                        // the SIGSEGV.
376                        continue;
377                    }
378                }
379            }
380            DeliveryAction::Terminate => {
381                // Release the signals lock. [`ThreadGroup::exit`] sends signals to threads which
382                // will include this one and cause a deadlock re-acquiring the signals lock.
383                drop(task_state);
384                return Some(ExitStatus::Kill(siginfo));
385            }
386            DeliveryAction::CoreDump => {
387                task_state.set_flags(TaskFlags::DUMP_ON_EXIT, true);
388                drop(task_state);
389                if let Some(exception) = restricted_exception {
390                    log_info!(
391                        registers:?=registers,
392                        exception:?=exception;
393                        "Restricted mode exception caused core dump",
394                    );
395                }
396                return Some(ExitStatus::CoreDump(siginfo));
397            }
398            DeliveryAction::Stop => {
399                drop(task_state);
400                task.thread_group().set_stopped(StopState::GroupStopping, Some(siginfo), false);
401            }
402            DeliveryAction::Continue => {
403                // Nothing to do. Effect already happened when the signal was raised.
404            }
405        };
406        break;
407    }
408    None
409}
410
411/// Prepares `current` state to execute the signal handler stored in `action`.
412///
413/// This function stores the state required to restore after the signal handler on the stack.
414fn dispatch_signal_handler(
415    task: &Task,
416    arch_width: ArchWidth,
417    registers: &mut RegisterState<RegisterStorageEnum>,
418    extended_pstate: &ExtendedPstateState,
419    signal_state: &mut SignalState,
420    siginfo: SignalInfo,
421    action: sigaction_t,
422) -> Result<(), Errno> {
423    let main_stack = registers.stack_pointer_register().checked_sub(RED_ZONE_SIZE);
424    let stack_bottom = if (action.sa_flags & SA_ONSTACK as u64) != 0 {
425        match signal_state.alt_stack {
426            Some(sigaltstack) => {
427                match main_stack {
428                    // Only install the sigaltstack if the stack pointer is not already in it.
429                    Some(sp) if sigaltstack_contains_pointer(&sigaltstack, sp) => main_stack,
430                    _ => {
431                        // Since the stack grows down, the size is added to the ss_sp when
432                        // calculating the "bottom" of the stack.
433                        // Use the main stack if sigaltstack overflows.
434                        sigaltstack
435                            .ss_sp
436                            .addr
437                            .checked_add(sigaltstack.ss_size)
438                            .map(|sp| sp as u64)
439                            .or(main_stack)
440                    }
441                }
442            }
443            None => main_stack,
444        }
445    } else {
446        main_stack
447    }
448    .ok_or_else(|| errno!(EINVAL))?;
449
450    let stack_pointer =
451        align_stack_pointer(stack_bottom.checked_sub(SIG_STACK_SIZE as u64).ok_or_else(|| {
452            errno!(
453                EINVAL,
454                format!(
455                    "Subtracting SIG_STACK_SIZE ({}) from stack bottom ({}) overflowed",
456                    SIG_STACK_SIZE, stack_bottom
457                )
458            )
459        })?);
460
461    // Check that if the stack pointer is inside altstack, the entire signal stack is inside
462    // altstack.
463    if let Some(alt_stack) = signal_state.alt_stack {
464        if sigaltstack_contains_pointer(&alt_stack, stack_pointer)
465            != sigaltstack_contains_pointer(&alt_stack, stack_bottom)
466        {
467            return error!(EINVAL);
468        }
469    }
470
471    let signal_stack_frame = SignalStackFrame::new(
472        task,
473        arch_width,
474        registers,
475        extended_pstate,
476        signal_state,
477        &siginfo,
478        action,
479        UserAddress::from(stack_pointer),
480    )?;
481
482    // Write the signal stack frame at the updated stack pointer.
483    task.write_memory(UserAddress::from(stack_pointer), signal_stack_frame.as_bytes())?;
484
485    let mut mask: SigSet = action.sa_mask.into();
486    if action.sa_flags & (SA_NODEFER as u64) == 0 {
487        mask = mask | siginfo.signal.into();
488    }
489
490    // Preserve the existing mask when handling a nested signal
491    signal_state.set_mask(mask | signal_state.mask());
492
493    registers.set_stack_pointer_register(stack_pointer);
494    registers.set_arg0_register(siginfo.signal.number() as u64);
495    if (action.sa_flags & SA_SIGINFO as u64) != 0 {
496        registers.set_arg1_register(
497            stack_pointer + memoffset::offset_of!(SignalStackFrame, siginfo_bytes) as u64,
498        );
499        registers.set_arg2_register(
500            stack_pointer + memoffset::offset_of!(SignalStackFrame, context) as u64,
501        );
502    }
503    registers.set_instruction_pointer_register(action.sa_handler.addr);
504    registers.reset_flags(); // TODO(https://fxbug.dev/413070731): Verify and update the logic in resetting the flags.
505
506    Ok(())
507}
508
509pub fn restore_from_signal_handler(current_task: &mut CurrentTask) -> Result<(), Errno> {
510    // Read the signal stack frame from memory.
511    let signal_frame_address = UserAddress::from(align_stack_pointer(
512        current_task.thread_state.registers.stack_pointer_register(),
513    ));
514    let signal_stack_bytes =
515        current_task.read_memory_to_array::<SIG_STACK_SIZE>(signal_frame_address)?;
516
517    // Grab the registers state from the stack frame.
518    let signal_stack_frame = SignalStackFrame::from_bytes(signal_stack_bytes);
519    restore_registers(current_task, &signal_stack_frame, signal_frame_address)?;
520
521    // Restore the stored signal mask.
522    current_task.write().set_signal_mask(signal_stack_frame.get_signal_mask());
523
524    Ok(())
525}
526
527/// Maybe adjust a task's registers to restart a syscall once the task switches back to userspace,
528/// based on whether the task previously had a syscall return with an error code indicating that a
529/// restart was required.
530pub fn prepare_to_restart_syscall(
531    thread_state: &mut ThreadState<RegisterStorageEnum>,
532    sigaction: Option<sigaction_t>,
533) {
534    // Taking the value ensures each syscall is only considered for restart once.
535    let Some(err) = thread_state.restart_code.take() else {
536        // Don't interact with register state at all unless other kernel code indicates that we may
537        // need to restart.
538        return;
539    };
540
541    if err.should_restart(sigaction) {
542        // This error code is returned for system calls that need restart_syscall() to adjust time
543        // related arguments when the syscall is restarted. Other syscall restarts can be dispatched
544        // directly to the original syscall implementation.
545        if err == ERESTART_RESTARTBLOCK {
546            thread_state.registers.prepare_for_custom_restart();
547        } else {
548            thread_state.registers.restore_original_return_register();
549        }
550
551        // TODO(https://fxbug.dev/388051291) figure out whether Linux relies on registers here
552        thread_state.registers.rewind_syscall_instruction();
553    } else {
554        thread_state.registers.set_return_register(EINTR.return_value());
555    }
556}
557
558pub fn sys_restart_syscall(
559    locked: &mut Locked<Unlocked>,
560    current_task: &mut CurrentTask,
561) -> Result<SyscallResult, Errno> {
562    match current_task.thread_state.syscall_restart_func.take() {
563        Some(f) => f(locked, current_task),
564        None => {
565            // This may indicate a bug where a syscall returns ERESTART_RESTARTBLOCK without
566            // setting a restart func. But it can also be triggered by userspace, e.g. by directly
567            // calling restart_syscall or injecting an ERESTART_RESTARTBLOCK error through ptrace.
568            log_warn!("restart_syscall called, but nothing to restart");
569            error!(EINTR)
570        }
571    }
572}
573
574/// Test utilities for signal handling.
575#[cfg(test)]
576pub(crate) mod testing {
577    use super::*;
578    use crate::testing::AutoReleasableTask;
579    use std::ops::DerefMut as _;
580
581    pub(crate) fn dequeue_signal_for_test(
582        locked: &mut Locked<Unlocked>,
583        current_task: &mut AutoReleasableTask,
584    ) {
585        dequeue_signal(locked, current_task.deref_mut());
586    }
587}