signal/ia64: Use the generic force_sigsegv in setup_frame
The ia64 handling of failure to setup a signal frame has been trying to set overlapping fields in struct siginfo since 2.3.43. The si_pid and si_uid fields are stomped when the si_addr field is set. The si_code of SI_KERNEL indicates that si_pid and si_uid should be valid, and that si_addr does not exist. Being at odds with the definition of SI_KERNEL and with nothing to indicate that this was a signal frame setup failure there is no way for userspace to know that si_addr was filled out instead. In practice failure to setup a signal frame is rare, and si_pid and si_uid are always set to 0 when si_code is SI_KERNEL so I expect no one has looked closely enough before to see this weirdness. Further the only difference between force_sigsegv_info and the generic force_sigsegv other than the return code is that force_sigsegv_info stomps the si_uid and si_pid fields. Remove the bug and simplify the code by using force_sigsegv in this case just like other architectures. Fixes: 2.3.43 Cc: Tony Luck <tony.luck@intel.com> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: linux-ia64@vger.kernel.org Acked-by: Tony Luck <tony.luck@intel.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
parent
795a837145
commit
8b9c6b2831
@ -231,37 +231,6 @@ rbs_on_sig_stack (unsigned long bsp)
|
||||
return (bsp - current->sas_ss_sp < current->sas_ss_size);
|
||||
}
|
||||
|
||||
static long
|
||||
force_sigsegv_info (int sig, void __user *addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct siginfo si;
|
||||
|
||||
clear_siginfo(&si);
|
||||
if (sig == SIGSEGV) {
|
||||
/*
|
||||
* Acquiring siglock around the sa_handler-update is almost
|
||||
* certainly overkill, but this isn't a
|
||||
* performance-critical path and I'd rather play it safe
|
||||
* here than having to debug a nasty race if and when
|
||||
* something changes in kernel/signal.c that would make it
|
||||
* no longer safe to modify sa_handler without holding the
|
||||
* lock.
|
||||
*/
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL;
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
}
|
||||
si.si_signo = SIGSEGV;
|
||||
si.si_errno = 0;
|
||||
si.si_code = SI_KERNEL;
|
||||
si.si_pid = task_pid_vnr(current);
|
||||
si.si_uid = from_kuid_munged(current_user_ns(), current_uid());
|
||||
si.si_addr = addr;
|
||||
force_sig_info(SIGSEGV, &si, current);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long
|
||||
setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
|
||||
{
|
||||
@ -295,15 +264,18 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
|
||||
* instead so we will die with SIGSEGV.
|
||||
*/
|
||||
check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN;
|
||||
if (!likely(on_sig_stack(check_sp)))
|
||||
return force_sigsegv_info(ksig->sig, (void __user *)
|
||||
check_sp);
|
||||
if (!likely(on_sig_stack(check_sp))) {
|
||||
force_sigsegv(ksig->sig, current);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN);
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
return force_sigsegv_info(ksig->sig, frame);
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
|
||||
force_sigsegv(ksig->sig, current);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = __put_user(ksig->sig, &frame->arg0);
|
||||
err |= __put_user(&frame->info, &frame->arg1);
|
||||
@ -317,8 +289,10 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
|
||||
err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12);
|
||||
err |= setup_sigcontext(&frame->sc, set, scr);
|
||||
|
||||
if (unlikely(err))
|
||||
return force_sigsegv_info(ksig->sig, frame);
|
||||
if (unlikely(err)) {
|
||||
force_sigsegv(ksig->sig, current);
|
||||
return 1;
|
||||
}
|
||||
|
||||
scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */
|
||||
scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
|
||||
|
Loading…
Reference in New Issue
Block a user