.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Based on arch/arm/kernel/ptrace.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * edited by Linus Torvalds |
---|
6 | 7 | * ARM modifications Copyright (C) 2000 Russell King |
---|
7 | 8 | * Copyright (C) 2012 ARM Ltd. |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License version 2 as |
---|
11 | | - * published by the Free Software Foundation. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License |
---|
19 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
20 | 9 | */ |
---|
21 | 10 | |
---|
22 | 11 | #include <linux/audit.h> |
---|
.. | .. |
---|
45 | 34 | #include <asm/cpufeature.h> |
---|
46 | 35 | #include <asm/debug-monitors.h> |
---|
47 | 36 | #include <asm/fpsimd.h> |
---|
48 | | -#include <asm/pgtable.h> |
---|
| 37 | +#include <asm/mte.h> |
---|
| 38 | +#include <asm/pointer_auth.h> |
---|
49 | 39 | #include <asm/stacktrace.h> |
---|
50 | 40 | #include <asm/syscall.h> |
---|
51 | 41 | #include <asm/traps.h> |
---|
.. | .. |
---|
182 | 172 | struct pt_regs *regs) |
---|
183 | 173 | { |
---|
184 | 174 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); |
---|
185 | | - siginfo_t info; |
---|
186 | | - |
---|
187 | | - clear_siginfo(&info); |
---|
188 | | - info.si_signo = SIGTRAP; |
---|
189 | | - info.si_errno = 0; |
---|
190 | | - info.si_code = TRAP_HWBKPT; |
---|
191 | | - info.si_addr = (void __user *)(bkpt->trigger); |
---|
| 175 | + const char *desc = "Hardware breakpoint trap (ptrace)"; |
---|
192 | 176 | |
---|
193 | 177 | #ifdef CONFIG_COMPAT |
---|
194 | 178 | if (is_compat_task()) { |
---|
.. | .. |
---|
208 | 192 | break; |
---|
209 | 193 | } |
---|
210 | 194 | } |
---|
211 | | - force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger); |
---|
| 195 | + arm64_force_sig_ptrace_errno_trap(si_errno, bkpt->trigger, |
---|
| 196 | + desc); |
---|
212 | 197 | } |
---|
213 | 198 | #endif |
---|
214 | | - arm64_force_sig_info(&info, "Hardware breakpoint trap (ptrace)", current); |
---|
| 199 | + arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, bkpt->trigger, desc); |
---|
215 | 200 | } |
---|
216 | 201 | |
---|
217 | 202 | /* |
---|
.. | .. |
---|
487 | 472 | |
---|
488 | 473 | static int hw_break_get(struct task_struct *target, |
---|
489 | 474 | const struct user_regset *regset, |
---|
490 | | - unsigned int pos, unsigned int count, |
---|
491 | | - void *kbuf, void __user *ubuf) |
---|
| 475 | + struct membuf to) |
---|
492 | 476 | { |
---|
493 | 477 | unsigned int note_type = regset->core_note_type; |
---|
494 | | - int ret, idx = 0, offset, limit; |
---|
| 478 | + int ret, idx = 0; |
---|
495 | 479 | u32 info, ctrl; |
---|
496 | 480 | u64 addr; |
---|
497 | 481 | |
---|
.. | .. |
---|
500 | 484 | if (ret) |
---|
501 | 485 | return ret; |
---|
502 | 486 | |
---|
503 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, |
---|
504 | | - sizeof(info)); |
---|
505 | | - if (ret) |
---|
506 | | - return ret; |
---|
507 | | - |
---|
508 | | - /* Pad */ |
---|
509 | | - offset = offsetof(struct user_hwdebug_state, pad); |
---|
510 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset, |
---|
511 | | - offset + PTRACE_HBP_PAD_SZ); |
---|
512 | | - if (ret) |
---|
513 | | - return ret; |
---|
514 | | - |
---|
| 487 | + membuf_write(&to, &info, sizeof(info)); |
---|
| 488 | + membuf_zero(&to, sizeof(u32)); |
---|
515 | 489 | /* (address, ctrl) registers */ |
---|
516 | | - offset = offsetof(struct user_hwdebug_state, dbg_regs); |
---|
517 | | - limit = regset->n * regset->size; |
---|
518 | | - while (count && offset < limit) { |
---|
| 490 | + while (to.left) { |
---|
519 | 491 | ret = ptrace_hbp_get_addr(note_type, target, idx, &addr); |
---|
520 | 492 | if (ret) |
---|
521 | 493 | return ret; |
---|
522 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr, |
---|
523 | | - offset, offset + PTRACE_HBP_ADDR_SZ); |
---|
524 | | - if (ret) |
---|
525 | | - return ret; |
---|
526 | | - offset += PTRACE_HBP_ADDR_SZ; |
---|
527 | | - |
---|
528 | 494 | ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl); |
---|
529 | 495 | if (ret) |
---|
530 | 496 | return ret; |
---|
531 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl, |
---|
532 | | - offset, offset + PTRACE_HBP_CTRL_SZ); |
---|
533 | | - if (ret) |
---|
534 | | - return ret; |
---|
535 | | - offset += PTRACE_HBP_CTRL_SZ; |
---|
536 | | - |
---|
537 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
538 | | - offset, |
---|
539 | | - offset + PTRACE_HBP_PAD_SZ); |
---|
540 | | - if (ret) |
---|
541 | | - return ret; |
---|
542 | | - offset += PTRACE_HBP_PAD_SZ; |
---|
| 497 | + membuf_store(&to, addr); |
---|
| 498 | + membuf_store(&to, ctrl); |
---|
| 499 | + membuf_zero(&to, sizeof(u32)); |
---|
543 | 500 | idx++; |
---|
544 | 501 | } |
---|
545 | | - |
---|
546 | 502 | return 0; |
---|
547 | 503 | } |
---|
548 | 504 | |
---|
.. | .. |
---|
602 | 558 | |
---|
603 | 559 | static int gpr_get(struct task_struct *target, |
---|
604 | 560 | const struct user_regset *regset, |
---|
605 | | - unsigned int pos, unsigned int count, |
---|
606 | | - void *kbuf, void __user *ubuf) |
---|
| 561 | + struct membuf to) |
---|
607 | 562 | { |
---|
608 | 563 | struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; |
---|
609 | | - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); |
---|
| 564 | + return membuf_write(&to, uregs, sizeof(*uregs)); |
---|
610 | 565 | } |
---|
611 | 566 | |
---|
612 | 567 | static int gpr_set(struct task_struct *target, const struct user_regset *regset, |
---|
.. | .. |
---|
639 | 594 | */ |
---|
640 | 595 | static int __fpr_get(struct task_struct *target, |
---|
641 | 596 | const struct user_regset *regset, |
---|
642 | | - unsigned int pos, unsigned int count, |
---|
643 | | - void *kbuf, void __user *ubuf, unsigned int start_pos) |
---|
| 597 | + struct membuf to) |
---|
644 | 598 | { |
---|
645 | 599 | struct user_fpsimd_state *uregs; |
---|
646 | 600 | |
---|
.. | .. |
---|
648 | 602 | |
---|
649 | 603 | uregs = &target->thread.uw.fpsimd_state; |
---|
650 | 604 | |
---|
651 | | - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, |
---|
652 | | - start_pos, start_pos + sizeof(*uregs)); |
---|
| 605 | + return membuf_write(&to, uregs, sizeof(*uregs)); |
---|
653 | 606 | } |
---|
654 | 607 | |
---|
655 | 608 | static int fpr_get(struct task_struct *target, const struct user_regset *regset, |
---|
656 | | - unsigned int pos, unsigned int count, |
---|
657 | | - void *kbuf, void __user *ubuf) |
---|
| 609 | + struct membuf to) |
---|
658 | 610 | { |
---|
659 | 611 | if (!system_supports_fpsimd()) |
---|
660 | 612 | return -EINVAL; |
---|
.. | .. |
---|
662 | 614 | if (target == current) |
---|
663 | 615 | fpsimd_preserve_current_state(); |
---|
664 | 616 | |
---|
665 | | - return __fpr_get(target, regset, pos, count, kbuf, ubuf, 0); |
---|
| 617 | + return __fpr_get(target, regset, to); |
---|
666 | 618 | } |
---|
667 | 619 | |
---|
668 | 620 | static int __fpr_set(struct task_struct *target, |
---|
.. | .. |
---|
712 | 664 | } |
---|
713 | 665 | |
---|
714 | 666 | static int tls_get(struct task_struct *target, const struct user_regset *regset, |
---|
715 | | - unsigned int pos, unsigned int count, |
---|
716 | | - void *kbuf, void __user *ubuf) |
---|
| 667 | + struct membuf to) |
---|
717 | 668 | { |
---|
718 | | - unsigned long *tls = &target->thread.uw.tp_value; |
---|
719 | | - |
---|
720 | 669 | if (target == current) |
---|
721 | 670 | tls_preserve_current_state(); |
---|
722 | 671 | |
---|
723 | | - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1); |
---|
| 672 | + return membuf_store(&to, target->thread.uw.tp_value); |
---|
724 | 673 | } |
---|
725 | 674 | |
---|
726 | 675 | static int tls_set(struct task_struct *target, const struct user_regset *regset, |
---|
.. | .. |
---|
740 | 689 | |
---|
741 | 690 | static int system_call_get(struct task_struct *target, |
---|
742 | 691 | const struct user_regset *regset, |
---|
743 | | - unsigned int pos, unsigned int count, |
---|
744 | | - void *kbuf, void __user *ubuf) |
---|
| 692 | + struct membuf to) |
---|
745 | 693 | { |
---|
746 | | - int syscallno = task_pt_regs(target)->syscallno; |
---|
747 | | - |
---|
748 | | - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
749 | | - &syscallno, 0, -1); |
---|
| 694 | + return membuf_store(&to, task_pt_regs(target)->syscallno); |
---|
750 | 695 | } |
---|
751 | 696 | |
---|
752 | 697 | static int system_call_set(struct task_struct *target, |
---|
.. | .. |
---|
793 | 738 | return ALIGN(header->size, SVE_VQ_BYTES); |
---|
794 | 739 | } |
---|
795 | 740 | |
---|
796 | | -static unsigned int sve_get_size(struct task_struct *target, |
---|
797 | | - const struct user_regset *regset) |
---|
798 | | -{ |
---|
799 | | - struct user_sve_header header; |
---|
800 | | - |
---|
801 | | - if (!system_supports_sve()) |
---|
802 | | - return 0; |
---|
803 | | - |
---|
804 | | - sve_init_header_from_task(&header, target); |
---|
805 | | - return sve_size_from_header(&header); |
---|
806 | | -} |
---|
807 | | - |
---|
808 | 741 | static int sve_get(struct task_struct *target, |
---|
809 | 742 | const struct user_regset *regset, |
---|
810 | | - unsigned int pos, unsigned int count, |
---|
811 | | - void *kbuf, void __user *ubuf) |
---|
| 743 | + struct membuf to) |
---|
812 | 744 | { |
---|
813 | | - int ret; |
---|
814 | 745 | struct user_sve_header header; |
---|
815 | 746 | unsigned int vq; |
---|
816 | 747 | unsigned long start, end; |
---|
.. | .. |
---|
822 | 753 | sve_init_header_from_task(&header, target); |
---|
823 | 754 | vq = sve_vq_from_vl(header.vl); |
---|
824 | 755 | |
---|
825 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header, |
---|
826 | | - 0, sizeof(header)); |
---|
827 | | - if (ret) |
---|
828 | | - return ret; |
---|
| 756 | + membuf_write(&to, &header, sizeof(header)); |
---|
829 | 757 | |
---|
830 | 758 | if (target == current) |
---|
831 | 759 | fpsimd_preserve_current_state(); |
---|
.. | .. |
---|
834 | 762 | |
---|
835 | 763 | BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header)); |
---|
836 | 764 | if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) |
---|
837 | | - return __fpr_get(target, regset, pos, count, kbuf, ubuf, |
---|
838 | | - SVE_PT_FPSIMD_OFFSET); |
---|
| 765 | + return __fpr_get(target, regset, to); |
---|
839 | 766 | |
---|
840 | 767 | /* Otherwise: full SVE case */ |
---|
841 | 768 | |
---|
842 | 769 | BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header)); |
---|
843 | 770 | start = SVE_PT_SVE_OFFSET; |
---|
844 | 771 | end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq); |
---|
845 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
846 | | - target->thread.sve_state, |
---|
847 | | - start, end); |
---|
848 | | - if (ret) |
---|
849 | | - return ret; |
---|
| 772 | + membuf_write(&to, target->thread.sve_state, end - start); |
---|
850 | 773 | |
---|
851 | 774 | start = end; |
---|
852 | 775 | end = SVE_PT_SVE_FPSR_OFFSET(vq); |
---|
853 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
854 | | - start, end); |
---|
855 | | - if (ret) |
---|
856 | | - return ret; |
---|
| 776 | + membuf_zero(&to, end - start); |
---|
857 | 777 | |
---|
858 | 778 | /* |
---|
859 | 779 | * Copy fpsr, and fpcr which must follow contiguously in |
---|
.. | .. |
---|
861 | 781 | */ |
---|
862 | 782 | start = end; |
---|
863 | 783 | end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE; |
---|
864 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
865 | | - &target->thread.uw.fpsimd_state.fpsr, |
---|
866 | | - start, end); |
---|
867 | | - if (ret) |
---|
868 | | - return ret; |
---|
| 784 | + membuf_write(&to, &target->thread.uw.fpsimd_state.fpsr, end - start); |
---|
869 | 785 | |
---|
870 | 786 | start = end; |
---|
871 | 787 | end = sve_size_from_header(&header); |
---|
872 | | - return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
873 | | - start, end); |
---|
| 788 | + return membuf_zero(&to, end - start); |
---|
874 | 789 | } |
---|
875 | 790 | |
---|
876 | 791 | static int sve_set(struct task_struct *target, |
---|
.. | .. |
---|
895 | 810 | goto out; |
---|
896 | 811 | |
---|
897 | 812 | /* |
---|
898 | | - * Apart from PT_SVE_REGS_MASK, all PT_SVE_* flags are consumed by |
---|
| 813 | + * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by |
---|
899 | 814 | * sve_set_vector_length(), which will also validate them for us: |
---|
900 | 815 | */ |
---|
901 | 816 | ret = sve_set_vector_length(target, header.vl, |
---|
.. | .. |
---|
971 | 886 | |
---|
972 | 887 | #endif /* CONFIG_ARM64_SVE */ |
---|
973 | 888 | |
---|
| 889 | +#ifdef CONFIG_ARM64_PTR_AUTH |
---|
| 890 | +static int pac_mask_get(struct task_struct *target, |
---|
| 891 | + const struct user_regset *regset, |
---|
| 892 | + struct membuf to) |
---|
| 893 | +{ |
---|
| 894 | + /* |
---|
| 895 | + * The PAC bits can differ across data and instruction pointers |
---|
| 896 | + * depending on TCR_EL1.TBID*, which we may make use of in future, so |
---|
| 897 | + * we expose separate masks. |
---|
| 898 | + */ |
---|
| 899 | + unsigned long mask = ptrauth_user_pac_mask(); |
---|
| 900 | + struct user_pac_mask uregs = { |
---|
| 901 | + .data_mask = mask, |
---|
| 902 | + .insn_mask = mask, |
---|
| 903 | + }; |
---|
| 904 | + |
---|
| 905 | + if (!system_supports_address_auth()) |
---|
| 906 | + return -EINVAL; |
---|
| 907 | + |
---|
| 908 | + return membuf_write(&to, &uregs, sizeof(uregs)); |
---|
| 909 | +} |
---|
| 910 | + |
---|
| 911 | +static int pac_enabled_keys_get(struct task_struct *target, |
---|
| 912 | + const struct user_regset *regset, |
---|
| 913 | + struct membuf to) |
---|
| 914 | +{ |
---|
| 915 | + long enabled_keys = ptrauth_get_enabled_keys(target); |
---|
| 916 | + |
---|
| 917 | + if (IS_ERR_VALUE(enabled_keys)) |
---|
| 918 | + return enabled_keys; |
---|
| 919 | + |
---|
| 920 | + return membuf_write(&to, &enabled_keys, sizeof(enabled_keys)); |
---|
| 921 | +} |
---|
| 922 | + |
---|
| 923 | +static int pac_enabled_keys_set(struct task_struct *target, |
---|
| 924 | + const struct user_regset *regset, |
---|
| 925 | + unsigned int pos, unsigned int count, |
---|
| 926 | + const void *kbuf, const void __user *ubuf) |
---|
| 927 | +{ |
---|
| 928 | + int ret; |
---|
| 929 | + long enabled_keys = ptrauth_get_enabled_keys(target); |
---|
| 930 | + |
---|
| 931 | + if (IS_ERR_VALUE(enabled_keys)) |
---|
| 932 | + return enabled_keys; |
---|
| 933 | + |
---|
| 934 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &enabled_keys, 0, |
---|
| 935 | + sizeof(long)); |
---|
| 936 | + if (ret) |
---|
| 937 | + return ret; |
---|
| 938 | + |
---|
| 939 | + return ptrauth_set_enabled_keys(target, PR_PAC_ENABLED_KEYS_MASK, |
---|
| 940 | + enabled_keys); |
---|
| 941 | +} |
---|
| 942 | + |
---|
| 943 | +#ifdef CONFIG_CHECKPOINT_RESTORE |
---|
| 944 | +static __uint128_t pac_key_to_user(const struct ptrauth_key *key) |
---|
| 945 | +{ |
---|
| 946 | + return (__uint128_t)key->hi << 64 | key->lo; |
---|
| 947 | +} |
---|
| 948 | + |
---|
| 949 | +static struct ptrauth_key pac_key_from_user(__uint128_t ukey) |
---|
| 950 | +{ |
---|
| 951 | + struct ptrauth_key key = { |
---|
| 952 | + .lo = (unsigned long)ukey, |
---|
| 953 | + .hi = (unsigned long)(ukey >> 64), |
---|
| 954 | + }; |
---|
| 955 | + |
---|
| 956 | + return key; |
---|
| 957 | +} |
---|
| 958 | + |
---|
| 959 | +static void pac_address_keys_to_user(struct user_pac_address_keys *ukeys, |
---|
| 960 | + const struct ptrauth_keys_user *keys) |
---|
| 961 | +{ |
---|
| 962 | + ukeys->apiakey = pac_key_to_user(&keys->apia); |
---|
| 963 | + ukeys->apibkey = pac_key_to_user(&keys->apib); |
---|
| 964 | + ukeys->apdakey = pac_key_to_user(&keys->apda); |
---|
| 965 | + ukeys->apdbkey = pac_key_to_user(&keys->apdb); |
---|
| 966 | +} |
---|
| 967 | + |
---|
| 968 | +static void pac_address_keys_from_user(struct ptrauth_keys_user *keys, |
---|
| 969 | + const struct user_pac_address_keys *ukeys) |
---|
| 970 | +{ |
---|
| 971 | + keys->apia = pac_key_from_user(ukeys->apiakey); |
---|
| 972 | + keys->apib = pac_key_from_user(ukeys->apibkey); |
---|
| 973 | + keys->apda = pac_key_from_user(ukeys->apdakey); |
---|
| 974 | + keys->apdb = pac_key_from_user(ukeys->apdbkey); |
---|
| 975 | +} |
---|
| 976 | + |
---|
| 977 | +static int pac_address_keys_get(struct task_struct *target, |
---|
| 978 | + const struct user_regset *regset, |
---|
| 979 | + struct membuf to) |
---|
| 980 | +{ |
---|
| 981 | + struct ptrauth_keys_user *keys = &target->thread.keys_user; |
---|
| 982 | + struct user_pac_address_keys user_keys; |
---|
| 983 | + |
---|
| 984 | + if (!system_supports_address_auth()) |
---|
| 985 | + return -EINVAL; |
---|
| 986 | + |
---|
| 987 | + pac_address_keys_to_user(&user_keys, keys); |
---|
| 988 | + |
---|
| 989 | + return membuf_write(&to, &user_keys, sizeof(user_keys)); |
---|
| 990 | +} |
---|
| 991 | + |
---|
| 992 | +static int pac_address_keys_set(struct task_struct *target, |
---|
| 993 | + const struct user_regset *regset, |
---|
| 994 | + unsigned int pos, unsigned int count, |
---|
| 995 | + const void *kbuf, const void __user *ubuf) |
---|
| 996 | +{ |
---|
| 997 | + struct ptrauth_keys_user *keys = &target->thread.keys_user; |
---|
| 998 | + struct user_pac_address_keys user_keys; |
---|
| 999 | + int ret; |
---|
| 1000 | + |
---|
| 1001 | + if (!system_supports_address_auth()) |
---|
| 1002 | + return -EINVAL; |
---|
| 1003 | + |
---|
| 1004 | + pac_address_keys_to_user(&user_keys, keys); |
---|
| 1005 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 1006 | + &user_keys, 0, -1); |
---|
| 1007 | + if (ret) |
---|
| 1008 | + return ret; |
---|
| 1009 | + pac_address_keys_from_user(keys, &user_keys); |
---|
| 1010 | + |
---|
| 1011 | + return 0; |
---|
| 1012 | +} |
---|
| 1013 | + |
---|
| 1014 | +static void pac_generic_keys_to_user(struct user_pac_generic_keys *ukeys, |
---|
| 1015 | + const struct ptrauth_keys_user *keys) |
---|
| 1016 | +{ |
---|
| 1017 | + ukeys->apgakey = pac_key_to_user(&keys->apga); |
---|
| 1018 | +} |
---|
| 1019 | + |
---|
| 1020 | +static void pac_generic_keys_from_user(struct ptrauth_keys_user *keys, |
---|
| 1021 | + const struct user_pac_generic_keys *ukeys) |
---|
| 1022 | +{ |
---|
| 1023 | + keys->apga = pac_key_from_user(ukeys->apgakey); |
---|
| 1024 | +} |
---|
| 1025 | + |
---|
| 1026 | +static int pac_generic_keys_get(struct task_struct *target, |
---|
| 1027 | + const struct user_regset *regset, |
---|
| 1028 | + struct membuf to) |
---|
| 1029 | +{ |
---|
| 1030 | + struct ptrauth_keys_user *keys = &target->thread.keys_user; |
---|
| 1031 | + struct user_pac_generic_keys user_keys; |
---|
| 1032 | + |
---|
| 1033 | + if (!system_supports_generic_auth()) |
---|
| 1034 | + return -EINVAL; |
---|
| 1035 | + |
---|
| 1036 | + pac_generic_keys_to_user(&user_keys, keys); |
---|
| 1037 | + |
---|
| 1038 | + return membuf_write(&to, &user_keys, sizeof(user_keys)); |
---|
| 1039 | +} |
---|
| 1040 | + |
---|
| 1041 | +static int pac_generic_keys_set(struct task_struct *target, |
---|
| 1042 | + const struct user_regset *regset, |
---|
| 1043 | + unsigned int pos, unsigned int count, |
---|
| 1044 | + const void *kbuf, const void __user *ubuf) |
---|
| 1045 | +{ |
---|
| 1046 | + struct ptrauth_keys_user *keys = &target->thread.keys_user; |
---|
| 1047 | + struct user_pac_generic_keys user_keys; |
---|
| 1048 | + int ret; |
---|
| 1049 | + |
---|
| 1050 | + if (!system_supports_generic_auth()) |
---|
| 1051 | + return -EINVAL; |
---|
| 1052 | + |
---|
| 1053 | + pac_generic_keys_to_user(&user_keys, keys); |
---|
| 1054 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 1055 | + &user_keys, 0, -1); |
---|
| 1056 | + if (ret) |
---|
| 1057 | + return ret; |
---|
| 1058 | + pac_generic_keys_from_user(keys, &user_keys); |
---|
| 1059 | + |
---|
| 1060 | + return 0; |
---|
| 1061 | +} |
---|
| 1062 | +#endif /* CONFIG_CHECKPOINT_RESTORE */ |
---|
| 1063 | +#endif /* CONFIG_ARM64_PTR_AUTH */ |
---|
| 1064 | + |
---|
| 1065 | +#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI |
---|
| 1066 | +static int tagged_addr_ctrl_get(struct task_struct *target, |
---|
| 1067 | + const struct user_regset *regset, |
---|
| 1068 | + struct membuf to) |
---|
| 1069 | +{ |
---|
| 1070 | + long ctrl = get_tagged_addr_ctrl(target); |
---|
| 1071 | + |
---|
| 1072 | + if (IS_ERR_VALUE(ctrl)) |
---|
| 1073 | + return ctrl; |
---|
| 1074 | + |
---|
| 1075 | + return membuf_write(&to, &ctrl, sizeof(ctrl)); |
---|
| 1076 | +} |
---|
| 1077 | + |
---|
| 1078 | +static int tagged_addr_ctrl_set(struct task_struct *target, const struct |
---|
| 1079 | + user_regset *regset, unsigned int pos, |
---|
| 1080 | + unsigned int count, const void *kbuf, const |
---|
| 1081 | + void __user *ubuf) |
---|
| 1082 | +{ |
---|
| 1083 | + int ret; |
---|
| 1084 | + long ctrl; |
---|
| 1085 | + |
---|
| 1086 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1); |
---|
| 1087 | + if (ret) |
---|
| 1088 | + return ret; |
---|
| 1089 | + |
---|
| 1090 | + return set_tagged_addr_ctrl(target, ctrl); |
---|
| 1091 | +} |
---|
| 1092 | +#endif |
---|
| 1093 | + |
---|
974 | 1094 | enum aarch64_regset { |
---|
975 | 1095 | REGSET_GPR, |
---|
976 | 1096 | REGSET_FPR, |
---|
.. | .. |
---|
983 | 1103 | #ifdef CONFIG_ARM64_SVE |
---|
984 | 1104 | REGSET_SVE, |
---|
985 | 1105 | #endif |
---|
| 1106 | +#ifdef CONFIG_ARM64_PTR_AUTH |
---|
| 1107 | + REGSET_PAC_MASK, |
---|
| 1108 | + REGSET_PAC_ENABLED_KEYS, |
---|
| 1109 | +#ifdef CONFIG_CHECKPOINT_RESTORE |
---|
| 1110 | + REGSET_PACA_KEYS, |
---|
| 1111 | + REGSET_PACG_KEYS, |
---|
| 1112 | +#endif |
---|
| 1113 | +#endif |
---|
| 1114 | +#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI |
---|
| 1115 | + REGSET_TAGGED_ADDR_CTRL, |
---|
| 1116 | +#endif |
---|
986 | 1117 | }; |
---|
987 | 1118 | |
---|
988 | 1119 | static const struct user_regset aarch64_regsets[] = { |
---|
.. | .. |
---|
991 | 1122 | .n = sizeof(struct user_pt_regs) / sizeof(u64), |
---|
992 | 1123 | .size = sizeof(u64), |
---|
993 | 1124 | .align = sizeof(u64), |
---|
994 | | - .get = gpr_get, |
---|
| 1125 | + .regset_get = gpr_get, |
---|
995 | 1126 | .set = gpr_set |
---|
996 | 1127 | }, |
---|
997 | 1128 | [REGSET_FPR] = { |
---|
.. | .. |
---|
1004 | 1135 | .size = sizeof(u32), |
---|
1005 | 1136 | .align = sizeof(u32), |
---|
1006 | 1137 | .active = fpr_active, |
---|
1007 | | - .get = fpr_get, |
---|
| 1138 | + .regset_get = fpr_get, |
---|
1008 | 1139 | .set = fpr_set |
---|
1009 | 1140 | }, |
---|
1010 | 1141 | [REGSET_TLS] = { |
---|
.. | .. |
---|
1012 | 1143 | .n = 1, |
---|
1013 | 1144 | .size = sizeof(void *), |
---|
1014 | 1145 | .align = sizeof(void *), |
---|
1015 | | - .get = tls_get, |
---|
| 1146 | + .regset_get = tls_get, |
---|
1016 | 1147 | .set = tls_set, |
---|
1017 | 1148 | }, |
---|
1018 | 1149 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
---|
.. | .. |
---|
1021 | 1152 | .n = sizeof(struct user_hwdebug_state) / sizeof(u32), |
---|
1022 | 1153 | .size = sizeof(u32), |
---|
1023 | 1154 | .align = sizeof(u32), |
---|
1024 | | - .get = hw_break_get, |
---|
| 1155 | + .regset_get = hw_break_get, |
---|
1025 | 1156 | .set = hw_break_set, |
---|
1026 | 1157 | }, |
---|
1027 | 1158 | [REGSET_HW_WATCH] = { |
---|
.. | .. |
---|
1029 | 1160 | .n = sizeof(struct user_hwdebug_state) / sizeof(u32), |
---|
1030 | 1161 | .size = sizeof(u32), |
---|
1031 | 1162 | .align = sizeof(u32), |
---|
1032 | | - .get = hw_break_get, |
---|
| 1163 | + .regset_get = hw_break_get, |
---|
1033 | 1164 | .set = hw_break_set, |
---|
1034 | 1165 | }, |
---|
1035 | 1166 | #endif |
---|
.. | .. |
---|
1038 | 1169 | .n = 1, |
---|
1039 | 1170 | .size = sizeof(int), |
---|
1040 | 1171 | .align = sizeof(int), |
---|
1041 | | - .get = system_call_get, |
---|
| 1172 | + .regset_get = system_call_get, |
---|
1042 | 1173 | .set = system_call_set, |
---|
1043 | 1174 | }, |
---|
1044 | 1175 | #ifdef CONFIG_ARM64_SVE |
---|
.. | .. |
---|
1048 | 1179 | SVE_VQ_BYTES), |
---|
1049 | 1180 | .size = SVE_VQ_BYTES, |
---|
1050 | 1181 | .align = SVE_VQ_BYTES, |
---|
1051 | | - .get = sve_get, |
---|
| 1182 | + .regset_get = sve_get, |
---|
1052 | 1183 | .set = sve_set, |
---|
1053 | | - .get_size = sve_get_size, |
---|
| 1184 | + }, |
---|
| 1185 | +#endif |
---|
| 1186 | +#ifdef CONFIG_ARM64_PTR_AUTH |
---|
| 1187 | + [REGSET_PAC_MASK] = { |
---|
| 1188 | + .core_note_type = NT_ARM_PAC_MASK, |
---|
| 1189 | + .n = sizeof(struct user_pac_mask) / sizeof(u64), |
---|
| 1190 | + .size = sizeof(u64), |
---|
| 1191 | + .align = sizeof(u64), |
---|
| 1192 | + .regset_get = pac_mask_get, |
---|
| 1193 | + /* this cannot be set dynamically */ |
---|
| 1194 | + }, |
---|
| 1195 | + [REGSET_PAC_ENABLED_KEYS] = { |
---|
| 1196 | + .core_note_type = NT_ARM_PAC_ENABLED_KEYS, |
---|
| 1197 | + .n = 1, |
---|
| 1198 | + .size = sizeof(long), |
---|
| 1199 | + .align = sizeof(long), |
---|
| 1200 | + .regset_get = pac_enabled_keys_get, |
---|
| 1201 | + .set = pac_enabled_keys_set, |
---|
| 1202 | + }, |
---|
| 1203 | +#ifdef CONFIG_CHECKPOINT_RESTORE |
---|
| 1204 | + [REGSET_PACA_KEYS] = { |
---|
| 1205 | + .core_note_type = NT_ARM_PACA_KEYS, |
---|
| 1206 | + .n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t), |
---|
| 1207 | + .size = sizeof(__uint128_t), |
---|
| 1208 | + .align = sizeof(__uint128_t), |
---|
| 1209 | + .regset_get = pac_address_keys_get, |
---|
| 1210 | + .set = pac_address_keys_set, |
---|
| 1211 | + }, |
---|
| 1212 | + [REGSET_PACG_KEYS] = { |
---|
| 1213 | + .core_note_type = NT_ARM_PACG_KEYS, |
---|
| 1214 | + .n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t), |
---|
| 1215 | + .size = sizeof(__uint128_t), |
---|
| 1216 | + .align = sizeof(__uint128_t), |
---|
| 1217 | + .regset_get = pac_generic_keys_get, |
---|
| 1218 | + .set = pac_generic_keys_set, |
---|
| 1219 | + }, |
---|
| 1220 | +#endif |
---|
| 1221 | +#endif |
---|
| 1222 | +#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI |
---|
| 1223 | + [REGSET_TAGGED_ADDR_CTRL] = { |
---|
| 1224 | + .core_note_type = NT_ARM_TAGGED_ADDR_CTRL, |
---|
| 1225 | + .n = 1, |
---|
| 1226 | + .size = sizeof(long), |
---|
| 1227 | + .align = sizeof(long), |
---|
| 1228 | + .regset_get = tagged_addr_ctrl_get, |
---|
| 1229 | + .set = tagged_addr_ctrl_set, |
---|
1054 | 1230 | }, |
---|
1055 | 1231 | #endif |
---|
1056 | 1232 | }; |
---|
.. | .. |
---|
1066 | 1242 | REGSET_COMPAT_VFP, |
---|
1067 | 1243 | }; |
---|
1068 | 1244 | |
---|
| 1245 | +static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx) |
---|
| 1246 | +{ |
---|
| 1247 | + struct pt_regs *regs = task_pt_regs(task); |
---|
| 1248 | + |
---|
| 1249 | + switch (idx) { |
---|
| 1250 | + case 15: |
---|
| 1251 | + return regs->pc; |
---|
| 1252 | + case 16: |
---|
| 1253 | + return pstate_to_compat_psr(regs->pstate); |
---|
| 1254 | + case 17: |
---|
| 1255 | + return regs->orig_x0; |
---|
| 1256 | + default: |
---|
| 1257 | + return regs->regs[idx]; |
---|
| 1258 | + } |
---|
| 1259 | +} |
---|
| 1260 | + |
---|
1069 | 1261 | static int compat_gpr_get(struct task_struct *target, |
---|
1070 | 1262 | const struct user_regset *regset, |
---|
1071 | | - unsigned int pos, unsigned int count, |
---|
1072 | | - void *kbuf, void __user *ubuf) |
---|
| 1263 | + struct membuf to) |
---|
1073 | 1264 | { |
---|
1074 | | - int ret = 0; |
---|
1075 | | - unsigned int i, start, num_regs; |
---|
| 1265 | + int i = 0; |
---|
1076 | 1266 | |
---|
1077 | | - /* Calculate the number of AArch32 registers contained in count */ |
---|
1078 | | - num_regs = count / regset->size; |
---|
1079 | | - |
---|
1080 | | - /* Convert pos into an register number */ |
---|
1081 | | - start = pos / regset->size; |
---|
1082 | | - |
---|
1083 | | - if (start + num_regs > regset->n) |
---|
1084 | | - return -EIO; |
---|
1085 | | - |
---|
1086 | | - for (i = 0; i < num_regs; ++i) { |
---|
1087 | | - unsigned int idx = start + i; |
---|
1088 | | - compat_ulong_t reg; |
---|
1089 | | - |
---|
1090 | | - switch (idx) { |
---|
1091 | | - case 15: |
---|
1092 | | - reg = task_pt_regs(target)->pc; |
---|
1093 | | - break; |
---|
1094 | | - case 16: |
---|
1095 | | - reg = task_pt_regs(target)->pstate; |
---|
1096 | | - reg = pstate_to_compat_psr(reg); |
---|
1097 | | - break; |
---|
1098 | | - case 17: |
---|
1099 | | - reg = task_pt_regs(target)->orig_x0; |
---|
1100 | | - break; |
---|
1101 | | - default: |
---|
1102 | | - reg = task_pt_regs(target)->regs[idx]; |
---|
1103 | | - } |
---|
1104 | | - |
---|
1105 | | - if (kbuf) { |
---|
1106 | | - memcpy(kbuf, ®, sizeof(reg)); |
---|
1107 | | - kbuf += sizeof(reg); |
---|
1108 | | - } else { |
---|
1109 | | - ret = copy_to_user(ubuf, ®, sizeof(reg)); |
---|
1110 | | - if (ret) { |
---|
1111 | | - ret = -EFAULT; |
---|
1112 | | - break; |
---|
1113 | | - } |
---|
1114 | | - |
---|
1115 | | - ubuf += sizeof(reg); |
---|
1116 | | - } |
---|
1117 | | - } |
---|
1118 | | - |
---|
1119 | | - return ret; |
---|
| 1267 | + while (to.left) |
---|
| 1268 | + membuf_store(&to, compat_get_user_reg(target, i++)); |
---|
| 1269 | + return 0; |
---|
1120 | 1270 | } |
---|
1121 | 1271 | |
---|
1122 | 1272 | static int compat_gpr_set(struct task_struct *target, |
---|
.. | .. |
---|
1183 | 1333 | |
---|
1184 | 1334 | static int compat_vfp_get(struct task_struct *target, |
---|
1185 | 1335 | const struct user_regset *regset, |
---|
1186 | | - unsigned int pos, unsigned int count, |
---|
1187 | | - void *kbuf, void __user *ubuf) |
---|
| 1336 | + struct membuf to) |
---|
1188 | 1337 | { |
---|
1189 | 1338 | struct user_fpsimd_state *uregs; |
---|
1190 | 1339 | compat_ulong_t fpscr; |
---|
1191 | | - int ret, vregs_end_pos; |
---|
1192 | 1340 | |
---|
1193 | 1341 | if (!system_supports_fpsimd()) |
---|
1194 | 1342 | return -EINVAL; |
---|
.. | .. |
---|
1202 | 1350 | * The VFP registers are packed into the fpsimd_state, so they all sit |
---|
1203 | 1351 | * nicely together for us. We just need to create the fpscr separately. |
---|
1204 | 1352 | */ |
---|
1205 | | - vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t); |
---|
1206 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, |
---|
1207 | | - 0, vregs_end_pos); |
---|
1208 | | - |
---|
1209 | | - if (count && !ret) { |
---|
1210 | | - fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) | |
---|
1211 | | - (uregs->fpcr & VFP_FPSCR_CTRL_MASK); |
---|
1212 | | - |
---|
1213 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fpscr, |
---|
1214 | | - vregs_end_pos, VFP_STATE_SIZE); |
---|
1215 | | - } |
---|
1216 | | - |
---|
1217 | | - return ret; |
---|
| 1353 | + membuf_write(&to, uregs, VFP_STATE_SIZE - sizeof(compat_ulong_t)); |
---|
| 1354 | + fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) | |
---|
| 1355 | + (uregs->fpcr & VFP_FPSCR_CTRL_MASK); |
---|
| 1356 | + return membuf_store(&to, fpscr); |
---|
1218 | 1357 | } |
---|
1219 | 1358 | |
---|
1220 | 1359 | static int compat_vfp_set(struct task_struct *target, |
---|
.. | .. |
---|
1249 | 1388 | } |
---|
1250 | 1389 | |
---|
1251 | 1390 | static int compat_tls_get(struct task_struct *target, |
---|
1252 | | - const struct user_regset *regset, unsigned int pos, |
---|
1253 | | - unsigned int count, void *kbuf, void __user *ubuf) |
---|
| 1391 | + const struct user_regset *regset, |
---|
| 1392 | + struct membuf to) |
---|
1254 | 1393 | { |
---|
1255 | | - compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value; |
---|
1256 | | - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); |
---|
| 1394 | + return membuf_store(&to, (compat_ulong_t)target->thread.uw.tp_value); |
---|
1257 | 1395 | } |
---|
1258 | 1396 | |
---|
1259 | 1397 | static int compat_tls_set(struct task_struct *target, |
---|
.. | .. |
---|
1278 | 1416 | .n = COMPAT_ELF_NGREG, |
---|
1279 | 1417 | .size = sizeof(compat_elf_greg_t), |
---|
1280 | 1418 | .align = sizeof(compat_elf_greg_t), |
---|
1281 | | - .get = compat_gpr_get, |
---|
| 1419 | + .regset_get = compat_gpr_get, |
---|
1282 | 1420 | .set = compat_gpr_set |
---|
1283 | 1421 | }, |
---|
1284 | 1422 | [REGSET_COMPAT_VFP] = { |
---|
.. | .. |
---|
1287 | 1425 | .size = sizeof(compat_ulong_t), |
---|
1288 | 1426 | .align = sizeof(compat_ulong_t), |
---|
1289 | 1427 | .active = fpr_active, |
---|
1290 | | - .get = compat_vfp_get, |
---|
| 1428 | + .regset_get = compat_vfp_get, |
---|
1291 | 1429 | .set = compat_vfp_set |
---|
1292 | 1430 | }, |
---|
1293 | 1431 | }; |
---|
.. | .. |
---|
1303 | 1441 | .n = COMPAT_ELF_NGREG, |
---|
1304 | 1442 | .size = sizeof(compat_elf_greg_t), |
---|
1305 | 1443 | .align = sizeof(compat_elf_greg_t), |
---|
1306 | | - .get = compat_gpr_get, |
---|
| 1444 | + .regset_get = compat_gpr_get, |
---|
1307 | 1445 | .set = compat_gpr_set |
---|
1308 | 1446 | }, |
---|
1309 | 1447 | [REGSET_FPR] = { |
---|
.. | .. |
---|
1311 | 1449 | .n = VFP_STATE_SIZE / sizeof(compat_ulong_t), |
---|
1312 | 1450 | .size = sizeof(compat_ulong_t), |
---|
1313 | 1451 | .align = sizeof(compat_ulong_t), |
---|
1314 | | - .get = compat_vfp_get, |
---|
| 1452 | + .regset_get = compat_vfp_get, |
---|
1315 | 1453 | .set = compat_vfp_set |
---|
1316 | 1454 | }, |
---|
1317 | 1455 | [REGSET_TLS] = { |
---|
.. | .. |
---|
1319 | 1457 | .n = 1, |
---|
1320 | 1458 | .size = sizeof(compat_ulong_t), |
---|
1321 | 1459 | .align = sizeof(compat_ulong_t), |
---|
1322 | | - .get = compat_tls_get, |
---|
| 1460 | + .regset_get = compat_tls_get, |
---|
1323 | 1461 | .set = compat_tls_set, |
---|
1324 | 1462 | }, |
---|
1325 | 1463 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
---|
.. | .. |
---|
1328 | 1466 | .n = sizeof(struct user_hwdebug_state) / sizeof(u32), |
---|
1329 | 1467 | .size = sizeof(u32), |
---|
1330 | 1468 | .align = sizeof(u32), |
---|
1331 | | - .get = hw_break_get, |
---|
| 1469 | + .regset_get = hw_break_get, |
---|
1332 | 1470 | .set = hw_break_set, |
---|
1333 | 1471 | }, |
---|
1334 | 1472 | [REGSET_HW_WATCH] = { |
---|
.. | .. |
---|
1336 | 1474 | .n = sizeof(struct user_hwdebug_state) / sizeof(u32), |
---|
1337 | 1475 | .size = sizeof(u32), |
---|
1338 | 1476 | .align = sizeof(u32), |
---|
1339 | | - .get = hw_break_get, |
---|
| 1477 | + .regset_get = hw_break_get, |
---|
1340 | 1478 | .set = hw_break_set, |
---|
1341 | 1479 | }, |
---|
1342 | 1480 | #endif |
---|
.. | .. |
---|
1345 | 1483 | .n = 1, |
---|
1346 | 1484 | .size = sizeof(int), |
---|
1347 | 1485 | .align = sizeof(int), |
---|
1348 | | - .get = system_call_get, |
---|
| 1486 | + .regset_get = system_call_get, |
---|
1349 | 1487 | .set = system_call_set, |
---|
1350 | 1488 | }, |
---|
1351 | 1489 | }; |
---|
.. | .. |
---|
1370 | 1508 | else if (off == COMPAT_PT_TEXT_END_ADDR) |
---|
1371 | 1509 | tmp = tsk->mm->end_code; |
---|
1372 | 1510 | else if (off < sizeof(compat_elf_gregset_t)) |
---|
1373 | | - return copy_regset_to_user(tsk, &user_aarch32_view, |
---|
1374 | | - REGSET_COMPAT_GPR, off, |
---|
1375 | | - sizeof(compat_ulong_t), ret); |
---|
| 1511 | + tmp = compat_get_user_reg(tsk, off >> 2); |
---|
1376 | 1512 | else if (off >= COMPAT_USER_SZ) |
---|
1377 | 1513 | return -EIO; |
---|
1378 | 1514 | else |
---|
.. | .. |
---|
1384 | 1520 | static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, |
---|
1385 | 1521 | compat_ulong_t val) |
---|
1386 | 1522 | { |
---|
1387 | | - int ret; |
---|
1388 | | - mm_segment_t old_fs = get_fs(); |
---|
| 1523 | + struct pt_regs newregs = *task_pt_regs(tsk); |
---|
| 1524 | + unsigned int idx = off / 4; |
---|
1389 | 1525 | |
---|
1390 | 1526 | if (off & 3 || off >= COMPAT_USER_SZ) |
---|
1391 | 1527 | return -EIO; |
---|
.. | .. |
---|
1393 | 1529 | if (off >= sizeof(compat_elf_gregset_t)) |
---|
1394 | 1530 | return 0; |
---|
1395 | 1531 | |
---|
1396 | | - set_fs(KERNEL_DS); |
---|
1397 | | - ret = copy_regset_from_user(tsk, &user_aarch32_view, |
---|
1398 | | - REGSET_COMPAT_GPR, off, |
---|
1399 | | - sizeof(compat_ulong_t), |
---|
1400 | | - &val); |
---|
1401 | | - set_fs(old_fs); |
---|
| 1532 | + switch (idx) { |
---|
| 1533 | + case 15: |
---|
| 1534 | + newregs.pc = val; |
---|
| 1535 | + break; |
---|
| 1536 | + case 16: |
---|
| 1537 | + newregs.pstate = compat_psr_to_pstate(val); |
---|
| 1538 | + break; |
---|
| 1539 | + case 17: |
---|
| 1540 | + newregs.orig_x0 = val; |
---|
| 1541 | + break; |
---|
| 1542 | + default: |
---|
| 1543 | + newregs.regs[idx] = val; |
---|
| 1544 | + } |
---|
1402 | 1545 | |
---|
1403 | | - return ret; |
---|
| 1546 | + if (!valid_user_regs(&newregs.user_regs, tsk)) |
---|
| 1547 | + return -EINVAL; |
---|
| 1548 | + |
---|
| 1549 | + *task_pt_regs(tsk) = newregs; |
---|
| 1550 | + return 0; |
---|
1404 | 1551 | } |
---|
1405 | 1552 | |
---|
1406 | 1553 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
---|
.. | .. |
---|
1625 | 1772 | long arch_ptrace(struct task_struct *child, long request, |
---|
1626 | 1773 | unsigned long addr, unsigned long data) |
---|
1627 | 1774 | { |
---|
| 1775 | + switch (request) { |
---|
| 1776 | + case PTRACE_PEEKMTETAGS: |
---|
| 1777 | + case PTRACE_POKEMTETAGS: |
---|
| 1778 | + return mte_ptrace_copy_tags(child, request, addr, data); |
---|
| 1779 | + } |
---|
| 1780 | + |
---|
1628 | 1781 | return ptrace_request(child, request, addr, data); |
---|
1629 | 1782 | } |
---|
1630 | 1783 | |
---|
.. | .. |
---|
1640 | 1793 | unsigned long saved_reg; |
---|
1641 | 1794 | |
---|
1642 | 1795 | /* |
---|
1643 | | - * A scratch register (ip(r12) on AArch32, x7 on AArch64) is |
---|
1644 | | - * used to denote syscall entry/exit: |
---|
| 1796 | + * We have some ABI weirdness here in the way that we handle syscall |
---|
| 1797 | + * exit stops because we indicate whether or not the stop has been |
---|
| 1798 | + * signalled from syscall entry or syscall exit by clobbering a general |
---|
| 1799 | + * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee |
---|
| 1800 | + * and restoring its old value after the stop. This means that: |
---|
| 1801 | + * |
---|
| 1802 | + * - Any writes by the tracer to this register during the stop are |
---|
| 1803 | + * ignored/discarded. |
---|
| 1804 | + * |
---|
| 1805 | + * - The actual value of the register is not available during the stop, |
---|
| 1806 | + * so the tracer cannot save it and restore it later. |
---|
| 1807 | + * |
---|
| 1808 | + * - Syscall stops behave differently to seccomp and pseudo-step traps |
---|
| 1809 | + * (the latter do not nobble any registers). |
---|
1645 | 1810 | */ |
---|
1646 | 1811 | regno = (is_compat_task() ? 12 : 7); |
---|
1647 | 1812 | saved_reg = regs->regs[regno]; |
---|
.. | .. |
---|
1668 | 1833 | |
---|
1669 | 1834 | int syscall_trace_enter(struct pt_regs *regs) |
---|
1670 | 1835 | { |
---|
1671 | | - if (test_thread_flag(TIF_SYSCALL_TRACE)) |
---|
| 1836 | + unsigned long flags = READ_ONCE(current_thread_info()->flags); |
---|
| 1837 | + |
---|
| 1838 | + if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) { |
---|
1672 | 1839 | tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); |
---|
| 1840 | + if (flags & _TIF_SYSCALL_EMU) |
---|
| 1841 | + return NO_SYSCALL; |
---|
| 1842 | + } |
---|
1673 | 1843 | |
---|
1674 | 1844 | /* Do the secure computing after ptrace; failures should be fast. */ |
---|
1675 | | - if (secure_computing(NULL) == -1) |
---|
1676 | | - return -1; |
---|
| 1845 | + if (secure_computing() == -1) |
---|
| 1846 | + return NO_SYSCALL; |
---|
1677 | 1847 | |
---|
1678 | 1848 | if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) |
---|
1679 | 1849 | trace_sys_enter(regs, regs->syscallno); |
---|
.. | .. |
---|
1691 | 1861 | audit_syscall_exit(regs); |
---|
1692 | 1862 | |
---|
1693 | 1863 | if (flags & _TIF_SYSCALL_TRACEPOINT) |
---|
1694 | | - trace_sys_exit(regs, regs_return_value(regs)); |
---|
| 1864 | + trace_sys_exit(regs, syscall_get_return_value(current, regs)); |
---|
1695 | 1865 | |
---|
1696 | 1866 | if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP)) |
---|
1697 | 1867 | tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT); |
---|
.. | .. |
---|
1710 | 1880 | * We also reserve IL for the kernel; SS is handled dynamically. |
---|
1711 | 1881 | */ |
---|
1712 | 1882 | #define SPSR_EL1_AARCH64_RES0_BITS \ |
---|
1713 | | - (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 25) | GENMASK_ULL(23, 22) | \ |
---|
1714 | | - GENMASK_ULL(20, 13) | GENMASK_ULL(11, 10) | GENMASK_ULL(5, 5)) |
---|
| 1883 | + (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 26) | GENMASK_ULL(23, 22) | \ |
---|
| 1884 | + GENMASK_ULL(20, 13) | GENMASK_ULL(5, 5)) |
---|
1715 | 1885 | #define SPSR_EL1_AARCH32_RES0_BITS \ |
---|
1716 | 1886 | (GENMASK_ULL(63, 32) | GENMASK_ULL(22, 22) | GENMASK_ULL(20, 20)) |
---|
1717 | 1887 | |
---|