Add a simple helper force_fatal_sig that causes a signal to be delivered to a process as if the signal handler was set to SIG_DFL. Reimplement force_sigsegv based upon this new helper. This fixes force_sigsegv so that when it forces the default signal handler to be used the code now forces the signal to be unblocked as well. Reusing the tested logic in force_sig_info_to_task that was built for force_sig_seccomp this makes the implementation trivial. This is interesting both because it makes force_sigsegv simpler and because there are a couple of buggy places in the kernel that call do_exit(SIGILL) or do_exit(SIGSYS) because there is no straight forward way today for those places to simply force the exit of a process with the chosen signal. Creating force_fatal_sig allows those places to be implemented with normal signal exits.
Showing the changes to kernel (1 of 2 files). Show all
Unified · Split
| @@ -1662,6 +1662,19 @@ void force_sig(int sig) · 1661 unmodified lines | |||
| 1662 | } | 1662 | } |
| 1663 | EXPORT_SYMBOL(force_sig); | 1663 | EXPORT_SYMBOL(force_sig); |
| 1664 | 1664 | ||
| 1665 | void force_fatal_sig(int sig) | ||
| 1666 | { | ||
| 1667 | struct kernel_siginfo info; | ||
| 1668 | |||
| 1669 | clear_siginfo(&info); | ||
| 1670 | info.si_signo = sig; | ||
| 1671 | info.si_errno = 0; | ||
| 1672 | info.si_code = SI_KERNEL; | ||
| 1673 | info.si_pid = 0; | ||
| 1674 | info.si_uid = 0; | ||
| 1675 | force_sig_info_to_task(&info, current, true); | ||
| 1676 | } | ||
| 1677 | |||
| 1665 | /* | 1678 | /* |
| 1666 | * When things go south during signal handling, we | 1679 | * When things go south during signal handling, we |
| 1667 | * will force a SIGSEGV. And if the signal that caused | 1680 | * will force a SIGSEGV. And if the signal that caused |
| @@ -1670,15 +1683,10 @@ EXPORT_SYMBOL(force_sig); · 2 unmodified lines | |||
| 1670 | */ | 1683 | */ |
| 1671 | void force_sigsegv(int sig) | 1684 | void force_sigsegv(int sig) |
| 1672 | { | 1685 | { |
| 1673 | struct task_struct *p = current; | 1686 | if (sig == SIGSEGV) |
| 1674 | 1687 | force_fatal_sig(SIGSEGV); | |
| 1675 | if (sig == SIGSEGV) { | 1688 | else |
| 1676 | unsigned long flags; | 1689 | force_sig(SIGSEGV); |
| 1677 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
| 1678 | p->sighand->action[sig - 1].sa.sa_handler = SIG_DFL; | ||
| 1679 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
| 1680 | } | ||
| 1681 | force_sig(SIGSEGV); | ||
| 1682 | } | 1690 | } |
| 1683 | 1691 | ||
| 1684 | int force_sig_fault_to_task(int sig, int code, void __user *addr | 1692 | int force_sig_fault_to_task(int sig, int code, void __user *addr |