diff options
Diffstat (limited to 'arch/x86/kernel/signal_32.c')
-rw-r--r-- | arch/x86/kernel/signal_32.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 6fb5bcdd8933..b21070ea33a4 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/wait.h> | 19 | #include <linux/wait.h> |
20 | #include <linux/tracehook.h> | ||
20 | #include <linux/elf.h> | 21 | #include <linux/elf.h> |
21 | #include <linux/smp.h> | 22 | #include <linux/smp.h> |
22 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | #include <asm/i387.h> | 28 | #include <asm/i387.h> |
28 | #include <asm/vdso.h> | 29 | #include <asm/vdso.h> |
30 | #include <asm/syscalls.h> | ||
29 | 31 | ||
30 | #include "sigframe.h" | 32 | #include "sigframe.h" |
31 | 33 | ||
@@ -159,28 +161,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
159 | } | 161 | } |
160 | 162 | ||
161 | { | 163 | { |
162 | struct _fpstate __user *buf; | 164 | void __user *buf; |
163 | 165 | ||
164 | err |= __get_user(buf, &sc->fpstate); | 166 | err |= __get_user(buf, &sc->fpstate); |
165 | if (buf) { | 167 | err |= restore_i387_xstate(buf); |
166 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
167 | goto badframe; | ||
168 | err |= restore_i387(buf); | ||
169 | } else { | ||
170 | struct task_struct *me = current; | ||
171 | |||
172 | if (used_math()) { | ||
173 | clear_fpu(me); | ||
174 | clear_used_math(); | ||
175 | } | ||
176 | } | ||
177 | } | 168 | } |
178 | 169 | ||
179 | err |= __get_user(*pax, &sc->ax); | 170 | err |= __get_user(*pax, &sc->ax); |
180 | return err; | 171 | return err; |
181 | |||
182 | badframe: | ||
183 | return 1; | ||
184 | } | 172 | } |
185 | 173 | ||
186 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 174 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) |
@@ -262,7 +250,7 @@ badframe: | |||
262 | * Set up a signal frame. | 250 | * Set up a signal frame. |
263 | */ | 251 | */ |
264 | static int | 252 | static int |
265 | setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | 253 | setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, |
266 | struct pt_regs *regs, unsigned long mask) | 254 | struct pt_regs *regs, unsigned long mask) |
267 | { | 255 | { |
268 | int tmp, err = 0; | 256 | int tmp, err = 0; |
@@ -289,7 +277,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
289 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 277 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
290 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 278 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); |
291 | 279 | ||
292 | tmp = save_i387(fpstate); | 280 | tmp = save_i387_xstate(fpstate); |
293 | if (tmp < 0) | 281 | if (tmp < 0) |
294 | err = 1; | 282 | err = 1; |
295 | else | 283 | else |
@@ -306,7 +294,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
306 | * Determine which stack to use.. | 294 | * Determine which stack to use.. |
307 | */ | 295 | */ |
308 | static inline void __user * | 296 | static inline void __user * |
309 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 297 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
298 | void **fpstate) | ||
310 | { | 299 | { |
311 | unsigned long sp; | 300 | unsigned long sp; |
312 | 301 | ||
@@ -332,6 +321,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
332 | sp = (unsigned long) ka->sa.sa_restorer; | 321 | sp = (unsigned long) ka->sa.sa_restorer; |
333 | } | 322 | } |
334 | 323 | ||
324 | if (used_math()) { | ||
325 | sp = sp - sig_xstate_size; | ||
326 | *fpstate = (struct _fpstate *) sp; | ||
327 | } | ||
328 | |||
335 | sp -= frame_size; | 329 | sp -= frame_size; |
336 | /* | 330 | /* |
337 | * Align the stack pointer according to the i386 ABI, | 331 | * Align the stack pointer according to the i386 ABI, |
@@ -350,8 +344,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
350 | void __user *restorer; | 344 | void __user *restorer; |
351 | int err = 0; | 345 | int err = 0; |
352 | int usig; | 346 | int usig; |
347 | void __user *fpstate = NULL; | ||
353 | 348 | ||
354 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 349 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
355 | 350 | ||
356 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 351 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
357 | goto give_sigsegv; | 352 | goto give_sigsegv; |
@@ -366,7 +361,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
366 | if (err) | 361 | if (err) |
367 | goto give_sigsegv; | 362 | goto give_sigsegv; |
368 | 363 | ||
369 | err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); | 364 | err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); |
370 | if (err) | 365 | if (err) |
371 | goto give_sigsegv; | 366 | goto give_sigsegv; |
372 | 367 | ||
@@ -427,8 +422,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
427 | void __user *restorer; | 422 | void __user *restorer; |
428 | int err = 0; | 423 | int err = 0; |
429 | int usig; | 424 | int usig; |
425 | void __user *fpstate = NULL; | ||
430 | 426 | ||
431 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 427 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
432 | 428 | ||
433 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 429 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
434 | goto give_sigsegv; | 430 | goto give_sigsegv; |
@@ -447,13 +443,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
447 | goto give_sigsegv; | 443 | goto give_sigsegv; |
448 | 444 | ||
449 | /* Create the ucontext. */ | 445 | /* Create the ucontext. */ |
450 | err |= __put_user(0, &frame->uc.uc_flags); | 446 | if (cpu_has_xsave) |
447 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
448 | else | ||
449 | err |= __put_user(0, &frame->uc.uc_flags); | ||
451 | err |= __put_user(0, &frame->uc.uc_link); | 450 | err |= __put_user(0, &frame->uc.uc_link); |
452 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 451 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
453 | err |= __put_user(sas_ss_flags(regs->sp), | 452 | err |= __put_user(sas_ss_flags(regs->sp), |
454 | &frame->uc.uc_stack.ss_flags); | 453 | &frame->uc.uc_stack.ss_flags); |
455 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 454 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
456 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 455 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
457 | regs, set->sig[0]); | 456 | regs, set->sig[0]); |
458 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 457 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
459 | if (err) | 458 | if (err) |
@@ -558,8 +557,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
558 | * handler too. | 557 | * handler too. |
559 | */ | 558 | */ |
560 | regs->flags &= ~X86_EFLAGS_TF; | 559 | regs->flags &= ~X86_EFLAGS_TF; |
561 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
562 | ptrace_notify(SIGTRAP); | ||
563 | 560 | ||
564 | spin_lock_irq(¤t->sighand->siglock); | 561 | spin_lock_irq(¤t->sighand->siglock); |
565 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | 562 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); |
@@ -568,6 +565,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
568 | recalc_sigpending(); | 565 | recalc_sigpending(); |
569 | spin_unlock_irq(¤t->sighand->siglock); | 566 | spin_unlock_irq(¤t->sighand->siglock); |
570 | 567 | ||
568 | tracehook_signal_handler(sig, info, ka, regs, | ||
569 | test_thread_flag(TIF_SINGLESTEP)); | ||
570 | |||
571 | return 0; | 571 | return 0; |
572 | } | 572 | } |
573 | 573 | ||
@@ -661,5 +661,10 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
661 | if (thread_info_flags & _TIF_SIGPENDING) | 661 | if (thread_info_flags & _TIF_SIGPENDING) |
662 | do_signal(regs); | 662 | do_signal(regs); |
663 | 663 | ||
664 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
665 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
666 | tracehook_notify_resume(regs); | ||
667 | } | ||
668 | |||
664 | clear_thread_flag(TIF_IRET); | 669 | clear_thread_flag(TIF_IRET); |
665 | } | 670 | } |