1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/kernel.h>
15#include <linux/stddef.h>
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <asm/ptrace.h>
19#include <asm/uaccess.h>
20#include <asm/user32.h>
21#include <asm/user.h>
22#include <asm/errno.h>
23#include <asm/debugreg.h>
24#include <asm/i387.h>
25#include <asm/fpu32.h>
26#include <linux/mm.h>
27
28
29
30#define FLAG_MASK 0x44dd5UL
31
32#define R32(l,q) \
33 case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
34
35static int putreg32(struct task_struct *child, unsigned regno, u32 val)
36{
37 int i;
38 __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs));
39
40 switch (regno) {
41 case offsetof(struct user32, regs.fs):
42 if (val && (val & 3) != 3) return -EIO;
43 child->thread.fs = val & 0xffff;
44 break;
45 case offsetof(struct user32, regs.gs):
46 if (val && (val & 3) != 3) return -EIO;
47 child->thread.gs = val & 0xffff;
48 break;
49 case offsetof(struct user32, regs.ds):
50 if (val && (val & 3) != 3) return -EIO;
51 child->thread.ds = val & 0xffff;
52 break;
53 case offsetof(struct user32, regs.es):
54 child->thread.es = val & 0xffff;
55 break;
56 case offsetof(struct user32, regs.ss):
57 if ((val & 3) != 3) return -EIO;
58 stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff;
59 break;
60 case offsetof(struct user32, regs.cs):
61 if ((val & 3) != 3) return -EIO;
62 stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff;
63 break;
64
65 R32(ebx, rbx);
66 R32(ecx, rcx);
67 R32(edx, rdx);
68 R32(edi, rdi);
69 R32(esi, rsi);
70 R32(ebp, rbp);
71 R32(eax, rax);
72 R32(orig_eax, orig_rax);
73 R32(eip, rip);
74 R32(esp, rsp);
75
76 case offsetof(struct user32, regs.eflags): {
77 __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
78 val &= FLAG_MASK;
79 *flags = val | (*flags & ~FLAG_MASK);
80 break;
81 }
82
83 case offsetof(struct user32, u_debugreg[4]):
84 case offsetof(struct user32, u_debugreg[5]):
85 return -EIO;
86
87 case offsetof(struct user32, u_debugreg[0]) ...
88 offsetof(struct user32, u_debugreg[3]):
89 case offsetof(struct user32, u_debugreg[6]):
90 child->thread.debugreg
91 [(regno-offsetof(struct user32, u_debugreg[0]))/4]
92 = val;
93 break;
94
95 case offsetof(struct user32, u_debugreg[7]):
96 val &= ~DR_CONTROL_RESERVED;
97
98 for(i=0; i<4; i++)
99 if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
100 return -EIO;
101 child->thread.debugreg[7] = val;
102 break;
103
104 default:
105 if (regno > sizeof(struct user32) || (regno & 3))
106 return -EIO;
107
108
109 break;
110 }
111 return 0;
112}
113
114#undef R32
115
116#define R32(l,q) \
117 case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break
118
119static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
120{
121 __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs));
122
123 switch (regno) {
124 case offsetof(struct user32, regs.fs):
125 *val = child->thread.fs;
126 break;
127 case offsetof(struct user32, regs.gs):
128 *val = child->thread.gs;
129 break;
130 case offsetof(struct user32, regs.ds):
131 *val = child->thread.ds;
132 break;
133 case offsetof(struct user32, regs.es):
134 *val = child->thread.es;
135 break;
136
137 R32(cs, cs);
138 R32(ss, ss);
139 R32(ebx, rbx);
140 R32(ecx, rcx);
141 R32(edx, rdx);
142 R32(edi, rdi);
143 R32(esi, rsi);
144 R32(ebp, rbp);
145 R32(eax, rax);
146 R32(orig_eax, orig_rax);
147 R32(eip, rip);
148 R32(eflags, eflags);
149 R32(esp, rsp);
150
151 case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[7]):
152 *val = child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4];
153 break;
154
155 default:
156 if (regno > sizeof(struct user32) || (regno & 3))
157 return -EIO;
158
159
160 *val = 0;
161 break;
162 }
163 return 0;
164}
165
166#undef R32
167
168static struct task_struct *find_target(int request, int pid, int *err)
169{
170 struct task_struct *child;
171
172 *err = -EPERM;
173 if (pid == 1)
174 return NULL;
175
176 *err = -ESRCH;
177 read_lock(&tasklist_lock);
178 child = find_task_by_pid(pid);
179 if (child)
180 get_task_struct(child);
181 read_unlock(&tasklist_lock);
182 if (child) {
183 *err = -EPERM;
184 if (pid == 1)
185 goto out;
186 *err = ptrace_check_attach(child, request == PTRACE_KILL);
187 if (*err < 0)
188 goto out;
189 return child;
190
191 out:
192 free_task_struct(child);
193 }
194 return NULL;
195
196}
197
198extern asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data);
199
200asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
201{
202 struct task_struct *child;
203 struct pt_regs *childregs;
204 int ret;
205 __u32 val;
206
207 switch (request) {
208 case PTRACE_TRACEME:
209 case PTRACE_ATTACH:
210 case PTRACE_SYSCALL:
211 case PTRACE_CONT:
212 case PTRACE_KILL:
213 case PTRACE_SINGLESTEP:
214 case PTRACE_DETACH:
215 case PTRACE_SETOPTIONS:
216 ret = sys_ptrace(request, pid, addr, data);
217 return ret;
218
219 case PTRACE_PEEKTEXT:
220 case PTRACE_PEEKDATA:
221 case PTRACE_POKEDATA:
222 case PTRACE_POKETEXT:
223 case PTRACE_POKEUSR:
224 case PTRACE_PEEKUSR:
225 case PTRACE_GETREGS:
226 case PTRACE_SETREGS:
227 case PTRACE_SETFPREGS:
228 case PTRACE_GETFPREGS:
229 case PTRACE_SETFPXREGS:
230 case PTRACE_GETFPXREGS:
231 break;
232
233 default:
234 return -EIO;
235 }
236
237 child = find_target(request, pid, &ret);
238 if (!child)
239 return ret;
240
241 childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs));
242
243 switch (request) {
244 case PTRACE_PEEKDATA:
245 case PTRACE_PEEKTEXT:
246 ret = 0;
247 if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32))
248 ret = -EIO;
249 else
250 ret = put_user(val, (unsigned int *)(u64)data);
251 break;
252
253 case PTRACE_POKEDATA:
254 case PTRACE_POKETEXT:
255 ret = 0;
256 if (access_process_vm(child, addr, &data, sizeof(u32), 1)!=sizeof(u32))
257 ret = -EIO;
258 break;
259
260 case PTRACE_PEEKUSR:
261 ret = getreg32(child, addr, &val);
262 if (ret == 0)
263 ret = put_user(val, (__u32 *)(unsigned long) data);
264 break;
265
266 case PTRACE_POKEUSR:
267 ret = putreg32(child, addr, data);
268 break;
269
270 case PTRACE_GETREGS: {
271 int i;
272 if (!access_ok(VERIFY_WRITE, (unsigned *)(unsigned long)data, 16*4)) {
273 ret = -EIO;
274 break;
275 }
276 ret = 0;
277 for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) {
278 getreg32(child, i, &val);
279 ret |= __put_user(val,(u32 *) (unsigned long) data);
280 data += sizeof(u32);
281 }
282 break;
283 }
284
285 case PTRACE_SETREGS: {
286 unsigned long tmp;
287 int i;
288 if (!access_ok(VERIFY_READ, (unsigned *)(unsigned long)data, 16*4)) {
289 ret = -EIO;
290 break;
291 }
292 ret = 0;
293 for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
294 ret |= __get_user(tmp, (u32 *) (unsigned long) data);
295 putreg32(child, i, tmp);
296 data += sizeof(u32);
297 }
298 break;
299 }
300
301 case PTRACE_GETFPREGS:
302 ret = -EIO;
303 if (!access_ok(VERIFY_READ, (void *)(u64)data,
304 sizeof(struct user_i387_struct)))
305 break;
306 save_i387_ia32(child, (void *)(u64)data, childregs, 1);
307 ret = 0;
308 break;
309
310 case PTRACE_SETFPREGS:
311 ret = -EIO;
312 if (!access_ok(VERIFY_WRITE, (void *)(u64)data,
313 sizeof(struct user_i387_struct)))
314 break;
315 ret = 0;
316
317 restore_i387_ia32(child, (void *)(u64)data, 1);
318 break;
319
320 case PTRACE_GETFPXREGS: {
321 struct user32_fxsr_struct *u = (void *)(u64)data;
322 init_fpu(child);
323 ret = -EIO;
324 if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
325 break;
326 ret = -EFAULT;
327 if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
328 break;
329 ret = __put_user(childregs->cs, &u->fcs);
330 ret |= __put_user(child->thread.ds, &u->fos);
331 break;
332 }
333 case PTRACE_SETFPXREGS: {
334 struct user32_fxsr_struct *u = (void *)(u64)data;
335 unlazy_fpu(child);
336 ret = -EIO;
337 if (!access_ok(VERIFY_READ, u, sizeof(*u)))
338 break;
339
340 __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
341 child->used_math = 1;
342 child->thread.i387.fxsave.mxcsr &= 0xffbf;
343 ret = 0;
344 break;
345 }
346
347 default:
348 ret = -EINVAL;
349 break;
350 }
351
352 free_task_struct(child);
353 return ret;
354}
355
356