| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * linux/kernel/ptrace.c |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 30 | 31 | #include <linux/cn_proc.h> |
|---|
| 31 | 32 | #include <linux/compat.h> |
|---|
| 32 | 33 | #include <linux/sched/signal.h> |
|---|
| 34 | + |
|---|
| 35 | +#include <asm/syscall.h> /* for syscall_get_* */ |
|---|
| 33 | 36 | |
|---|
| 34 | 37 | /* |
|---|
| 35 | 38 | * Access another process' address space via ptrace. |
|---|
| .. | .. |
|---|
| 115 | 118 | BUG_ON(!child->ptrace); |
|---|
| 116 | 119 | |
|---|
| 117 | 120 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
|---|
| 121 | +#ifdef TIF_SYSCALL_EMU |
|---|
| 122 | + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
|---|
| 123 | +#endif |
|---|
| 118 | 124 | |
|---|
| 119 | 125 | child->parent = child->real_parent; |
|---|
| 120 | 126 | list_del_init(&child->ptrace_entry); |
|---|
| .. | .. |
|---|
| 364 | 370 | return !err; |
|---|
| 365 | 371 | } |
|---|
| 366 | 372 | |
|---|
| 373 | +static int check_ptrace_options(unsigned long data) |
|---|
| 374 | +{ |
|---|
| 375 | + if (data & ~(unsigned long)PTRACE_O_MASK) |
|---|
| 376 | + return -EINVAL; |
|---|
| 377 | + |
|---|
| 378 | + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { |
|---|
| 379 | + if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || |
|---|
| 380 | + !IS_ENABLED(CONFIG_SECCOMP)) |
|---|
| 381 | + return -EINVAL; |
|---|
| 382 | + |
|---|
| 383 | + if (!capable(CAP_SYS_ADMIN)) |
|---|
| 384 | + return -EPERM; |
|---|
| 385 | + |
|---|
| 386 | + if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || |
|---|
| 387 | + current->ptrace & PT_SUSPEND_SECCOMP) |
|---|
| 388 | + return -EPERM; |
|---|
| 389 | + } |
|---|
| 390 | + return 0; |
|---|
| 391 | +} |
|---|
| 392 | + |
|---|
| 367 | 393 | static int ptrace_attach(struct task_struct *task, long request, |
|---|
| 368 | 394 | unsigned long addr, |
|---|
| 369 | 395 | unsigned long flags) |
|---|
| .. | .. |
|---|
| 375 | 401 | if (seize) { |
|---|
| 376 | 402 | if (addr != 0) |
|---|
| 377 | 403 | goto out; |
|---|
| 404 | + /* |
|---|
| 405 | + * This duplicates the check in check_ptrace_options() because |
|---|
| 406 | + * ptrace_attach() and ptrace_setoptions() have historically |
|---|
| 407 | + * used different error codes for unknown ptrace options. |
|---|
| 408 | + */ |
|---|
| 378 | 409 | if (flags & ~(unsigned long)PTRACE_O_MASK) |
|---|
| 379 | 410 | goto out; |
|---|
| 411 | + retval = check_ptrace_options(flags); |
|---|
| 412 | + if (retval) |
|---|
| 413 | + return retval; |
|---|
| 380 | 414 | flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT); |
|---|
| 381 | 415 | } else { |
|---|
| 382 | 416 | flags = PT_PTRACED; |
|---|
| .. | .. |
|---|
| 420 | 454 | |
|---|
| 421 | 455 | /* SEIZE doesn't trap tracee on attach */ |
|---|
| 422 | 456 | if (!seize) |
|---|
| 423 | | - send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); |
|---|
| 457 | + send_sig_info(SIGSTOP, SEND_SIG_PRIV, task); |
|---|
| 424 | 458 | |
|---|
| 425 | 459 | spin_lock(&task->sighand->siglock); |
|---|
| 426 | 460 | |
|---|
| .. | .. |
|---|
| 587 | 621 | |
|---|
| 588 | 622 | list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { |
|---|
| 589 | 623 | if (unlikely(p->ptrace & PT_EXITKILL)) |
|---|
| 590 | | - send_sig_info(SIGKILL, SEND_SIG_FORCED, p); |
|---|
| 624 | + send_sig_info(SIGKILL, SEND_SIG_PRIV, p); |
|---|
| 591 | 625 | |
|---|
| 592 | 626 | if (__ptrace_detach(tracer, p)) |
|---|
| 593 | 627 | list_add(&p->ptrace_entry, dead); |
|---|
| .. | .. |
|---|
| 649 | 683 | static int ptrace_setoptions(struct task_struct *child, unsigned long data) |
|---|
| 650 | 684 | { |
|---|
| 651 | 685 | unsigned flags; |
|---|
| 686 | + int ret; |
|---|
| 652 | 687 | |
|---|
| 653 | | - if (data & ~(unsigned long)PTRACE_O_MASK) |
|---|
| 654 | | - return -EINVAL; |
|---|
| 655 | | - |
|---|
| 656 | | - if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { |
|---|
| 657 | | - if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || |
|---|
| 658 | | - !IS_ENABLED(CONFIG_SECCOMP)) |
|---|
| 659 | | - return -EINVAL; |
|---|
| 660 | | - |
|---|
| 661 | | - if (!capable(CAP_SYS_ADMIN)) |
|---|
| 662 | | - return -EPERM; |
|---|
| 663 | | - |
|---|
| 664 | | - if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || |
|---|
| 665 | | - current->ptrace & PT_SUSPEND_SECCOMP) |
|---|
| 666 | | - return -EPERM; |
|---|
| 667 | | - } |
|---|
| 688 | + ret = check_ptrace_options(data); |
|---|
| 689 | + if (ret) |
|---|
| 690 | + return ret; |
|---|
| 668 | 691 | |
|---|
| 669 | 692 | /* Avoid intermediate state when all opts are cleared */ |
|---|
| 670 | 693 | flags = child->ptrace; |
|---|
| .. | .. |
|---|
| 675 | 698 | return 0; |
|---|
| 676 | 699 | } |
|---|
| 677 | 700 | |
|---|
| 678 | | -static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) |
|---|
| 701 | +static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info) |
|---|
| 679 | 702 | { |
|---|
| 680 | 703 | unsigned long flags; |
|---|
| 681 | 704 | int error = -ESRCH; |
|---|
| .. | .. |
|---|
| 691 | 714 | return error; |
|---|
| 692 | 715 | } |
|---|
| 693 | 716 | |
|---|
| 694 | | -static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) |
|---|
| 717 | +static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info) |
|---|
| 695 | 718 | { |
|---|
| 696 | 719 | unsigned long flags; |
|---|
| 697 | 720 | int error = -ESRCH; |
|---|
| .. | .. |
|---|
| 737 | 760 | pending = &child->pending; |
|---|
| 738 | 761 | |
|---|
| 739 | 762 | for (i = 0; i < arg.nr; ) { |
|---|
| 740 | | - siginfo_t info; |
|---|
| 763 | + kernel_siginfo_t info; |
|---|
| 741 | 764 | unsigned long off = arg.off + i; |
|---|
| 742 | 765 | bool found = false; |
|---|
| 743 | 766 | |
|---|
| .. | .. |
|---|
| 908 | 931 | * to ensure no machine forgets it. |
|---|
| 909 | 932 | */ |
|---|
| 910 | 933 | EXPORT_SYMBOL_GPL(task_user_regset_view); |
|---|
| 911 | | -#endif |
|---|
| 934 | + |
|---|
| 935 | +static unsigned long |
|---|
| 936 | +ptrace_get_syscall_info_entry(struct task_struct *child, struct pt_regs *regs, |
|---|
| 937 | + struct ptrace_syscall_info *info) |
|---|
| 938 | +{ |
|---|
| 939 | + unsigned long args[ARRAY_SIZE(info->entry.args)]; |
|---|
| 940 | + int i; |
|---|
| 941 | + |
|---|
| 942 | + info->op = PTRACE_SYSCALL_INFO_ENTRY; |
|---|
| 943 | + info->entry.nr = syscall_get_nr(child, regs); |
|---|
| 944 | + syscall_get_arguments(child, regs, args); |
|---|
| 945 | + for (i = 0; i < ARRAY_SIZE(args); i++) |
|---|
| 946 | + info->entry.args[i] = args[i]; |
|---|
| 947 | + |
|---|
| 948 | + /* args is the last field in struct ptrace_syscall_info.entry */ |
|---|
| 949 | + return offsetofend(struct ptrace_syscall_info, entry.args); |
|---|
| 950 | +} |
|---|
| 951 | + |
|---|
| 952 | +static unsigned long |
|---|
| 953 | +ptrace_get_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs, |
|---|
| 954 | + struct ptrace_syscall_info *info) |
|---|
| 955 | +{ |
|---|
| 956 | + /* |
|---|
| 957 | + * As struct ptrace_syscall_info.entry is currently a subset |
|---|
| 958 | + * of struct ptrace_syscall_info.seccomp, it makes sense to |
|---|
| 959 | + * initialize that subset using ptrace_get_syscall_info_entry(). |
|---|
| 960 | + * This can be reconsidered in the future if these structures |
|---|
| 961 | + * diverge significantly enough. |
|---|
| 962 | + */ |
|---|
| 963 | + ptrace_get_syscall_info_entry(child, regs, info); |
|---|
| 964 | + info->op = PTRACE_SYSCALL_INFO_SECCOMP; |
|---|
| 965 | + info->seccomp.ret_data = child->ptrace_message; |
|---|
| 966 | + |
|---|
| 967 | + /* ret_data is the last field in struct ptrace_syscall_info.seccomp */ |
|---|
| 968 | + return offsetofend(struct ptrace_syscall_info, seccomp.ret_data); |
|---|
| 969 | +} |
|---|
| 970 | + |
|---|
| 971 | +static unsigned long |
|---|
| 972 | +ptrace_get_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, |
|---|
| 973 | + struct ptrace_syscall_info *info) |
|---|
| 974 | +{ |
|---|
| 975 | + info->op = PTRACE_SYSCALL_INFO_EXIT; |
|---|
| 976 | + info->exit.rval = syscall_get_error(child, regs); |
|---|
| 977 | + info->exit.is_error = !!info->exit.rval; |
|---|
| 978 | + if (!info->exit.is_error) |
|---|
| 979 | + info->exit.rval = syscall_get_return_value(child, regs); |
|---|
| 980 | + |
|---|
| 981 | + /* is_error is the last field in struct ptrace_syscall_info.exit */ |
|---|
| 982 | + return offsetofend(struct ptrace_syscall_info, exit.is_error); |
|---|
| 983 | +} |
|---|
| 984 | + |
|---|
| 985 | +static int |
|---|
| 986 | +ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size, |
|---|
| 987 | + void __user *datavp) |
|---|
| 988 | +{ |
|---|
| 989 | + struct pt_regs *regs = task_pt_regs(child); |
|---|
| 990 | + struct ptrace_syscall_info info = { |
|---|
| 991 | + .op = PTRACE_SYSCALL_INFO_NONE, |
|---|
| 992 | + .arch = syscall_get_arch(child), |
|---|
| 993 | + .instruction_pointer = instruction_pointer(regs), |
|---|
| 994 | + .stack_pointer = user_stack_pointer(regs), |
|---|
| 995 | + }; |
|---|
| 996 | + unsigned long actual_size = offsetof(struct ptrace_syscall_info, entry); |
|---|
| 997 | + unsigned long write_size; |
|---|
| 998 | + |
|---|
| 999 | + /* |
|---|
| 1000 | + * This does not need lock_task_sighand() to access |
|---|
| 1001 | + * child->last_siginfo because ptrace_freeze_traced() |
|---|
| 1002 | + * called earlier by ptrace_check_attach() ensures that |
|---|
| 1003 | + * the tracee cannot go away and clear its last_siginfo. |
|---|
| 1004 | + */ |
|---|
| 1005 | + switch (child->last_siginfo ? child->last_siginfo->si_code : 0) { |
|---|
| 1006 | + case SIGTRAP | 0x80: |
|---|
| 1007 | + switch (child->ptrace_message) { |
|---|
| 1008 | + case PTRACE_EVENTMSG_SYSCALL_ENTRY: |
|---|
| 1009 | + actual_size = ptrace_get_syscall_info_entry(child, regs, |
|---|
| 1010 | + &info); |
|---|
| 1011 | + break; |
|---|
| 1012 | + case PTRACE_EVENTMSG_SYSCALL_EXIT: |
|---|
| 1013 | + actual_size = ptrace_get_syscall_info_exit(child, regs, |
|---|
| 1014 | + &info); |
|---|
| 1015 | + break; |
|---|
| 1016 | + } |
|---|
| 1017 | + break; |
|---|
| 1018 | + case SIGTRAP | (PTRACE_EVENT_SECCOMP << 8): |
|---|
| 1019 | + actual_size = ptrace_get_syscall_info_seccomp(child, regs, |
|---|
| 1020 | + &info); |
|---|
| 1021 | + break; |
|---|
| 1022 | + } |
|---|
| 1023 | + |
|---|
| 1024 | + write_size = min(actual_size, user_size); |
|---|
| 1025 | + return copy_to_user(datavp, &info, write_size) ? -EFAULT : actual_size; |
|---|
| 1026 | +} |
|---|
| 1027 | +#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ |
|---|
| 912 | 1028 | |
|---|
| 913 | 1029 | int ptrace_request(struct task_struct *child, long request, |
|---|
| 914 | 1030 | unsigned long addr, unsigned long data) |
|---|
| 915 | 1031 | { |
|---|
| 916 | 1032 | bool seized = child->ptrace & PT_SEIZED; |
|---|
| 917 | 1033 | int ret = -EIO; |
|---|
| 918 | | - siginfo_t siginfo, *si; |
|---|
| 1034 | + kernel_siginfo_t siginfo, *si; |
|---|
| 919 | 1035 | void __user *datavp = (void __user *) data; |
|---|
| 920 | 1036 | unsigned long __user *datalp = datavp; |
|---|
| 921 | 1037 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 949 | 1065 | break; |
|---|
| 950 | 1066 | |
|---|
| 951 | 1067 | case PTRACE_SETSIGINFO: |
|---|
| 952 | | - if (copy_from_user(&siginfo, datavp, sizeof siginfo)) |
|---|
| 953 | | - ret = -EFAULT; |
|---|
| 954 | | - else |
|---|
| 1068 | + ret = copy_siginfo_from_user(&siginfo, datavp); |
|---|
| 1069 | + if (!ret) |
|---|
| 955 | 1070 | ret = ptrace_setsiginfo(child, &siginfo); |
|---|
| 956 | 1071 | break; |
|---|
| 957 | 1072 | |
|---|
| .. | .. |
|---|
| 1104 | 1219 | return ptrace_resume(child, request, data); |
|---|
| 1105 | 1220 | |
|---|
| 1106 | 1221 | case PTRACE_KILL: |
|---|
| 1107 | | - if (child->exit_state) /* already dead */ |
|---|
| 1108 | | - return 0; |
|---|
| 1109 | | - return ptrace_resume(child, request, SIGKILL); |
|---|
| 1222 | + send_sig_info(SIGKILL, SEND_SIG_NOINFO, child); |
|---|
| 1223 | + return 0; |
|---|
| 1110 | 1224 | |
|---|
| 1111 | 1225 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
|---|
| 1112 | 1226 | case PTRACE_GETREGSET: |
|---|
| .. | .. |
|---|
| 1114 | 1228 | struct iovec kiov; |
|---|
| 1115 | 1229 | struct iovec __user *uiov = datavp; |
|---|
| 1116 | 1230 | |
|---|
| 1117 | | - if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) |
|---|
| 1231 | + if (!access_ok(uiov, sizeof(*uiov))) |
|---|
| 1118 | 1232 | return -EFAULT; |
|---|
| 1119 | 1233 | |
|---|
| 1120 | 1234 | if (__get_user(kiov.iov_base, &uiov->iov_base) || |
|---|
| .. | .. |
|---|
| 1126 | 1240 | ret = __put_user(kiov.iov_len, &uiov->iov_len); |
|---|
| 1127 | 1241 | break; |
|---|
| 1128 | 1242 | } |
|---|
| 1243 | + |
|---|
| 1244 | + case PTRACE_GET_SYSCALL_INFO: |
|---|
| 1245 | + ret = ptrace_get_syscall_info(child, addr, datavp); |
|---|
| 1246 | + break; |
|---|
| 1129 | 1247 | #endif |
|---|
| 1130 | 1248 | |
|---|
| 1131 | 1249 | case PTRACE_SECCOMP_GET_FILTER: |
|---|
| .. | .. |
|---|
| 1221 | 1339 | { |
|---|
| 1222 | 1340 | compat_ulong_t __user *datap = compat_ptr(data); |
|---|
| 1223 | 1341 | compat_ulong_t word; |
|---|
| 1224 | | - siginfo_t siginfo; |
|---|
| 1342 | + kernel_siginfo_t siginfo; |
|---|
| 1225 | 1343 | int ret; |
|---|
| 1226 | 1344 | |
|---|
| 1227 | 1345 | switch (request) { |
|---|
| .. | .. |
|---|
| 1255 | 1373 | break; |
|---|
| 1256 | 1374 | |
|---|
| 1257 | 1375 | case PTRACE_SETSIGINFO: |
|---|
| 1258 | | - if (copy_siginfo_from_user32( |
|---|
| 1259 | | - &siginfo, (struct compat_siginfo __user *) datap)) |
|---|
| 1260 | | - ret = -EFAULT; |
|---|
| 1261 | | - else |
|---|
| 1376 | + ret = copy_siginfo_from_user32( |
|---|
| 1377 | + &siginfo, (struct compat_siginfo __user *) datap); |
|---|
| 1378 | + if (!ret) |
|---|
| 1262 | 1379 | ret = ptrace_setsiginfo(child, &siginfo); |
|---|
| 1263 | 1380 | break; |
|---|
| 1264 | 1381 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
|---|
| .. | .. |
|---|
| 1271 | 1388 | compat_uptr_t ptr; |
|---|
| 1272 | 1389 | compat_size_t len; |
|---|
| 1273 | 1390 | |
|---|
| 1274 | | - if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) |
|---|
| 1391 | + if (!access_ok(uiov, sizeof(*uiov))) |
|---|
| 1275 | 1392 | return -EFAULT; |
|---|
| 1276 | 1393 | |
|---|
| 1277 | 1394 | if (__get_user(ptr, &uiov->iov_base) || |
|---|