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
12 #include <asm/segment.h>
13 #include <asm/system.h>
14
15
16
17
18
19
20
21
22 #define FLAG_MASK 0x00000dd9
23
24
25 #define TRAP_FLAG 0x100
26
27
28
29
30
31 #define MAGICNUMBER 68
32
33
34 static inline struct task_struct * get_task(int pid)
35 {
36 int i;
37
38 for (i = 1; i < NR_TASKS; i++) {
39 if (task[i] != NULL && (task[i]->pid == pid))
40 return task[i];
41 }
42 return NULL;
43 }
44
45
46
47
48
49
50
51 static inline int get_stack_long(struct task_struct *task, int offset)
52 {
53 unsigned char *stack;
54
55 stack = (unsigned char *)task->tss.esp0;
56 stack += offset;
57 return (*((int *)stack));
58 }
59
60
61
62
63
64
65
66 static inline int put_stack_long(struct task_struct *task, int offset,
67 unsigned long data)
68 {
69 unsigned char * stack;
70
71 stack = (unsigned char *) task->tss.esp0;
72 stack += offset;
73 *(unsigned long *) stack = data;
74 return 0;
75 }
76
77
78
79
80
81
82
83
84
85
86 static unsigned long get_long(struct task_struct * tsk,
87 unsigned long addr)
88 {
89 unsigned long page;
90
91 repeat:
92 page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
93 page = *(unsigned long *) page;
94 if (page & PAGE_PRESENT) {
95 page &= 0xfffff000;
96 page += (addr >> 10) & 0xffc;
97 page = *((unsigned long *) page);
98 }
99 if (!(page & PAGE_PRESENT)) {
100 do_no_page(0,addr,tsk,0);
101 goto repeat;
102 }
103 page &= 0xfffff000;
104 page += addr & 0xfff;
105 return *(unsigned long *) page;
106 }
107
108
109
110
111
112
113
114 static void put_long(struct task_struct * tsk, unsigned long addr,
115 unsigned long data)
116 {
117 unsigned long page, pte;
118
119 repeat:
120 page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
121 page = *(unsigned long *) page;
122 if (page & PAGE_PRESENT) {
123 page &= 0xfffff000;
124 page += (addr >> 10) & 0xffc;
125 pte = page;
126 page = *((unsigned long *) page);
127 }
128 if (!(page & PAGE_PRESENT)) {
129 do_no_page(0,addr,tsk,0);
130 goto repeat;
131 }
132 if (!(page & PAGE_RW)) {
133 do_wp_page(0,addr,tsk,0);
134 goto repeat;
135 }
136
137 *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
138 page &= 0xfffff000;
139 page += addr & 0xfff;
140 *(unsigned long *) page = data;
141 }
142
143
144
145
146
147 static int read_long(struct task_struct * tsk, unsigned long addr,
148 unsigned long * result)
149 {
150 unsigned long low,high;
151
152 if (addr > TASK_SIZE-4)
153 return -EIO;
154 if ((addr & 0xfff) > PAGE_SIZE-4) {
155 low = get_long(tsk,addr & 0xfffffffc);
156 high = get_long(tsk,(addr+4) & 0xfffffffc);
157 switch (addr & 3) {
158 case 1:
159 low >>= 8;
160 low |= high << 24;
161 break;
162 case 2:
163 low >>= 16;
164 low |= high << 16;
165 break;
166 case 3:
167 low >>= 24;
168 low |= high << 8;
169 break;
170 }
171 *result = low;
172 } else
173 *result = get_long(tsk,addr);
174 return 0;
175 }
176
177
178
179
180
181 static int write_long(struct task_struct * tsk, unsigned long addr,
182 unsigned long data)
183 {
184 unsigned long low,high;
185
186 if (addr > TASK_SIZE-4)
187 return -EIO;
188 if ((addr & 0xfff) > PAGE_SIZE-4) {
189 low = get_long(tsk,addr & 0xfffffffc);
190 high = get_long(tsk,(addr+4) & 0xfffffffc);
191 switch (addr & 3) {
192 case 0:
193 low = data;
194 break;
195 case 1:
196 low &= 0x000000ff;
197 low |= data << 8;
198 high &= 0xffffff00;
199 high |= data >> 24;
200 break;
201 case 2:
202 low &= 0x0000ffff;
203 low |= data << 16;
204 high &= 0xffff0000;
205 high |= data >> 16;
206 break;
207 case 3:
208 low &= 0x00ffffff;
209 low |= data << 24;
210 high &= 0xff000000;
211 high |= data >> 8;
212 break;
213 }
214 put_long(tsk,addr & 0xfffffffc,low);
215 put_long(tsk,(addr+4) & 0xfffffffc,high);
216 } else
217 put_long(tsk,addr,data);
218 return 0;
219 }
220
221 int sys_ptrace(long request, long pid, long addr, long data)
222 {
223 struct task_struct *child;
224
225 if (request == PTRACE_TRACEME) {
226
227 if (current->flags & PF_PTRACED)
228 return -EPERM;
229
230 current->flags |= PF_PTRACED;
231 return 0;
232 }
233 if (pid == 1)
234 return -EPERM;
235 if (!(child = get_task(pid)))
236 return -ESRCH;
237 if (request == PTRACE_ATTACH) {
238 if (child == current)
239 return -EPERM;
240 if ((!child->dumpable || (current->uid != child->euid) ||
241 (current->gid != child->egid)) && !suser())
242 return -EPERM;
243
244 if (child->flags & PF_PTRACED)
245 return -EPERM;
246 child->flags |= PF_PTRACED;
247 if (child->p_pptr != current) {
248 REMOVE_LINKS(child);
249 child->p_pptr = current;
250 SET_LINKS(child);
251 }
252 send_sig(SIGSTOP, child, 1);
253 return 0;
254 }
255 if (!(child->flags & PF_PTRACED))
256 return -ESRCH;
257 if (child->state != TASK_STOPPED && request != PTRACE_DETACH)
258 return -ESRCH;
259 if (child->p_pptr != current)
260 return -ESRCH;
261
262 switch (request) {
263
264 case PTRACE_PEEKTEXT:
265 case PTRACE_PEEKDATA: {
266 unsigned long tmp;
267 int res;
268
269 res = read_long(child, addr, &tmp);
270 if (res < 0)
271 return res;
272 res = verify_area(VERIFY_WRITE, (void *) data, 4);
273 if (!res)
274 put_fs_long(tmp,(unsigned long *) data);
275 return res;
276 }
277
278
279 case PTRACE_PEEKUSR: {
280 unsigned long tmp;
281 int res;
282
283 addr = addr >> 2;
284 if (addr < 0 || addr >= 17)
285 return -EIO;
286 res = verify_area(VERIFY_WRITE, (void *) data, 4);
287 if (res)
288 return res;
289 tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
290 put_fs_long(tmp,(unsigned long *) data);
291 return 0;
292 }
293
294
295 case PTRACE_POKETEXT:
296 case PTRACE_POKEDATA:
297 return write_long(child,addr,data);
298
299 case PTRACE_POKEUSR:
300 addr = addr >> 2;
301 if (addr < 0 || addr >= 17)
302 return -EIO;
303 if (addr == ORIG_EAX)
304 return -EIO;
305 if (addr == EFL) {
306 data &= FLAG_MASK;
307 data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
308 }
309 if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
310 return -EIO;
311 return 0;
312
313 case PTRACE_SYSCALL:
314 case PTRACE_CONT: {
315 long tmp;
316
317 if ((unsigned long) data > NSIG)
318 return -EIO;
319 if (request == PTRACE_SYSCALL)
320 child->flags |= PF_TRACESYS;
321 else
322 child->flags &= ~PF_TRACESYS;
323 child->exit_code = data;
324 child->state = TASK_RUNNING;
325
326 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
327 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
328 return 0;
329 }
330
331
332
333
334
335
336 case PTRACE_KILL: {
337 long tmp;
338
339 child->state = TASK_RUNNING;
340 child->exit_code = SIGKILL;
341
342 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
343 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
344 return 0;
345 }
346
347 case PTRACE_SINGLESTEP: {
348 long tmp;
349
350 if ((unsigned long) data > NSIG)
351 return -EIO;
352 child->flags &= ~PF_TRACESYS;
353 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
354 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
355 child->state = TASK_RUNNING;
356 child->exit_code = data;
357
358 return 0;
359 }
360
361 case PTRACE_DETACH: {
362 long tmp;
363
364 if ((unsigned long) data > NSIG)
365 return -EIO;
366 child->flags &= ~(PF_PTRACED|PF_TRACESYS);
367 child->state = TASK_RUNNING;
368 child->exit_code = data;
369 REMOVE_LINKS(child);
370 child->p_pptr = child->p_opptr;
371 SET_LINKS(child);
372
373 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
374 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
375 return 0;
376 }
377
378 default:
379 return -EIO;
380 }
381 }
382
383 void syscall_trace(void)
384 {
385 if ((current->flags & (PF_PTRACED|PF_TRACESYS))
386 != (PF_PTRACED|PF_TRACESYS))
387 return;
388 current->exit_code = SIGTRAP;
389 current->state = TASK_STOPPED;
390 notify_parent(current);
391 schedule();
392
393
394
395
396
397 if (current->exit_code)
398 current->signal |= (1 << (current->exit_code - 1));
399 current->exit_code = 0;
400 }