diff options
Diffstat (limited to 'arch/x86/kernel/signal_64.c')
-rw-r--r-- | arch/x86/kernel/signal_64.c | 111 |
1 files changed, 44 insertions, 67 deletions
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 2f1464050059..694aa888bb19 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -15,17 +15,20 @@ | |||
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/wait.h> | 16 | #include <linux/wait.h> |
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/tracehook.h> | ||
18 | #include <linux/unistd.h> | 19 | #include <linux/unistd.h> |
19 | #include <linux/stddef.h> | 20 | #include <linux/stddef.h> |
20 | #include <linux/personality.h> | 21 | #include <linux/personality.h> |
21 | #include <linux/compiler.h> | 22 | #include <linux/compiler.h> |
23 | #include <linux/uaccess.h> | ||
24 | |||
22 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
23 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/i387.h> | 27 | #include <asm/i387.h> |
26 | #include <asm/proto.h> | 28 | #include <asm/proto.h> |
27 | #include <asm/ia32_unistd.h> | 29 | #include <asm/ia32_unistd.h> |
28 | #include <asm/mce.h> | 30 | #include <asm/mce.h> |
31 | #include <asm/syscall.h> | ||
29 | #include <asm/syscalls.h> | 32 | #include <asm/syscalls.h> |
30 | #include "sigframe.h" | 33 | #include "sigframe.h" |
31 | 34 | ||
@@ -42,11 +45,6 @@ | |||
42 | # define FIX_EFLAGS __FIX_EFLAGS | 45 | # define FIX_EFLAGS __FIX_EFLAGS |
43 | #endif | 46 | #endif |
44 | 47 | ||
45 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
46 | sigset_t *set, struct pt_regs * regs); | ||
47 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
48 | sigset_t *set, struct pt_regs * regs); | ||
49 | |||
50 | asmlinkage long | 48 | asmlinkage long |
51 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 49 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
52 | struct pt_regs *regs) | 50 | struct pt_regs *regs) |
@@ -129,7 +127,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
129 | /* Always make any pending restarted system calls return -EINTR */ | 127 | /* Always make any pending restarted system calls return -EINTR */ |
130 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 128 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
131 | 129 | ||
132 | #define COPY(x) err |= __get_user(regs->x, &sc->x) | 130 | #define COPY(x) (err |= __get_user(regs->x, &sc->x)) |
133 | 131 | ||
134 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 132 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
135 | COPY(dx); COPY(cx); COPY(ip); | 133 | COPY(dx); COPY(cx); COPY(ip); |
@@ -159,7 +157,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
159 | } | 157 | } |
160 | 158 | ||
161 | { | 159 | { |
162 | struct _fpstate __user * buf; | 160 | struct _fpstate __user *buf; |
163 | err |= __get_user(buf, &sc->fpstate); | 161 | err |= __get_user(buf, &sc->fpstate); |
164 | 162 | ||
165 | if (buf) { | 163 | if (buf) { |
@@ -199,7 +197,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
199 | current->blocked = set; | 197 | current->blocked = set; |
200 | recalc_sigpending(); | 198 | recalc_sigpending(); |
201 | spin_unlock_irq(¤t->sighand->siglock); | 199 | spin_unlock_irq(¤t->sighand->siglock); |
202 | 200 | ||
203 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 201 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) |
204 | goto badframe; | 202 | goto badframe; |
205 | 203 | ||
@@ -209,16 +207,17 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
209 | return ax; | 207 | return ax; |
210 | 208 | ||
211 | badframe: | 209 | badframe: |
212 | signal_fault(regs,frame,"sigreturn"); | 210 | signal_fault(regs, frame, "sigreturn"); |
213 | return 0; | 211 | return 0; |
214 | } | 212 | } |
215 | 213 | ||
216 | /* | 214 | /* |
217 | * Set up a signal frame. | 215 | * Set up a signal frame. |
218 | */ | 216 | */ |
219 | 217 | ||
220 | static inline int | 218 | static inline int |
221 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me) | 219 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
220 | unsigned long mask, struct task_struct *me) | ||
222 | { | 221 | { |
223 | int err = 0; | 222 | int err = 0; |
224 | 223 | ||
@@ -274,35 +273,35 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) | |||
274 | } | 273 | } |
275 | 274 | ||
276 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 275 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
277 | sigset_t *set, struct pt_regs * regs) | 276 | sigset_t *set, struct pt_regs *regs) |
278 | { | 277 | { |
279 | struct rt_sigframe __user *frame; | 278 | struct rt_sigframe __user *frame; |
280 | struct _fpstate __user *fp = NULL; | 279 | struct _fpstate __user *fp = NULL; |
281 | int err = 0; | 280 | int err = 0; |
282 | struct task_struct *me = current; | 281 | struct task_struct *me = current; |
283 | 282 | ||
284 | if (used_math()) { | 283 | if (used_math()) { |
285 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); | 284 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); |
286 | frame = (void __user *)round_down( | 285 | frame = (void __user *)round_down( |
287 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | 286 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
288 | 287 | ||
289 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) | 288 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) |
290 | goto give_sigsegv; | 289 | goto give_sigsegv; |
291 | 290 | ||
292 | if (save_i387(fp) < 0) | 291 | if (save_i387(fp) < 0) |
293 | err |= -1; | 292 | err |= -1; |
294 | } else | 293 | } else |
295 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; | 294 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
296 | 295 | ||
297 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 296 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
298 | goto give_sigsegv; | 297 | goto give_sigsegv; |
299 | 298 | ||
300 | if (ka->sa.sa_flags & SA_SIGINFO) { | 299 | if (ka->sa.sa_flags & SA_SIGINFO) { |
301 | err |= copy_siginfo_to_user(&frame->info, info); | 300 | err |= copy_siginfo_to_user(&frame->info, info); |
302 | if (err) | 301 | if (err) |
303 | goto give_sigsegv; | 302 | goto give_sigsegv; |
304 | } | 303 | } |
305 | 304 | ||
306 | /* Create the ucontext. */ | 305 | /* Create the ucontext. */ |
307 | err |= __put_user(0, &frame->uc.uc_flags); | 306 | err |= __put_user(0, &frame->uc.uc_flags); |
308 | err |= __put_user(0, &frame->uc.uc_link); | 307 | err |= __put_user(0, &frame->uc.uc_link); |
@@ -312,9 +311,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
312 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 311 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
313 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); | 312 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); |
314 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); | 313 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); |
315 | if (sizeof(*set) == 16) { | 314 | if (sizeof(*set) == 16) { |
316 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | 315 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); |
317 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); | 316 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); |
318 | } else | 317 | } else |
319 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 318 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
320 | 319 | ||
@@ -325,7 +324,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
325 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 324 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
326 | } else { | 325 | } else { |
327 | /* could use a vstub here */ | 326 | /* could use a vstub here */ |
328 | goto give_sigsegv; | 327 | goto give_sigsegv; |
329 | } | 328 | } |
330 | 329 | ||
331 | if (err) | 330 | if (err) |
@@ -333,7 +332,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
333 | 332 | ||
334 | /* Set up registers for signal handler */ | 333 | /* Set up registers for signal handler */ |
335 | regs->di = sig; | 334 | regs->di = sig; |
336 | /* In case the signal handler was declared without prototypes */ | 335 | /* In case the signal handler was declared without prototypes */ |
337 | regs->ax = 0; | 336 | regs->ax = 0; |
338 | 337 | ||
339 | /* This also works for non SA_SIGINFO handlers because they expect the | 338 | /* This also works for non SA_SIGINFO handlers because they expect the |
@@ -356,37 +355,8 @@ give_sigsegv: | |||
356 | } | 355 | } |
357 | 356 | ||
358 | /* | 357 | /* |
359 | * Return -1L or the syscall number that @regs is executing. | ||
360 | */ | ||
361 | static long current_syscall(struct pt_regs *regs) | ||
362 | { | ||
363 | /* | ||
364 | * We always sign-extend a -1 value being set here, | ||
365 | * so this is always either -1L or a syscall number. | ||
366 | */ | ||
367 | return regs->orig_ax; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Return a value that is -EFOO if the system call in @regs->orig_ax | ||
372 | * returned an error. This only works for @regs from @current. | ||
373 | */ | ||
374 | static long current_syscall_ret(struct pt_regs *regs) | ||
375 | { | ||
376 | #ifdef CONFIG_IA32_EMULATION | ||
377 | if (test_thread_flag(TIF_IA32)) | ||
378 | /* | ||
379 | * Sign-extend the value so (int)-EFOO becomes (long)-EFOO | ||
380 | * and will match correctly in comparisons. | ||
381 | */ | ||
382 | return (int) regs->ax; | ||
383 | #endif | ||
384 | return regs->ax; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * OK, we're invoking a handler | 358 | * OK, we're invoking a handler |
389 | */ | 359 | */ |
390 | 360 | ||
391 | static int | 361 | static int |
392 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 362 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
@@ -395,9 +365,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
395 | int ret; | 365 | int ret; |
396 | 366 | ||
397 | /* Are we from a system call? */ | 367 | /* Are we from a system call? */ |
398 | if (current_syscall(regs) >= 0) { | 368 | if (syscall_get_nr(current, regs) >= 0) { |
399 | /* If so, check system call restarting.. */ | 369 | /* If so, check system call restarting.. */ |
400 | switch (current_syscall_ret(regs)) { | 370 | switch (syscall_get_error(current, regs)) { |
401 | case -ERESTART_RESTARTBLOCK: | 371 | case -ERESTART_RESTARTBLOCK: |
402 | case -ERESTARTNOHAND: | 372 | case -ERESTARTNOHAND: |
403 | regs->ax = -EINTR; | 373 | regs->ax = -EINTR; |
@@ -430,7 +400,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
430 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); | 400 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); |
431 | else | 401 | else |
432 | ret = ia32_setup_frame(sig, ka, oldset, regs); | 402 | ret = ia32_setup_frame(sig, ka, oldset, regs); |
433 | } else | 403 | } else |
434 | #endif | 404 | #endif |
435 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 405 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
436 | 406 | ||
@@ -454,15 +424,16 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
454 | * handler too. | 424 | * handler too. |
455 | */ | 425 | */ |
456 | regs->flags &= ~X86_EFLAGS_TF; | 426 | regs->flags &= ~X86_EFLAGS_TF; |
457 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
458 | ptrace_notify(SIGTRAP); | ||
459 | 427 | ||
460 | spin_lock_irq(¤t->sighand->siglock); | 428 | spin_lock_irq(¤t->sighand->siglock); |
461 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 429 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); |
462 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 430 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
463 | sigaddset(¤t->blocked,sig); | 431 | sigaddset(¤t->blocked, sig); |
464 | recalc_sigpending(); | 432 | recalc_sigpending(); |
465 | spin_unlock_irq(¤t->sighand->siglock); | 433 | spin_unlock_irq(¤t->sighand->siglock); |
434 | |||
435 | tracehook_signal_handler(sig, info, ka, regs, | ||
436 | test_thread_flag(TIF_SINGLESTEP)); | ||
466 | } | 437 | } |
467 | 438 | ||
468 | return ret; | 439 | return ret; |
@@ -519,9 +490,9 @@ static void do_signal(struct pt_regs *regs) | |||
519 | } | 490 | } |
520 | 491 | ||
521 | /* Did we come from a system call? */ | 492 | /* Did we come from a system call? */ |
522 | if (current_syscall(regs) >= 0) { | 493 | if (syscall_get_nr(current, regs) >= 0) { |
523 | /* Restart the system call - no handlers present */ | 494 | /* Restart the system call - no handlers present */ |
524 | switch (current_syscall_ret(regs)) { | 495 | switch (syscall_get_error(current, regs)) { |
525 | case -ERESTARTNOHAND: | 496 | case -ERESTARTNOHAND: |
526 | case -ERESTARTSYS: | 497 | case -ERESTARTSYS: |
527 | case -ERESTARTNOINTR: | 498 | case -ERESTARTNOINTR: |
@@ -559,17 +530,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused, | |||
559 | /* deal with pending signal delivery */ | 530 | /* deal with pending signal delivery */ |
560 | if (thread_info_flags & _TIF_SIGPENDING) | 531 | if (thread_info_flags & _TIF_SIGPENDING) |
561 | do_signal(regs); | 532 | do_signal(regs); |
533 | |||
534 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
535 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
536 | tracehook_notify_resume(regs); | ||
537 | } | ||
562 | } | 538 | } |
563 | 539 | ||
564 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 540 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |
565 | { | 541 | { |
566 | struct task_struct *me = current; | 542 | struct task_struct *me = current; |
567 | if (show_unhandled_signals && printk_ratelimit()) { | 543 | if (show_unhandled_signals && printk_ratelimit()) { |
568 | printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | 544 | printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", |
569 | me->comm,me->pid,where,frame,regs->ip,regs->sp,regs->orig_ax); | 545 | me->comm, me->pid, where, frame, regs->ip, |
546 | regs->sp, regs->orig_ax); | ||
570 | print_vma_addr(" in ", regs->ip); | 547 | print_vma_addr(" in ", regs->ip); |
571 | printk("\n"); | 548 | printk("\n"); |
572 | } | 549 | } |
573 | 550 | ||
574 | force_sig(SIGSEGV, me); | 551 | force_sig(SIGSEGV, me); |
575 | } | 552 | } |