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