.. | .. |
---|
| 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); |
---|
.. | .. |
---|
190 | 196 | spin_lock_irq(&task->sighand->siglock); |
---|
191 | 197 | if (task_is_traced(task) && !looks_like_a_spurious_pid(task) && |
---|
192 | 198 | !__fatal_signal_pending(task)) { |
---|
193 | | - task->state = __TASK_TRACED; |
---|
| 199 | + unsigned long flags; |
---|
| 200 | + |
---|
| 201 | + raw_spin_lock_irqsave(&task->pi_lock, flags); |
---|
| 202 | + if (task->state & __TASK_TRACED) |
---|
| 203 | + task->state = __TASK_TRACED; |
---|
| 204 | + else |
---|
| 205 | + task->saved_state = __TASK_TRACED; |
---|
| 206 | + raw_spin_unlock_irqrestore(&task->pi_lock, flags); |
---|
194 | 207 | ret = true; |
---|
195 | 208 | } |
---|
196 | 209 | spin_unlock_irq(&task->sighand->siglock); |
---|
.. | .. |
---|
200 | 213 | |
---|
201 | 214 | static void ptrace_unfreeze_traced(struct task_struct *task) |
---|
202 | 215 | { |
---|
203 | | - if (task->state != __TASK_TRACED) |
---|
204 | | - return; |
---|
| 216 | + unsigned long flags; |
---|
| 217 | + bool frozen = true; |
---|
205 | 218 | |
---|
206 | 219 | WARN_ON(!task->ptrace || task->parent != current); |
---|
207 | 220 | |
---|
.. | .. |
---|
210 | 223 | * Recheck state under the lock to close this race. |
---|
211 | 224 | */ |
---|
212 | 225 | spin_lock_irq(&task->sighand->siglock); |
---|
213 | | - if (task->state == __TASK_TRACED) { |
---|
214 | | - if (__fatal_signal_pending(task)) |
---|
215 | | - wake_up_state(task, __TASK_TRACED); |
---|
216 | | - else |
---|
217 | | - task->state = TASK_TRACED; |
---|
218 | | - } |
---|
| 226 | + |
---|
| 227 | + raw_spin_lock_irqsave(&task->pi_lock, flags); |
---|
| 228 | + if (task->state == __TASK_TRACED) |
---|
| 229 | + task->state = TASK_TRACED; |
---|
| 230 | + else if (task->saved_state == __TASK_TRACED) |
---|
| 231 | + task->saved_state = TASK_TRACED; |
---|
| 232 | + else |
---|
| 233 | + frozen = false; |
---|
| 234 | + raw_spin_unlock_irqrestore(&task->pi_lock, flags); |
---|
| 235 | + |
---|
| 236 | + if (frozen && __fatal_signal_pending(task)) |
---|
| 237 | + wake_up_state(task, __TASK_TRACED); |
---|
| 238 | + |
---|
219 | 239 | spin_unlock_irq(&task->sighand->siglock); |
---|
220 | 240 | } |
---|
221 | 241 | |
---|
.. | .. |
---|
364 | 384 | return !err; |
---|
365 | 385 | } |
---|
366 | 386 | |
---|
| 387 | +static int check_ptrace_options(unsigned long data) |
---|
| 388 | +{ |
---|
| 389 | + if (data & ~(unsigned long)PTRACE_O_MASK) |
---|
| 390 | + return -EINVAL; |
---|
| 391 | + |
---|
| 392 | + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { |
---|
| 393 | + if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || |
---|
| 394 | + !IS_ENABLED(CONFIG_SECCOMP)) |
---|
| 395 | + return -EINVAL; |
---|
| 396 | + |
---|
| 397 | + if (!capable(CAP_SYS_ADMIN)) |
---|
| 398 | + return -EPERM; |
---|
| 399 | + |
---|
| 400 | + if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || |
---|
| 401 | + current->ptrace & PT_SUSPEND_SECCOMP) |
---|
| 402 | + return -EPERM; |
---|
| 403 | + } |
---|
| 404 | + return 0; |
---|
| 405 | +} |
---|
| 406 | + |
---|
367 | 407 | static int ptrace_attach(struct task_struct *task, long request, |
---|
368 | 408 | unsigned long addr, |
---|
369 | 409 | unsigned long flags) |
---|
.. | .. |
---|
375 | 415 | if (seize) { |
---|
376 | 416 | if (addr != 0) |
---|
377 | 417 | goto out; |
---|
| 418 | + /* |
---|
| 419 | + * This duplicates the check in check_ptrace_options() because |
---|
| 420 | + * ptrace_attach() and ptrace_setoptions() have historically |
---|
| 421 | + * used different error codes for unknown ptrace options. |
---|
| 422 | + */ |
---|
378 | 423 | if (flags & ~(unsigned long)PTRACE_O_MASK) |
---|
379 | 424 | goto out; |
---|
| 425 | + retval = check_ptrace_options(flags); |
---|
| 426 | + if (retval) |
---|
| 427 | + return retval; |
---|
380 | 428 | flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT); |
---|
381 | 429 | } else { |
---|
382 | 430 | flags = PT_PTRACED; |
---|
.. | .. |
---|
420 | 468 | |
---|
421 | 469 | /* SEIZE doesn't trap tracee on attach */ |
---|
422 | 470 | if (!seize) |
---|
423 | | - send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); |
---|
| 471 | + send_sig_info(SIGSTOP, SEND_SIG_PRIV, task); |
---|
424 | 472 | |
---|
425 | 473 | spin_lock(&task->sighand->siglock); |
---|
426 | 474 | |
---|
.. | .. |
---|
587 | 635 | |
---|
588 | 636 | list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { |
---|
589 | 637 | if (unlikely(p->ptrace & PT_EXITKILL)) |
---|
590 | | - send_sig_info(SIGKILL, SEND_SIG_FORCED, p); |
---|
| 638 | + send_sig_info(SIGKILL, SEND_SIG_PRIV, p); |
---|
591 | 639 | |
---|
592 | 640 | if (__ptrace_detach(tracer, p)) |
---|
593 | 641 | list_add(&p->ptrace_entry, dead); |
---|
.. | .. |
---|
649 | 697 | static int ptrace_setoptions(struct task_struct *child, unsigned long data) |
---|
650 | 698 | { |
---|
651 | 699 | unsigned flags; |
---|
| 700 | + int ret; |
---|
652 | 701 | |
---|
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 | | - } |
---|
| 702 | + ret = check_ptrace_options(data); |
---|
| 703 | + if (ret) |
---|
| 704 | + return ret; |
---|
668 | 705 | |
---|
669 | 706 | /* Avoid intermediate state when all opts are cleared */ |
---|
670 | 707 | flags = child->ptrace; |
---|
.. | .. |
---|
675 | 712 | return 0; |
---|
676 | 713 | } |
---|
677 | 714 | |
---|
678 | | -static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) |
---|
| 715 | +static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info) |
---|
679 | 716 | { |
---|
680 | 717 | unsigned long flags; |
---|
681 | 718 | int error = -ESRCH; |
---|
.. | .. |
---|
691 | 728 | return error; |
---|
692 | 729 | } |
---|
693 | 730 | |
---|
694 | | -static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) |
---|
| 731 | +static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info) |
---|
695 | 732 | { |
---|
696 | 733 | unsigned long flags; |
---|
697 | 734 | int error = -ESRCH; |
---|
.. | .. |
---|
737 | 774 | pending = &child->pending; |
---|
738 | 775 | |
---|
739 | 776 | for (i = 0; i < arg.nr; ) { |
---|
740 | | - siginfo_t info; |
---|
| 777 | + kernel_siginfo_t info; |
---|
741 | 778 | unsigned long off = arg.off + i; |
---|
742 | 779 | bool found = false; |
---|
743 | 780 | |
---|
.. | .. |
---|
908 | 945 | * to ensure no machine forgets it. |
---|
909 | 946 | */ |
---|
910 | 947 | EXPORT_SYMBOL_GPL(task_user_regset_view); |
---|
911 | | -#endif |
---|
| 948 | + |
---|
| 949 | +static unsigned long |
---|
| 950 | +ptrace_get_syscall_info_entry(struct task_struct *child, struct pt_regs *regs, |
---|
| 951 | + struct ptrace_syscall_info *info) |
---|
| 952 | +{ |
---|
| 953 | + unsigned long args[ARRAY_SIZE(info->entry.args)]; |
---|
| 954 | + int i; |
---|
| 955 | + |
---|
| 956 | + info->op = PTRACE_SYSCALL_INFO_ENTRY; |
---|
| 957 | + info->entry.nr = syscall_get_nr(child, regs); |
---|
| 958 | + syscall_get_arguments(child, regs, args); |
---|
| 959 | + for (i = 0; i < ARRAY_SIZE(args); i++) |
---|
| 960 | + info->entry.args[i] = args[i]; |
---|
| 961 | + |
---|
| 962 | + /* args is the last field in struct ptrace_syscall_info.entry */ |
---|
| 963 | + return offsetofend(struct ptrace_syscall_info, entry.args); |
---|
| 964 | +} |
---|
| 965 | + |
---|
| 966 | +static unsigned long |
---|
| 967 | +ptrace_get_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs, |
---|
| 968 | + struct ptrace_syscall_info *info) |
---|
| 969 | +{ |
---|
| 970 | + /* |
---|
| 971 | + * As struct ptrace_syscall_info.entry is currently a subset |
---|
| 972 | + * of struct ptrace_syscall_info.seccomp, it makes sense to |
---|
| 973 | + * initialize that subset using ptrace_get_syscall_info_entry(). |
---|
| 974 | + * This can be reconsidered in the future if these structures |
---|
| 975 | + * diverge significantly enough. |
---|
| 976 | + */ |
---|
| 977 | + ptrace_get_syscall_info_entry(child, regs, info); |
---|
| 978 | + info->op = PTRACE_SYSCALL_INFO_SECCOMP; |
---|
| 979 | + info->seccomp.ret_data = child->ptrace_message; |
---|
| 980 | + |
---|
| 981 | + /* ret_data is the last field in struct ptrace_syscall_info.seccomp */ |
---|
| 982 | + return offsetofend(struct ptrace_syscall_info, seccomp.ret_data); |
---|
| 983 | +} |
---|
| 984 | + |
---|
| 985 | +static unsigned long |
---|
| 986 | +ptrace_get_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, |
---|
| 987 | + struct ptrace_syscall_info *info) |
---|
| 988 | +{ |
---|
| 989 | + info->op = PTRACE_SYSCALL_INFO_EXIT; |
---|
| 990 | + info->exit.rval = syscall_get_error(child, regs); |
---|
| 991 | + info->exit.is_error = !!info->exit.rval; |
---|
| 992 | + if (!info->exit.is_error) |
---|
| 993 | + info->exit.rval = syscall_get_return_value(child, regs); |
---|
| 994 | + |
---|
| 995 | + /* is_error is the last field in struct ptrace_syscall_info.exit */ |
---|
| 996 | + return offsetofend(struct ptrace_syscall_info, exit.is_error); |
---|
| 997 | +} |
---|
| 998 | + |
---|
| 999 | +static int |
---|
| 1000 | +ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size, |
---|
| 1001 | + void __user *datavp) |
---|
| 1002 | +{ |
---|
| 1003 | + struct pt_regs *regs = task_pt_regs(child); |
---|
| 1004 | + struct ptrace_syscall_info info = { |
---|
| 1005 | + .op = PTRACE_SYSCALL_INFO_NONE, |
---|
| 1006 | + .arch = syscall_get_arch(child), |
---|
| 1007 | + .instruction_pointer = instruction_pointer(regs), |
---|
| 1008 | + .stack_pointer = user_stack_pointer(regs), |
---|
| 1009 | + }; |
---|
| 1010 | + unsigned long actual_size = offsetof(struct ptrace_syscall_info, entry); |
---|
| 1011 | + unsigned long write_size; |
---|
| 1012 | + |
---|
| 1013 | + /* |
---|
| 1014 | + * This does not need lock_task_sighand() to access |
---|
| 1015 | + * child->last_siginfo because ptrace_freeze_traced() |
---|
| 1016 | + * called earlier by ptrace_check_attach() ensures that |
---|
| 1017 | + * the tracee cannot go away and clear its last_siginfo. |
---|
| 1018 | + */ |
---|
| 1019 | + switch (child->last_siginfo ? child->last_siginfo->si_code : 0) { |
---|
| 1020 | + case SIGTRAP | 0x80: |
---|
| 1021 | + switch (child->ptrace_message) { |
---|
| 1022 | + case PTRACE_EVENTMSG_SYSCALL_ENTRY: |
---|
| 1023 | + actual_size = ptrace_get_syscall_info_entry(child, regs, |
---|
| 1024 | + &info); |
---|
| 1025 | + break; |
---|
| 1026 | + case PTRACE_EVENTMSG_SYSCALL_EXIT: |
---|
| 1027 | + actual_size = ptrace_get_syscall_info_exit(child, regs, |
---|
| 1028 | + &info); |
---|
| 1029 | + break; |
---|
| 1030 | + } |
---|
| 1031 | + break; |
---|
| 1032 | + case SIGTRAP | (PTRACE_EVENT_SECCOMP << 8): |
---|
| 1033 | + actual_size = ptrace_get_syscall_info_seccomp(child, regs, |
---|
| 1034 | + &info); |
---|
| 1035 | + break; |
---|
| 1036 | + } |
---|
| 1037 | + |
---|
| 1038 | + write_size = min(actual_size, user_size); |
---|
| 1039 | + return copy_to_user(datavp, &info, write_size) ? -EFAULT : actual_size; |
---|
| 1040 | +} |
---|
| 1041 | +#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ |
---|
912 | 1042 | |
---|
913 | 1043 | int ptrace_request(struct task_struct *child, long request, |
---|
914 | 1044 | unsigned long addr, unsigned long data) |
---|
915 | 1045 | { |
---|
916 | 1046 | bool seized = child->ptrace & PT_SEIZED; |
---|
917 | 1047 | int ret = -EIO; |
---|
918 | | - siginfo_t siginfo, *si; |
---|
| 1048 | + kernel_siginfo_t siginfo, *si; |
---|
919 | 1049 | void __user *datavp = (void __user *) data; |
---|
920 | 1050 | unsigned long __user *datalp = datavp; |
---|
921 | 1051 | unsigned long flags; |
---|
.. | .. |
---|
949 | 1079 | break; |
---|
950 | 1080 | |
---|
951 | 1081 | case PTRACE_SETSIGINFO: |
---|
952 | | - if (copy_from_user(&siginfo, datavp, sizeof siginfo)) |
---|
953 | | - ret = -EFAULT; |
---|
954 | | - else |
---|
| 1082 | + ret = copy_siginfo_from_user(&siginfo, datavp); |
---|
| 1083 | + if (!ret) |
---|
955 | 1084 | ret = ptrace_setsiginfo(child, &siginfo); |
---|
956 | 1085 | break; |
---|
957 | 1086 | |
---|
.. | .. |
---|
1104 | 1233 | return ptrace_resume(child, request, data); |
---|
1105 | 1234 | |
---|
1106 | 1235 | case PTRACE_KILL: |
---|
1107 | | - if (child->exit_state) /* already dead */ |
---|
1108 | | - return 0; |
---|
1109 | | - return ptrace_resume(child, request, SIGKILL); |
---|
| 1236 | + send_sig_info(SIGKILL, SEND_SIG_NOINFO, child); |
---|
| 1237 | + return 0; |
---|
1110 | 1238 | |
---|
1111 | 1239 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
---|
1112 | 1240 | case PTRACE_GETREGSET: |
---|
.. | .. |
---|
1114 | 1242 | struct iovec kiov; |
---|
1115 | 1243 | struct iovec __user *uiov = datavp; |
---|
1116 | 1244 | |
---|
1117 | | - if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) |
---|
| 1245 | + if (!access_ok(uiov, sizeof(*uiov))) |
---|
1118 | 1246 | return -EFAULT; |
---|
1119 | 1247 | |
---|
1120 | 1248 | if (__get_user(kiov.iov_base, &uiov->iov_base) || |
---|
.. | .. |
---|
1126 | 1254 | ret = __put_user(kiov.iov_len, &uiov->iov_len); |
---|
1127 | 1255 | break; |
---|
1128 | 1256 | } |
---|
| 1257 | + |
---|
| 1258 | + case PTRACE_GET_SYSCALL_INFO: |
---|
| 1259 | + ret = ptrace_get_syscall_info(child, addr, datavp); |
---|
| 1260 | + break; |
---|
1129 | 1261 | #endif |
---|
1130 | 1262 | |
---|
1131 | 1263 | case PTRACE_SECCOMP_GET_FILTER: |
---|
.. | .. |
---|
1221 | 1353 | { |
---|
1222 | 1354 | compat_ulong_t __user *datap = compat_ptr(data); |
---|
1223 | 1355 | compat_ulong_t word; |
---|
1224 | | - siginfo_t siginfo; |
---|
| 1356 | + kernel_siginfo_t siginfo; |
---|
1225 | 1357 | int ret; |
---|
1226 | 1358 | |
---|
1227 | 1359 | switch (request) { |
---|
.. | .. |
---|
1255 | 1387 | break; |
---|
1256 | 1388 | |
---|
1257 | 1389 | case PTRACE_SETSIGINFO: |
---|
1258 | | - if (copy_siginfo_from_user32( |
---|
1259 | | - &siginfo, (struct compat_siginfo __user *) datap)) |
---|
1260 | | - ret = -EFAULT; |
---|
1261 | | - else |
---|
| 1390 | + ret = copy_siginfo_from_user32( |
---|
| 1391 | + &siginfo, (struct compat_siginfo __user *) datap); |
---|
| 1392 | + if (!ret) |
---|
1262 | 1393 | ret = ptrace_setsiginfo(child, &siginfo); |
---|
1263 | 1394 | break; |
---|
1264 | 1395 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
---|
.. | .. |
---|
1271 | 1402 | compat_uptr_t ptr; |
---|
1272 | 1403 | compat_size_t len; |
---|
1273 | 1404 | |
---|
1274 | | - if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) |
---|
| 1405 | + if (!access_ok(uiov, sizeof(*uiov))) |
---|
1275 | 1406 | return -EFAULT; |
---|
1276 | 1407 | |
---|
1277 | 1408 | if (__get_user(ptr, &uiov->iov_base) || |
---|