1use 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#[derive(PartialEq)]
35enum SignalPriority {
36 First,
37 Last,
38}
39
40pub fn send_signal_first(task: &Task, task_state: TaskWriteGuard<'_>, signal_info: SignalInfo) {
48 send_signal_prio(
49 task,
50 task_state,
51 signal_info.into(),
52 SignalPriority::First,
53 true,
54 )
55 .expect("send_signal(SignalPriority::First) is not expected to fail")
56}
57
58pub fn send_standard_signal(task: &Task, signal_info: SignalInfo) {
63 debug_assert!(!signal_info.signal.is_real_time());
64 let state = task.write();
65 send_signal_prio(
66 task,
67 state,
68 signal_info.into(),
69 SignalPriority::Last,
70 false,
71 )
72 .expect("send_signal(SignalPriority::Last) is not expected to fail for standard signals.")
73}
74
75pub fn send_signal(task: &Task, signal_info: SignalInfo) -> Result<(), Errno> {
83 let state = task.write();
84 send_signal_prio(
85 task,
86 state,
87 signal_info.into(),
88 SignalPriority::Last,
89 false,
90 )
91}
92
93pub fn send_freeze_signal(task: &Task, waiter: Waiter) -> Result<(), Errno> {
94 let state = task.write();
95 send_signal_prio(
96 task,
97 state,
98 KernelSignalInfo::Freeze(waiter),
99 SignalPriority::First,
100 true,
101 )
102}
103
104fn send_signal_prio(
105 task: &Task,
106 mut task_state: TaskWriteGuard<'_>,
107 kernel_signal_info: KernelSignalInfo,
108 prio: SignalPriority,
109 force_wake: bool,
110) -> Result<(), Errno> {
111 let (signal_info, signal, is_masked, was_masked, is_real_time, sigaction, action) =
112 match kernel_signal_info {
113 KernelSignalInfo::User(ref user_signal_info) => {
114 if (!task_state.is_ptraced() || user_signal_info.signal == SIGKILL)
115 && task.thread_group().ignores_signal(user_signal_info)
116 {
117 return Ok(());
118 }
119 if user_signal_info.signal == SIGKILL {
120 drop(task_state);
121 task.thread_group().write().force_exit_for_sigkill(user_signal_info.clone());
127 return Ok(());
128 }
129 let signal = user_signal_info.signal;
130 let is_masked = task_state.is_signal_masked(signal);
131 let was_masked = task_state.is_signal_masked_by_saved_mask(signal);
132 let sigaction = task.get_signal_action(signal);
133 let action = action_for_signal(user_signal_info, sigaction);
134 (
135 Some(user_signal_info.clone()),
136 Some(signal),
137 is_masked,
138 was_masked,
139 signal.is_real_time(),
140 Some(sigaction),
141 Some(action),
142 )
143 }
144 KernelSignalInfo::Freeze(_) => (None, None, false, false, false, None, None),
145 };
146
147 if is_real_time && prio != SignalPriority::First {
148 if task_state.pending_signal_count()
149 >= task.thread_group().get_rlimit(Resource::SIGPENDING) as usize
150 {
151 return error!(EAGAIN);
152 }
153 }
154
155 let is_queued = action.is_none()
160 || action != Some(DeliveryAction::Ignore)
161 || is_masked
162 || was_masked
163 || task_state.is_ptraced();
164 if is_queued {
165 match kernel_signal_info {
166 KernelSignalInfo::User(ref signal_info) => {
167 if prio == SignalPriority::First {
168 task_state.enqueue_signal_front(signal_info.clone());
169 } else {
170 task_state.enqueue_signal(signal_info.clone());
171 }
172 task_state.set_flags(TaskFlags::SIGNALS_AVAILABLE, true);
173 }
174 KernelSignalInfo::Freeze(waiter) => {
175 task_state.enqueue_kernel_signal(KernelSignal::Freeze(waiter))
176 }
177 }
178 }
179
180 drop(task_state);
181 if is_queued
182 && !is_masked
183 && action.map_or_else(|| true, |action| action.must_interrupt(sigaction))
184 {
185 task.interrupt();
188 }
189
190 if signal == Some(SIGCONT) || force_wake {
194 task.thread_group().set_stopped(
195 StopState::Waking,
196 signal_info,
197 false,
198 );
199 task.write().set_stopped(
200 StopState::Waking,
201 None,
202 None,
203 None,
204 );
205 }
206
207 Ok(())
208}
209
210#[derive(Debug, PartialEq)]
214pub enum DeliveryAction {
215 Ignore,
216 CallHandler,
217 Terminate,
218 CoreDump,
219 Stop,
220 Continue,
221}
222
223impl DeliveryAction {
224 pub fn must_interrupt(&self, sigaction: Option<sigaction_t>) -> bool {
230 match *self {
231 Self::Continue => false,
232 Self::Ignore => sigaction.map_or(false, |sa| sa.sa_handler == SIG_IGN),
233 _ => true,
234 }
235 }
236}
237
238pub fn action_for_signal(siginfo: &SignalInfo, sigaction: sigaction_t) -> DeliveryAction {
239 let handler = if siginfo.force && sigaction.sa_handler == SIG_IGN {
240 SIG_DFL
241 } else {
242 sigaction.sa_handler
243 };
244 match handler {
245 SIG_DFL => match siginfo.signal {
246 SIGCHLD | SIGURG | SIGWINCH => DeliveryAction::Ignore,
247 sig if sig.is_real_time() => DeliveryAction::Ignore,
248 SIGHUP | SIGINT | SIGKILL | SIGPIPE | SIGALRM | SIGTERM | SIGUSR1 | SIGUSR2
249 | SIGPROF | SIGVTALRM | SIGSTKFLT | SIGIO | SIGPWR => DeliveryAction::Terminate,
250 SIGQUIT | SIGILL | SIGABRT | SIGFPE | SIGSEGV | SIGBUS | SIGSYS | SIGTRAP | SIGXCPU
251 | SIGXFSZ => DeliveryAction::CoreDump,
252 SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => DeliveryAction::Stop,
253 SIGCONT => DeliveryAction::Continue,
254 _ => panic!("Unknown signal"),
255 },
256 SIG_IGN => DeliveryAction::Ignore,
257 _ => DeliveryAction::CallHandler,
258 }
259}
260
261pub fn dequeue_signal(current_task: &mut CurrentTask) {
263 let &mut CurrentTask { ref task, ref mut thread_state, .. } = current_task;
264 if !task.should_check_for_pending_signals() {
265 return;
266 }
267
268 let mut task_state = task.write();
269 if task.load_stopped().is_stopping_or_stopped() {
272 return;
273 }
274
275 let kernel_signal = task_state.take_kernel_signal();
277 let siginfo = if kernel_signal.is_some() { None } else { task_state.take_any_signal() };
278 prepare_to_restart_syscall(
279 thread_state,
280 siginfo.as_ref().map(|siginfo| task.thread_group().signal_actions.get(siginfo.signal)),
281 );
282
283 if let Some(ref siginfo) = siginfo {
284 if task_state.ptrace_on_signal_consume() && siginfo.signal != SIGKILL {
285 task_state.set_stopped(
289 StopState::SignalDeliveryStopping,
290 Some(siginfo.clone()),
291 None,
292 None,
293 );
294 return;
295 }
296 }
297
298 task_state.restore_signal_mask();
301
302 if let Some(kernel_signal) = kernel_signal {
303 let KernelSignal::Freeze(waiter) = kernel_signal;
304 drop(task_state);
305
306 waiter.freeze(current_task);
307 } else if let Some(ref siginfo) = siginfo {
308 if let SignalDetail::Timer { timer } = &siginfo.detail {
309 timer.on_signal_delivered();
310 }
311 if let Some(status) = deliver_signal(
312 &task,
313 current_task.thread_state.arch_width(),
314 task_state,
315 siginfo.clone(),
316 &mut current_task.thread_state.registers,
317 ¤t_task.thread_state.extended_pstate,
318 None,
319 ) {
320 current_task.kill_thread_group(status);
321 }
322 };
323}
324
325fn deliver_signal(
326 task: &Task,
327 arch_width: ArchWidth,
328 mut task_state: TaskWriteGuard<'_>,
329 mut siginfo: SignalInfo,
330 registers: &mut RegisterState<RegisterStorageEnum>,
331 extended_pstate: &ArchExtendedPstateStorage,
332 restricted_exception: Option<zx::ExceptionReport>,
333) -> Option<ExitStatus> {
334 loop {
335 if task.thread_group().ignores_signal(&siginfo) {
342 return None;
343 }
344 let signal = siginfo.signal;
345 let mut sigaction = task.thread_group().signal_actions.get(signal);
346 let masked_signals = task_state.signal_mask();
347 if siginfo.force && (masked_signals.has_signal(signal) || sigaction.sa_handler == SIG_IGN) {
357 task_state.set_signal_mask(masked_signals & !SigSet::from(signal));
358 sigaction = sigaction_t::default();
359 task.thread_group().signal_actions.set(signal, sigaction);
360 }
361
362 let action = action_for_signal(&siginfo, sigaction);
363 log_trace!("handling signal {:?} with action {:?}", siginfo, action);
364 match action {
365 DeliveryAction::Ignore => {}
366 DeliveryAction::CallHandler => {
367 if sigaction.sa_flags & (SA_RESETHAND as u64) != 0 {
370 let new_sigaction = sigaction_t {
371 sa_handler: SIG_DFL,
372 sa_flags: sigaction.sa_flags & !(SA_RESETHAND as u64),
373 ..sigaction
374 };
375 task.thread_group().signal_actions.set(signal, new_sigaction);
376 }
377 let core_dump_during_shutdown = task.kernel().is_shutting_down()
378 && action_for_signal(&siginfo, sigaction_t::default())
379 == DeliveryAction::CoreDump;
380 if let Err(err) = dispatch_signal_handler(
381 task,
382 arch_width,
383 registers,
384 extended_pstate,
385 task_state.signals_mut(),
386 siginfo,
387 sigaction,
388 ) {
389 log_warn!("failed to deliver signal {:?}: {:?}", signal, err);
390 if signal == SIGSEGV {
391 task.thread_group().signal_actions.set(SIGSEGV, sigaction_t::default());
392 }
393 siginfo = SignalInfo::forced(SIGSEGV);
394 continue;
395 }
396 if core_dump_during_shutdown {
397 task_state.set_flags(TaskFlags::IN_CORE_DUMP_SIGNAL_HANDLER, true);
398 }
399 }
400 DeliveryAction::Terminate => {
401 drop(task_state);
404 return Some(ExitStatus::Kill(siginfo));
405 }
406 DeliveryAction::CoreDump => {
407 task_state.set_flags(TaskFlags::DUMP_ON_EXIT, true);
408 drop(task_state);
409 if let Some(exception) = restricted_exception {
410 log_info!(
411 registers:?=registers,
412 exception:?=exception;
413 "Restricted mode exception caused core dump",
415 );
417 if let SignalDetail::SigFault { addr } = siginfo.detail {
418 if let Ok(mm) = task.mm() {
419 mm.log_memory_map(task, UserAddress::from(addr));
420 }
421 }
422 }
423 return Some(ExitStatus::CoreDump(siginfo));
424 }
425 DeliveryAction::Stop => {
426 drop(task_state);
427 task.thread_group().set_stopped(StopState::GroupStopping, Some(siginfo), false);
428 }
429 DeliveryAction::Continue => {
430 }
432 };
433 break;
434 }
435 None
436}
437
438pub fn force_signal(
444 current_task: &mut CurrentTask,
445 mut siginfo: SignalInfo,
446 restricted_exception: Option<zx::ExceptionReport>,
447) {
448 siginfo.force = true;
449 let mut task_state = current_task.task.write();
450 if task_state.ptrace_on_signal_consume() && siginfo.signal != SIGKILL {
451 task_state.set_stopped(
452 StopState::SignalDeliveryStopping,
453 Some(siginfo),
454 Some(current_task),
455 None,
456 );
457 return;
458 }
459
460 if let Some(status) = deliver_signal(
461 ¤t_task.task,
462 current_task.thread_state.arch_width(),
463 task_state,
464 siginfo,
465 &mut current_task.thread_state.registers,
466 ¤t_task.thread_state.extended_pstate,
467 restricted_exception,
468 ) {
469 current_task.kill_thread_group(status);
470 }
471}
472
473fn dispatch_signal_handler(
477 task: &Task,
478 arch_width: ArchWidth,
479 registers: &mut RegisterState<RegisterStorageEnum>,
480 extended_pstate: &ArchExtendedPstateStorage,
481 signal_state: &mut SignalState,
482 siginfo: SignalInfo,
483 action: sigaction_t,
484) -> Result<(), Errno> {
485 let stack_pointer_register = registers.stack_pointer_register();
486 let on_sigaltstack = signal_state.alt_stack.is_some_and(|sigaltstack| {
487 sigaltstack_contains_pointer(&sigaltstack, stack_pointer_register)
488 });
489 let main_stack = stack_pointer_register.checked_sub(RED_ZONE_SIZE);
490 let stack_bottom = if (action.sa_flags & SA_ONSTACK as u64) != 0 {
491 match signal_state.alt_stack {
492 Some(sigaltstack) => {
493 if on_sigaltstack {
495 main_stack
496 } else {
497 sigaltstack
501 .ss_sp
502 .addr
503 .checked_add(sigaltstack.ss_size)
504 .map(|sp| sp as u64)
505 .or(main_stack)
506 }
507 }
508 None => main_stack,
509 }
510 } else {
511 main_stack
512 }
513 .ok_or_else(|| errno!(EINVAL))?;
514
515 let stack_pointer =
516 align_stack_pointer(stack_bottom.checked_sub(SIG_STACK_SIZE as u64).ok_or_else(|| {
517 errno!(
518 EINVAL,
519 format!(
520 "Subtracting SIG_STACK_SIZE ({}) from stack bottom ({}) overflowed",
521 SIG_STACK_SIZE, stack_bottom
522 )
523 )
524 })?);
525
526 if let Some(alt_stack) = signal_state.alt_stack {
529 if sigaltstack_contains_pointer(&alt_stack, stack_pointer)
530 != (on_sigaltstack || sigaltstack_contains_pointer(&alt_stack, stack_bottom))
531 {
532 return error!(EINVAL);
533 }
534 }
535
536 let signal_stack_frame = SignalStackFrame::new(
537 task,
538 arch_width,
539 registers,
540 extended_pstate,
541 signal_state,
542 &siginfo,
543 action,
544 UserAddress::from(stack_pointer),
545 )?;
546
547 task.write_memory(UserAddress::from(stack_pointer), signal_stack_frame.as_bytes())?;
549
550 let mut mask: SigSet = action.sa_mask.into();
551 if action.sa_flags & (SA_NODEFER as u64) == 0 {
552 mask = mask | siginfo.signal.into();
553 }
554
555 signal_state.set_mask(mask | signal_state.mask());
557
558 registers.set_stack_pointer_register(stack_pointer);
559 registers.set_arg0_register(siginfo.signal.number() as u64);
560 if (action.sa_flags & SA_SIGINFO as u64) != 0 {
561 registers.set_arg1_register(
562 stack_pointer + memoffset::offset_of!(SignalStackFrame, siginfo_bytes) as u64,
563 );
564 registers.set_arg2_register(
565 stack_pointer + memoffset::offset_of!(SignalStackFrame, context) as u64,
566 );
567 }
568 registers.set_instruction_pointer_register(action.sa_handler.addr);
569 registers.reset_flags(); Ok(())
572}
573
574pub fn restore_from_signal_handler(current_task: &mut CurrentTask) -> Result<(), Errno> {
575 let signal_frame_address = UserAddress::from(align_stack_pointer(
577 current_task.thread_state.registers.stack_pointer_register(),
578 ));
579 let signal_stack_bytes =
580 current_task.read_memory_to_array::<SIG_STACK_SIZE>(signal_frame_address)?;
581
582 let signal_stack_frame = SignalStackFrame::from_bytes(signal_stack_bytes);
584 restore_registers(current_task, &signal_stack_frame, signal_frame_address)?;
585
586 let mut task_state = current_task.write();
588 task_state.set_signal_mask(signal_stack_frame.get_signal_mask(current_task.is_arch32()));
589 task_state.set_flags(TaskFlags::IN_CORE_DUMP_SIGNAL_HANDLER, false);
590
591 Ok(())
592}
593
594pub fn prepare_to_restart_syscall(
598 thread_state: &mut ThreadState<RegisterStorageEnum>,
599 sigaction: Option<sigaction_t>,
600) {
601 let Some(err) = thread_state.restart_code.take() else {
603 return;
606 };
607
608 if err.should_restart(sigaction) {
609 if err == ERESTART_RESTARTBLOCK {
613 thread_state.registers.prepare_for_custom_restart();
614 } else {
615 thread_state.registers.restore_original_return_register();
616 }
617
618 thread_state.registers.rewind_syscall_instruction();
620 } else {
621 thread_state.registers.set_return_register(EINTR.return_value());
622 }
623}
624
625pub fn sys_restart_syscall(current_task: &mut CurrentTask) -> Result<SyscallResult, Errno> {
626 match current_task.thread_state.syscall_restart_func.take() {
627 Some(f) => f(current_task),
628 None => {
629 log_warn!("restart_syscall called, but nothing to restart");
633 error!(EINTR)
634 }
635 }
636}
637
638#[cfg(test)]
640pub(crate) mod testing {
641 use super::*;
642 use crate::testing::AutoReleasableTask;
643 use std::ops::DerefMut as _;
644
645 pub(crate) fn dequeue_signal_for_test(current_task: &mut AutoReleasableTask) {
646 dequeue_signal(current_task.deref_mut());
647 }
648}