| .. | .. |
|---|
| 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 | |
|---|