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