diff options
| -rw-r--r-- | arch/x86/kernel/signal_32.c | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/signal_64.c | 116 |
2 files changed, 121 insertions, 1 deletions
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index e9f71298e746..b1f4d34e0a38 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
| @@ -1,8 +1,10 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 1991, 1992 Linus Torvalds | 2 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs | ||
| 3 | * | 4 | * |
| 4 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson | 5 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson |
| 5 | * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes | 6 | * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes |
| 7 | * 2000-2002 x86-64 support by Andi Kleen | ||
| 6 | */ | 8 | */ |
| 7 | 9 | ||
| 8 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
| @@ -481,6 +483,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 481 | } | 483 | } |
| 482 | #endif /* CONFIG_X86_32 */ | 484 | #endif /* CONFIG_X86_32 */ |
| 483 | 485 | ||
| 486 | #ifdef CONFIG_X86_32 | ||
| 484 | /* | 487 | /* |
| 485 | * Atomically swap in the new signal mask, and wait for a signal. | 488 | * Atomically swap in the new signal mask, and wait for a signal. |
| 486 | */ | 489 | */ |
| @@ -535,6 +538,7 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
| 535 | 538 | ||
| 536 | return ret; | 539 | return ret; |
| 537 | } | 540 | } |
| 541 | #endif /* CONFIG_X86_32 */ | ||
| 538 | 542 | ||
| 539 | #ifdef CONFIG_X86_32 | 543 | #ifdef CONFIG_X86_32 |
| 540 | asmlinkage int sys_sigaltstack(unsigned long bx) | 544 | asmlinkage int sys_sigaltstack(unsigned long bx) |
| @@ -561,6 +565,7 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
| 561 | /* | 565 | /* |
| 562 | * Do a signal return; undo the signal stack. | 566 | * Do a signal return; undo the signal stack. |
| 563 | */ | 567 | */ |
| 568 | #ifdef CONFIG_X86_32 | ||
| 564 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 569 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) |
| 565 | { | 570 | { |
| 566 | struct sigframe __user *frame; | 571 | struct sigframe __user *frame; |
| @@ -603,6 +608,7 @@ badframe: | |||
| 603 | 608 | ||
| 604 | return 0; | 609 | return 0; |
| 605 | } | 610 | } |
| 611 | #endif /* CONFIG_X86_32 */ | ||
| 606 | 612 | ||
| 607 | static long do_rt_sigreturn(struct pt_regs *regs) | 613 | static long do_rt_sigreturn(struct pt_regs *regs) |
| 608 | { | 614 | { |
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 2da7e6e60807..b1f4d34e0a38 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
| @@ -54,12 +54,24 @@ | |||
| 54 | err |= __get_user(regs->x, &sc->x); \ | 54 | err |= __get_user(regs->x, &sc->x); \ |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | #define COPY_SEG(seg) { \ | ||
| 58 | unsigned short tmp; \ | ||
| 59 | err |= __get_user(tmp, &sc->seg); \ | ||
| 60 | regs->seg = tmp; \ | ||
| 61 | } | ||
| 62 | |||
| 57 | #define COPY_SEG_CPL3(seg) { \ | 63 | #define COPY_SEG_CPL3(seg) { \ |
| 58 | unsigned short tmp; \ | 64 | unsigned short tmp; \ |
| 59 | err |= __get_user(tmp, &sc->seg); \ | 65 | err |= __get_user(tmp, &sc->seg); \ |
| 60 | regs->seg = tmp | 3; \ | 66 | regs->seg = tmp | 3; \ |
| 61 | } | 67 | } |
| 62 | 68 | ||
| 69 | #define GET_SEG(seg) { \ | ||
| 70 | unsigned short tmp; \ | ||
| 71 | err |= __get_user(tmp, &sc->seg); \ | ||
| 72 | loadsegment(seg, tmp); \ | ||
| 73 | } | ||
| 74 | |||
| 63 | static int | 75 | static int |
| 64 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 76 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
| 65 | unsigned long *pax) | 77 | unsigned long *pax) |
| @@ -472,6 +484,63 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 472 | #endif /* CONFIG_X86_32 */ | 484 | #endif /* CONFIG_X86_32 */ |
| 473 | 485 | ||
| 474 | #ifdef CONFIG_X86_32 | 486 | #ifdef CONFIG_X86_32 |
| 487 | /* | ||
| 488 | * Atomically swap in the new signal mask, and wait for a signal. | ||
| 489 | */ | ||
| 490 | asmlinkage int | ||
| 491 | sys_sigsuspend(int history0, int history1, old_sigset_t mask) | ||
| 492 | { | ||
| 493 | mask &= _BLOCKABLE; | ||
| 494 | spin_lock_irq(¤t->sighand->siglock); | ||
| 495 | current->saved_sigmask = current->blocked; | ||
| 496 | siginitset(¤t->blocked, mask); | ||
| 497 | recalc_sigpending(); | ||
| 498 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 499 | |||
| 500 | current->state = TASK_INTERRUPTIBLE; | ||
| 501 | schedule(); | ||
| 502 | set_restore_sigmask(); | ||
| 503 | |||
| 504 | return -ERESTARTNOHAND; | ||
| 505 | } | ||
| 506 | |||
| 507 | asmlinkage int | ||
| 508 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
| 509 | struct old_sigaction __user *oact) | ||
| 510 | { | ||
| 511 | struct k_sigaction new_ka, old_ka; | ||
| 512 | int ret; | ||
| 513 | |||
| 514 | if (act) { | ||
| 515 | old_sigset_t mask; | ||
| 516 | |||
| 517 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
| 518 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
| 519 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
| 520 | return -EFAULT; | ||
| 521 | |||
| 522 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
| 523 | __get_user(mask, &act->sa_mask); | ||
| 524 | siginitset(&new_ka.sa.sa_mask, mask); | ||
| 525 | } | ||
| 526 | |||
| 527 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
| 528 | |||
| 529 | if (!ret && oact) { | ||
| 530 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
| 531 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
| 532 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
| 533 | return -EFAULT; | ||
| 534 | |||
| 535 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
| 536 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
| 537 | } | ||
| 538 | |||
| 539 | return ret; | ||
| 540 | } | ||
| 541 | #endif /* CONFIG_X86_32 */ | ||
| 542 | |||
| 543 | #ifdef CONFIG_X86_32 | ||
| 475 | asmlinkage int sys_sigaltstack(unsigned long bx) | 544 | asmlinkage int sys_sigaltstack(unsigned long bx) |
| 476 | { | 545 | { |
| 477 | /* | 546 | /* |
| @@ -496,6 +565,51 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
| 496 | /* | 565 | /* |
| 497 | * Do a signal return; undo the signal stack. | 566 | * Do a signal return; undo the signal stack. |
| 498 | */ | 567 | */ |
| 568 | #ifdef CONFIG_X86_32 | ||
| 569 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | ||
| 570 | { | ||
| 571 | struct sigframe __user *frame; | ||
| 572 | struct pt_regs *regs; | ||
| 573 | unsigned long ax; | ||
| 574 | sigset_t set; | ||
| 575 | |||
| 576 | regs = (struct pt_regs *) &__unused; | ||
| 577 | frame = (struct sigframe __user *)(regs->sp - 8); | ||
| 578 | |||
| 579 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
| 580 | goto badframe; | ||
| 581 | if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 | ||
| 582 | && __copy_from_user(&set.sig[1], &frame->extramask, | ||
| 583 | sizeof(frame->extramask)))) | ||
| 584 | goto badframe; | ||
| 585 | |||
| 586 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
| 587 | spin_lock_irq(¤t->sighand->siglock); | ||
| 588 | current->blocked = set; | ||
| 589 | recalc_sigpending(); | ||
| 590 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 591 | |||
| 592 | if (restore_sigcontext(regs, &frame->sc, &ax)) | ||
| 593 | goto badframe; | ||
| 594 | return ax; | ||
| 595 | |||
| 596 | badframe: | ||
| 597 | if (show_unhandled_signals && printk_ratelimit()) { | ||
| 598 | printk("%s%s[%d] bad frame in sigreturn frame:" | ||
| 599 | "%p ip:%lx sp:%lx oeax:%lx", | ||
| 600 | task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, | ||
| 601 | current->comm, task_pid_nr(current), frame, regs->ip, | ||
| 602 | regs->sp, regs->orig_ax); | ||
| 603 | print_vma_addr(" in ", regs->ip); | ||
| 604 | printk(KERN_CONT "\n"); | ||
| 605 | } | ||
| 606 | |||
| 607 | force_sig(SIGSEGV, current); | ||
| 608 | |||
| 609 | return 0; | ||
| 610 | } | ||
| 611 | #endif /* CONFIG_X86_32 */ | ||
| 612 | |||
| 499 | static long do_rt_sigreturn(struct pt_regs *regs) | 613 | static long do_rt_sigreturn(struct pt_regs *regs) |
| 500 | { | 614 | { |
| 501 | struct rt_sigframe __user *frame; | 615 | struct rt_sigframe __user *frame; |
| @@ -542,7 +656,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
| 542 | #endif /* CONFIG_X86_32 */ | 656 | #endif /* CONFIG_X86_32 */ |
| 543 | 657 | ||
| 544 | /* | 658 | /* |
| 545 | * OK, we're invoking a handler | 659 | * OK, we're invoking a handler: |
| 546 | */ | 660 | */ |
| 547 | static int signr_convert(int sig) | 661 | static int signr_convert(int sig) |
| 548 | { | 662 | { |
