^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/sched/task_stack.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <asm/syscall.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) static int collect_syscall(struct task_struct *target, struct syscall_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) unsigned long args[6] = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct pt_regs *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) if (!try_get_task_stack(target)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /* Task has no stack, so the task isn't in a syscall. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) memset(info, 0, sizeof(*info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) info->data.nr = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) regs = task_pt_regs(target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) if (unlikely(!regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) put_task_stack(target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) info->sp = user_stack_pointer(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) info->data.instruction_pointer = instruction_pointer(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) info->data.nr = syscall_get_nr(target, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (info->data.nr != -1L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) syscall_get_arguments(target, regs, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) info->data.args[0] = args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) info->data.args[1] = args[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) info->data.args[2] = args[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) info->data.args[3] = args[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) info->data.args[4] = args[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) info->data.args[5] = args[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) put_task_stack(target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * task_current_syscall - Discover what a blocked task is doing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * @target: thread to examine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * @info: structure with the following fields:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * .sp - filled with user stack pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * .data.nr - filled with system call number or -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * .data.args - filled with @maxargs system call arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * .data.instruction_pointer - filled with user PC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * If @target is blocked in a system call, returns zero with @info.data.nr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * set to the call's number and @info.data.args filled in with its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * arguments. Registers not used for system call arguments may not be available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * and it is not kosher to use &struct user_regset calls while the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * call is still in progress. Note we may get this result if @target
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * has finished its system call but not yet returned to user mode, such
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * as when it's stopped for signal handling or syscall exit tracing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * If @target is blocked in the kernel during a fault or exception,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * returns zero with *@info.data.nr set to -1 and does not fill in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * @info.data.args. If so, it's now safe to examine @target using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * &struct user_regset get() calls as long as we're sure @target won't return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * to user mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * Returns -%EAGAIN if @target does not remain blocked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int task_current_syscall(struct task_struct *target, struct syscall_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) long state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) unsigned long ncsw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (target == current)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return collect_syscall(target, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) state = target->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (unlikely(!state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ncsw = wait_task_inactive(target, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (unlikely(!ncsw) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unlikely(collect_syscall(target, info)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unlikely(wait_task_inactive(target, state) != ncsw))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }