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