Skip to main content

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