Commit 7af959b5 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'SA_IMMUTABLE-fixes-for-v5.16-rc2' of...

Merge branch 'SA_IMMUTABLE-fixes-for-v5.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull exit-vs-signal handling fixes from Eric Biederman:
 "This is a small set of changes where debuggers were no longer able to
  intercept synchronous SIGTRAP and SIGSEGV, introduced by the exit
  cleanups.

  This is essentially the change you suggested with all of i's dotted
  and the t's crossed so that ptrace can intercept all of the cases it
  has been able to intercept the past, and all of the cases that made it
  to exit without giving ptrace a chance still don't give ptrace a
  chance"

* 'SA_IMMUTABLE-fixes-for-v5.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  signal: Replace force_fatal_sig with force_exit_sig when in doubt
  signal: Don't always set SA_IMMUTABLE for forced signals
parents ecd510d2 fcb116bc
...@@ -1145,7 +1145,7 @@ asmlinkage void set_esp0(unsigned long ssp) ...@@ -1145,7 +1145,7 @@ asmlinkage void set_esp0(unsigned long ssp)
*/ */
asmlinkage void fpsp040_die(void) asmlinkage void fpsp040_die(void)
{ {
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
} }
#ifdef CONFIG_M68KFPU_EMU #ifdef CONFIG_M68KFPU_EMU
......
...@@ -1063,7 +1063,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, ...@@ -1063,7 +1063,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
* We kill the task with a SIGSEGV in this situation. * We kill the task with a SIGSEGV in this situation.
*/ */
if (do_setcontext(new_ctx, regs, 0)) { if (do_setcontext(new_ctx, regs, 0)) {
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
return -EFAULT; return -EFAULT;
} }
......
...@@ -704,7 +704,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, ...@@ -704,7 +704,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
*/ */
if (__get_user_sigset(&set, &new_ctx->uc_sigmask)) { if (__get_user_sigset(&set, &new_ctx->uc_sigmask)) {
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
return -EFAULT; return -EFAULT;
} }
set_current_blocked(&set); set_current_blocked(&set);
...@@ -713,7 +713,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, ...@@ -713,7 +713,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
return -EFAULT; return -EFAULT;
if (__unsafe_restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext)) { if (__unsafe_restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext)) {
user_read_access_end(); user_read_access_end();
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
return -EFAULT; return -EFAULT;
} }
user_read_access_end(); user_read_access_end();
......
...@@ -84,7 +84,7 @@ static void default_trap_handler(struct pt_regs *regs) ...@@ -84,7 +84,7 @@ static void default_trap_handler(struct pt_regs *regs)
{ {
if (user_mode(regs)) { if (user_mode(regs)) {
report_user_fault(regs, SIGSEGV, 0); report_user_fault(regs, SIGSEGV, 0);
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
} else } else
die(regs, "Unknown program exception"); die(regs, "Unknown program exception");
} }
......
...@@ -244,7 +244,7 @@ static int setup_frame(struct ksignal *ksig, struct pt_regs *regs, ...@@ -244,7 +244,7 @@ static int setup_frame(struct ksignal *ksig, struct pt_regs *regs,
get_sigframe(ksig, regs, sigframe_size); get_sigframe(ksig, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size)) { if (invalid_frame_pointer(sf, sigframe_size)) {
force_fatal_sig(SIGILL); force_exit_sig(SIGILL);
return -EINVAL; return -EINVAL;
} }
...@@ -336,7 +336,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, ...@@ -336,7 +336,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs,
sf = (struct rt_signal_frame __user *) sf = (struct rt_signal_frame __user *)
get_sigframe(ksig, regs, sigframe_size); get_sigframe(ksig, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size)) { if (invalid_frame_pointer(sf, sigframe_size)) {
force_fatal_sig(SIGILL); force_exit_sig(SIGILL);
return -EINVAL; return -EINVAL;
} }
......
...@@ -122,7 +122,7 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who) ...@@ -122,7 +122,7 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who)
if ((sp & 7) || if ((sp & 7) ||
copy_to_user((char __user *) sp, &tp->reg_window[window], copy_to_user((char __user *) sp, &tp->reg_window[window],
sizeof(struct reg_window32))) { sizeof(struct reg_window32))) {
force_fatal_sig(SIGILL); force_exit_sig(SIGILL);
return; return;
} }
} }
......
...@@ -226,7 +226,7 @@ bool emulate_vsyscall(unsigned long error_code, ...@@ -226,7 +226,7 @@ bool emulate_vsyscall(unsigned long error_code,
if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) { if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
warn_bad_vsyscall(KERN_DEBUG, regs, warn_bad_vsyscall(KERN_DEBUG, regs,
"seccomp tried to change syscall nr or ip"); "seccomp tried to change syscall nr or ip");
force_fatal_sig(SIGSYS); force_exit_sig(SIGSYS);
return true; return true;
} }
regs->orig_ax = -1; regs->orig_ax = -1;
......
...@@ -160,7 +160,7 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) ...@@ -160,7 +160,7 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
user_access_end(); user_access_end();
Efault: Efault:
pr_alert("could not access userspace vm86 info\n"); pr_alert("could not access userspace vm86 info\n");
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
goto exit_vm86; goto exit_vm86;
} }
......
...@@ -352,6 +352,7 @@ extern __must_check bool do_notify_parent(struct task_struct *, int); ...@@ -352,6 +352,7 @@ extern __must_check bool do_notify_parent(struct task_struct *, int);
extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent);
extern void force_sig(int); extern void force_sig(int);
extern void force_fatal_sig(int); extern void force_fatal_sig(int);
extern void force_exit_sig(int);
extern int send_sig(int, struct task_struct *, int); extern int send_sig(int, struct task_struct *, int);
extern int zap_other_threads(struct task_struct *p); extern int zap_other_threads(struct task_struct *p);
extern struct sigqueue *sigqueue_alloc(void); extern struct sigqueue *sigqueue_alloc(void);
......
...@@ -48,7 +48,7 @@ bool syscall_user_dispatch(struct pt_regs *regs) ...@@ -48,7 +48,7 @@ bool syscall_user_dispatch(struct pt_regs *regs)
* the selector is loaded by userspace. * the selector is loaded by userspace.
*/ */
if (unlikely(__get_user(state, sd->selector))) { if (unlikely(__get_user(state, sd->selector))) {
force_fatal_sig(SIGSEGV); force_exit_sig(SIGSEGV);
return true; return true;
} }
...@@ -56,7 +56,7 @@ bool syscall_user_dispatch(struct pt_regs *regs) ...@@ -56,7 +56,7 @@ bool syscall_user_dispatch(struct pt_regs *regs)
return false; return false;
if (state != SYSCALL_DISPATCH_FILTER_BLOCK) { if (state != SYSCALL_DISPATCH_FILTER_BLOCK) {
force_fatal_sig(SIGSYS); force_exit_sig(SIGSYS);
return true; return true;
} }
} }
......
...@@ -1298,6 +1298,12 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p ...@@ -1298,6 +1298,12 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p
return ret; return ret;
} }
enum sig_handler {
HANDLER_CURRENT, /* If reachable use the current handler */
HANDLER_SIG_DFL, /* Always use SIG_DFL handler semantics */
HANDLER_EXIT, /* Only visible as the process exit code */
};
/* /*
* Force a signal that the process can't ignore: if necessary * Force a signal that the process can't ignore: if necessary
* we unblock the signal and change any SIG_IGN to SIG_DFL. * we unblock the signal and change any SIG_IGN to SIG_DFL.
...@@ -1310,7 +1316,8 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p ...@@ -1310,7 +1316,8 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p
* that is why we also clear SIGNAL_UNKILLABLE. * that is why we also clear SIGNAL_UNKILLABLE.
*/ */
static int static int
force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool sigdfl) force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t,
enum sig_handler handler)
{ {
unsigned long int flags; unsigned long int flags;
int ret, blocked, ignored; int ret, blocked, ignored;
...@@ -1321,9 +1328,10 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool ...@@ -1321,9 +1328,10 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool
action = &t->sighand->action[sig-1]; action = &t->sighand->action[sig-1];
ignored = action->sa.sa_handler == SIG_IGN; ignored = action->sa.sa_handler == SIG_IGN;
blocked = sigismember(&t->blocked, sig); blocked = sigismember(&t->blocked, sig);
if (blocked || ignored || sigdfl) { if (blocked || ignored || (handler != HANDLER_CURRENT)) {
action->sa.sa_handler = SIG_DFL; action->sa.sa_handler = SIG_DFL;
action->sa.sa_flags |= SA_IMMUTABLE; if (handler == HANDLER_EXIT)
action->sa.sa_flags |= SA_IMMUTABLE;
if (blocked) { if (blocked) {
sigdelset(&t->blocked, sig); sigdelset(&t->blocked, sig);
recalc_sigpending_and_wake(t); recalc_sigpending_and_wake(t);
...@@ -1343,7 +1351,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool ...@@ -1343,7 +1351,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool
int force_sig_info(struct kernel_siginfo *info) int force_sig_info(struct kernel_siginfo *info)
{ {
return force_sig_info_to_task(info, current, false); return force_sig_info_to_task(info, current, HANDLER_CURRENT);
} }
/* /*
...@@ -1660,7 +1668,20 @@ void force_fatal_sig(int sig) ...@@ -1660,7 +1668,20 @@ void force_fatal_sig(int sig)
info.si_code = SI_KERNEL; info.si_code = SI_KERNEL;
info.si_pid = 0; info.si_pid = 0;
info.si_uid = 0; info.si_uid = 0;
force_sig_info_to_task(&info, current, true); force_sig_info_to_task(&info, current, HANDLER_SIG_DFL);
}
void force_exit_sig(int sig)
{
struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = sig;
info.si_errno = 0;
info.si_code = SI_KERNEL;
info.si_pid = 0;
info.si_uid = 0;
force_sig_info_to_task(&info, current, HANDLER_EXIT);
} }
/* /*
...@@ -1693,7 +1714,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addr ...@@ -1693,7 +1714,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addr
info.si_flags = flags; info.si_flags = flags;
info.si_isr = isr; info.si_isr = isr;
#endif #endif
return force_sig_info_to_task(&info, t, false); return force_sig_info_to_task(&info, t, HANDLER_CURRENT);
} }
int force_sig_fault(int sig, int code, void __user *addr int force_sig_fault(int sig, int code, void __user *addr
...@@ -1813,7 +1834,8 @@ int force_sig_seccomp(int syscall, int reason, bool force_coredump) ...@@ -1813,7 +1834,8 @@ int force_sig_seccomp(int syscall, int reason, bool force_coredump)
info.si_errno = reason; info.si_errno = reason;
info.si_arch = syscall_get_arch(current); info.si_arch = syscall_get_arch(current);
info.si_syscall = syscall; info.si_syscall = syscall;
return force_sig_info_to_task(&info, current, force_coredump); return force_sig_info_to_task(&info, current,
force_coredump ? HANDLER_EXIT : HANDLER_CURRENT);
} }
/* For the crazy architectures that include trap information in /* For the crazy architectures that include trap information in
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment