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