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