diff options
Diffstat (limited to 'arch/x86/kernel/signal_64.c')
-rw-r--r-- | arch/x86/kernel/signal_64.c | 108 |
1 files changed, 45 insertions, 63 deletions
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 1c83e5124c65..827179c5b32a 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -19,17 +19,28 @@ | |||
19 | #include <linux/stddef.h> | 19 | #include <linux/stddef.h> |
20 | #include <linux/personality.h> | 20 | #include <linux/personality.h> |
21 | #include <linux/compiler.h> | 21 | #include <linux/compiler.h> |
22 | #include <asm/processor.h> | ||
22 | #include <asm/ucontext.h> | 23 | #include <asm/ucontext.h> |
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <asm/i387.h> | 25 | #include <asm/i387.h> |
25 | #include <asm/proto.h> | 26 | #include <asm/proto.h> |
26 | #include <asm/ia32_unistd.h> | 27 | #include <asm/ia32_unistd.h> |
27 | #include <asm/mce.h> | 28 | #include <asm/mce.h> |
28 | 29 | #include "sigframe.h" | |
29 | /* #define DEBUG_SIG 1 */ | ||
30 | 30 | ||
31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
32 | 32 | ||
33 | #define __FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ | ||
34 | X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ | ||
35 | X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ | ||
36 | X86_EFLAGS_CF) | ||
37 | |||
38 | #ifdef CONFIG_X86_32 | ||
39 | # define FIX_EFLAGS (__FIX_EFLAGS | X86_EFLAGS_RF) | ||
40 | #else | ||
41 | # define FIX_EFLAGS __FIX_EFLAGS | ||
42 | #endif | ||
43 | |||
33 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 44 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
34 | sigset_t *set, struct pt_regs * regs); | 45 | sigset_t *set, struct pt_regs * regs); |
35 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | 46 | int ia32_setup_frame(int sig, struct k_sigaction *ka, |
@@ -46,16 +57,9 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
46 | /* | 57 | /* |
47 | * Do a signal return; undo the signal stack. | 58 | * Do a signal return; undo the signal stack. |
48 | */ | 59 | */ |
49 | |||
50 | struct rt_sigframe | ||
51 | { | ||
52 | char __user *pretcode; | ||
53 | struct ucontext uc; | ||
54 | struct siginfo info; | ||
55 | }; | ||
56 | |||
57 | static int | 60 | static int |
58 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax) | 61 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
62 | unsigned long *pax) | ||
59 | { | 63 | { |
60 | unsigned int err = 0; | 64 | unsigned int err = 0; |
61 | 65 | ||
@@ -87,7 +91,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned | |||
87 | { | 91 | { |
88 | unsigned int tmpflags; | 92 | unsigned int tmpflags; |
89 | err |= __get_user(tmpflags, &sc->flags); | 93 | err |= __get_user(tmpflags, &sc->flags); |
90 | regs->flags = (regs->flags & ~0x40DD5) | (tmpflags & 0x40DD5); | 94 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
91 | regs->orig_ax = -1; /* disable syscall checks */ | 95 | regs->orig_ax = -1; /* disable syscall checks */ |
92 | } | 96 | } |
93 | 97 | ||
@@ -108,7 +112,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned | |||
108 | } | 112 | } |
109 | } | 113 | } |
110 | 114 | ||
111 | err |= __get_user(*prax, &sc->ax); | 115 | err |= __get_user(*pax, &sc->ax); |
112 | return err; | 116 | return err; |
113 | 117 | ||
114 | badframe: | 118 | badframe: |
@@ -121,13 +125,11 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
121 | sigset_t set; | 125 | sigset_t set; |
122 | unsigned long ax; | 126 | unsigned long ax; |
123 | 127 | ||
124 | frame = (struct rt_sigframe __user *)(regs->sp - 8); | 128 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); |
125 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) { | 129 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
126 | goto badframe; | 130 | goto badframe; |
127 | } | 131 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
128 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) { | ||
129 | goto badframe; | 132 | goto badframe; |
130 | } | ||
131 | 133 | ||
132 | sigdelsetmask(&set, ~_BLOCKABLE); | 134 | sigdelsetmask(&set, ~_BLOCKABLE); |
133 | spin_lock_irq(¤t->sighand->siglock); | 135 | spin_lock_irq(¤t->sighand->siglock); |
@@ -138,10 +140,6 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
138 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 140 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) |
139 | goto badframe; | 141 | goto badframe; |
140 | 142 | ||
141 | #ifdef DEBUG_SIG | ||
142 | printk("%d sigreturn ip:%lx sp:%lx frame:%p ax:%lx\n",current->pid,regs->ip,regs->sp,frame,ax); | ||
143 | #endif | ||
144 | |||
145 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | 143 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) |
146 | goto badframe; | 144 | goto badframe; |
147 | 145 | ||
@@ -270,10 +268,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
270 | if (err) | 268 | if (err) |
271 | goto give_sigsegv; | 269 | goto give_sigsegv; |
272 | 270 | ||
273 | #ifdef DEBUG_SIG | ||
274 | printk("%d old ip %lx old sp %lx old ax %lx\n", current->pid,regs->ip,regs->sp,regs->ax); | ||
275 | #endif | ||
276 | |||
277 | /* Set up registers for signal handler */ | 271 | /* Set up registers for signal handler */ |
278 | regs->di = sig; | 272 | regs->di = sig; |
279 | /* In case the signal handler was declared without prototypes */ | 273 | /* In case the signal handler was declared without prototypes */ |
@@ -298,10 +292,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
298 | regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF); | 292 | regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF); |
299 | if (test_thread_flag(TIF_SINGLESTEP)) | 293 | if (test_thread_flag(TIF_SINGLESTEP)) |
300 | ptrace_notify(SIGTRAP); | 294 | ptrace_notify(SIGTRAP); |
301 | #ifdef DEBUG_SIG | ||
302 | printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%p\n", | ||
303 | current->comm, current->pid, frame, regs->ip, frame->pretcode); | ||
304 | #endif | ||
305 | 295 | ||
306 | return 0; | 296 | return 0; |
307 | 297 | ||
@@ -345,35 +335,29 @@ static long current_syscall_ret(struct pt_regs *regs) | |||
345 | 335 | ||
346 | static int | 336 | static int |
347 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 337 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
348 | sigset_t *oldset, struct pt_regs *regs) | 338 | sigset_t *oldset, struct pt_regs *regs) |
349 | { | 339 | { |
350 | int ret; | 340 | int ret; |
351 | 341 | ||
352 | #ifdef DEBUG_SIG | ||
353 | printk("handle_signal pid:%d sig:%lu ip:%lx sp:%lx regs=%p\n", | ||
354 | current->pid, sig, | ||
355 | regs->ip, regs->sp, regs); | ||
356 | #endif | ||
357 | |||
358 | /* Are we from a system call? */ | 342 | /* Are we from a system call? */ |
359 | if (current_syscall(regs) >= 0) { | 343 | if (current_syscall(regs) >= 0) { |
360 | /* If so, check system call restarting.. */ | 344 | /* If so, check system call restarting.. */ |
361 | switch (current_syscall_ret(regs)) { | 345 | switch (current_syscall_ret(regs)) { |
362 | case -ERESTART_RESTARTBLOCK: | 346 | case -ERESTART_RESTARTBLOCK: |
363 | case -ERESTARTNOHAND: | 347 | case -ERESTARTNOHAND: |
364 | regs->ax = -EINTR; | 348 | regs->ax = -EINTR; |
365 | break; | 349 | break; |
366 | 350 | ||
367 | case -ERESTARTSYS: | 351 | case -ERESTARTSYS: |
368 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 352 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
369 | regs->ax = -EINTR; | 353 | regs->ax = -EINTR; |
370 | break; | ||
371 | } | ||
372 | /* fallthrough */ | ||
373 | case -ERESTARTNOINTR: | ||
374 | regs->ax = regs->orig_ax; | ||
375 | regs->ip -= 2; | ||
376 | break; | 354 | break; |
355 | } | ||
356 | /* fallthrough */ | ||
357 | case -ERESTARTNOINTR: | ||
358 | regs->ax = regs->orig_ax; | ||
359 | regs->ip -= 2; | ||
360 | break; | ||
377 | } | 361 | } |
378 | } | 362 | } |
379 | 363 | ||
@@ -420,10 +404,11 @@ static void do_signal(struct pt_regs *regs) | |||
420 | sigset_t *oldset; | 404 | sigset_t *oldset; |
421 | 405 | ||
422 | /* | 406 | /* |
423 | * We want the common case to go fast, which | 407 | * We want the common case to go fast, which is why we may in certain |
424 | * is why we may in certain cases get here from | 408 | * cases get here from kernel mode. Just return without doing anything |
425 | * kernel mode. Just return without doing anything | ||
426 | * if so. | 409 | * if so. |
410 | * X86_32: vm86 regs switched out by assembly code before reaching | ||
411 | * here, so testing against kernel CS suffices. | ||
427 | */ | 412 | */ |
428 | if (!user_mode(regs)) | 413 | if (!user_mode(regs)) |
429 | return; | 414 | return; |
@@ -473,22 +458,19 @@ static void do_signal(struct pt_regs *regs) | |||
473 | } | 458 | } |
474 | } | 459 | } |
475 | 460 | ||
476 | /* if there's no signal to deliver, we just put the saved sigmask | 461 | /* |
477 | back. */ | 462 | * If there's no signal to deliver, we just put the saved sigmask |
463 | * back. | ||
464 | */ | ||
478 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 465 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
479 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 466 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
480 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 467 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
481 | } | 468 | } |
482 | } | 469 | } |
483 | 470 | ||
484 | void | 471 | void do_notify_resume(struct pt_regs *regs, void *unused, |
485 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | 472 | __u32 thread_info_flags) |
486 | { | 473 | { |
487 | #ifdef DEBUG_SIG | ||
488 | printk("do_notify_resume flags:%x ip:%lx sp:%lx caller:%p pending:%x\n", | ||
489 | thread_info_flags, regs->ip, regs->sp, __builtin_return_address(0),signal_pending(current)); | ||
490 | #endif | ||
491 | |||
492 | /* Pending single-step? */ | 474 | /* Pending single-step? */ |
493 | if (thread_info_flags & _TIF_SINGLESTEP) { | 475 | if (thread_info_flags & _TIF_SINGLESTEP) { |
494 | regs->flags |= X86_EFLAGS_TF; | 476 | regs->flags |= X86_EFLAGS_TF; |
@@ -502,7 +484,7 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
502 | #endif /* CONFIG_X86_MCE */ | 484 | #endif /* CONFIG_X86_MCE */ |
503 | 485 | ||
504 | /* deal with pending signal delivery */ | 486 | /* deal with pending signal delivery */ |
505 | if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK)) | 487 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
506 | do_signal(regs); | 488 | do_signal(regs); |
507 | 489 | ||
508 | if (thread_info_flags & _TIF_HRTICK_RESCHED) | 490 | if (thread_info_flags & _TIF_HRTICK_RESCHED) |