This source file includes following definitions.
- get_task
- get_stack_long
- put_stack_long
- get_long
- put_long
- find_vma
- read_long
- write_long
- sys_ptrace
- syscall_trace
1
2
3
4
5 #include <linux/head.h>
6 #include <linux/kernel.h>
7 #include <linux/sched.h>
8 #include <linux/mm.h>
9 #include <linux/errno.h>
10 #include <linux/ptrace.h>
11 #include <linux/user.h>
12
13 #include <asm/segment.h>
14 #include <asm/system.h>
15 #include <linux/debugreg.h>
16
17
18
19
20
21
22
23
24 #define FLAG_MASK 0x00044dd5
25
26
27 #define TRAP_FLAG 0x100
28
29
30
31
32
33 #define MAGICNUMBER 68
34
35
36 static inline struct task_struct * get_task(int pid)
37 {
38 int i;
39
40 for (i = 1; i < NR_TASKS; i++) {
41 if (task[i] != NULL && (task[i]->pid == pid))
42 return task[i];
43 }
44 return NULL;
45 }
46
47
48
49
50
51
52
53 static inline int get_stack_long(struct task_struct *task, int offset)
54 {
55 unsigned char *stack;
56
57 stack = (unsigned char *)task->tss.esp0;
58 stack += offset;
59 return (*((int *)stack));
60 }
61
62
63
64
65
66
67
68 static inline int put_stack_long(struct task_struct *task, int offset,
69 unsigned long data)
70 {
71 unsigned char * stack;
72
73 stack = (unsigned char *) task->tss.esp0;
74 stack += offset;
75 *(unsigned long *) stack = data;
76 return 0;
77 }
78
79
80
81
82
83
84
85 static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
86 {
87 unsigned long page;
88
89 repeat:
90 page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
91 if (page & PAGE_PRESENT) {
92 page &= PAGE_MASK;
93 page += PAGE_PTR(addr);
94 page = *((unsigned long *) page);
95 }
96 if (!(page & PAGE_PRESENT)) {
97 do_no_page(vma, addr, 0);
98 goto repeat;
99 }
100
101 if (page >= high_memory)
102 return 0;
103 page &= PAGE_MASK;
104 page += addr & ~PAGE_MASK;
105 return *(unsigned long *) page;
106 }
107
108
109
110
111
112
113
114
115
116
117 static void put_long(struct vm_area_struct * vma, unsigned long addr,
118 unsigned long data)
119 {
120 unsigned long page, pte = 0;
121 int readonly = 0;
122
123 repeat:
124 page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
125 if (page & PAGE_PRESENT) {
126 page &= PAGE_MASK;
127 page += PAGE_PTR(addr);
128 pte = page;
129 page = *((unsigned long *) page);
130 }
131 if (!(page & PAGE_PRESENT)) {
132 do_no_page(vma, addr, 0 );
133 goto repeat;
134 }
135 if (!(page & PAGE_RW)) {
136 if (!(page & PAGE_COW))
137 readonly = 1;
138 do_wp_page(vma, addr, PAGE_RW | PAGE_PRESENT);
139 goto repeat;
140 }
141
142 if (page >= high_memory)
143 return;
144
145 *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
146 page &= PAGE_MASK;
147 page += addr & ~PAGE_MASK;
148 *(unsigned long *) page = data;
149 if (readonly) {
150 *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
151 invalidate();
152 }
153 }
154
155 static struct vm_area_struct * find_vma(struct task_struct * tsk, unsigned long addr)
156 {
157 struct vm_area_struct * vma;
158
159 addr &= PAGE_MASK;
160 for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) {
161 if (!vma)
162 return NULL;
163 if (vma->vm_end > addr)
164 break;
165 }
166 if (vma->vm_start <= addr)
167 return vma;
168 if (!(vma->vm_flags & VM_GROWSDOWN))
169 return NULL;
170 if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
171 return NULL;
172 vma->vm_offset -= vma->vm_start - addr;
173 vma->vm_start = addr;
174 return vma;
175 }
176
177
178
179
180
181 static int read_long(struct task_struct * tsk, unsigned long addr,
182 unsigned long * result)
183 {
184 struct vm_area_struct * vma = find_vma(tsk, addr);
185
186 if (!vma)
187 return -EIO;
188 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
189 unsigned long low,high;
190 struct vm_area_struct * vma_high = vma;
191
192 if (addr + sizeof(long) >= vma->vm_end) {
193 vma_high = vma->vm_next;
194 if (!vma_high || vma_high->vm_start != vma->vm_end)
195 return -EIO;
196 }
197 low = get_long(vma, addr & ~(sizeof(long)-1));
198 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
199 switch (addr & (sizeof(long)-1)) {
200 case 1:
201 low >>= 8;
202 low |= high << 24;
203 break;
204 case 2:
205 low >>= 16;
206 low |= high << 16;
207 break;
208 case 3:
209 low >>= 24;
210 low |= high << 8;
211 break;
212 }
213 *result = low;
214 } else
215 *result = get_long(vma, addr);
216 return 0;
217 }
218
219
220
221
222
223 static int write_long(struct task_struct * tsk, unsigned long addr,
224 unsigned long data)
225 {
226 struct vm_area_struct * vma = find_vma(tsk, addr);
227
228 if (!vma)
229 return -EIO;
230 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
231 unsigned long low,high;
232 struct vm_area_struct * vma_high = vma;
233
234 if (addr + sizeof(long) >= vma->vm_end) {
235 vma_high = vma->vm_next;
236 if (!vma_high || vma_high->vm_start != vma->vm_end)
237 return -EIO;
238 }
239 low = get_long(vma, addr & ~(sizeof(long)-1));
240 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
241 switch (addr & (sizeof(long)-1)) {
242 case 0:
243 low = data;
244 break;
245 case 1:
246 low &= 0x000000ff;
247 low |= data << 8;
248 high &= ~0xff;
249 high |= data >> 24;
250 break;
251 case 2:
252 low &= 0x0000ffff;
253 low |= data << 16;
254 high &= ~0xffff;
255 high |= data >> 16;
256 break;
257 case 3:
258 low &= 0x00ffffff;
259 low |= data << 24;
260 high &= ~0xffffff;
261 high |= data >> 8;
262 break;
263 }
264 put_long(vma, addr & ~(sizeof(long)-1),low);
265 put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
266 } else
267 put_long(vma, addr, data);
268 return 0;
269 }
270
271 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
272 {
273 struct task_struct *child;
274 struct user * dummy;
275 int i;
276
277 dummy = NULL;
278
279 if (request == PTRACE_TRACEME) {
280
281 if (current->flags & PF_PTRACED)
282 return -EPERM;
283
284 current->flags |= PF_PTRACED;
285 return 0;
286 }
287 if (pid == 1)
288 return -EPERM;
289 if (!(child = get_task(pid)))
290 return -ESRCH;
291 if (request == PTRACE_ATTACH) {
292 if (child == current)
293 return -EPERM;
294 if ((!child->dumpable ||
295 (current->uid != child->euid) ||
296 (current->uid != child->uid) ||
297 (current->gid != child->egid) ||
298 (current->gid != child->gid)) && !suser())
299 return -EPERM;
300
301 if (child->flags & PF_PTRACED)
302 return -EPERM;
303 child->flags |= PF_PTRACED;
304 if (child->p_pptr != current) {
305 REMOVE_LINKS(child);
306 child->p_pptr = current;
307 SET_LINKS(child);
308 }
309 send_sig(SIGSTOP, child, 1);
310 return 0;
311 }
312 if (!(child->flags & PF_PTRACED))
313 return -ESRCH;
314 if (child->state != TASK_STOPPED) {
315 if (request != PTRACE_KILL)
316 return -ESRCH;
317 }
318 if (child->p_pptr != current)
319 return -ESRCH;
320
321 switch (request) {
322
323 case PTRACE_PEEKTEXT:
324 case PTRACE_PEEKDATA: {
325 unsigned long tmp;
326 int res;
327
328 res = read_long(child, addr, &tmp);
329 if (res < 0)
330 return res;
331 res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
332 if (!res)
333 put_fs_long(tmp,(unsigned long *) data);
334 return res;
335 }
336
337
338 case PTRACE_PEEKUSR: {
339 unsigned long tmp;
340 int res;
341
342 if ((addr & 3) || addr < 0 ||
343 addr > sizeof(struct user) - 3)
344 return -EIO;
345
346 res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
347 if (res)
348 return res;
349 tmp = 0;
350 if(addr < 17*sizeof(long)) {
351 addr = addr >> 2;
352
353 tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
354 if (addr == DS || addr == ES ||
355 addr == FS || addr == GS ||
356 addr == CS || addr == SS)
357 tmp &= 0xffff;
358 };
359 if(addr >= (long) &dummy->u_debugreg[0] &&
360 addr <= (long) &dummy->u_debugreg[7]){
361 addr -= (long) &dummy->u_debugreg[0];
362 addr = addr >> 2;
363 tmp = child->debugreg[addr];
364 };
365 put_fs_long(tmp,(unsigned long *) data);
366 return 0;
367 }
368
369
370 case PTRACE_POKETEXT:
371 case PTRACE_POKEDATA:
372 return write_long(child,addr,data);
373
374 case PTRACE_POKEUSR:
375 if ((addr & 3) || addr < 0 ||
376 addr > sizeof(struct user) - 3)
377 return -EIO;
378
379 addr = addr >> 2;
380
381 if (addr == ORIG_EAX)
382 return -EIO;
383 if (addr == DS || addr == ES ||
384 addr == FS || addr == GS ||
385 addr == CS || addr == SS) {
386 data &= 0xffff;
387 if (data && (data & 3) != 3)
388 return -EIO;
389 }
390 if (addr == EFL) {
391 data &= FLAG_MASK;
392 data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
393 }
394
395
396 if(addr < 17){
397 if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
398 return -EIO;
399 return 0;
400 };
401
402
403
404
405
406
407 addr = addr << 2;
408 if(addr >= (long) &dummy->u_debugreg[0] &&
409 addr <= (long) &dummy->u_debugreg[7]){
410
411 if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
412 if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
413 if(addr < (long) &dummy->u_debugreg[4] &&
414 ((unsigned long) data) >= 0xbffffffd) return -EIO;
415
416 if(addr == (long) &dummy->u_debugreg[7]) {
417 data &= ~DR_CONTROL_RESERVED;
418 for(i=0; i<4; i++)
419 if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
420 return -EIO;
421 };
422
423 addr -= (long) &dummy->u_debugreg;
424 addr = addr >> 2;
425 child->debugreg[addr] = data;
426 return 0;
427 };
428 return -EIO;
429
430 case PTRACE_SYSCALL:
431 case PTRACE_CONT: {
432 long tmp;
433
434 if ((unsigned long) data > NSIG)
435 return -EIO;
436 if (request == PTRACE_SYSCALL)
437 child->flags |= PF_TRACESYS;
438 else
439 child->flags &= ~PF_TRACESYS;
440 child->exit_code = data;
441 child->state = TASK_RUNNING;
442
443 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
444 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
445 return 0;
446 }
447
448
449
450
451
452
453 case PTRACE_KILL: {
454 long tmp;
455
456 child->state = TASK_RUNNING;
457 child->exit_code = SIGKILL;
458
459 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
460 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
461 return 0;
462 }
463
464 case PTRACE_SINGLESTEP: {
465 long tmp;
466
467 if ((unsigned long) data > NSIG)
468 return -EIO;
469 child->flags &= ~PF_TRACESYS;
470 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
471 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
472 child->state = TASK_RUNNING;
473 child->exit_code = data;
474
475 return 0;
476 }
477
478 case PTRACE_DETACH: {
479 long tmp;
480
481 if ((unsigned long) data > NSIG)
482 return -EIO;
483 child->flags &= ~(PF_PTRACED|PF_TRACESYS);
484 child->state = TASK_RUNNING;
485 child->exit_code = data;
486 REMOVE_LINKS(child);
487 child->p_pptr = child->p_opptr;
488 SET_LINKS(child);
489
490 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
491 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
492 return 0;
493 }
494
495 default:
496 return -EIO;
497 }
498 }
499
500 asmlinkage void syscall_trace(void)
501 {
502 if ((current->flags & (PF_PTRACED|PF_TRACESYS))
503 != (PF_PTRACED|PF_TRACESYS))
504 return;
505 current->exit_code = SIGTRAP;
506 current->state = TASK_STOPPED;
507 notify_parent(current);
508 schedule();
509
510
511
512
513
514 if (current->exit_code)
515 current->signal |= (1 << (current->exit_code - 1));
516 current->exit_code = 0;
517 }