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