um: merge signal_{32,64}.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
committed by
Richard Weinberger
parent
fbe9868693
commit
f67aa2ffb7
@@ -9,7 +9,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
obj-y = bug.o bugs_$(BITS).o delay_$(BITS).o fault.o ksyms.o ldt.o \
|
obj-y = bug.o bugs_$(BITS).o delay_$(BITS).o fault.o ksyms.o ldt.o \
|
||||||
ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal_$(BITS).o \
|
ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
|
||||||
stub_$(BITS).o stub_segv.o syscalls_$(BITS).o \
|
stub_$(BITS).o stub_segv.o syscalls_$(BITS).o \
|
||||||
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
|
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
|
||||||
mem_$(BITS).o subarch.o os-$(OS)/
|
mem_$(BITS).o subarch.o os-$(OS)/
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
#define PT_REGS_ORIG_RAX(r) UPT_ORIG_RAX(&(r)->regs)
|
#define PT_REGS_ORIG_RAX(r) UPT_ORIG_RAX(&(r)->regs)
|
||||||
#define PT_REGS_RIP(r) UPT_IP(&(r)->regs)
|
#define PT_REGS_RIP(r) UPT_IP(&(r)->regs)
|
||||||
#define PT_REGS_RSP(r) UPT_SP(&(r)->regs)
|
#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
|
||||||
|
|
||||||
#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
|
#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
|
||||||
|
|
||||||
|
@@ -1,15 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
* Copyright (C) 2003 PathScale, Inc.
|
||||||
|
* Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
||||||
* Licensed under the GPL
|
* Licensed under the GPL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/personality.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <asm/unistd.h>
|
#include <asm/unistd.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/ucontext.h>
|
#include <asm/ucontext.h>
|
||||||
#include "frame_kern.h"
|
#include "frame_kern.h"
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FPU tag word conversions.
|
* FPU tag word conversions.
|
||||||
*/
|
*/
|
||||||
@@ -142,6 +148,8 @@ static int convert_fxsr_from_user(struct user_fxsr_struct *fxsave,
|
|||||||
|
|
||||||
extern int have_fpx_regs;
|
extern int have_fpx_regs;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int copy_sc_from_user(struct pt_regs *regs,
|
static int copy_sc_from_user(struct pt_regs *regs,
|
||||||
struct sigcontext __user *from)
|
struct sigcontext __user *from)
|
||||||
{
|
{
|
||||||
@@ -152,14 +160,14 @@ static int copy_sc_from_user(struct pt_regs *regs,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
pid = userspace_pid[current_thread_info()->cpu];
|
|
||||||
|
|
||||||
#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname
|
#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
GETREG(GS, gs);
|
GETREG(GS, gs);
|
||||||
GETREG(FS, fs);
|
GETREG(FS, fs);
|
||||||
GETREG(ES, es);
|
GETREG(ES, es);
|
||||||
GETREG(DS, ds);
|
GETREG(DS, ds);
|
||||||
|
#endif
|
||||||
GETREG(DI, di);
|
GETREG(DI, di);
|
||||||
GETREG(SI, si);
|
GETREG(SI, si);
|
||||||
GETREG(BP, bp);
|
GETREG(BP, bp);
|
||||||
@@ -169,11 +177,28 @@ static int copy_sc_from_user(struct pt_regs *regs,
|
|||||||
GETREG(CX, cx);
|
GETREG(CX, cx);
|
||||||
GETREG(AX, ax);
|
GETREG(AX, ax);
|
||||||
GETREG(IP, ip);
|
GETREG(IP, ip);
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
GETREG(R8, r8);
|
||||||
|
GETREG(R9, r9);
|
||||||
|
GETREG(R10, r10);
|
||||||
|
GETREG(R11, r11);
|
||||||
|
GETREG(R12, r12);
|
||||||
|
GETREG(R13, r13);
|
||||||
|
GETREG(R14, r14);
|
||||||
|
GETREG(R15, r15);
|
||||||
|
#endif
|
||||||
|
|
||||||
GETREG(CS, cs);
|
GETREG(CS, cs);
|
||||||
GETREG(EFLAGS, flags);
|
GETREG(EFLAGS, flags);
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
GETREG(SS, ss);
|
GETREG(SS, ss);
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef GETREG
|
#undef GETREG
|
||||||
|
|
||||||
|
pid = userspace_pid[current_thread_info()->cpu];
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
if (have_fpx_regs) {
|
if (have_fpx_regs) {
|
||||||
struct user_fxsr_struct fpx;
|
struct user_fxsr_struct fpx;
|
||||||
|
|
||||||
@@ -194,7 +219,9 @@ static int copy_sc_from_user(struct pt_regs *regs,
|
|||||||
-err);
|
-err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
struct user_i387_struct fp;
|
struct user_i387_struct fp;
|
||||||
|
|
||||||
err = copy_from_user(&fp, sc.fpstate,
|
err = copy_from_user(&fp, sc.fpstate,
|
||||||
@@ -210,43 +237,66 @@ static int copy_sc_from_user(struct pt_regs *regs,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_sc_to_user(struct sigcontext __user *to,
|
static int copy_sc_to_user(struct sigcontext __user *to,
|
||||||
struct _fpstate __user *to_fp, struct pt_regs *regs)
|
struct _fpstate __user *to_fp, struct pt_regs *regs,
|
||||||
|
unsigned long mask)
|
||||||
{
|
{
|
||||||
struct sigcontext sc;
|
struct sigcontext sc;
|
||||||
struct faultinfo * fi = ¤t->thread.arch.faultinfo;
|
struct faultinfo * fi = ¤t->thread.arch.faultinfo;
|
||||||
int err, pid;
|
int err, pid;
|
||||||
memset(&sc, 0, sizeof(struct sigcontext));
|
memset(&sc, 0, sizeof(struct sigcontext));
|
||||||
|
|
||||||
sc.gs = REGS_GS(regs->regs.gp);
|
#define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno]
|
||||||
sc.fs = REGS_FS(regs->regs.gp);
|
|
||||||
sc.es = REGS_ES(regs->regs.gp);
|
#ifdef CONFIG_X86_32
|
||||||
sc.ds = REGS_DS(regs->regs.gp);
|
PUTREG(GS, gs);
|
||||||
sc.di = REGS_EDI(regs->regs.gp);
|
PUTREG(FS, fs);
|
||||||
sc.si = REGS_ESI(regs->regs.gp);
|
PUTREG(ES, es);
|
||||||
sc.bp = REGS_EBP(regs->regs.gp);
|
PUTREG(DS, ds);
|
||||||
sc.sp = REGS_SP(regs->regs.gp);
|
#endif
|
||||||
sc.bx = REGS_EBX(regs->regs.gp);
|
PUTREG(DI, di);
|
||||||
sc.dx = REGS_EDX(regs->regs.gp);
|
PUTREG(SI, si);
|
||||||
sc.cx = REGS_ECX(regs->regs.gp);
|
PUTREG(BP, bp);
|
||||||
sc.ax = REGS_EAX(regs->regs.gp);
|
PUTREG(SP, sp);
|
||||||
sc.ip = REGS_IP(regs->regs.gp);
|
PUTREG(BX, bx);
|
||||||
sc.cs = REGS_CS(regs->regs.gp);
|
PUTREG(DX, dx);
|
||||||
sc.flags = REGS_EFLAGS(regs->regs.gp);
|
PUTREG(CX, cx);
|
||||||
sc.sp_at_signal = regs->regs.gp[UESP];
|
PUTREG(AX, ax);
|
||||||
sc.ss = regs->regs.gp[SS];
|
#ifdef CONFIG_X86_64
|
||||||
|
PUTREG(R8, r8);
|
||||||
|
PUTREG(R9, r9);
|
||||||
|
PUTREG(R10, r10);
|
||||||
|
PUTREG(R11, r11);
|
||||||
|
PUTREG(R12, r12);
|
||||||
|
PUTREG(R13, r13);
|
||||||
|
PUTREG(R14, r14);
|
||||||
|
PUTREG(R15, r15);
|
||||||
|
#endif
|
||||||
|
|
||||||
sc.cr2 = fi->cr2;
|
sc.cr2 = fi->cr2;
|
||||||
sc.err = fi->error_code;
|
sc.err = fi->error_code;
|
||||||
sc.trapno = fi->trap_no;
|
sc.trapno = fi->trap_no;
|
||||||
|
PUTREG(IP, ip);
|
||||||
to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
|
PUTREG(CS, cs);
|
||||||
|
PUTREG(EFLAGS, flags);
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
PUTREG(SP, sp_at_signal);
|
||||||
|
PUTREG(SS, ss);
|
||||||
|
#endif
|
||||||
|
#undef PUTREG
|
||||||
|
sc.oldmask = mask;
|
||||||
sc.fpstate = to_fp;
|
sc.fpstate = to_fp;
|
||||||
|
|
||||||
|
err = copy_to_user(to, &sc, sizeof(struct sigcontext));
|
||||||
|
if (err)
|
||||||
|
return 1;
|
||||||
|
|
||||||
pid = userspace_pid[current_thread_info()->cpu];
|
pid = userspace_pid[current_thread_info()->cpu];
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
if (have_fpx_regs) {
|
if (have_fpx_regs) {
|
||||||
struct user_fxsr_struct fpx;
|
struct user_fxsr_struct fpx;
|
||||||
|
|
||||||
@@ -269,8 +319,9 @@ static int copy_sc_to_user(struct sigcontext __user *to,
|
|||||||
if (copy_to_user(&to_fp->_fxsr_env[0], &fpx,
|
if (copy_to_user(&to_fp->_fxsr_env[0], &fpx,
|
||||||
sizeof(struct user_fxsr_struct)))
|
sizeof(struct user_fxsr_struct)))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else
|
||||||
else {
|
#endif
|
||||||
|
{
|
||||||
struct user_i387_struct fp;
|
struct user_i387_struct fp;
|
||||||
|
|
||||||
err = save_fp_registers(pid, (unsigned long *) &fp);
|
err = save_fp_registers(pid, (unsigned long *) &fp);
|
||||||
@@ -278,9 +329,10 @@ static int copy_sc_to_user(struct sigcontext __user *to,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy_to_user(to, &sc, sizeof(sc));
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
static int copy_ucontext_to_user(struct ucontext __user *uc,
|
static int copy_ucontext_to_user(struct ucontext __user *uc,
|
||||||
struct _fpstate __user *fp, sigset_t *set,
|
struct _fpstate __user *fp, sigset_t *set,
|
||||||
unsigned long sp)
|
unsigned long sp)
|
||||||
@@ -290,7 +342,7 @@ static int copy_ucontext_to_user(struct ucontext __user *uc,
|
|||||||
err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
|
err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
|
||||||
err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
|
err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
|
||||||
err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
|
err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
|
||||||
err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs);
|
err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, 0);
|
||||||
err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
|
err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -337,8 +389,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
|
|||||||
|
|
||||||
err |= __put_user(restorer, &frame->pretcode);
|
err |= __put_user(restorer, &frame->pretcode);
|
||||||
err |= __put_user(sig, &frame->sig);
|
err |= __put_user(sig, &frame->sig);
|
||||||
err |= copy_sc_to_user(&frame->sc, NULL, regs);
|
err |= copy_sc_to_user(&frame->sc, &frame->fpstate, regs, mask->sig[0]);
|
||||||
err |= __put_user(mask->sig[0], &frame->sc.oldmask);
|
|
||||||
if (_NSIG_WORDS > 1)
|
if (_NSIG_WORDS > 1)
|
||||||
err |= __copy_to_user(&frame->extramask, &mask->sig[1],
|
err |= __copy_to_user(&frame->extramask, &mask->sig[1],
|
||||||
sizeof(frame->extramask));
|
sizeof(frame->extramask));
|
||||||
@@ -418,7 +469,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long sys_sigreturn(struct pt_regs regs)
|
long sys_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long sp = PT_REGS_SP(¤t->thread.regs);
|
unsigned long sp = PT_REGS_SP(¤t->thread.regs);
|
||||||
struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
|
struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
|
||||||
@@ -447,16 +498,103 @@ long sys_sigreturn(struct pt_regs regs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long sys_rt_sigreturn(struct pt_regs regs)
|
#else
|
||||||
|
|
||||||
|
struct rt_sigframe
|
||||||
|
{
|
||||||
|
char __user *pretcode;
|
||||||
|
struct ucontext uc;
|
||||||
|
struct siginfo info;
|
||||||
|
struct _fpstate fpstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
int setup_signal_stack_si(unsigned long stack_top, int sig,
|
||||||
|
struct k_sigaction *ka, struct pt_regs * regs,
|
||||||
|
siginfo_t *info, sigset_t *set)
|
||||||
|
{
|
||||||
|
struct rt_sigframe __user *frame;
|
||||||
|
int err = 0;
|
||||||
|
struct task_struct *me = current;
|
||||||
|
|
||||||
|
frame = (struct rt_sigframe __user *)
|
||||||
|
round_down(stack_top - sizeof(struct rt_sigframe), 16);
|
||||||
|
/* Subtract 128 for a red zone and 8 for proper alignment */
|
||||||
|
frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (ka->sa.sa_flags & SA_SIGINFO) {
|
||||||
|
err |= copy_siginfo_to_user(&frame->info, info);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the ucontext. */
|
||||||
|
err |= __put_user(0, &frame->uc.uc_flags);
|
||||||
|
err |= __put_user(0, &frame->uc.uc_link);
|
||||||
|
err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||||
|
err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)),
|
||||||
|
&frame->uc.uc_stack.ss_flags);
|
||||||
|
err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||||
|
err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
|
||||||
|
set->sig[0]);
|
||||||
|
err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
|
||||||
|
if (sizeof(*set) == 16) {
|
||||||
|
__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
|
||||||
|
__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set,
|
||||||
|
sizeof(*set));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up to return from userspace. If provided, use a stub
|
||||||
|
* already in userspace.
|
||||||
|
*/
|
||||||
|
/* x86-64 should always use SA_RESTORER. */
|
||||||
|
if (ka->sa.sa_flags & SA_RESTORER)
|
||||||
|
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
|
||||||
|
else
|
||||||
|
/* could use a vstub here */
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Set up registers for signal handler */
|
||||||
|
{
|
||||||
|
struct exec_domain *ed = current_thread_info()->exec_domain;
|
||||||
|
if (unlikely(ed && ed->signal_invmap && sig < 32))
|
||||||
|
sig = ed->signal_invmap[sig];
|
||||||
|
}
|
||||||
|
|
||||||
|
PT_REGS_SP(regs) = (unsigned long) frame;
|
||||||
|
PT_REGS_RDI(regs) = sig;
|
||||||
|
/* In case the signal handler was declared without prototypes */
|
||||||
|
PT_REGS_RAX(regs) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This also works for non SA_SIGINFO handlers because they expect the
|
||||||
|
* next argument after the signal number on the stack.
|
||||||
|
*/
|
||||||
|
PT_REGS_RSI(regs) = (unsigned long) &frame->info;
|
||||||
|
PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
|
||||||
|
PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
long sys_rt_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long sp = PT_REGS_SP(¤t->thread.regs);
|
unsigned long sp = PT_REGS_SP(¤t->thread.regs);
|
||||||
struct rt_sigframe __user *frame =
|
struct rt_sigframe __user *frame =
|
||||||
(struct rt_sigframe __user *) (sp - 4);
|
(struct rt_sigframe __user *)(sp - sizeof(long));
|
||||||
sigset_t set;
|
|
||||||
struct ucontext __user *uc = &frame->uc;
|
struct ucontext __user *uc = &frame->uc;
|
||||||
int sig_size = _NSIG_WORDS * sizeof(unsigned long);
|
sigset_t set;
|
||||||
|
|
||||||
if (copy_from_user(&set, &uc->uc_sigmask, sig_size))
|
if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
|
||||||
goto segfault;
|
goto segfault;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
@@ -473,3 +611,14 @@ long sys_rt_sigreturn(struct pt_regs regs)
|
|||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
long ptregs_sigreturn(void)
|
||||||
|
{
|
||||||
|
return sys_sigreturn(NULL);
|
||||||
|
}
|
||||||
|
long ptregs_rt_sigreturn(void)
|
||||||
|
{
|
||||||
|
return sys_rt_sigreturn(NULL);
|
||||||
|
}
|
||||||
|
#endif
|
@@ -1,236 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2003 PathScale, Inc.
|
|
||||||
* Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/personality.h>
|
|
||||||
#include <linux/ptrace.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <asm/ucontext.h>
|
|
||||||
#include "frame_kern.h"
|
|
||||||
#include "skas.h"
|
|
||||||
|
|
||||||
static int copy_sc_from_user(struct pt_regs *regs,
|
|
||||||
struct sigcontext __user *from)
|
|
||||||
{
|
|
||||||
struct sigcontext sc;
|
|
||||||
struct user_i387_struct fp;
|
|
||||||
void __user *buf;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = copy_from_user(&sc, from, sizeof(sc));
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname
|
|
||||||
|
|
||||||
GETREG(R8, r8);
|
|
||||||
GETREG(R9, r9);
|
|
||||||
GETREG(R10, r10);
|
|
||||||
GETREG(R11, r11);
|
|
||||||
GETREG(R12, r12);
|
|
||||||
GETREG(R13, r13);
|
|
||||||
GETREG(R14, r14);
|
|
||||||
GETREG(R15, r15);
|
|
||||||
GETREG(DI, di);
|
|
||||||
GETREG(SI, si);
|
|
||||||
GETREG(BP, bp);
|
|
||||||
GETREG(BX, bx);
|
|
||||||
GETREG(DX, dx);
|
|
||||||
GETREG(AX, ax);
|
|
||||||
GETREG(CX, cx);
|
|
||||||
GETREG(SP, sp);
|
|
||||||
GETREG(IP, ip);
|
|
||||||
GETREG(EFLAGS, flags);
|
|
||||||
GETREG(CS, cs);
|
|
||||||
#undef GETREG
|
|
||||||
|
|
||||||
buf = sc.fpstate;
|
|
||||||
|
|
||||||
err = copy_from_user(&fp, buf, sizeof(struct user_i387_struct));
|
|
||||||
if (err)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
err = restore_fp_registers(userspace_pid[current_thread_info()->cpu],
|
|
||||||
(unsigned long *) &fp);
|
|
||||||
if (err < 0) {
|
|
||||||
printk(KERN_ERR "copy_sc_from_user - "
|
|
||||||
"restore_fp_registers failed, errno = %d\n",
|
|
||||||
-err);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int copy_sc_to_user(struct sigcontext __user *to,
|
|
||||||
struct _fpstate __user *to_fp, struct pt_regs *regs,
|
|
||||||
unsigned long mask)
|
|
||||||
{
|
|
||||||
struct faultinfo * fi = ¤t->thread.arch.faultinfo;
|
|
||||||
struct sigcontext sc;
|
|
||||||
struct user_i387_struct fp;
|
|
||||||
int err = 0;
|
|
||||||
memset(&sc, 0, sizeof(struct sigcontext));
|
|
||||||
|
|
||||||
#define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno]
|
|
||||||
|
|
||||||
PUTREG(DI, di);
|
|
||||||
PUTREG(SI, si);
|
|
||||||
PUTREG(BP, bp);
|
|
||||||
PUTREG(SP, sp);
|
|
||||||
PUTREG(BX, bx);
|
|
||||||
PUTREG(DX, dx);
|
|
||||||
PUTREG(CX, cx);
|
|
||||||
PUTREG(AX, ax);
|
|
||||||
PUTREG(R8, r8);
|
|
||||||
PUTREG(R9, r9);
|
|
||||||
PUTREG(R10, r10);
|
|
||||||
PUTREG(R11, r11);
|
|
||||||
PUTREG(R12, r12);
|
|
||||||
PUTREG(R13, r13);
|
|
||||||
PUTREG(R14, r14);
|
|
||||||
PUTREG(R15, r15);
|
|
||||||
PUTREG(CS, cs); /* XXX x86_64 doesn't do this */
|
|
||||||
|
|
||||||
sc.cr2 = fi->cr2;
|
|
||||||
sc.err = fi->error_code;
|
|
||||||
sc.trapno = fi->trap_no;
|
|
||||||
|
|
||||||
PUTREG(IP, ip);
|
|
||||||
PUTREG(EFLAGS, flags);
|
|
||||||
#undef PUTREG
|
|
||||||
|
|
||||||
sc.oldmask = mask;
|
|
||||||
|
|
||||||
err = copy_to_user(to, &sc, sizeof(struct sigcontext));
|
|
||||||
if (err)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
err = save_fp_registers(userspace_pid[current_thread_info()->cpu],
|
|
||||||
(unsigned long *) &fp);
|
|
||||||
if (err < 0) {
|
|
||||||
printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
|
|
||||||
"failed, errno = %d\n", -err);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct rt_sigframe
|
|
||||||
{
|
|
||||||
char __user *pretcode;
|
|
||||||
struct ucontext uc;
|
|
||||||
struct siginfo info;
|
|
||||||
struct _fpstate fpstate;
|
|
||||||
};
|
|
||||||
|
|
||||||
int setup_signal_stack_si(unsigned long stack_top, int sig,
|
|
||||||
struct k_sigaction *ka, struct pt_regs * regs,
|
|
||||||
siginfo_t *info, sigset_t *set)
|
|
||||||
{
|
|
||||||
struct rt_sigframe __user *frame;
|
|
||||||
int err = 0;
|
|
||||||
struct task_struct *me = current;
|
|
||||||
|
|
||||||
frame = (struct rt_sigframe __user *)
|
|
||||||
round_down(stack_top - sizeof(struct rt_sigframe), 16);
|
|
||||||
/* Subtract 128 for a red zone and 8 for proper alignment */
|
|
||||||
frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);
|
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (ka->sa.sa_flags & SA_SIGINFO) {
|
|
||||||
err |= copy_siginfo_to_user(&frame->info, info);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the ucontext. */
|
|
||||||
err |= __put_user(0, &frame->uc.uc_flags);
|
|
||||||
err |= __put_user(0, &frame->uc.uc_link);
|
|
||||||
err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
|
||||||
err |= __put_user(sas_ss_flags(PT_REGS_RSP(regs)),
|
|
||||||
&frame->uc.uc_stack.ss_flags);
|
|
||||||
err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
|
||||||
err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
|
|
||||||
set->sig[0]);
|
|
||||||
err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
|
|
||||||
if (sizeof(*set) == 16) {
|
|
||||||
__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
|
|
||||||
__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set,
|
|
||||||
sizeof(*set));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up to return from userspace. If provided, use a stub
|
|
||||||
* already in userspace.
|
|
||||||
*/
|
|
||||||
/* x86-64 should always use SA_RESTORER. */
|
|
||||||
if (ka->sa.sa_flags & SA_RESTORER)
|
|
||||||
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
|
|
||||||
else
|
|
||||||
/* could use a vstub here */
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/* Set up registers for signal handler */
|
|
||||||
{
|
|
||||||
struct exec_domain *ed = current_thread_info()->exec_domain;
|
|
||||||
if (unlikely(ed && ed->signal_invmap && sig < 32))
|
|
||||||
sig = ed->signal_invmap[sig];
|
|
||||||
}
|
|
||||||
|
|
||||||
PT_REGS_RSP(regs) = (unsigned long) frame;
|
|
||||||
PT_REGS_RDI(regs) = sig;
|
|
||||||
/* In case the signal handler was declared without prototypes */
|
|
||||||
PT_REGS_RAX(regs) = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This also works for non SA_SIGINFO handlers because they expect the
|
|
||||||
* next argument after the signal number on the stack.
|
|
||||||
*/
|
|
||||||
PT_REGS_RSI(regs) = (unsigned long) &frame->info;
|
|
||||||
PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
|
|
||||||
PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
long sys_rt_sigreturn(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
unsigned long sp = PT_REGS_SP(¤t->thread.regs);
|
|
||||||
struct rt_sigframe __user *frame =
|
|
||||||
(struct rt_sigframe __user *)(sp - 8);
|
|
||||||
struct ucontext __user *uc = &frame->uc;
|
|
||||||
sigset_t set;
|
|
||||||
|
|
||||||
if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
|
|
||||||
goto segfault;
|
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
|
||||||
set_current_blocked(&set);
|
|
||||||
|
|
||||||
if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext))
|
|
||||||
goto segfault;
|
|
||||||
|
|
||||||
/* Avoid ERESTART handling */
|
|
||||||
PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1;
|
|
||||||
return PT_REGS_SYSCALL_RET(¤t->thread.regs);
|
|
||||||
|
|
||||||
segfault:
|
|
||||||
force_sig(SIGSEGV, current);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -13,10 +13,8 @@
|
|||||||
#define ptregs_execve sys_execve
|
#define ptregs_execve sys_execve
|
||||||
#define ptregs_iopl sys_iopl
|
#define ptregs_iopl sys_iopl
|
||||||
#define ptregs_vm86old sys_vm86old
|
#define ptregs_vm86old sys_vm86old
|
||||||
#define ptregs_sigreturn sys_sigreturn
|
|
||||||
#define ptregs_clone sys_clone
|
#define ptregs_clone sys_clone
|
||||||
#define ptregs_vm86 sys_vm86
|
#define ptregs_vm86 sys_vm86
|
||||||
#define ptregs_rt_sigreturn sys_rt_sigreturn
|
|
||||||
#define ptregs_sigaltstack sys_sigaltstack
|
#define ptregs_sigaltstack sys_sigaltstack
|
||||||
#define ptregs_vfork sys_vfork
|
#define ptregs_vfork sys_vfork
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@ void __show_regs(struct pt_regs *regs)
|
|||||||
current->comm, print_tainted(), init_utsname()->release);
|
current->comm, print_tainted(), init_utsname()->release);
|
||||||
printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
|
printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
|
||||||
PT_REGS_RIP(regs));
|
PT_REGS_RIP(regs));
|
||||||
printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs),
|
printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_SP(regs),
|
||||||
PT_REGS_EFLAGS(regs));
|
PT_REGS_EFLAGS(regs));
|
||||||
printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
|
printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
|
||||||
PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
|
PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
|
||||||
|
Reference in New Issue
Block a user