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 will not be interrupted if the signal is the action is the Continue action, or if
167    /// the action is Ignore and the user specifically requested to ignore the signal.
168    pub fn must_interrupt(&self, sigaction: Option<sigaction_t>) -> bool {
169        match *self {
170            Self::Continue => false,
171            Self::Ignore => sigaction.map_or(false, |sa| sa.sa_handler == SIG_IGN),
172            _ => true,
173        }
174    }
175}
176
177pub fn action_for_signal(siginfo: &SignalInfo, sigaction: sigaction_t) -> DeliveryAction {
178    let handler = if siginfo.force && sigaction.sa_handler == SIG_IGN {
179        SIG_DFL
180    } else {
181        sigaction.sa_handler
182    };
183    match handler {
184        SIG_DFL => match siginfo.signal {
185            SIGCHLD | SIGURG | SIGWINCH => DeliveryAction::Ignore,
186            sig if sig.is_real_time() => DeliveryAction::Ignore,
187            SIGHUP | SIGINT | SIGKILL | SIGPIPE | SIGALRM | SIGTERM | SIGUSR1 | SIGUSR2
188            | SIGPROF | SIGVTALRM | SIGSTKFLT | SIGIO | SIGPWR => DeliveryAction::Terminate,
189            SIGQUIT | SIGILL | SIGABRT | SIGFPE | SIGSEGV | SIGBUS | SIGSYS | SIGTRAP | SIGXCPU
190            | SIGXFSZ => DeliveryAction::CoreDump,
191            SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => DeliveryAction::Stop,
192            SIGCONT => DeliveryAction::Continue,
193            _ => panic!("Unknown signal"),
194        },
195        SIG_IGN => DeliveryAction::Ignore,
196        _ => DeliveryAction::CallHandler,
197    }
198}
199
200/// Dequeues and handles a pending signal for `current_task`.
201pub fn dequeue_signal(current_task: &mut CurrentTask) {
202    let &mut CurrentTask { ref task, ref mut thread_state, .. } = current_task;
203    if !task.should_check_for_pending_signals() {
204        return;
205    }
206
207    let mut task_state = task.write();
208    // This code is occasionally executed as the task is stopping. Stopping /
209    // stopped threads should not get signals.
210    if task.load_stopped().is_stopping_or_stopped() {
211        return;
212    }
213
214    // If there is a kernel signal needs to handle, deliver the signal right away.
215    let kernel_signal = task_state.take_kernel_signal();
216    let siginfo = if kernel_signal.is_some() { None } else { task_state.take_any_signal() };
217    prepare_to_restart_syscall(
218        thread_state,
219        siginfo.as_ref().map(|siginfo| task.thread_group().signal_actions.get(siginfo.signal)),
220    );
221
222    if let Some(ref siginfo) = siginfo {
223        if task_state.ptrace_on_signal_consume() && siginfo.signal != SIGKILL {
224            // Indicate we will be stopping for ptrace at the next opportunity.
225            // Whether you actually deliver the signal is now up to ptrace, so
226            // we can return.
227            task_state.set_stopped(
228                StopState::SignalDeliveryStopping,
229                Some(siginfo.clone()),
230                None,
231                None,
232            );
233            return;
234        }
235    }
236
237    // A syscall may have been waiting with a temporary mask which should be used to dequeue the
238    // signal, but after the signal has been dequeued the old mask should be restored.
239    task_state.restore_signal_mask();
240    {
241        let (clear, set) = if task_state.pending_signal_count() == 0 {
242            (TaskFlags::SIGNALS_AVAILABLE, TaskFlags::empty())
243        } else {
244            (TaskFlags::empty(), TaskFlags::SIGNALS_AVAILABLE)
245        };
246        task_state.update_flags(clear | TaskFlags::TEMPORARY_SIGNAL_MASK, set);
247    };
248
249    if let Some(kernel_signal) = kernel_signal {
250        let KernelSignal::Freeze(waiter) = kernel_signal;
251        drop(task_state);
252
253        waiter.freeze(current_task);
254    } else if let Some(ref siginfo) = siginfo {
255        if let SignalDetail::Timer { timer } = &siginfo.detail {
256            timer.on_signal_delivered();
257        }
258        if let Some(status) = deliver_signal(
259            &task,
260            current_task.thread_state.arch_width(),
261            task_state,
262            siginfo.clone(),
263            &mut current_task.thread_state.registers,
264            &current_task.thread_state.extended_pstate,
265            None,
266        ) {
267            current_task.kill_thread_group(status);
268        }
269    };
270}
271
272pub fn deliver_signal(
273    task: &Task,
274    arch_width: ArchWidth,
275    mut task_state: TaskWriteGuard<'_>,
276    mut siginfo: SignalInfo,
277    registers: &mut RegisterState<RegisterStorageEnum>,
278    extended_pstate: &ArchExtendedPstateStorage,
279    restricted_exception: Option<zx::ExceptionReport>,
280) -> Option<ExitStatus> {
281    loop {
282        let sigaction = task.thread_group().signal_actions.get(siginfo.signal);
283        let action = action_for_signal(&siginfo, sigaction);
284        log_trace!("handling signal {:?} with action {:?}", siginfo, action);
285        match action {
286            DeliveryAction::Ignore => {}
287            DeliveryAction::CallHandler => {
288                let sigaction = task.thread_group().signal_actions.get(siginfo.signal);
289                let signal = siginfo.signal;
290                match dispatch_signal_handler(
291                    task,
292                    arch_width,
293                    registers,
294                    extended_pstate,
295                    task_state.signals_mut(),
296                    siginfo,
297                    sigaction,
298                ) {
299                    Ok(_) => {
300                        // Reset the signal handler if `SA_RESETHAND` was set.
301                        if sigaction.sa_flags & (SA_RESETHAND as u64) != 0 {
302                            let new_sigaction = sigaction_t {
303                                sa_handler: SIG_DFL,
304                                sa_flags: sigaction.sa_flags & !(SA_RESETHAND as u64),
305                                ..sigaction
306                            };
307                            task.thread_group().signal_actions.set(signal, new_sigaction);
308                        }
309                    }
310                    Err(err) => {
311                        log_warn!("failed to deliver signal {:?}: {:?}", signal, err);
312
313                        siginfo = SignalInfo::kernel(SIGSEGV);
314                        // The behavior that we want is:
315                        //  1. If we failed to send a SIGSEGV, or SIGSEGV is masked, or SIGSEGV is
316                        //  ignored, we reset the signal disposition and unmask SIGSEGV.
317                        //  2. Send a SIGSEGV to the program, with the (possibly) updated signal
318                        //  disposition and mask.
319                        let sigaction = task.thread_group().signal_actions.get(siginfo.signal);
320                        let action = action_for_signal(&siginfo, sigaction);
321                        let masked_signals = task_state.signal_mask();
322                        if signal == SIGSEGV
323                            || masked_signals.has_signal(SIGSEGV)
324                            || action == DeliveryAction::Ignore
325                        {
326                            task_state.set_signal_mask(masked_signals & !SigSet::from(SIGSEGV));
327                            task.thread_group().signal_actions.set(SIGSEGV, sigaction_t::default());
328                        }
329
330                        // Try to deliver the SIGSEGV.
331                        // We already checked whether we needed to unmask or reset the signal
332                        // disposition.
333                        // This could not lead to an infinite loop, because if we had a SIGSEGV
334                        // handler, and we failed to send a SIGSEGV, we remove the handler and resend
335                        // the SIGSEGV.
336                        continue;
337                    }
338                }
339            }
340            DeliveryAction::Terminate => {
341                // Release the signals lock. [`ThreadGroup::exit`] sends signals to threads which
342                // will include this one and cause a deadlock re-acquiring the signals lock.
343                drop(task_state);
344                return Some(ExitStatus::Kill(siginfo));
345            }
346            DeliveryAction::CoreDump => {
347                task_state.set_flags(TaskFlags::DUMP_ON_EXIT, true);
348                drop(task_state);
349                if let Some(exception) = restricted_exception {
350                    log_info!(
351                        registers:?=registers,
352                        exception:?=exception;
353                        // LINT.IfChange(restricted_mode_core_dump_tefmo)
354                        "Restricted mode exception caused core dump",
355                        // LINT.ThenChange(//tools/testing/tefmocheck/string_in_log_check.go:restricted_mode_core_dump_tefmo)
356                    );
357                    if let SignalDetail::SigFault { addr } = siginfo.detail {
358                        if let Ok(mm) = task.mm() {
359                            mm.log_memory_map(task, UserAddress::from(addr));
360                        }
361                    }
362                }
363                return Some(ExitStatus::CoreDump(siginfo));
364            }
365            DeliveryAction::Stop => {
366                drop(task_state);
367                task.thread_group().set_stopped(StopState::GroupStopping, Some(siginfo), false);
368            }
369            DeliveryAction::Continue => {
370                // Nothing to do. Effect already happened when the signal was raised.
371            }
372        };
373        break;
374    }
375    None
376}
377
378/// Prepares `current` state to execute the signal handler stored in `action`.
379///
380/// This function stores the state required to restore after the signal handler on the stack.
381fn dispatch_signal_handler(
382    task: &Task,
383    arch_width: ArchWidth,
384    registers: &mut RegisterState<RegisterStorageEnum>,
385    extended_pstate: &ArchExtendedPstateStorage,
386    signal_state: &mut SignalState,
387    siginfo: SignalInfo,
388    action: sigaction_t,
389) -> Result<(), Errno> {
390    let main_stack = registers.stack_pointer_register().checked_sub(RED_ZONE_SIZE);
391    let stack_bottom = if (action.sa_flags & SA_ONSTACK as u64) != 0 {
392        match signal_state.alt_stack {
393            Some(sigaltstack) => {
394                match main_stack {
395                    // Only install the sigaltstack if the stack pointer is not already in it.
396                    Some(sp) if sigaltstack_contains_pointer(&sigaltstack, sp) => main_stack,
397                    _ => {
398                        // Since the stack grows down, the size is added to the ss_sp when
399                        // calculating the "bottom" of the stack.
400                        // Use the main stack if sigaltstack overflows.
401                        sigaltstack
402                            .ss_sp
403                            .addr
404                            .checked_add(sigaltstack.ss_size)
405                            .map(|sp| sp as u64)
406                            .or(main_stack)
407                    }
408                }
409            }
410            None => main_stack,
411        }
412    } else {
413        main_stack
414    }
415    .ok_or_else(|| errno!(EINVAL))?;
416
417    let stack_pointer =
418        align_stack_pointer(stack_bottom.checked_sub(SIG_STACK_SIZE as u64).ok_or_else(|| {
419            errno!(
420                EINVAL,
421                format!(
422                    "Subtracting SIG_STACK_SIZE ({}) from stack bottom ({}) overflowed",
423                    SIG_STACK_SIZE, stack_bottom
424                )
425            )
426        })?);
427
428    // Check that if the stack pointer is inside altstack, the entire signal stack is inside
429    // altstack.
430    if let Some(alt_stack) = signal_state.alt_stack {
431        if sigaltstack_contains_pointer(&alt_stack, stack_pointer)
432            != sigaltstack_contains_pointer(&alt_stack, stack_bottom)
433        {
434            return error!(EINVAL);
435        }
436    }
437
438    let signal_stack_frame = SignalStackFrame::new(
439        task,
440        arch_width,
441        registers,
442        extended_pstate,
443        signal_state,
444        &siginfo,
445        action,
446        UserAddress::from(stack_pointer),
447    )?;
448
449    // Write the signal stack frame at the updated stack pointer.
450    task.write_memory(UserAddress::from(stack_pointer), signal_stack_frame.as_bytes())?;
451
452    let mut mask: SigSet = action.sa_mask.into();
453    if action.sa_flags & (SA_NODEFER as u64) == 0 {
454        mask = mask | siginfo.signal.into();
455    }
456
457    // Preserve the existing mask when handling a nested signal
458    signal_state.set_mask(mask | signal_state.mask());
459
460    registers.set_stack_pointer_register(stack_pointer);
461    registers.set_arg0_register(siginfo.signal.number() as u64);
462    if (action.sa_flags & SA_SIGINFO as u64) != 0 {
463        registers.set_arg1_register(
464            stack_pointer + memoffset::offset_of!(SignalStackFrame, siginfo_bytes) as u64,
465        );
466        registers.set_arg2_register(
467            stack_pointer + memoffset::offset_of!(SignalStackFrame, context) as u64,
468        );
469    }
470    registers.set_instruction_pointer_register(action.sa_handler.addr);
471    registers.reset_flags(); // TODO(https://fxbug.dev/413070731): Verify and update the logic in resetting the flags.
472
473    Ok(())
474}
475
476pub fn restore_from_signal_handler(current_task: &mut CurrentTask) -> Result<(), Errno> {
477    // Read the signal stack frame from memory.
478    let signal_frame_address = UserAddress::from(align_stack_pointer(
479        current_task.thread_state.registers.stack_pointer_register(),
480    ));
481    let signal_stack_bytes =
482        current_task.read_memory_to_array::<SIG_STACK_SIZE>(signal_frame_address)?;
483
484    // Grab the registers state from the stack frame.
485    let signal_stack_frame = SignalStackFrame::from_bytes(signal_stack_bytes);
486    restore_registers(current_task, &signal_stack_frame, signal_frame_address)?;
487
488    // Restore the stored signal mask.
489    current_task
490        .write()
491        .set_signal_mask(signal_stack_frame.get_signal_mask(current_task.is_arch32()));
492
493    Ok(())
494}
495
496/// Maybe adjust a task's registers to restart a syscall once the task switches back to userspace,
497/// based on whether the task previously had a syscall return with an error code indicating that a
498/// restart was required.
499pub fn prepare_to_restart_syscall(
500    thread_state: &mut ThreadState<RegisterStorageEnum>,
501    sigaction: Option<sigaction_t>,
502) {
503    // Taking the value ensures each syscall is only considered for restart once.
504    let Some(err) = thread_state.restart_code.take() else {
505        // Don't interact with register state at all unless other kernel code indicates that we may
506        // need to restart.
507        return;
508    };
509
510    if err.should_restart(sigaction) {
511        // This error code is returned for system calls that need restart_syscall() to adjust time
512        // related arguments when the syscall is restarted. Other syscall restarts can be dispatched
513        // directly to the original syscall implementation.
514        if err == ERESTART_RESTARTBLOCK {
515            thread_state.registers.prepare_for_custom_restart();
516        } else {
517            thread_state.registers.restore_original_return_register();
518        }
519
520        // TODO(https://fxbug.dev/388051291) figure out whether Linux relies on registers here
521        thread_state.registers.rewind_syscall_instruction();
522    } else {
523        thread_state.registers.set_return_register(EINTR.return_value());
524    }
525}
526
527pub fn sys_restart_syscall(current_task: &mut CurrentTask) -> Result<SyscallResult, Errno> {
528    match current_task.thread_state.syscall_restart_func.take() {
529        Some(f) => f(current_task),
530        None => {
531            // This may indicate a bug where a syscall returns ERESTART_RESTARTBLOCK without
532            // setting a restart func. But it can also be triggered by userspace, e.g. by directly
533            // calling restart_syscall or injecting an ERESTART_RESTARTBLOCK error through ptrace.
534            log_warn!("restart_syscall called, but nothing to restart");
535            error!(EINTR)
536        }
537    }
538}
539
540/// Test utilities for signal handling.
541#[cfg(test)]
542pub(crate) mod testing {
543    use super::*;
544    use crate::testing::AutoReleasableTask;
545    use std::ops::DerefMut as _;
546
547    pub(crate) fn dequeue_signal_for_test(current_task: &mut AutoReleasableTask) {
548        dequeue_signal(current_task.deref_mut());
549    }
550}