This source file includes following definitions.
- get_task
- get_long
- put_long
- find_extend_vma
- read_long
- read_byte
- write_long
- write_byte
- pt_error_return
- pt_succ_return
- read_sunos_user
- write_sunos_user
- do_ptrace
- syscall_trace
1
2
3
4
5
6
7
8
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/errno.h>
13 #include <linux/ptrace.h>
14 #include <linux/user.h>
15
16 #include <asm/pgtable.h>
17 #include <asm/system.h>
18
19
20 static inline struct task_struct * get_task(int pid)
21 {
22 int i;
23
24 for (i = 1; i < NR_TASKS; i++) {
25 if (task[i] != NULL && (task[i]->pid == pid))
26 return task[i];
27 }
28 return NULL;
29 }
30
31
32
33
34
35
36
37 static unsigned long get_long(struct task_struct * tsk,
38 struct vm_area_struct * vma, unsigned long addr)
39 {
40 pgd_t * pgdir;
41 pmd_t * pgmiddle;
42 pte_t * pgtable;
43 unsigned long page, retval;
44
45 repeat:
46 pgdir = pgd_offset(vma->vm_mm, addr);
47 if (pgd_none(*pgdir)) {
48 do_no_page(tsk, vma, addr, 0);
49 goto repeat;
50 }
51 if (pgd_bad(*pgdir)) {
52 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
53 pgd_clear(pgdir);
54 return 0;
55 }
56 pgmiddle = pmd_offset(pgdir, addr);
57 if (pmd_none(*pgmiddle)) {
58 do_no_page(tsk, vma, addr, 0);
59 goto repeat;
60 }
61 if (pmd_bad(*pgmiddle)) {
62 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
63 pmd_clear(pgmiddle);
64 return 0;
65 }
66 pgtable = pte_offset(pgmiddle, addr);
67 if (!pte_present(*pgtable)) {
68 do_no_page(tsk, vma, addr, 0);
69 goto repeat;
70 }
71 page = pte_page(*pgtable);
72
73 if (page >= high_memory)
74 return 0;
75 page += addr & ~PAGE_MASK;
76 retval = *(unsigned long *) page;
77 flush_page_to_ram(page);
78 return retval;
79 }
80
81
82
83
84
85
86
87
88
89
90 static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
91 unsigned long addr, unsigned long data)
92 {
93 pgd_t *pgdir;
94 pmd_t *pgmiddle;
95 pte_t *pgtable;
96 unsigned long page;
97
98 repeat:
99 pgdir = pgd_offset(vma->vm_mm, addr);
100 if (!pgd_present(*pgdir)) {
101 do_no_page(tsk, vma, addr, 1);
102 goto repeat;
103 }
104 if (pgd_bad(*pgdir)) {
105 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
106 pgd_clear(pgdir);
107 return;
108 }
109 pgmiddle = pmd_offset(pgdir, addr);
110 if (pmd_none(*pgmiddle)) {
111 do_no_page(tsk, vma, addr, 1);
112 goto repeat;
113 }
114 if (pmd_bad(*pgmiddle)) {
115 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
116 pmd_clear(pgmiddle);
117 return;
118 }
119 pgtable = pte_offset(pgmiddle, addr);
120 if (!pte_present(*pgtable)) {
121 do_no_page(tsk, vma, addr, 1);
122 goto repeat;
123 }
124 page = pte_page(*pgtable);
125 if (!pte_write(*pgtable)) {
126 do_wp_page(tsk, vma, addr, 1);
127 goto repeat;
128 }
129
130 flush_cache_page(vma, page);
131 if (page < high_memory) {
132 *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
133 flush_page_to_ram(page);
134 }
135
136
137 set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
138 flush_tlb_page(vma, page);
139 }
140
141 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
142 unsigned long addr)
143 {
144 struct vm_area_struct * vma;
145
146 addr &= PAGE_MASK;
147 vma = find_vma(tsk,addr);
148 if (!vma)
149 return NULL;
150 if (vma->vm_start <= addr)
151 return vma;
152 if (!(vma->vm_flags & VM_GROWSDOWN))
153 return NULL;
154 if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
155 return NULL;
156 vma->vm_offset -= vma->vm_start - addr;
157 vma->vm_start = addr;
158 return vma;
159 }
160
161
162
163
164
165 static int read_long(struct task_struct * tsk, unsigned long addr,
166 unsigned long * result)
167 {
168 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
169
170 if (!vma)
171 return -EIO;
172 *result = get_long(tsk, vma, addr);
173 return 0;
174 }
175
176 static int read_byte(struct task_struct *tsk, unsigned long addr,
177 unsigned char *result)
178 {
179 struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3);
180 unsigned long tmp;
181
182 if(!vma)
183 return -EIO;
184 tmp = get_long(tsk, vma, (addr & ~3));
185 switch(addr & 3) {
186 case 0:
187 *result = (tmp & 0xff000000)>>24;
188 break;
189 case 1:
190 *result = (tmp & 0x00ff0000)>>16;
191 break;
192 case 2:
193 *result = (tmp & 0x0000ff00)>>8;
194 break;
195 case 3:
196 *result = (tmp & 0x000000ff);
197 break;
198 }
199 return 0;
200 }
201
202
203
204
205
206 static int write_long(struct task_struct * tsk, unsigned long addr,
207 unsigned long data)
208 {
209 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
210
211 if (!vma)
212 return -EIO;
213 put_long(tsk, vma, addr, data);
214 return 0;
215 }
216
217 static int write_byte(struct task_struct * tsk, unsigned long addr,
218 unsigned char data)
219 {
220 struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3));
221 unsigned long tmp;
222
223 if (!vma)
224 return -EIO;
225 tmp = get_long(tsk, vma, (addr & ~3));
226 switch(addr & 3) {
227 case 0:
228 tmp &= 0x00ffffff;
229 tmp |= (data << 24);
230 break;
231 case 1:
232 tmp &= 0xff00ffff;
233 tmp |= ((data << 16) & 0x00ff0000);
234 break;
235 case 2:
236 tmp &= 0xffff00ff;
237 tmp |= ((data << 8) & 0x0000ff00);
238 break;
239 case 3:
240 tmp &= 0xffffff00;
241 tmp |= (data & 0x000000ff);
242 break;
243 }
244 put_long(tsk, vma, (addr & ~3), tmp);
245 return 0;
246 }
247
248
249
250
251
252
253 static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
254 {
255 regs->u_regs[UREG_I0] = error;
256 regs->psr |= PSR_C;
257 regs->pc = regs->npc;
258 regs->npc += 4;
259 }
260
261 static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
262 {
263 regs->u_regs[UREG_I0] = value;
264 regs->psr &= ~PSR_C;
265 regs->pc = regs->npc;
266 regs->npc += 4;
267 }
268
269
270 static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
271 struct task_struct *tsk)
272 {
273 struct pt_regs *cregs = tsk->tss.kregs;
274 struct thread_struct *t = &tsk->tss;
275
276 if(offset >= 1024)
277 offset -= 1024;
278 if(offset & ((sizeof(unsigned long) - 1))) {
279 pt_error_return(regs, EIO);
280 return;
281 }
282 if(offset >= 16 && offset < 784) {
283 offset -= 16; offset >>= 2;
284 pt_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset));
285 return;
286 }
287 if(offset >= 784 && offset < 832) {
288 offset -= 784; offset >>= 2;
289 pt_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset));
290 return;
291 }
292 switch(offset) {
293 case 0:
294 regs->u_regs[UREG_I0] = t->ksp;
295 break;
296 case 4:
297 regs->u_regs[UREG_I0] = t->kpc;
298 break;
299 case 8:
300 regs->u_regs[UREG_I0] = t->kpsr;
301 break;
302 case 12:
303 regs->u_regs[UREG_I0] = t->uwinmask;
304 break;
305 case 832:
306 regs->u_regs[UREG_I0] = t->w_saved;
307 break;
308 case 896:
309 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
310 break;
311 case 900:
312 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
313 break;
314 case 904:
315 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I2];
316 break;
317 case 908:
318 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I3];
319 break;
320 case 912:
321 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I4];
322 break;
323 case 916:
324 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I5];
325 break;
326 case 920:
327 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I6];
328 break;
329 case 924:
330 if(tsk->tss.flags & 0x80000000)
331 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_G1];
332 else
333 regs->u_regs[UREG_I0] = 0;
334 break;
335 case 940:
336 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
337 break;
338 case 944:
339 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
340 break;
341
342 case 948:
343
344 if(cregs->psr & PSR_C)
345 regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0] << 24;
346 else
347 regs->u_regs[UREG_I0] = 0;
348 break;
349
350
351 default:
352 printk("%s [%d]: Wants to read user offset %d\n",
353 current->comm, current->pid, offset);
354 pt_error_return(regs, EIO);
355 return;
356 }
357 regs->psr &= ~PSR_C;
358 regs->pc = regs->npc;
359 regs->npc += 4;
360 return;
361 }
362
363 static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
364 struct task_struct *tsk)
365 {
366 struct pt_regs *cregs = tsk->tss.kregs;
367 struct thread_struct *t = &tsk->tss;
368 unsigned long value = regs->u_regs[UREG_I3];
369
370 if(offset >= 1024)
371 offset -= 1024;
372 if(offset & ((sizeof(unsigned long) - 1)))
373 goto failure;
374 if(offset >= 16 && offset < 784) {
375 offset -= 16; offset >>= 2;
376 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
377 goto success;
378 }
379 if(offset >= 784 && offset < 832) {
380 offset -= 784; offset >>= 2;
381 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
382 goto success;
383 }
384 switch(offset) {
385 case 896:
386 cregs->u_regs[UREG_I0] = value;
387 break;
388 case 900:
389 cregs->u_regs[UREG_I1] = value;
390 break;
391 case 904:
392 cregs->u_regs[UREG_I2] = value;
393 break;
394 case 908:
395 cregs->u_regs[UREG_I3] = value;
396 break;
397 case 912:
398 cregs->u_regs[UREG_I4] = value;
399 break;
400 case 916:
401 cregs->u_regs[UREG_I5] = value;
402 break;
403 case 920:
404 cregs->u_regs[UREG_I6] = value;
405 break;
406 case 924:
407 cregs->u_regs[UREG_I7] = value;
408 break;
409 case 940:
410 cregs->u_regs[UREG_I0] = value;
411 break;
412 case 944:
413 cregs->u_regs[UREG_I1] = value;
414 break;
415
416
417 default:
418 printk("%s [%d]: Wants to write user offset %d\n",
419 current->comm, current->pid, offset);
420 goto failure;
421 }
422 success:
423 pt_succ_return(regs, 0);
424 return;
425 failure:
426 pt_error_return(regs, EIO);
427 return;
428 }
429
430
431
432
433 asmlinkage void do_ptrace(struct pt_regs *regs)
434 {
435 unsigned long request = regs->u_regs[UREG_I0];
436 unsigned long pid = regs->u_regs[UREG_I1];
437 unsigned long addr = regs->u_regs[UREG_I2];
438 unsigned long data = regs->u_regs[UREG_I3];
439 unsigned long addr2 = regs->u_regs[UREG_I4];
440 struct task_struct *child;
441
442 #ifdef DEBUG_PTRACE
443 printk("do_ptrace: rq=%d pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
444 (int) request, (int) pid, addr, data, addr2);
445 #endif
446 if(request == PTRACE_TRACEME) {
447
448 if (current->flags & PF_PTRACED) {
449 pt_error_return(regs, EPERM);
450 return;
451 }
452
453 current->flags |= PF_PTRACED;
454 pt_succ_return(regs, 0);
455 return;
456 }
457 #ifndef ALLOW_INIT_TRACING
458 if(pid == 1) {
459
460 pt_error_return(regs, EPERM);
461 return;
462 }
463 #endif
464 if(!(child = get_task(pid))) {
465 pt_error_return(regs, ESRCH);
466 return;
467 }
468
469 if(request == PTRACE_SUNATTACH) {
470 if(child == current) {
471
472
473
474 pt_error_return(regs, EPERM);
475 return;
476 }
477 if((!child->dumpable ||
478 (current->uid != child->euid) ||
479 (current->uid != child->uid) ||
480 (current->gid != child->egid) ||
481 (current->gid != child->gid)) && !suser()) {
482 pt_error_return(regs, EPERM);
483 return;
484 }
485
486 if (child->flags & PF_PTRACED) {
487 pt_error_return(regs, EPERM);
488 return;
489 }
490 child->flags |= PF_PTRACED;
491 if(child->p_pptr != current) {
492 REMOVE_LINKS(child);
493 child->p_pptr = current;
494 SET_LINKS(child);
495 }
496 send_sig(SIGSTOP, child, 1);
497 pt_succ_return(regs, 0);
498 return;
499 }
500 if(!(child->flags & PF_PTRACED)) {
501 pt_error_return(regs, ESRCH);
502 return;
503 }
504 if(child->state != TASK_STOPPED) {
505 if(request != PTRACE_KILL) {
506 pt_error_return(regs, ESRCH);
507 return;
508 }
509 }
510 if(child->p_pptr != current) {
511 pt_error_return(regs, ESRCH);
512 return;
513 }
514 switch(request) {
515 case PTRACE_PEEKTEXT:
516 case PTRACE_PEEKDATA: {
517 unsigned long tmp;
518 int res;
519
520
521 if(addr & (sizeof(unsigned long) - 1)) {
522 pt_error_return(regs, EINVAL);
523 return;
524 }
525 res = read_long(child, addr, &tmp);
526 if (res < 0) {
527 pt_error_return(regs, -res);
528 return;
529 }
530 pt_succ_return(regs, tmp);
531 return;
532 }
533
534 case PTRACE_PEEKUSR:
535 read_sunos_user(regs, addr, child);
536 return;
537
538 case PTRACE_POKEUSR:
539 write_sunos_user(regs, addr, child);
540 return;
541
542 case PTRACE_POKETEXT:
543 case PTRACE_POKEDATA: {
544 struct vm_area_struct *vma;
545 int res;
546
547
548 if(addr & (sizeof(unsigned long) - 1)) {
549 pt_error_return(regs, EINVAL);
550 return;
551 }
552 vma = find_extend_vma(child, addr);
553 if(vma && request == PTRACE_POKEDATA && (vma->vm_flags & VM_EXEC)) {
554 pt_error_return(regs, EIO);
555 return;
556 }
557 res = write_long(child, addr, data);
558 if(res < 0)
559 pt_error_return(regs, -res);
560 else
561 pt_succ_return(regs, res);
562 return;
563 }
564
565 case PTRACE_GETREGS: {
566 struct pt_regs *pregs = (struct pt_regs *) addr;
567 struct pt_regs *cregs = child->tss.kregs;
568 int rval;
569
570 rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs) - 4);
571 if(rval) {
572 pt_error_return(regs, rval);
573 return;
574 }
575 pregs->psr = cregs->psr;
576 pregs->pc = cregs->pc;
577 pregs->npc = cregs->npc;
578 pregs->y = cregs->y;
579 for(rval = 1; rval < 16; rval++)
580 pregs->u_regs[rval - 1] = cregs->u_regs[rval];
581 pt_succ_return(regs, 0);
582 return;
583 }
584
585 case PTRACE_SETREGS: {
586 struct pt_regs *pregs = (struct pt_regs *) addr;
587 struct pt_regs *cregs = child->tss.kregs;
588 unsigned long psr;
589 int rval, i;
590
591 rval = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs) - 4);
592 if(rval) {
593 pt_error_return(regs, rval);
594 return;
595 }
596
597
598
599 psr = (pregs->psr) & PSR_ICC;
600 cregs->psr &= ~PSR_ICC;
601 cregs->psr |= psr;
602 if(!((pregs->pc | pregs->npc) & 3)) {
603 cregs->pc = pregs->pc;
604 cregs->npc = pregs->npc;
605 }
606 cregs->y = pregs->y;
607 for(i = 1; i < 16; i++)
608 cregs->u_regs[i] = pregs->u_regs[i-1];
609 pt_succ_return(regs, 0);
610 return;
611 }
612
613 case PTRACE_GETFPREGS: {
614 struct fps {
615 unsigned long regs[32];
616 unsigned long fsr;
617 unsigned long flags;
618 unsigned long extra;
619 unsigned long fpqd;
620 struct fq {
621 unsigned long *insnaddr;
622 unsigned long insn;
623 } fpq[16];
624 } *fps = (struct fps *) addr;
625 int rval, i;
626
627 rval = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
628 if(rval) { pt_error_return(regs, rval); return; }
629 for(i = 0; i < 32; i++)
630 fps->regs[i] = child->tss.float_regs[i];
631 fps->fsr = child->tss.fsr;
632 fps->fpqd = child->tss.fpqdepth;
633 fps->flags = fps->extra = 0;
634 for(i = 0; i < 16; i++) {
635 fps->fpq[i].insnaddr = child->tss.fpqueue[i].insn_addr;
636 fps->fpq[i].insn = child->tss.fpqueue[i].insn;
637 }
638 pt_succ_return(regs, 0);
639 return;
640 }
641
642 case PTRACE_SETFPREGS: {
643 struct fps {
644 unsigned long regs[32];
645 unsigned long fsr;
646 unsigned long flags;
647 unsigned long extra;
648 unsigned long fpqd;
649 struct fq {
650 unsigned long *insnaddr;
651 unsigned long insn;
652 } fpq[16];
653 } *fps = (struct fps *) addr;
654 int rval, i;
655
656 rval = verify_area(VERIFY_READ, fps, sizeof(struct fps));
657 if(rval) { pt_error_return(regs, rval); return; }
658 for(i = 0; i < 32; i++)
659 child->tss.float_regs[i] = fps->regs[i];
660 child->tss.fsr = fps->fsr;
661 child->tss.fpqdepth = fps->fpqd;
662 for(i = 0; i < 16; i++) {
663 child->tss.fpqueue[i].insn_addr = fps->fpq[i].insnaddr;
664 child->tss.fpqueue[i].insn = fps->fpq[i].insn;
665 }
666 pt_succ_return(regs, 0);
667 return;
668 }
669
670 case PTRACE_READTEXT:
671 case PTRACE_READDATA: {
672 unsigned char *dest = (unsigned char *) addr2;
673 unsigned long src = addr;
674 unsigned char tmp;
675 int res, len = data;
676
677 res = verify_area(VERIFY_WRITE, (void *) dest, len);
678 if(res) {
679 pt_error_return(regs, -res);
680 return;
681 }
682 while(len) {
683 res = read_byte(child, src, &tmp);
684 if(res < 0) {
685 pt_error_return(regs, -res);
686 return;
687 }
688 *dest = tmp;
689 src++; dest++; len--;
690 }
691 pt_succ_return(regs, 0);
692 return;
693 }
694
695 case PTRACE_WRITETEXT:
696 case PTRACE_WRITEDATA: {
697 unsigned char *src = (unsigned char *) addr2;
698 unsigned long dest = addr;
699 int res, len = data;
700
701 res = verify_area(VERIFY_READ, (void *) src, len);
702 if(res) {
703 pt_error_return(regs, -res);
704 return;
705 }
706 while(len) {
707 res = write_byte(child, dest, *src);
708 if(res < 0) {
709 pt_error_return(regs, -res);
710 return;
711 }
712 src++; dest++; len--;
713 }
714 pt_succ_return(regs, 0);
715 return;
716 }
717
718 case PTRACE_SYSCALL:
719 data = 0;
720 addr = 1;
721
722 case PTRACE_CONT: {
723 if ((unsigned long) data > NSIG) {
724 pt_error_return(regs, EIO);
725 return;
726 }
727 if (request == PTRACE_SYSCALL)
728 child->flags |= PF_TRACESYS;
729 else
730 child->flags &= ~PF_TRACESYS;
731 child->exit_code = data;
732 if((addr != 1) & !(addr & 3)) {
733 child->tss.kregs->pc = addr;
734 child->tss.kregs->npc = addr + 4;
735 }
736 wake_up_process(child);
737 pt_succ_return(regs, 0);
738 return;
739 }
740
741
742
743
744
745
746 case PTRACE_KILL: {
747 if (child->state == TASK_ZOMBIE) {
748 pt_succ_return(regs, 0);
749 return;
750 }
751 wake_up_process(child);
752 child->exit_code = SIGKILL;
753 pt_succ_return(regs, 0);
754 return;
755 }
756
757 case PTRACE_SUNDETACH: {
758 if ((unsigned long) data > NSIG) {
759 pt_error_return(regs, EIO);
760 return;
761 }
762 child->flags &= ~(PF_PTRACED|PF_TRACESYS);
763 wake_up_process(child);
764 child->exit_code = data;
765 REMOVE_LINKS(child);
766 child->p_pptr = child->p_opptr;
767 SET_LINKS(child);
768 pt_succ_return(regs, 0);
769 return;
770 }
771
772
773
774 default:
775 pt_error_return(regs, EIO);
776 return;
777 }
778 }
779
780 asmlinkage void syscall_trace(void)
781 {
782 #ifdef DEBUG_PTRACE
783 printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
784 #endif
785 if ((current->flags & (PF_PTRACED|PF_TRACESYS))
786 != (PF_PTRACED|PF_TRACESYS))
787 return;
788 current->exit_code = SIGTRAP;
789 current->state = TASK_STOPPED;
790 current->tss.flags ^= 0x80000000;
791 notify_parent(current);
792 schedule();
793
794
795
796
797
798 if (current->exit_code)
799 current->signal |= (1 << (current->exit_code - 1));
800 current->exit_code = 0;
801 }