This source file includes following definitions.
- offset_of_register
- unset_singlestep
- set_singlestep
- get_task
- get_stack_long
- put_stack_long
- get_long
- put_long
- find_extend_vma
- read_long
- write_long
- set_success
- set_failure
- sys_ptrace
- syscall_trace
1
2
3
4
5
6 #include <linux/head.h>
7 #include <linux/kernel.h>
8 #include <linux/sched.h>
9 #include <linux/mm.h>
10 #include <linux/errno.h>
11 #include <linux/ptrace.h>
12 #include <linux/user.h>
13 #include <linux/debugreg.h>
14
15 #include <asm/segment.h>
16 #include <asm/pgtable.h>
17 #include <asm/system.h>
18
19
20 #define MAGICNUM 496
21
22
23
24
25
26
27
28
29 #define FLAG_MASK 0x00044dd5
30
31
32 #define TRAP_FLAG 0x100
33
34
35
36
37
38
39
40
41
42
43
44
45
46 static int map_reg_to_offset[] = {
47 320+0,320+8,320+16,320+24,320+32,320+40,320+48,320+56,320+64,
48 0,8,16,24,32,40,48,
49 320+184,320+192,320+200,
50 320+72,320+80,320+88,320+96,320+104,320+112,320+120,
51 320+128,320+136,320+144,320+176,320+160,-1,
52
53
54 64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,
55 200,208,216,224,232,240,248,256,264,272,280,288,296,304,312,
56
57
58 320+168
59 };
60
61 static int offset_of_register(int reg_num) {
62 if(reg_num<0 || reg_num>64) {
63 return -1;
64 }
65 return map_reg_to_offset[reg_num];
66 }
67
68 static void unset_singlestep(struct task_struct *child) {
69 }
70
71 static void set_singlestep(struct task_struct *child) {
72 }
73
74
75 static inline struct task_struct * get_task(int pid)
76 {
77 int i;
78
79 for (i = 1; i < NR_TASKS; i++) {
80 if (task[i] != NULL && (task[i]->pid == pid))
81 return task[i];
82 }
83 return NULL;
84 }
85
86
87
88
89
90
91
92
93
94 static inline long get_stack_long(struct task_struct *task, unsigned long offset)
95 {
96 unsigned char *stack;
97
98 stack = (unsigned char *)task->tss.ksp;
99 stack += offset+MAGICNUM;
100 return (*((long *)stack));
101 }
102
103
104
105
106
107
108
109 static inline int put_stack_long(struct task_struct *task, unsigned long offset,
110 unsigned long data)
111 {
112 unsigned char * stack;
113
114 stack = (unsigned char *) task->tss.ksp;
115 stack += offset+MAGICNUM;
116 *(unsigned long *) stack = data;
117 return 0;
118 }
119
120
121
122
123
124
125
126 static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
127 {
128 pgd_t * pgdir;
129 pmd_t * pgmiddle;
130 pte_t * pgtable;
131 unsigned long page;
132
133 #ifdef DEBUG
134 printk("Getting long at 0x%lx\n",addr);
135 #endif
136 repeat:
137 pgdir = pgd_offset(vma->vm_task, addr);
138 if (pgd_none(*pgdir)) {
139 do_no_page(vma, addr, 0);
140 goto repeat;
141 }
142 if (pgd_bad(*pgdir)) {
143 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
144 pgd_clear(pgdir);
145 return 0;
146 }
147 pgmiddle = pmd_offset(pgdir, addr);
148 if (pmd_none(*pgmiddle)) {
149 do_no_page(vma, addr, 0);
150 goto repeat;
151 }
152 if (pmd_bad(*pgmiddle)) {
153 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
154 pmd_clear(pgmiddle);
155 return 0;
156 }
157 pgtable = pte_offset(pgmiddle, addr);
158 if (!pte_present(*pgtable)) {
159 do_no_page(vma, addr, 0);
160 goto repeat;
161 }
162 page = pte_page(*pgtable);
163
164 if (page >= high_memory)
165 return 0;
166 page += addr & ~PAGE_MASK;
167 return *(unsigned long *) page;
168 }
169
170
171
172
173
174
175
176
177
178
179 static void put_long(struct vm_area_struct * vma, unsigned long addr,
180 unsigned long data)
181 {
182 pgd_t *pgdir;
183 pmd_t *pgmiddle;
184 pte_t *pgtable;
185 unsigned long page;
186
187 repeat:
188 pgdir = pgd_offset(vma->vm_task, addr);
189 if (!pgd_present(*pgdir)) {
190 do_no_page(vma, addr, 1);
191 goto repeat;
192 }
193 if (pgd_bad(*pgdir)) {
194 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
195 pgd_clear(pgdir);
196 return;
197 }
198 pgmiddle = pmd_offset(pgdir, addr);
199 if (pmd_none(*pgmiddle)) {
200 do_no_page(vma, addr, 1);
201 goto repeat;
202 }
203 if (pmd_bad(*pgmiddle)) {
204 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
205 pmd_clear(pgmiddle);
206 return;
207 }
208 pgtable = pte_offset(pgmiddle, addr);
209 if (!pte_present(*pgtable)) {
210 do_no_page(vma, addr, 1);
211 goto repeat;
212 }
213 page = pte_page(*pgtable);
214 if (!pte_write(*pgtable)) {
215 do_wp_page(vma, addr, 1);
216 goto repeat;
217 }
218
219 if (page < high_memory) {
220 page += addr & ~PAGE_MASK;
221 *(unsigned long *) page = data;
222 }
223
224
225 *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
226 invalidate();
227 }
228
229 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
230 {
231 struct vm_area_struct * vma;
232
233 addr &= PAGE_MASK;
234 vma = find_vma(tsk,addr);
235 if (!vma)
236 return NULL;
237 if (vma->vm_start <= addr)
238 return vma;
239 if (!(vma->vm_flags & VM_GROWSDOWN))
240 return NULL;
241 if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
242 return NULL;
243 vma->vm_offset -= vma->vm_start - addr;
244 vma->vm_start = addr;
245 return vma;
246 }
247
248
249
250
251
252 static int read_long(struct task_struct * tsk, unsigned long addr,
253 unsigned long * result)
254 {
255 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
256
257 #ifdef DEBUG
258 printk("in read_long\n");
259 #endif
260 if (!vma) {
261 printk("Unable to find vma for addr 0x%lx\n",addr);
262 return -EIO;
263 }
264 if ((addr & ~PAGE_MASK) > (PAGE_SIZE-sizeof(long))) {
265 unsigned long low,high;
266 struct vm_area_struct * vma_high = vma;
267
268 if (addr + sizeof(long) >= vma->vm_end) {
269 vma_high = vma->vm_next;
270 if (!vma_high || vma_high->vm_start != vma->vm_end)
271 return -EIO;
272 }
273 low = get_long(vma, addr & ~(sizeof(long)-1));
274 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
275 switch (addr & (sizeof(long)-1)) {
276 case 1:
277 low >>= 8;
278 low |= high << 56;
279 break;
280 case 2:
281 low >>= 16;
282 low |= high << 48;
283 break;
284 case 3:
285 low >>= 24;
286 low |= high << 40;
287 break;
288 case 4:
289 low >>= 32;
290 low |= high << 32;
291 break;
292 case 5:
293 low >>= 40;
294 low |= high << 24;
295 break;
296 case 6:
297 low >>= 48;
298 low |= high << 16;
299 break;
300 case 7:
301 low >>= 56;
302 low |= high << 8;
303 break;
304 }
305 *result = low;
306 } else {
307 long l =get_long(vma, addr);
308
309 #ifdef DEBUG
310 printk("value is 0x%lx\n",l);
311 #endif
312 *result = l;
313 }
314 return 0;
315 }
316
317
318
319
320
321 static int write_long(struct task_struct * tsk, unsigned long addr,
322 unsigned long data)
323 {
324 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
325
326 if (!vma)
327 return -EIO;
328 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
329 unsigned long low,high;
330 struct vm_area_struct * vma_high = vma;
331
332 if (addr + sizeof(long) >= vma->vm_end) {
333 vma_high = vma->vm_next;
334 if (!vma_high || vma_high->vm_start != vma->vm_end)
335 return -EIO;
336 }
337 low = get_long(vma, addr & ~(sizeof(long)-1));
338 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
339 switch (addr & (sizeof(long)-1)) {
340 case 0:
341 low = data;
342 break;
343 case 1:
344 low &= 0x00000000000000ffL;
345 low |= data << 8;
346 high &= ~0x000000000000ffL;
347 high |= data >> 56;
348 break;
349 case 2:
350 low &= 0x000000000000ffffL;
351 low |= data << 16;
352 high &= ~0x0000000000ffffL;
353 high |= data >> 48;
354 break;
355 case 3:
356 low &= 0x0000000000ffffffL;
357 low |= data << 24;
358 high &= ~0x00000000ffffffL;
359 high |= data >> 40;
360 break;
361 case 4:
362 low &= 0x00000000ffffffffL;
363 low |= data << 32;
364 high &= ~0x000000ffffffffL;
365 high |= data >> 32;
366 break;
367
368 case 5:
369 low &= 0x000000ffffffffffL;
370 low |= data << 40;
371 high &= ~0x0000ffffffffffL;
372 high |= data >> 24;
373 break;
374 case 6:
375 low &= 0x0000ffffffffffffL;
376 low |= data << 48;
377 high &= ~0x00ffffffffffffL;
378 high |= data >> 16;
379 break;
380 case 7:
381 low &= 0x00ffffffffffffffL;
382 low |= data << 56;
383 high &= ~0xffffffffffffffL;
384 high |= data >> 8;
385 break;
386 }
387 put_long(vma, addr & ~(sizeof(long)-1),low);
388 put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
389 } else
390 put_long(vma, addr, data);
391 return 0;
392 }
393
394
395
396
397
398
399 static inline void set_success(struct pt_regs *regs,long resval) {
400 regs->r19=resval;
401 }
402
403
404
405
406
407 static inline void set_failure(struct pt_regs *regs,long errcode) {
408 regs->r19=0;
409 }
410
411 asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5, struct pt_regs regs)
412 {
413 struct task_struct *child;
414 struct user * dummy;
415
416 dummy = NULL;
417
418 #ifdef DEBUG
419 printk("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data);
420 #endif
421 set_success(®s,0);
422 if (request == PTRACE_TRACEME) {
423
424 if (current->flags & PF_PTRACED) {
425 set_failure(®s,-EPERM);
426 return -EPERM;
427 }
428
429 current->flags |= PF_PTRACED;
430 return 0;
431 }
432 if (pid == 1) {
433 set_failure(®s,-EPERM);
434 return -EPERM;
435 }
436 if (!(child = get_task(pid))) {
437 set_failure(®s,-ESRCH);
438 return -ESRCH;
439 }
440 if (request == PTRACE_ATTACH) {
441 if (child == current) {
442 set_failure(®s,-EPERM);
443 return -EPERM;
444 }
445 if ((!child->dumpable ||
446 (current->uid != child->euid) ||
447 (current->uid != child->uid) ||
448 (current->gid != child->egid) ||
449 (current->gid != child->gid)) && !suser()) {
450 set_failure(®s,-EPERM);
451 return -EPERM;
452 }
453
454 if (child->flags & PF_PTRACED) {
455 set_failure(®s,-EPERM);
456 return -EPERM;
457 }
458 child->flags |= PF_PTRACED;
459 if (child->p_pptr != current) {
460 REMOVE_LINKS(child);
461 child->p_pptr = current;
462 SET_LINKS(child);
463 }
464 send_sig(SIGSTOP, child, 1);
465 return 0;
466 }
467 if (!(child->flags & PF_PTRACED)) {
468 #ifdef DEBUG
469 printk("child not traced\n");
470 #endif
471 set_failure(®s,-ESRCH);
472 return -ESRCH;
473 }
474 if (child->state != TASK_STOPPED) {
475 #ifdef DEBUG
476 printk("child process not stopped\n");
477 #endif
478 if (request != PTRACE_KILL) {
479 set_failure(®s,-ESRCH);
480 return -ESRCH;
481 }
482 }
483 if (child->p_pptr != current) {
484 #ifdef DEBUG
485 printk("child not parent of this process\n");
486 #endif
487 set_failure(®s,-ESRCH);
488 return -ESRCH;
489 }
490
491 switch (request) {
492
493 case PTRACE_PEEKTEXT:
494 case PTRACE_PEEKDATA: {
495 unsigned long tmp;
496 int res;
497
498 #ifdef DEBUG
499 printk("doing request at addr 0x%lx\n",addr);
500 #endif
501 res = read_long(child, addr, &tmp);
502 if (res < 0) {
503 set_failure(®s,res);
504 return res;
505 }
506 else {
507 set_success(®s,tmp);
508 return 0;
509 }
510 }
511
512
513 case PTRACE_PEEKUSR: {
514
515 unsigned long tmp;
516
517 tmp = 0;
518 if(addr==30) {
519
520 tmp=child->tss.usp;
521 }
522 else {
523 int reg=addr;
524 addr = offset_of_register(addr);
525 if(addr < 0) {
526 set_failure(®s,-EIO);
527 return -EIO;
528 }
529 tmp = get_stack_long(child, addr);
530 #ifdef DEBUG
531 printk("%d = reg 0x%lx=tmp\n",reg,tmp);
532 #endif
533 }
534 set_success(®s,tmp);
535 return 0;
536 }
537
538
539 case PTRACE_POKETEXT:
540 case PTRACE_POKEDATA: {
541 long res=write_long(child,addr,data);
542 if(res) {
543 set_failure(®s,res);
544 }
545 return res;
546 }
547
548 case PTRACE_POKEUSR:
549 {
550 long res;
551 addr= offset_of_register(addr);
552 if(addr < 0) {
553 set_failure(®s,-EIO);
554 return -EIO;
555 }
556 res=put_stack_long(child,addr,data);
557 if(res) {
558 set_failure(®s,res);
559 }
560 return res;
561 }
562
563 case PTRACE_SYSCALL:
564
565 case PTRACE_CONT: {
566 if ((unsigned long) data > NSIG) {
567 set_failure(®s,-EIO);
568 return -EIO;
569 }
570 if (request == PTRACE_SYSCALL)
571 child->flags |= PF_TRACESYS;
572 else
573 child->flags &= ~PF_TRACESYS;
574 child->exit_code = data;
575 child->state = TASK_RUNNING;
576 unset_singlestep(child);
577 set_success(®s,data);
578 return 0;
579 }
580
581
582
583
584
585
586 case PTRACE_KILL: {
587 child->state = TASK_RUNNING;
588 child->exit_code = SIGKILL;
589 unset_singlestep(child);
590 return 0;
591 }
592
593 case PTRACE_SINGLESTEP: {
594 if ((unsigned long) data > NSIG) {
595 set_failure(®s,-EIO);
596 return -EIO;
597 }
598 child->flags &= ~PF_TRACESYS;
599 set_singlestep(child);
600 child->state = TASK_RUNNING;
601 child->exit_code = data;
602
603 return 0;
604 }
605
606 case PTRACE_DETACH: {
607 if ((unsigned long) data > NSIG) {
608 set_failure(®s,-EIO);
609 return -EIO;
610 }
611 child->flags &= ~(PF_PTRACED|PF_TRACESYS);
612 child->state = TASK_RUNNING;
613 child->exit_code = data;
614 REMOVE_LINKS(child);
615 child->p_pptr = child->p_opptr;
616 SET_LINKS(child);
617
618 unset_singlestep(child);
619 return 0;
620 }
621
622 default:
623 {
624 set_failure(®s,-EIO);
625 return -EIO;
626 }
627 }
628 }
629
630 asmlinkage void syscall_trace(void)
631 {
632 if ((current->flags & (PF_PTRACED|PF_TRACESYS))
633 != (PF_PTRACED|PF_TRACESYS))
634 return;
635 current->exit_code = SIGTRAP;
636 current->state = TASK_STOPPED;
637 notify_parent(current);
638 schedule();
639
640
641
642
643
644 if (current->exit_code)
645 current->signal |= (1 << (current->exit_code - 1));
646 current->exit_code = 0;
647 }