.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * PowerPC version |
---|
3 | 4 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
---|
.. | .. |
---|
5 | 6 | * Derived from "arch/i386/kernel/signal.c" |
---|
6 | 7 | * Copyright (C) 1991, 1992 Linus Torvalds |
---|
7 | 8 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or |
---|
10 | | - * modify it under the terms of the GNU General Public License |
---|
11 | | - * as published by the Free Software Foundation; either version |
---|
12 | | - * 2 of the License, or (at your option) any later version. |
---|
13 | 9 | */ |
---|
14 | 10 | |
---|
15 | 11 | #include <linux/sched.h> |
---|
.. | .. |
---|
25 | 21 | #include <linux/ptrace.h> |
---|
26 | 22 | #include <linux/ratelimit.h> |
---|
27 | 23 | #include <linux/syscalls.h> |
---|
| 24 | +#include <linux/pagemap.h> |
---|
28 | 25 | |
---|
29 | 26 | #include <asm/sigcontext.h> |
---|
30 | 27 | #include <asm/ucontext.h> |
---|
31 | 28 | #include <linux/uaccess.h> |
---|
32 | | -#include <asm/pgtable.h> |
---|
33 | 29 | #include <asm/unistd.h> |
---|
34 | 30 | #include <asm/cacheflush.h> |
---|
35 | 31 | #include <asm/syscalls.h> |
---|
.. | .. |
---|
44 | 40 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) |
---|
45 | 41 | #define FP_REGS_SIZE sizeof(elf_fpregset_t) |
---|
46 | 42 | |
---|
47 | | -#define TRAMP_TRACEBACK 3 |
---|
48 | | -#define TRAMP_SIZE 6 |
---|
| 43 | +#define TRAMP_TRACEBACK 4 |
---|
| 44 | +#define TRAMP_SIZE 7 |
---|
49 | 45 | |
---|
50 | 46 | /* |
---|
51 | 47 | * When we have signals to deliver, we set up on the user stack, |
---|
.. | .. |
---|
354 | 350 | err |= __get_user(regs->link, &sc->gp_regs[PT_LNK]); |
---|
355 | 351 | err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]); |
---|
356 | 352 | err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]); |
---|
357 | | - /* skip SOFTE */ |
---|
358 | | - regs->trap = 0; |
---|
| 353 | + /* Don't allow userspace to set SOFTE */ |
---|
| 354 | + set_trap_norestart(regs); |
---|
359 | 355 | err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); |
---|
360 | 356 | err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); |
---|
361 | 357 | err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]); |
---|
.. | .. |
---|
376 | 372 | err |= __get_user(v_regs, &sc->v_regs); |
---|
377 | 373 | if (err) |
---|
378 | 374 | return err; |
---|
379 | | - if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128))) |
---|
| 375 | + if (v_regs && !access_ok(v_regs, 34 * sizeof(vector128))) |
---|
380 | 376 | return -EFAULT; |
---|
381 | 377 | /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ |
---|
382 | 378 | if (v_regs != NULL && (msr & MSR_VEC) != 0) { |
---|
.. | .. |
---|
476 | 472 | &sc->gp_regs[PT_XER]); |
---|
477 | 473 | err |= __get_user(tsk->thread.ckpt_regs.ccr, |
---|
478 | 474 | &sc->gp_regs[PT_CCR]); |
---|
479 | | - |
---|
480 | | - /* Don't allow userspace to set the trap value */ |
---|
481 | | - regs->trap = 0; |
---|
482 | | - |
---|
| 475 | + /* Don't allow userspace to set SOFTE */ |
---|
| 476 | + set_trap_norestart(regs); |
---|
483 | 477 | /* These regs are not checkpointed; they can go in 'regs'. */ |
---|
484 | 478 | err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); |
---|
485 | 479 | err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); |
---|
.. | .. |
---|
497 | 491 | err |= __get_user(tm_v_regs, &tm_sc->v_regs); |
---|
498 | 492 | if (err) |
---|
499 | 493 | return err; |
---|
500 | | - if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128))) |
---|
| 494 | + if (v_regs && !access_ok(v_regs, 34 * sizeof(vector128))) |
---|
501 | 495 | return -EFAULT; |
---|
502 | | - if (tm_v_regs && !access_ok(VERIFY_READ, |
---|
503 | | - tm_v_regs, 34 * sizeof(vector128))) |
---|
| 496 | + if (tm_v_regs && !access_ok(tm_v_regs, 34 * sizeof(vector128))) |
---|
504 | 497 | return -EFAULT; |
---|
505 | 498 | /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ |
---|
506 | 499 | if (v_regs != NULL && tm_v_regs != NULL && (msr & MSR_VEC) != 0) { |
---|
.. | .. |
---|
561 | 554 | preempt_disable(); |
---|
562 | 555 | |
---|
563 | 556 | /* pull in MSR TS bits from user context */ |
---|
564 | | - regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); |
---|
| 557 | + regs->msr |= msr & MSR_TS_MASK; |
---|
565 | 558 | |
---|
566 | 559 | /* |
---|
567 | 560 | * Ensure that TM is enabled in regs->msr before we leave the signal |
---|
.. | .. |
---|
608 | 601 | int i; |
---|
609 | 602 | long err = 0; |
---|
610 | 603 | |
---|
| 604 | + /* bctrl # call the handler */ |
---|
| 605 | + err |= __put_user(PPC_INST_BCTRL, &tramp[0]); |
---|
611 | 606 | /* addi r1, r1, __SIGNAL_FRAMESIZE # Pop the dummy stackframe */ |
---|
612 | | - err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]); |
---|
| 607 | + err |= __put_user(PPC_INST_ADDI | __PPC_RT(R1) | __PPC_RA(R1) | |
---|
| 608 | + (__SIGNAL_FRAMESIZE & 0xffff), &tramp[1]); |
---|
613 | 609 | /* li r0, __NR_[rt_]sigreturn| */ |
---|
614 | | - err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]); |
---|
| 610 | + err |= __put_user(PPC_INST_ADDI | (syscall & 0xffff), &tramp[2]); |
---|
615 | 611 | /* sc */ |
---|
616 | | - err |= __put_user(0x44000002UL, &tramp[2]); |
---|
| 612 | + err |= __put_user(PPC_INST_SC, &tramp[3]); |
---|
617 | 613 | |
---|
618 | 614 | /* Minimal traceback info */ |
---|
619 | 615 | for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++) |
---|
.. | .. |
---|
639 | 635 | SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, |
---|
640 | 636 | struct ucontext __user *, new_ctx, long, ctx_size) |
---|
641 | 637 | { |
---|
642 | | - unsigned char tmp; |
---|
643 | 638 | sigset_t set; |
---|
644 | 639 | unsigned long new_msr = 0; |
---|
645 | 640 | int ctx_has_vsx_region = 0; |
---|
.. | .. |
---|
665 | 660 | ctx_has_vsx_region = 1; |
---|
666 | 661 | |
---|
667 | 662 | if (old_ctx != NULL) { |
---|
668 | | - if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size) |
---|
| 663 | + if (!access_ok(old_ctx, ctx_size) |
---|
669 | 664 | || setup_sigcontext(&old_ctx->uc_mcontext, current, 0, NULL, 0, |
---|
670 | 665 | ctx_has_vsx_region) |
---|
671 | 666 | || __copy_to_user(&old_ctx->uc_sigmask, |
---|
.. | .. |
---|
674 | 669 | } |
---|
675 | 670 | if (new_ctx == NULL) |
---|
676 | 671 | return 0; |
---|
677 | | - if (!access_ok(VERIFY_READ, new_ctx, ctx_size) |
---|
678 | | - || __get_user(tmp, (u8 __user *) new_ctx) |
---|
679 | | - || __get_user(tmp, (u8 __user *) new_ctx + ctx_size - 1)) |
---|
| 672 | + if (!access_ok(new_ctx, ctx_size) || |
---|
| 673 | + fault_in_pages_readable((u8 __user *)new_ctx, ctx_size)) |
---|
680 | 674 | return -EFAULT; |
---|
681 | 675 | |
---|
682 | 676 | /* |
---|
.. | .. |
---|
719 | 713 | /* Always make any pending restarted system calls return -EINTR */ |
---|
720 | 714 | current->restart_block.fn = do_no_restart_syscall; |
---|
721 | 715 | |
---|
722 | | - if (!access_ok(VERIFY_READ, uc, sizeof(*uc))) |
---|
| 716 | + if (!access_ok(uc, sizeof(*uc))) |
---|
723 | 717 | goto badframe; |
---|
724 | 718 | |
---|
725 | 719 | if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) |
---|
.. | .. |
---|
739 | 733 | */ |
---|
740 | 734 | if (MSR_TM_SUSPENDED(mfmsr())) |
---|
741 | 735 | tm_reclaim_current(0); |
---|
| 736 | + |
---|
| 737 | + /* |
---|
| 738 | + * Disable MSR[TS] bit also, so, if there is an exception in the |
---|
| 739 | + * code below (as a page fault in copy_ckvsx_to_user()), it does |
---|
| 740 | + * not recheckpoint this task if there was a context switch inside |
---|
| 741 | + * the exception. |
---|
| 742 | + * |
---|
| 743 | + * A major page fault can indirectly call schedule(). A reschedule |
---|
| 744 | + * process in the middle of an exception can have a side effect |
---|
| 745 | + * (Changing the CPU MSR[TS] state), since schedule() is called |
---|
| 746 | + * with the CPU MSR[TS] disable and returns with MSR[TS]=Suspended |
---|
| 747 | + * (switch_to() calls tm_recheckpoint() for the 'new' process). In |
---|
| 748 | + * this case, the process continues to be the same in the CPU, but |
---|
| 749 | + * the CPU state just changed. |
---|
| 750 | + * |
---|
| 751 | + * This can cause a TM Bad Thing, since the MSR in the stack will |
---|
| 752 | + * have the MSR[TS]=0, and this is what will be used to RFID. |
---|
| 753 | + * |
---|
| 754 | + * Clearing MSR[TS] state here will avoid a recheckpoint if there |
---|
| 755 | + * is any process reschedule in kernel space. The MSR[TS] state |
---|
| 756 | + * does not need to be saved also, since it will be replaced with |
---|
| 757 | + * the MSR[TS] that came from user context later, at |
---|
| 758 | + * restore_tm_sigcontexts. |
---|
| 759 | + */ |
---|
| 760 | + regs->msr &= ~MSR_TS_MASK; |
---|
742 | 761 | |
---|
743 | 762 | if (__get_user(msr, &uc->uc_mcontext.gp_regs[PT_MSR])) |
---|
744 | 763 | goto badframe; |
---|
.. | .. |
---|
787 | 806 | current->comm, current->pid, "rt_sigreturn", |
---|
788 | 807 | (long)uc, regs->nip, regs->link); |
---|
789 | 808 | |
---|
790 | | - force_sig(SIGSEGV, current); |
---|
| 809 | + force_sig(SIGSEGV); |
---|
791 | 810 | return 0; |
---|
792 | 811 | } |
---|
793 | 812 | |
---|
.. | .. |
---|
846 | 865 | |
---|
847 | 866 | /* Set up to return from userspace. */ |
---|
848 | 867 | if (vdso64_rt_sigtramp && tsk->mm->context.vdso_base) { |
---|
849 | | - regs->link = tsk->mm->context.vdso_base + vdso64_rt_sigtramp; |
---|
| 868 | + regs->nip = tsk->mm->context.vdso_base + vdso64_rt_sigtramp; |
---|
850 | 869 | } else { |
---|
851 | 870 | err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); |
---|
852 | 871 | if (err) |
---|
853 | 872 | goto badframe; |
---|
854 | | - regs->link = (unsigned long) &frame->tramp[0]; |
---|
| 873 | + regs->nip = (unsigned long) &frame->tramp[0]; |
---|
855 | 874 | } |
---|
856 | 875 | |
---|
857 | 876 | /* Allocate a dummy caller frame for the signal handler. */ |
---|
.. | .. |
---|
860 | 879 | |
---|
861 | 880 | /* Set up "regs" so we "return" to the signal handler. */ |
---|
862 | 881 | if (is_elf2_task()) { |
---|
863 | | - regs->nip = (unsigned long) ksig->ka.sa.sa_handler; |
---|
864 | | - regs->gpr[12] = regs->nip; |
---|
| 882 | + regs->ctr = (unsigned long) ksig->ka.sa.sa_handler; |
---|
| 883 | + regs->gpr[12] = regs->ctr; |
---|
865 | 884 | } else { |
---|
866 | 885 | /* Handler is *really* a pointer to the function descriptor for |
---|
867 | 886 | * the signal routine. The first entry in the function |
---|
.. | .. |
---|
871 | 890 | func_descr_t __user *funct_desc_ptr = |
---|
872 | 891 | (func_descr_t __user *) ksig->ka.sa.sa_handler; |
---|
873 | 892 | |
---|
874 | | - err |= get_user(regs->nip, &funct_desc_ptr->entry); |
---|
| 893 | + err |= get_user(regs->ctr, &funct_desc_ptr->entry); |
---|
875 | 894 | err |= get_user(regs->gpr[2], &funct_desc_ptr->toc); |
---|
876 | 895 | } |
---|
877 | 896 | |
---|