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.
Unified · Split
| @@ -338,6 +338,7 @@ extern int kill_pid(struct pid *pid, int sig, int priv); · 337 unmodified lines | ||
| 338 | 338 | extern __must_check bool do_notify_parent(struct task_struct *, int); |
| 339 | 339 | extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); |
| 340 | 340 | extern void force_sig(int); |
| 341 | +extern void force_fatal_sig(int); | |
| 341 | 342 | extern int send_sig(int, struct task_struct *, int); |
| 342 | 343 | extern int zap_other_threads(struct task_struct *p); |
| 343 | 344 | extern struct sigqueue *sigqueue_alloc(void); |
| @@ -1662,6 +1662,19 @@ void force_sig(int sig) · 1661 unmodified lines | ||
| 1662 | 1662 | } |
| 1663 | 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 | 1679 | * When things go south during signal handling, we |
| 1667 | 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 | 1684 | void force_sigsegv(int sig) |
| 1672 | 1685 | { |
| 1673 | − struct task_struct *p = current; | |
| 1674 | − | |
| 1675 | − if (sig == SIGSEGV) { | |
| 1676 | − unsigned long flags; | |
| 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); | |
| 1686 | + if (sig == SIGSEGV) | |
| 1687 | + force_fatal_sig(SIGSEGV); | |
| 1688 | + else | |
| 1689 | + force_sig(SIGSEGV); | |
| 1682 | 1690 | } |
| 1683 | 1691 | |
| 1684 | 1692 | int force_sig_fault_to_task(int sig, int code, void __user *addr |