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