---
# System prepended metadata

title: Signal
tags: [Linux, Signal]

---

# Signal

###### tags: `Linux` `Signal`

* 其他篇筆記:
    * https://hackmd.io/@LJP/SkrXX8OSc

# Kernel

## 發生 signal
### `arch_do_signal_or_restart()`
* https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/signal.c#L864
```c
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 */
void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal)
{
	struct ksignal ksig;

    // 取得 ksig 結構
	if (has_signal && get_signal(&ksig)) {
		/* Whee! Actually deliver the signal.  */
		handle_signal(&ksig, regs);
		return;
	}

	/* Did we come from a system call? */
	if (syscall_get_nr(current, regs) != -1) {
		/* Restart the system call - no handlers present */
		switch (syscall_get_error(current, regs)) {
		case -ERESTARTNOHAND:
		case -ERESTARTSYS:
		case -ERESTARTNOINTR:
			regs->ax = regs->orig_ax;
			regs->ip -= 2;
			break;

		case -ERESTART_RESTARTBLOCK:
			regs->ax = get_nr_restart_syscall(regs);
			regs->ip -= 2;
			break;
		}
	}

	/*
	 * If there's no signal to deliver, we just put the saved sigmask
	 * back.
	 */
	restore_saved_sigmask();
}
```

### `handle_signal()`
* https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/signal.c#L786
```c
static void
handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
	bool stepping, failed;
	struct fpu *fpu = &current->thread.fpu;

	if (v8086_mode(regs))
		save_v86_state((struct kernel_vm86_regs *) regs, VM86_SIGNAL);

	/* Are we from a system call? */
	if (syscall_get_nr(current, regs) != -1) {
		/* If so, check system call restarting.. */
		switch (syscall_get_error(current, regs)) {
		case -ERESTART_RESTARTBLOCK:
		case -ERESTARTNOHAND:
			regs->ax = -EINTR;
			break;

		case -ERESTARTSYS:
			if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
				regs->ax = -EINTR;
				break;
			}
			fallthrough;
		case -ERESTARTNOINTR:
			regs->ax = regs->orig_ax;
			regs->ip -= 2;
			break;
		}
	}

	/*
	 * If TF is set due to a debugger (TIF_FORCED_TF), clear TF now
	 * so that register information in the sigcontext is correct and
	 * then notify the tracer before entering the signal handler.
	 */
	stepping = test_thread_flag(TIF_SINGLESTEP);
	if (stepping)
		user_disable_single_step(current);

	failed = (setup_rt_frame(ksig, regs) < 0);
	if (!failed) {
		/*
		 * Clear the direction flag as per the ABI for function entry.
		 *
		 * Clear RF when entering the signal handler, because
		 * it might disable possible debug exception from the
		 * signal handler.
		 *
		 * Clear TF for the case when it wasn't set by debugger to
		 * avoid the recursive send_sigtrap() in SIGTRAP handler.
		 */
		regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF);
		/*
		 * Ensure the signal handler starts with the new fpu state.
		 */
		fpu__clear_user_states(fpu);
	}
	signal_setup_done(failed, ksig, stepping);
}
```

### `setup_rt_frame()`
* https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/signal.c#L763
```c
// ksig 結構決定等等的 rt_sigframe 內部要放什麼
static int
setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
{
	int usig = ksig->sig;
	sigset_t *set = sigmask_to_save();
	compat_sigset_t *cset = (compat_sigset_t *) set;

	/* Perform fixup for the pre-signal frame. */
	rseq_signal_deliver(ksig, regs);

	/* Set up the stack frame */
	if (is_ia32_frame(ksig)) {
		if (ksig->ka.sa.sa_flags & SA_SIGINFO)
			return ia32_setup_rt_frame(usig, ksig, cset, regs);
		else
			return ia32_setup_frame(usig, ksig, cset, regs);
	} else if (is_x32_frame(ksig)) {
		return x32_setup_rt_frame(ksig, cset, regs);
	} else {
		return __setup_rt_frame(ksig->sig, ksig, set, regs);
	}
}
```

### `__setup_rt_frame()`
* https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/signal.c#L460
```c
static int __setup_rt_frame(int sig, struct ksignal *ksig,
			    sigset_t *set, struct pt_regs *regs)
{
	struct rt_sigframe __user *frame;
	void __user *fp = NULL;
	unsigned long uc_flags;

	/* x86-64 should always use SA_RESTORER. */
	if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
		return -EFAULT;

	frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
	uc_flags = frame_uc_flags(regs);

	if (!user_access_begin(frame, sizeof(*frame)))
		return -EFAULT;

	/* Create the ucontext.  */
	unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
	unsafe_put_user(0, &frame->uc.uc_link, Efault);
	unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
    // 設定 pretcode
	unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault);
	unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
	unsafe_put_sigmask(set, frame, Efault);
	user_access_end();

	if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
		if (copy_siginfo_to_user(&frame->info, &ksig->info))
			return -EFAULT;
	}

	/* Set up registers for signal handler */
	regs->di = sig;
	/* In case the signal handler was declared without prototypes */
	regs->ax = 0;

	/* This also works for non SA_SIGINFO handlers because they expect the
	   next argument after the signal number on the stack. */
	regs->si = (unsigned long)&frame->info;
	regs->dx = (unsigned long)&frame->uc;
	regs->ip = (unsigned long) ksig->ka.sa.sa_handler;

	regs->sp = (unsigned long)frame;

	/*
	 * Set up the CS and SS registers to run signal handlers in
	 * 64-bit mode, even if the handler happens to be interrupting
	 * 32-bit or 16-bit code.
	 *
	 * SS is subtle.  In 64-bit mode, we don't need any particular
	 * SS descriptor, but we do need SS to be valid.  It's possible
	 * that the old SS is entirely bogus -- this can happen if the
	 * signal we're trying to deliver is #GP or #SS caused by a bad
	 * SS value.  We also have a compatibility issue here: DOSEMU
	 * relies on the contents of the SS register indicating the
	 * SS value at the time of the signal, even though that code in
	 * DOSEMU predates sigreturn's ability to restore SS.  (DOSEMU
	 * avoids relying on sigreturn to restore SS; instead it uses
	 * a trampoline.)  So we do our best: if the old SS was valid,
	 * we keep it.  Otherwise we replace it.
	 */
	regs->cs = __USER_CS;

	if (unlikely(regs->ss != __USER_DS))
		force_valid_ss(regs);

	return 0;

Efault:
	user_access_end();
	return -EFAULT;
}
```


## signal handler 返回 (呼叫 sigreturn)
### syscall rt_sigreturn
* https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/signal.c#L657
```c
SYSCALL_DEFINE0(rt_sigreturn)
{
	struct pt_regs *regs = current_pt_regs();
	struct rt_sigframe __user *frame;
	sigset_t set;
	unsigned long uc_flags;

	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
	if (!access_ok(frame, sizeof(*frame)))
		goto badframe;
	if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask))
		goto badframe;
	if (__get_user(uc_flags, &frame->uc.uc_flags))
		goto badframe;

	set_current_blocked(&set);

	if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
		goto badframe;

	if (restore_altstack(&frame->uc.uc_stack))
		goto badframe;

	return regs->ax;

badframe:
	signal_fault(regs, frame, "rt_sigreturn");
	return 0;
}
```

# Libc
## `signal`
* https://elixir.bootlin.com/glibc/glibc-2.31/source/sysdeps/posix/signal.c#L29
```c
/* Set the handler for the signal SIG to HANDLER,
   returning the old handler, or SIG_ERR on error.  */
__sighandler_t
__bsd_signal (int sig, __sighandler_t handler)
{
  struct sigaction act, oact;

  /* Check signal extents to protect __sigismember.  */
  if (handler == SIG_ERR || sig < 1 || sig >= NSIG
      || __is_internal_signal (sig))
    {
      __set_errno (EINVAL);
      return SIG_ERR;
    }

  act.sa_handler = handler;
  __sigemptyset (&act.sa_mask);
  __sigaddset (&act.sa_mask, sig);
  act.sa_flags = __sigismember (&_sigintr, sig) ? 0 : SA_RESTART;
  if (__sigaction (sig, &act, &oact) < 0)
    return SIG_ERR;

  return oact.sa_handler;
}
weak_alias (__bsd_signal, bsd_signal)
weak_alias (__bsd_signal, signal)
weak_alias (__bsd_signal, ssignal)
```

## `__sigaction`
* https://elixir.bootlin.com/glibc/glibc-2.31/source/nptl/sigaction.c#L22
```c
int
__sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
  if (sig <= 0 || sig >= NSIG || __is_internal_signal (sig))
    {
      __set_errno (EINVAL);
      return -1;
    }

  return __libc_sigaction (sig, act, oact);
}
libc_hidden_weak (__sigaction)
weak_alias (__sigaction, sigaction)
```
## `__libc_sigaction`
* https://elixir.bootlin.com/glibc/glibc-2.31/source/sysdeps/unix/sysv/linux/sigaction.c#L42
```c
/* If ACT is not NULL, change the action for SIG to *ACT.
   If OACT is not NULL, put the old action for SIG in *OACT.  */
int
__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
  int result;

  struct kernel_sigaction kact, koact;

  if (act)
    {
      kact.k_sa_handler = act->sa_handler;
      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
      kact.sa_flags = act->sa_flags;
      SET_SA_RESTORER (&kact, act);
    }

  /* XXX The size argument hopefully will have to be changed to the
     real size of the user-level sigset_t.  */
  result = INLINE_SYSCALL_CALL (rt_sigaction, sig,
				act ? &kact : NULL,
				oact ? &koact : NULL, STUB (act, _NSIG / 8));

  if (oact && result >= 0)
    {
      oact->sa_handler = koact.k_sa_handler;
      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
      oact->sa_flags = koact.sa_flags;
      RESET_SA_RESTORER (oact, &koact);
    }
  return result;
}
libc_hidden_def (__libc_sigaction)
```
* `SET_SA_RESTORER` 設定了 sa_restorer

## `SET_SA_RESTORER`
* https://elixir.bootlin.com/glibc/glibc-2.31/source/sysdeps/unix/sysv/linux/x86_64/sigaction.c#L24
```c
extern void restore_rt (void) asm ("__restore_rt") attribute_hidden;

#define SET_SA_RESTORER(kact, act)			\
  (kact)->sa_flags = (act)->sa_flags | SA_RESTORER;	\
  (kact)->sa_restorer = &restore_rt
```

* `restore_rt` 被改標成 `__restore_rt`, 繼續看以下 macro 展開
```c
/* The return code for realtime-signals.  */
RESTORE (restore_rt, __NR_rt_sigreturn)
```

* `RESTORE` 也是在同一檔案
```c
#define RESTORE(name, syscall) RESTORE2 (name, syscall)
# define RESTORE2(name, syscall) \
asm									\
  (									\
   /* `nop' for debuggers assuming `call' should not disalign the code.  */ \
   "	nop\n"								\
   ".align 16\n"							\
   ".LSTART_" #name ":\n"						\
   "	.type __" #name ",@function\n"					\
   "__" #name ":\n"							\
   "	movq $" #syscall ", %rax\n"					\
   "	syscall\n"							\
   ".LEND_" #name ":\n"							\
   ".section .eh_frame,\"a\",@progbits\n"				\
   ".LSTARTFRAME_" #name ":\n"						\
   "	.long .LENDCIE_" #name "-.LSTARTCIE_" #name "\n"		\
   ".LSTARTCIE_" #name ":\n"						\
   "	.long 0\n"	/* CIE ID */					\
   "	.byte 1\n"	/* Version number */				\
   "	.string \"zRS\"\n" /* NUL-terminated augmentation string */	\
   "	.uleb128 1\n"	/* Code alignment factor */			\
   "	.sleb128 -8\n"	/* Data alignment factor */			\
   "	.uleb128 16\n"	/* Return address register column (rip) */	\
   /* Augmentation value length */					\
   "	.uleb128 .LENDAUGMNT_" #name "-.LSTARTAUGMNT_" #name "\n"	\
   ".LSTARTAUGMNT_" #name ":\n"						\
   "	.byte 0x1b\n"	/* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */		\
   ".LENDAUGMNT_" #name ":\n"						\
   "	.align " LP_SIZE "\n"						\
   ".LENDCIE_" #name ":\n"						\
   "	.long .LENDFDE_" #name "-.LSTARTFDE_" #name "\n" /* FDE len */	\
   ".LSTARTFDE_" #name ":\n"						\
   "	.long .LSTARTFDE_" #name "-.LSTARTFRAME_" #name "\n" /* CIE */	\
   /* `LSTART_' is subtracted 1 as debuggers assume a `call' here.  */	\
   "	.long (.LSTART_" #name "-1)-.\n" /* PC-relative start addr.  */	\
   "	.long .LEND_" #name "-(.LSTART_" #name "-1)\n"			\
   "	.uleb128 0\n"			/* FDE augmentation length */	\
   do_cfa_expr								\
   do_expr (8 /* r8 */, oR8)						\
   do_expr (9 /* r9 */, oR9)						\
   do_expr (10 /* r10 */, oR10)						\
   do_expr (11 /* r11 */, oR11)						\
   do_expr (12 /* r12 */, oR12)						\
   do_expr (13 /* r13 */, oR13)						\
   do_expr (14 /* r14 */, oR14)						\
   do_expr (15 /* r15 */, oR15)						\
   do_expr (5 /* rdi */, oRDI)						\
   do_expr (4 /* rsi */, oRSI)						\
   do_expr (6 /* rbp */, oRBP)						\
   do_expr (3 /* rbx */, oRBX)						\
   do_expr (1 /* rdx */, oRDX)						\
   do_expr (0 /* rax */, oRAX)						\
   do_expr (2 /* rcx */, oRCX)						\
   do_expr (7 /* rsp */, oRSP)						\
   do_expr (16 /* rip */, oRIP)						\
   /* libgcc-4.1.1 has only `DWARF_FRAME_REGISTERS == 17'.  */		\
   /* do_expr (49 |* rflags *|, oEFL) */				\
   /* `cs'/`ds'/`fs' are unaligned and a different size.  */		\
   /* gas: Error: register save offset not a multiple of 8  */		\
   "	.align " LP_SIZE "\n"						\
   ".LENDFDE_" #name ":\n"						\
   "	.previous\n"							\
   );
```

* 展開後:
```c
asm ( " nop\n" ".align 16\n" ".LSTART_" "restore_rt" ":\n" "      .type __" "restore_rt" ",@function\n" "__" "restore_rt" ":\n" "     movq $" "__NR_rt_sigreturn" ", %rax\n" "  syscall\n" ".LEND_" "restore_rt" ":\n" ".section .eh_frame,\"a\",@progbits\n" ".LSTARTFRAME_" "restore_rt" ":\n" "  .long .LENDCIE_" "restore_rt" "-.LSTARTCIE_" "restore_rt" "\n" ".LSTARTCIE_" "restore_rt" ":\n" "   .long 0\n" "  .byte 1\n" "        .string \"zRS\"\n" "    .uleb128 1\n" " .sleb128 -8\n" "  .uleb128 16\n" "    .uleb128 .LENDAUGMNT_" "restore_rt" "-.LSTARTAUGMNT_" "restore_rt" "\n" ".LSTARTAUGMNT_" "restore_rt" ":\n" "   .byte 0x1b\n" ".LENDAUGMNT_" "restore_rt" ":\n" "     .align " LP_SIZE "\n" ".LENDCIE_" "restore_rt" ":\n" "    .long .LENDFDE_" "restore_rt" "-.LSTARTFDE_" "restore_rt" "\n" ".LSTARTFDE_" "restore_rt" ":\n" "       .long .LSTARTFDE_" "restore_rt" "-.LSTARTFRAME_" "restore_rt" "\n" "  .long (.LSTART_" "restore_rt" "-1)-.\n" "   .long .LEND_" "restore_rt" "-(.LSTART_" "restore_rt" "-1)\n" "        .uleb128 0\n" do_cfa_expr do_expr (8 , oR8) do_expr (9 , oR9) do_expr (10 , oR10) do_expr (11 , oR11) do_expr (12 , oR12) do_expr (13 , oR13) do_expr (14 , oR14) do_expr (15 , oR15) do_expr (5 , oRDI) do_expr (4 , oRSI) do_expr (6 , oRBP) do_expr (3 , oRBX) do_expr (1 , oRDX) do_expr (0 , oRAX) do_expr (2 , oRCX) do_expr (7 , oRSP) do_expr (16 , oRIP) "     .align " LP_SIZE "\n" ".LENDFDE_" "restore_rt" ":\n" "    .previous\n" );
```
* 整理一番:
```c
asm ( 
    " nop\n" 
    ".align 16\n" 
    ".LSTART_restore_rt:\n"
    "      .type __restore_rt,@function\n"
    "__restore_rt:\n"
    "     movq $__NR_rt_sigreturn, %rax\n"
    "  syscall\n"
    ".LEND_restore_rt:\n"
    ".section .eh_frame,\"a\",@progbits\n"
    ".LSTARTFRAME_restore_rt:\n"
    "  .long .LENDCIE_restore_rt-.LSTARTCIE_restore_rt\n"
    ".LSTARTCIE_restore_rt:\n"
    "   .long 0\n"
    "  .byte 1\n"
    "        .string \"zRS\"\n"
    "    .uleb128 1\n"
    " .sleb128 -8\n"
    "  .uleb128 16\n"
    "    .uleb128 .LENDAUGMNT_restore_rt-.LSTARTAUGMNT_restore_rt\n"
    ".LSTARTAUGMNT_restore_rt:\n"
    "   .byte 0x1b\n"
    ".LENDAUGMNT_restore_rt:\n"
    "     .align " LP_SIZE "\n"
    ".LENDCIE_restore_rt:\n"
    "    .long .LENDFDE_restore_rt-.LSTARTFDE_restore_rt\n"
    ".LSTARTFDE_restore_rt:\n"
    "       .long .LSTARTFDE_restore_rt-.LSTARTFRAME_restore_rt\n"
    "  .long (.LSTART_" "restore_rt" "-1)-.\n"
    "   .long .LEND_restore_rt-(.LSTART_restore_rt-1)\n"
    "        .uleb128 0\n"
    do_cfa_expr 
    do_expr (8 , oR8) 
    do_expr (9 , oR9) 
    do_expr (10 , oR10) 
    do_expr (11 , oR11) 
    do_expr (12 , oR12) 
    do_expr (13 , oR13) 
    do_expr (14 , oR14) 
    do_expr (15 , oR15) 
    do_expr (5 , oRDI) 
    do_expr (4 , oRSI) 
    do_expr (6 , oRBP) 
    do_expr (3 , oRBX)
    do_expr (1 , oRDX) 
    do_expr (0 , oRAX) 
    do_expr (2 , oRCX) 
    do_expr (7 , oRSP) 
    do_expr (16 , oRIP)
    "     .align " LP_SIZE "\n"
    ".LENDFDE_" "restore_rt" ":\n"
    "    .previous\n"
);
```
* 能夠看見關於 `__restore_rt` 的定義:
```c
    "__restore_rt:\n"
    "     movq $__NR_rt_sigreturn, %rax\n"
    "  syscall\n"
```
* 呼叫 rt_sigreturn syscall:

![](https://i.imgur.com/gRaUejW.png)

![](https://i.imgur.com/6Zpls5e.png)

