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