blob: ba13e924c430ffeaaf50a17fda93b3dd0ca2cf2d [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Roland McGrathbbc69862008-07-25 19:45:59 -07002#include <linux/ptrace.h>
3#include <linux/sched.h>
Ingo Molnar68db0cf2017-02-08 18:51:37 +01004#include <linux/sched/task_stack.h>
Paul Gortmaker8bc3bcc2011-11-16 21:29:17 -05005#include <linux/export.h>
Roland McGrathbbc69862008-07-25 19:45:59 -07006#include <asm/syscall.h>
7
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -05008static int collect_syscall(struct task_struct *target, struct syscall_info *info)
Roland McGrathbbc69862008-07-25 19:45:59 -07009{
Willy Tarreau4f134b82020-11-30 08:36:48 +010010 unsigned long args[6] = { };
Andy Lutomirskiaa1f1a62016-09-15 22:45:47 -070011 struct pt_regs *regs;
12
13 if (!try_get_task_stack(target)) {
14 /* Task has no stack, so the task isn't in a syscall. */
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050015 memset(info, 0, sizeof(*info));
16 info->data.nr = -1;
Andy Lutomirskiaa1f1a62016-09-15 22:45:47 -070017 return 0;
18 }
19
20 regs = task_pt_regs(target);
21 if (unlikely(!regs)) {
22 put_task_stack(target);
Roland McGrathbbc69862008-07-25 19:45:59 -070023 return -EAGAIN;
Andy Lutomirskiaa1f1a62016-09-15 22:45:47 -070024 }
Roland McGrathbbc69862008-07-25 19:45:59 -070025
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050026 info->sp = user_stack_pointer(regs);
27 info->data.instruction_pointer = instruction_pointer(regs);
Roland McGrathbbc69862008-07-25 19:45:59 -070028
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050029 info->data.nr = syscall_get_nr(target, regs);
30 if (info->data.nr != -1L)
Willy Tarreau4f134b82020-11-30 08:36:48 +010031 syscall_get_arguments(target, regs, args);
32
33 info->data.args[0] = args[0];
34 info->data.args[1] = args[1];
35 info->data.args[2] = args[2];
36 info->data.args[3] = args[3];
37 info->data.args[4] = args[4];
38 info->data.args[5] = args[5];
Roland McGrathbbc69862008-07-25 19:45:59 -070039
Andy Lutomirskiaa1f1a62016-09-15 22:45:47 -070040 put_task_stack(target);
Roland McGrathbbc69862008-07-25 19:45:59 -070041 return 0;
42}
43
44/**
45 * task_current_syscall - Discover what a blocked task is doing.
46 * @target: thread to examine
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050047 * @info: structure with the following fields:
48 * .sp - filled with user stack pointer
49 * .data.nr - filled with system call number or -1
50 * .data.args - filled with @maxargs system call arguments
51 * .data.instruction_pointer - filled with user PC
Roland McGrathbbc69862008-07-25 19:45:59 -070052 *
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050053 * If @target is blocked in a system call, returns zero with @info.data.nr
Randy Dunlap408a93a2020-10-15 20:11:07 -070054 * set to the call's number and @info.data.args filled in with its
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050055 * arguments. Registers not used for system call arguments may not be available
56 * and it is not kosher to use &struct user_regset calls while the system
Roland McGrathbbc69862008-07-25 19:45:59 -070057 * call is still in progress. Note we may get this result if @target
58 * has finished its system call but not yet returned to user mode, such
59 * as when it's stopped for signal handling or syscall exit tracing.
60 *
61 * If @target is blocked in the kernel during a fault or exception,
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050062 * returns zero with *@info.data.nr set to -1 and does not fill in
63 * @info.data.args. If so, it's now safe to examine @target using
64 * &struct user_regset get() calls as long as we're sure @target won't return
65 * to user mode.
Roland McGrathbbc69862008-07-25 19:45:59 -070066 *
67 * Returns -%EAGAIN if @target does not remain blocked.
Roland McGrathbbc69862008-07-25 19:45:59 -070068 */
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050069int task_current_syscall(struct task_struct *target, struct syscall_info *info)
Roland McGrathbbc69862008-07-25 19:45:59 -070070{
71 long state;
72 unsigned long ncsw;
73
Roland McGrathbbc69862008-07-25 19:45:59 -070074 if (target == current)
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050075 return collect_syscall(target, info);
Roland McGrathbbc69862008-07-25 19:45:59 -070076
77 state = target->state;
78 if (unlikely(!state))
79 return -EAGAIN;
80
81 ncsw = wait_task_inactive(target, state);
82 if (unlikely(!ncsw) ||
Steven Rostedt (Red Hat)631b7ab2016-11-07 16:26:35 -050083 unlikely(collect_syscall(target, info)) ||
Roland McGrathbbc69862008-07-25 19:45:59 -070084 unlikely(wait_task_inactive(target, state) != ncsw))
85 return -EAGAIN;
86
87 return 0;
88}