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 *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
178
179
180 set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
181 invalidate();
182 }
183
184 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
185 {
186 struct vm_area_struct * vma;
187
188 addr &= PAGE_MASK;
189 vma = find_vma(tsk,addr);
190 if (!vma)
191 return NULL;
192 if (vma->vm_start <= addr)
193 return vma;
194 if (!(vma->vm_flags & VM_GROWSDOWN))
195 return NULL;
196 if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
197 return NULL;
198 vma->vm_offset -= vma->vm_start - addr;
199 vma->vm_start = addr;
200 return vma;
201 }
202
203
204
205
206
207 static int read_long(struct task_struct * tsk, unsigned long addr,
208 unsigned long * result)
209 {
210 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
211
212 if (!vma)
213 return -EIO;
214 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
215 unsigned long low,high;
216 struct vm_area_struct * vma_high = vma;
217
218 if (addr + sizeof(long) >= vma->vm_end) {
219 vma_high = vma->vm_next;
220 if (!vma_high || vma_high->vm_start != vma->vm_end)
221 return -EIO;
222 }
223 low = get_long(vma, addr & ~(sizeof(long)-1));
224 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
225 switch (addr & (sizeof(long)-1)) {
226 case 1:
227 low >>= 8;
228 low |= high << 24;
229 break;
230 case 2:
231 low >>= 16;
232 low |= high << 16;
233 break;
234 case 3:
235 low >>= 24;
236 low |= high << 8;
237 break;
238 }
239 *result = low;
240 } else
241 *result = get_long(vma, addr);
242 return 0;
243 }
244
245
246
247
248
249 static int write_long(struct task_struct * tsk, unsigned long addr,
250 unsigned long data)
251 {
252 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
253
254 if (!vma)
255 return -EIO;
256 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
257 unsigned long low,high;
258 struct vm_area_struct * vma_high = vma;
259
260 if (addr + sizeof(long) >= vma->vm_end) {
261 vma_high = vma->vm_next;
262 if (!vma_high || vma_high->vm_start != vma->vm_end)
263 return -EIO;
264 }
265 low = get_long(vma, addr & ~(sizeof(long)-1));
266 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
267 switch (addr & (sizeof(long)-1)) {
268 case 0:
269 low = data;
270 break;
271 case 1:
272 low &= 0x000000ff;
273 low |= data << 8;
274 high &= ~0xff;
275 high |= data >> 24;
276 break;
277 case 2:
278 low &= 0x0000ffff;
279 low |= data << 16;
280 high &= ~0xffff;
281 high |= data >> 16;
282 break;
283 case 3:
284 low &= 0x00ffffff;
285 low |= data << 24;
286 high &= ~0xffffff;
287 high |= data >> 8;
288 break;
289 }
290 put_long(vma, addr & ~(sizeof(long)-1),low);
291 put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
292 } else
293 put_long(vma, addr, data);
294 return 0;
295 }
296
297 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
298 {
299 struct task_struct *child;
300 struct user * dummy;
301 int i;
302
303 dummy = NULL;
304
305 if (request == PTRACE_TRACEME) {
306
307 if (current->flags & PF_PTRACED)
308 return -EPERM;
309
310 current->flags |= PF_PTRACED;
311 return 0;
312 }
313 if (pid == 1)
314 return -EPERM;
315 if (!(child = get_task(pid)))
316 return -ESRCH;
317 if (request == PTRACE_ATTACH) {
318 if (child == current)
319 return -EPERM;
320 if ((!child->dumpable ||
321 (current->uid != child->euid) ||
322 (current->uid != child->uid) ||
323 (current->gid != child->egid) ||
324 (current->gid != child->gid)) && !suser())
325 return -EPERM;
326
327 if (child->flags & PF_PTRACED)
328 return -EPERM;
329 child->flags |= PF_PTRACED;
330 if (child->p_pptr != current) {
331 REMOVE_LINKS(child);
332 child->p_pptr = current;
333 SET_LINKS(child);
334 }
335 send_sig(SIGSTOP, child, 1);
336 return 0;
337 }
338 if (!(child->flags & PF_PTRACED))
339 return -ESRCH;
340 if (child->state != TASK_STOPPED) {
341 if (request != PTRACE_KILL)
342 return -ESRCH;
343 }
344 if (child->p_pptr != current)
345 return -ESRCH;
346
347 switch (request) {
348
349 case PTRACE_PEEKTEXT:
350 case PTRACE_PEEKDATA: {
351 unsigned long tmp;
352 int res;
353
354 res = read_long(child, addr, &tmp);
355 if (res < 0)
356 return res;
357 res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
358 if (!res)
359 put_fs_long(tmp,(unsigned long *) data);
360 return res;
361 }
362
363
364 case PTRACE_PEEKUSR: {
365 unsigned long tmp;
366 int res;
367
368 if ((addr & 3) || addr < 0 ||
369 addr > sizeof(struct user) - 3)
370 return -EIO;
371
372 res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
373 if (res)
374 return res;
375 tmp = 0;
376 if(addr < 17*sizeof(long)) {
377 addr = addr >> 2;
378
379 tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
380 if (addr == DS || addr == ES ||
381 addr == FS || addr == GS ||
382 addr == CS || addr == SS)
383 tmp &= 0xffff;
384 };
385 if(addr >= (long) &dummy->u_debugreg[0] &&
386 addr <= (long) &dummy->u_debugreg[7]){
387 addr -= (long) &dummy->u_debugreg[0];
388 addr = addr >> 2;
389 tmp = child->debugreg[addr];
390 };
391 put_fs_long(tmp,(unsigned long *) data);
392 return 0;
393 }
394
395
396 case PTRACE_POKETEXT:
397 case PTRACE_POKEDATA:
398 return write_long(child,addr,data);
399
400 case PTRACE_POKEUSR:
401 if ((addr & 3) || addr < 0 ||
402 addr > sizeof(struct user) - 3)
403 return -EIO;
404
405 addr = addr >> 2;
406
407 if (addr == ORIG_EAX)
408 return -EIO;
409 if (addr == DS || addr == ES ||
410 addr == FS || addr == GS ||
411 addr == CS || addr == SS) {
412 data &= 0xffff;
413 if (data && (data & 3) != 3)
414 return -EIO;
415 }
416 if (addr == EFL) {
417 data &= FLAG_MASK;
418 data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
419 }
420
421
422 if(addr < 17){
423 if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
424 return -EIO;
425 return 0;
426 };
427
428
429
430
431
432
433 addr = addr << 2;
434 if(addr >= (long) &dummy->u_debugreg[0] &&
435 addr <= (long) &dummy->u_debugreg[7]){
436
437 if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
438 if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
439 if(addr < (long) &dummy->u_debugreg[4] &&
440 ((unsigned long) data) >= 0xbffffffd) return -EIO;
441
442 if(addr == (long) &dummy->u_debugreg[7]) {
443 data &= ~DR_CONTROL_RESERVED;
444 for(i=0; i<4; i++)
445 if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
446 return -EIO;
447 };
448
449 addr -= (long) &dummy->u_debugreg;
450 addr = addr >> 2;
451 child->debugreg[addr] = data;
452 return 0;
453 };
454 return -EIO;
455
456 case PTRACE_SYSCALL:
457 case PTRACE_CONT: {
458 long tmp;
459
460 if ((unsigned long) data > NSIG)
461 return -EIO;
462 if (request == PTRACE_SYSCALL)
463 child->flags |= PF_TRACESYS;
464 else
465 child->flags &= ~PF_TRACESYS;
466 child->exit_code = data;
467 wake_up_process(child);
468
469 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
470 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
471 return 0;
472 }
473
474
475
476
477
478
479 case PTRACE_KILL: {
480 long tmp;
481
482 wake_up_process(child);
483 child->exit_code = SIGKILL;
484
485 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
486 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
487 return 0;
488 }
489
490 case PTRACE_SINGLESTEP: {
491 long tmp;
492
493 if ((unsigned long) data > NSIG)
494 return -EIO;
495 child->flags &= ~PF_TRACESYS;
496 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
497 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
498 wake_up_process(child);
499 child->exit_code = data;
500
501 return 0;
502 }
503
504 case PTRACE_DETACH: {
505 long tmp;
506
507 if ((unsigned long) data > NSIG)
508 return -EIO;
509 child->flags &= ~(PF_PTRACED|PF_TRACESYS);
510 wake_up_process(child);
511 child->exit_code = data;
512 REMOVE_LINKS(child);
513 child->p_pptr = child->p_opptr;
514 SET_LINKS(child);
515
516 tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
517 put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
518 return 0;
519 }
520
521 default:
522 return -EIO;
523 }
524 }
525
526 asmlinkage void syscall_trace(void)
527 {
528 if ((current->flags & (PF_PTRACED|PF_TRACESYS))
529 != (PF_PTRACED|PF_TRACESYS))
530 return;
531 current->exit_code = SIGTRAP;
532 current->state = TASK_STOPPED;
533 notify_parent(current);
534 schedule();
535
536
537
538
539
540 if (current->exit_code)
541 current->signal |= (1 << (current->exit_code - 1));
542 current->exit_code = 0;
543 }