Commit 84e9c95a authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'x86/signal' into core/signal

parents 206855c3 1389ac4b
...@@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, ...@@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
savesegment(es, tmp); savesegment(es, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->es); err |= __put_user(tmp, (unsigned int __user *)&sc->es);
err |= __put_user((u32)regs->di, &sc->di); err |= __put_user(regs->di, &sc->di);
err |= __put_user((u32)regs->si, &sc->si); err |= __put_user(regs->si, &sc->si);
err |= __put_user((u32)regs->bp, &sc->bp); err |= __put_user(regs->bp, &sc->bp);
err |= __put_user((u32)regs->sp, &sc->sp); err |= __put_user(regs->sp, &sc->sp);
err |= __put_user((u32)regs->bx, &sc->bx); err |= __put_user(regs->bx, &sc->bx);
err |= __put_user((u32)regs->dx, &sc->dx); err |= __put_user(regs->dx, &sc->dx);
err |= __put_user((u32)regs->cx, &sc->cx); err |= __put_user(regs->cx, &sc->cx);
err |= __put_user((u32)regs->ax, &sc->ax); err |= __put_user(regs->ax, &sc->ax);
err |= __put_user((u32)regs->cs, &sc->cs); err |= __put_user(regs->cs, &sc->cs);
err |= __put_user((u32)regs->ss, &sc->ss); err |= __put_user(regs->ss, &sc->ss);
err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.trap_no, &sc->trapno);
err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(current->thread.error_code, &sc->err);
err |= __put_user((u32)regs->ip, &sc->ip); err |= __put_user(regs->ip, &sc->ip);
err |= __put_user((u32)regs->flags, &sc->flags); err |= __put_user(regs->flags, &sc->flags);
err |= __put_user((u32)regs->sp, &sc->sp_at_signal); err |= __put_user(regs->sp, &sc->sp_at_signal);
tmp = save_i387_xstate_ia32(fpstate); tmp = save_i387_xstate_ia32(fpstate);
if (tmp < 0) if (tmp < 0)
err = -EFAULT; err = -EFAULT;
else { else
clear_used_math();
stts();
err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
&sc->fpstate); &sc->fpstate);
}
/* non-iBCS2 extensions.. */ /* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask); err |= __put_user(mask, &sc->oldmask);
......
...@@ -113,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx) ...@@ -113,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx)
return do_sigaltstack(uss, uoss, regs->sp); return do_sigaltstack(uss, uoss, regs->sp);
} }
#define COPY(x) { \
err |= __get_user(regs->x, &sc->x); \
}
#define COPY_SEG(seg) { \
unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->seg = tmp; \
}
#define COPY_SEG_STRICT(seg) { \
unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->seg = tmp | 3; \
}
#define GET_SEG(seg) { \
unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
loadsegment(seg, tmp); \
}
/* /*
* Do a signal return; undo the signal stack. * Do a signal return; undo the signal stack.
...@@ -121,28 +142,13 @@ static int ...@@ -121,28 +142,13 @@ static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
unsigned long *pax) unsigned long *pax)
{ {
void __user *buf;
unsigned int tmpflags;
unsigned int err = 0; unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */ /* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall; current_thread_info()->restart_block.fn = do_no_restart_syscall;
#define COPY(x) err |= __get_user(regs->x, &sc->x)
#define COPY_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->seg = tmp; }
#define COPY_SEG_STRICT(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->seg = tmp|3; }
#define GET_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
loadsegment(seg, tmp); }
GET_SEG(gs); GET_SEG(gs);
COPY_SEG(fs); COPY_SEG(fs);
COPY_SEG(es); COPY_SEG(es);
...@@ -152,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, ...@@ -152,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
COPY_SEG_STRICT(cs); COPY_SEG_STRICT(cs);
COPY_SEG_STRICT(ss); COPY_SEG_STRICT(ss);
{ err |= __get_user(tmpflags, &sc->flags);
unsigned int tmpflags; regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
regs->orig_ax = -1; /* disable syscall checks */
err |= __get_user(tmpflags, &sc->flags);
regs->flags = (regs->flags & ~FIX_EFLAGS) |
(tmpflags & FIX_EFLAGS);
regs->orig_ax = -1; /* disable syscall checks */
}
{
void __user *buf;
err |= __get_user(buf, &sc->fpstate); err |= __get_user(buf, &sc->fpstate);
err |= restore_i387_xstate(buf); err |= restore_i387_xstate(buf);
}
err |= __get_user(*pax, &sc->ax); err |= __get_user(*pax, &sc->ax);
return err; return err;
...@@ -482,24 +479,34 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -482,24 +479,34 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* /*
* OK, we're invoking a handler: * OK, we're invoking a handler:
*/ */
static int signr_convert(int sig)
{
struct thread_info *info = current_thread_info();
if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
return info->exec_domain->signal_invmap[sig];
return sig;
}
#define is_ia32 1
#define ia32_setup_frame __setup_frame
#define ia32_setup_rt_frame __setup_rt_frame
static int static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs) sigset_t *set, struct pt_regs *regs)
{ {
int usig = signr_convert(sig);
int ret; int ret;
int usig;
usig = current_thread_info()->exec_domain
&& current_thread_info()->exec_domain->signal_invmap
&& sig < 32
? current_thread_info()->exec_domain->signal_invmap[sig]
: sig;
/* Set up the stack frame */ /* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO) if (is_ia32) {
ret = __setup_rt_frame(usig, ka, info, set, regs); if (ka->sa.sa_flags & SA_SIGINFO)
else ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
ret = __setup_frame(usig, ka, set, regs); else
ret = ia32_setup_frame(usig, ka, set, regs);
} else
ret = __setup_rt_frame(sig, ka, info, set, regs);
if (ret) { if (ret) {
force_sigsegv(sig, current); force_sigsegv(sig, current);
...@@ -550,6 +557,15 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, ...@@ -550,6 +557,15 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
if (ret) if (ret)
return ret; return ret;
#ifdef CONFIG_X86_64
/*
* This has nothing to do with segment registers,
* despite the name. This magic affects uaccess.h
* macros' behavior. Reset it to the normal setting.
*/
set_fs(USER_DS);
#endif
/* /*
* Clear the direction flag as per the ABI for function entry. * Clear the direction flag as per the ABI for function entry.
*/ */
...@@ -663,6 +679,12 @@ static void do_signal(struct pt_regs *regs) ...@@ -663,6 +679,12 @@ static void do_signal(struct pt_regs *regs)
void void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{ {
#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
/* notify userspace of pending MCEs */
if (thread_info_flags & _TIF_MCE_NOTIFY)
mce_notify_user();
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
/* deal with pending signal delivery */ /* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING) if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs); do_signal(regs);
...@@ -672,7 +694,9 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) ...@@ -672,7 +694,9 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
tracehook_notify_resume(regs); tracehook_notify_resume(regs);
} }
#ifdef CONFIG_X86_32
clear_thread_flag(TIF_IRET); clear_thread_flag(TIF_IRET);
#endif /* CONFIG_X86_32 */
} }
void signal_fault(struct pt_regs *regs, void __user *frame, char *where) void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
......
...@@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, ...@@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
return do_sigaltstack(uss, uoss, regs->sp); return do_sigaltstack(uss, uoss, regs->sp);
} }
#define COPY(x) { \
err |= __get_user(regs->x, &sc->x); \
}
#define COPY_SEG_STRICT(seg) { \
unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->seg = tmp | 3; \
}
/* /*
* Do a signal return; undo the signal stack. * Do a signal return; undo the signal stack.
*/ */
...@@ -59,13 +69,13 @@ static int ...@@ -59,13 +69,13 @@ static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
unsigned long *pax) unsigned long *pax)
{ {
void __user *buf;
unsigned int tmpflags;
unsigned int err = 0; unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */ /* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall; current_thread_info()->restart_block.fn = do_no_restart_syscall;
#define COPY(x) (err |= __get_user(regs->x, &sc->x))
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip); COPY(dx); COPY(cx); COPY(ip);
COPY(r8); COPY(r8);
...@@ -80,25 +90,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, ...@@ -80,25 +90,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
/* Kernel saves and restores only the CS segment register on signals, /* Kernel saves and restores only the CS segment register on signals,
* which is the bare minimum needed to allow mixed 32/64-bit code. * which is the bare minimum needed to allow mixed 32/64-bit code.
* App's signal handler can save/restore other segments if needed. */ * App's signal handler can save/restore other segments if needed. */
{ COPY_SEG_STRICT(cs);
unsigned cs;
err |= __get_user(cs, &sc->cs);
regs->cs = cs | 3; /* Force into user mode */
}
{ err |= __get_user(tmpflags, &sc->flags);
unsigned int tmpflags; regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
err |= __get_user(tmpflags, &sc->flags); regs->orig_ax = -1; /* disable syscall checks */
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
regs->orig_ax = -1; /* disable syscall checks */
}
{
void __user *buf;
err |= __get_user(buf, &sc->fpstate); err |= __get_user(buf, &sc->fpstate);
err |= restore_i387_xstate(buf); err |= restore_i387_xstate(buf);
}
err |= __get_user(*pax, &sc->ax); err |= __get_user(*pax, &sc->ax);
return err; return err;
...@@ -281,21 +280,32 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -281,21 +280,32 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* /*
* OK, we're invoking a handler * OK, we're invoking a handler
*/ */
static int signr_convert(int sig)
{
return sig;
}
#ifdef CONFIG_IA32_EMULATION
#define is_ia32 test_thread_flag(TIF_IA32)
#else
#define is_ia32 0
#endif
static int static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs) sigset_t *set, struct pt_regs *regs)
{ {
int usig = signr_convert(sig);
int ret; int ret;
#ifdef CONFIG_IA32_EMULATION /* Set up the stack frame */
if (test_thread_flag(TIF_IA32)) { if (is_ia32) {
if (ka->sa.sa_flags & SA_SIGINFO) if (ka->sa.sa_flags & SA_SIGINFO)
ret = ia32_setup_rt_frame(sig, ka, info, set, regs); ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
else else
ret = ia32_setup_frame(sig, ka, set, regs); ret = ia32_setup_frame(usig, ka, set, regs);
} else } else
#endif ret = __setup_rt_frame(sig, ka, info, set, regs);
ret = __setup_rt_frame(sig, ka, info, set, regs);
if (ret) { if (ret) {
force_sigsegv(sig, current); force_sigsegv(sig, current);
...@@ -346,12 +356,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, ...@@ -346,12 +356,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
if (ret) if (ret)
return ret; return ret;
#ifdef CONFIG_X86_64
/* /*
* This has nothing to do with segment registers, * This has nothing to do with segment registers,
* despite the name. This magic affects uaccess.h * despite the name. This magic affects uaccess.h
* macros' behavior. Reset it to the normal setting. * macros' behavior. Reset it to the normal setting.
*/ */
set_fs(USER_DS); set_fs(USER_DS);
#endif
/* /*
* Clear the direction flag as per the ABI for function entry. * Clear the direction flag as per the ABI for function entry.
...@@ -410,7 +422,8 @@ static void do_signal(struct pt_regs *regs) ...@@ -410,7 +422,8 @@ static void do_signal(struct pt_regs *regs)
signr = get_signal_to_deliver(&info, &ka, regs, NULL); signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) { if (signr > 0) {
/* Re-enable any watchpoints before delivering the /*
* Re-enable any watchpoints before delivering the
* signal to user space. The processor register will * signal to user space. The processor register will
* have been cleared if the watchpoint triggered * have been cleared if the watchpoint triggered
* inside the kernel. * inside the kernel.
...@@ -418,7 +431,7 @@ static void do_signal(struct pt_regs *regs) ...@@ -418,7 +431,7 @@ static void do_signal(struct pt_regs *regs)
if (current->thread.debugreg7) if (current->thread.debugreg7)
set_debugreg(current->thread.debugreg7, 7); set_debugreg(current->thread.debugreg7, 7);
/* Whee! Actually deliver the signal. */ /* Whee! Actually deliver the signal. */
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
/* /*
* A signal was successfully delivered; the saved * A signal was successfully delivered; the saved
...@@ -441,6 +454,7 @@ static void do_signal(struct pt_regs *regs) ...@@ -441,6 +454,7 @@ static void do_signal(struct pt_regs *regs)
regs->ax = regs->orig_ax; regs->ax = regs->orig_ax;
regs->ip -= 2; regs->ip -= 2;
break; break;
case -ERESTART_RESTARTBLOCK: case -ERESTART_RESTARTBLOCK:
regs->ax = NR_restart_syscall; regs->ax = NR_restart_syscall;
regs->ip -= 2; regs->ip -= 2;
...@@ -458,14 +472,18 @@ static void do_signal(struct pt_regs *regs) ...@@ -458,14 +472,18 @@ static void do_signal(struct pt_regs *regs)
} }
} }
void do_notify_resume(struct pt_regs *regs, void *unused, /*
__u32 thread_info_flags) * notification of userspace execution resumption
* - triggered by the TIF_WORK_MASK flags
*/
void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{ {
#ifdef CONFIG_X86_MCE #if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
/* notify userspace of pending MCEs */ /* notify userspace of pending MCEs */
if (thread_info_flags & _TIF_MCE_NOTIFY) if (thread_info_flags & _TIF_MCE_NOTIFY)
mce_notify_user(); mce_notify_user();
#endif /* CONFIG_X86_MCE */ #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
/* deal with pending signal delivery */ /* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING) if (thread_info_flags & _TIF_SIGPENDING)
...@@ -475,6 +493,10 @@ void do_notify_resume(struct pt_regs *regs, void *unused, ...@@ -475,6 +493,10 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
clear_thread_flag(TIF_NOTIFY_RESUME); clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs); tracehook_notify_resume(regs);
} }
#ifdef CONFIG_X86_32
clear_thread_flag(TIF_IRET);
#endif /* CONFIG_X86_32 */
} }
void signal_fault(struct pt_regs *regs, void __user *frame, char *where) void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
......
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