1
2
3
4
5
6
7
8
9
10#include <linux/kernel.h>
11#include <linux/sched.h>
12#include <linux/mm.h>
13#include <linux/smp.h>
14#include <linux/errno.h>
15#include <linux/ptrace.h>
16#include <linux/tracehook.h>
17#include <linux/user.h>
18#include <linux/personality.h>
19#include <linux/security.h>
20#include <linux/seccomp.h>
21#include <linux/compat.h>
22#include <linux/signal.h>
23#include <linux/audit.h>
24
25#include <asm/uaccess.h>
26#include <asm/pgtable.h>
27#include <asm/processor.h>
28#include <asm/asm-offsets.h>
29
30
31#define USER_PSW_BITS (PSW_N | PSW_B | PSW_V | PSW_CB)
32
33
34
35
36
37
38void ptrace_disable(struct task_struct *task)
39{
40 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
41 clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
42
43
44 pa_psw(task)->r = 0;
45 pa_psw(task)->t = 0;
46 pa_psw(task)->h = 0;
47 pa_psw(task)->l = 0;
48}
49
50
51
52
53
54void user_disable_single_step(struct task_struct *task)
55{
56 ptrace_disable(task);
57}
58
59void user_enable_single_step(struct task_struct *task)
60{
61 clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
62 set_tsk_thread_flag(task, TIF_SINGLESTEP);
63
64 if (pa_psw(task)->n) {
65 struct siginfo si;
66
67
68 task_regs(task)->iaoq[0] = task_regs(task)->iaoq[1];
69 task_regs(task)->iasq[0] = task_regs(task)->iasq[1];
70 task_regs(task)->iaoq[1] = task_regs(task)->iaoq[0] + 4;
71 pa_psw(task)->n = 0;
72 pa_psw(task)->x = 0;
73 pa_psw(task)->y = 0;
74 pa_psw(task)->z = 0;
75 pa_psw(task)->b = 0;
76 ptrace_disable(task);
77
78
79 si.si_code = TRAP_TRACE;
80 si.si_addr = (void __user *) (task_regs(task)->iaoq[0] & ~3);
81 si.si_signo = SIGTRAP;
82 si.si_errno = 0;
83 force_sig_info(SIGTRAP, &si, task);
84
85 return;
86 }
87
88
89
90
91
92
93
94
95
96 pa_psw(task)->r = 1;
97 pa_psw(task)->t = 0;
98 pa_psw(task)->h = 0;
99 pa_psw(task)->l = 0;
100}
101
102void user_enable_block_step(struct task_struct *task)
103{
104 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
105 set_tsk_thread_flag(task, TIF_BLOCKSTEP);
106
107
108 pa_psw(task)->r = 0;
109 pa_psw(task)->t = 1;
110 pa_psw(task)->h = 0;
111 pa_psw(task)->l = 0;
112}
113
114long arch_ptrace(struct task_struct *child, long request,
115 unsigned long addr, unsigned long data)
116{
117 unsigned long tmp;
118 long ret = -EIO;
119
120 switch (request) {
121
122
123
124 case PTRACE_PEEKUSR:
125 if ((addr & (sizeof(unsigned long)-1)) ||
126 addr >= sizeof(struct pt_regs))
127 break;
128 tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
129 ret = put_user(tmp, (unsigned long __user *) data);
130 break;
131
132
133
134
135
136
137
138 case PTRACE_POKEUSR:
139
140
141
142
143 if (addr == PT_PSW) {
144
145
146
147
148
149 data &= USER_PSW_BITS;
150 task_regs(child)->gr[0] &= ~USER_PSW_BITS;
151 task_regs(child)->gr[0] |= data;
152 ret = 0;
153 break;
154 }
155
156 if ((addr & (sizeof(unsigned long)-1)) ||
157 addr >= sizeof(struct pt_regs))
158 break;
159 if ((addr >= PT_GR1 && addr <= PT_GR31) ||
160 addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
161 (addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
162 addr == PT_SAR) {
163 *(unsigned long *) ((char *) task_regs(child) + addr) = data;
164 ret = 0;
165 }
166 break;
167
168 default:
169 ret = ptrace_request(child, request, addr, data);
170 break;
171 }
172
173 return ret;
174}
175
176
177#ifdef CONFIG_COMPAT
178
179
180
181
182
183
184
185
186
187
188
189
190static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
191{
192 if (offset < 0)
193 return sizeof(struct pt_regs);
194 else if (offset <= 32*4)
195 return offset * 2 + 4;
196 else if (offset <= 32*4+32*8)
197 return offset + 32*4;
198 else if (offset < sizeof(struct pt_regs)/2 + 32*4)
199 return offset * 2 + 4 - 32*8;
200 else
201 return sizeof(struct pt_regs);
202}
203
204long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
205 compat_ulong_t addr, compat_ulong_t data)
206{
207 compat_uint_t tmp;
208 long ret = -EIO;
209
210 switch (request) {
211
212 case PTRACE_PEEKUSR:
213 if (addr & (sizeof(compat_uint_t)-1))
214 break;
215 addr = translate_usr_offset(addr);
216 if (addr >= sizeof(struct pt_regs))
217 break;
218
219 tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr);
220 ret = put_user(tmp, (compat_uint_t *) (unsigned long) data);
221 break;
222
223
224
225
226
227
228
229 case PTRACE_POKEUSR:
230
231
232
233
234 if (addr == PT_PSW) {
235
236
237
238 ret = arch_ptrace(child, request, addr, data);
239 } else {
240 if (addr & (sizeof(compat_uint_t)-1))
241 break;
242 addr = translate_usr_offset(addr);
243 if (addr >= sizeof(struct pt_regs))
244 break;
245 if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
246
247 *(__u64 *) ((char *) task_regs(child) + addr) = data;
248 ret = 0;
249 }
250 else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
251 addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
252 addr == PT_SAR+4) {
253
254 *(__u32 *) ((char *) task_regs(child) + addr - 4) = 0;
255 *(__u32 *) ((char *) task_regs(child) + addr) = data;
256 ret = 0;
257 }
258 }
259 break;
260
261 default:
262 ret = compat_ptrace_request(child, request, addr, data);
263 break;
264 }
265
266 return ret;
267}
268#endif
269
270long do_syscall_trace_enter(struct pt_regs *regs)
271{
272
273 if (secure_computing() == -1)
274 return -1;
275
276 if (test_thread_flag(TIF_SYSCALL_TRACE) &&
277 tracehook_report_syscall_entry(regs)) {
278
279
280
281
282
283 regs->gr[20] = -1UL;
284 goto out;
285 }
286
287#ifdef CONFIG_64BIT
288 if (!is_compat_task())
289 audit_syscall_entry(regs->gr[20], regs->gr[26], regs->gr[25],
290 regs->gr[24], regs->gr[23]);
291 else
292#endif
293 audit_syscall_entry(regs->gr[20] & 0xffffffff,
294 regs->gr[26] & 0xffffffff,
295 regs->gr[25] & 0xffffffff,
296 regs->gr[24] & 0xffffffff,
297 regs->gr[23] & 0xffffffff);
298
299out:
300
301
302
303
304 return (int) ((u32) regs->gr[20]);
305}
306
307void do_syscall_trace_exit(struct pt_regs *regs)
308{
309 int stepping = test_thread_flag(TIF_SINGLESTEP) ||
310 test_thread_flag(TIF_BLOCKSTEP);
311
312 audit_syscall_exit(regs);
313
314 if (stepping || test_thread_flag(TIF_SYSCALL_TRACE))
315 tracehook_report_syscall_exit(regs, stepping);
316}
317