1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
4 | */ |
5 | |
6 | #include <linux/audit.h> |
7 | #include <linux/ptrace.h> |
8 | #include <linux/sched.h> |
9 | #include <linux/uaccess.h> |
10 | #include <asm/ptrace-abi.h> |
11 | |
12 | void user_enable_single_step(struct task_struct *child) |
13 | { |
14 | set_tsk_thread_flag(tsk: child, TIF_SINGLESTEP); |
15 | |
16 | #ifdef SUBARCH_SET_SINGLESTEPPING |
17 | SUBARCH_SET_SINGLESTEPPING(child, 1); |
18 | #endif |
19 | } |
20 | |
21 | void user_disable_single_step(struct task_struct *child) |
22 | { |
23 | clear_tsk_thread_flag(tsk: child, TIF_SINGLESTEP); |
24 | |
25 | #ifdef SUBARCH_SET_SINGLESTEPPING |
26 | SUBARCH_SET_SINGLESTEPPING(child, 0); |
27 | #endif |
28 | } |
29 | |
30 | /* |
31 | * Called by kernel/ptrace.c when detaching.. |
32 | */ |
33 | void ptrace_disable(struct task_struct *child) |
34 | { |
35 | user_disable_single_step(child); |
36 | } |
37 | |
38 | extern int peek_user(struct task_struct * child, long addr, long data); |
39 | extern int poke_user(struct task_struct * child, long addr, long data); |
40 | |
41 | long arch_ptrace(struct task_struct *child, long request, |
42 | unsigned long addr, unsigned long data) |
43 | { |
44 | int i, ret; |
45 | unsigned long __user *p = (void __user *)data; |
46 | void __user *vp = p; |
47 | |
48 | switch (request) { |
49 | /* read the word at location addr in the USER area. */ |
50 | case PTRACE_PEEKUSR: |
51 | ret = peek_user(child, addr, data); |
52 | break; |
53 | |
54 | /* write the word at location addr in the USER area */ |
55 | case PTRACE_POKEUSR: |
56 | ret = poke_user(child, addr, data); |
57 | break; |
58 | |
59 | case PTRACE_SYSEMU: |
60 | case PTRACE_SYSEMU_SINGLESTEP: |
61 | ret = -EIO; |
62 | break; |
63 | |
64 | #ifdef PTRACE_GETREGS |
65 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ |
66 | if (!access_ok(p, MAX_REG_OFFSET)) { |
67 | ret = -EIO; |
68 | break; |
69 | } |
70 | for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { |
71 | __put_user(getreg(child, i), p); |
72 | p++; |
73 | } |
74 | ret = 0; |
75 | break; |
76 | } |
77 | #endif |
78 | #ifdef PTRACE_SETREGS |
79 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ |
80 | unsigned long tmp = 0; |
81 | if (!access_ok(p, MAX_REG_OFFSET)) { |
82 | ret = -EIO; |
83 | break; |
84 | } |
85 | for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { |
86 | __get_user(tmp, p); |
87 | putreg(child, i, tmp); |
88 | p++; |
89 | } |
90 | ret = 0; |
91 | break; |
92 | } |
93 | #endif |
94 | case PTRACE_GET_THREAD_AREA: |
95 | ret = ptrace_get_thread_area(child, addr, vp); |
96 | break; |
97 | |
98 | case PTRACE_SET_THREAD_AREA: |
99 | ret = ptrace_set_thread_area(child, addr, vp); |
100 | break; |
101 | |
102 | default: |
103 | ret = ptrace_request(child, request, addr, data); |
104 | if (ret == -EIO) |
105 | ret = subarch_ptrace(child, request, addr, data); |
106 | break; |
107 | } |
108 | |
109 | return ret; |
110 | } |
111 | |
112 | static void send_sigtrap(struct uml_pt_regs *regs, int error_code) |
113 | { |
114 | /* Send us the fake SIGTRAP */ |
115 | force_sig_fault(SIGTRAP, TRAP_BRKPT, |
116 | /* User-mode eip? */ |
117 | addr: UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL); |
118 | } |
119 | |
120 | /* |
121 | * XXX Check TIF_SINGLESTEP for singlestepping check and |
122 | * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check |
123 | */ |
124 | int syscall_trace_enter(struct pt_regs *regs) |
125 | { |
126 | audit_syscall_entry(major: UPT_SYSCALL_NR(®s->regs), |
127 | a0: UPT_SYSCALL_ARG1(®s->regs), |
128 | a1: UPT_SYSCALL_ARG2(®s->regs), |
129 | a2: UPT_SYSCALL_ARG3(®s->regs), |
130 | a3: UPT_SYSCALL_ARG4(®s->regs)); |
131 | |
132 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) |
133 | return 0; |
134 | |
135 | return ptrace_report_syscall_entry(regs); |
136 | } |
137 | |
138 | void syscall_trace_leave(struct pt_regs *regs) |
139 | { |
140 | int ptraced = current->ptrace; |
141 | |
142 | audit_syscall_exit(pt_regs: regs); |
143 | |
144 | /* Fake a debug trap */ |
145 | if (test_thread_flag(TIF_SINGLESTEP)) |
146 | send_sigtrap(regs: ®s->regs, error_code: 0); |
147 | |
148 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) |
149 | return; |
150 | |
151 | ptrace_report_syscall_exit(regs, step: 0); |
152 | /* force do_signal() --> is_syscall() */ |
153 | if (ptraced & PT_PTRACED) |
154 | set_thread_flag(TIF_SIGPENDING); |
155 | } |
156 | |