This source file includes following definitions.
- get_task
- get_stack_long
- put_stack_long
- get_long
- put_long
- read_long
- write_long
- sys_ptrace
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 addr += tsk->start_code;
92 repeat:
93 page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
94 page = *(unsigned long *) page;
95 if (page & PAGE_PRESENT) {
96 page &= 0xfffff000;
97 page += (addr >> 10) & 0xffc;
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 &= 0xfffff000;
105 page += addr & 0xfff;
106 return *(unsigned long *) page;
107 }
108
109
110
111
112
113
114
115 static void put_long(struct task_struct * tsk, unsigned long addr,
116 unsigned long data)
117 {
118 unsigned long page;
119
120 addr += tsk->start_code;
121 repeat:
122 page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
123 page = *(unsigned long *) page;
124 if (page & PAGE_PRESENT) {
125 page &= 0xfffff000;
126 page += (addr >> 10) & 0xffc;
127 page = *((unsigned long *) page);
128 }
129 if (!(page & PAGE_PRESENT)) {
130 do_no_page(0,addr,tsk,0);
131 goto repeat;
132 }
133 if (!(page & PAGE_RW)) {
134 do_wp_page(0,addr,tsk,0);
135 goto repeat;
136 }
137 page &= 0xfffff000;
138 page += addr & 0xfff;
139 *(unsigned long *) page = data;
140 }
141
142
143
144
145
146 static int read_long(struct task_struct * tsk, unsigned long addr,
147 unsigned long * result)
148 {
149 unsigned long low,high;
150
151 if (addr > TASK_SIZE-4)
152 return -EIO;
153 if ((addr & 0xfff) > PAGE_SIZE-4) {
154 low = get_long(tsk,addr & 0xfffffffc);
155 high = get_long(tsk,(addr+4) & 0xfffffffc);
156 switch (addr & 3) {
157 case 1:
158 low >>= 8;
159 low |= high << 24;
160 break;
161 case 2:
162 low >>= 16;
163 low |= high << 16;
164 break;
165 case 3:
166 low >>= 24;
167 low |= high << 8;
168 break;
169 }
170 *result = low;
171 } else
172 *result = get_long(tsk,addr);
173 return 0;
174 }
175
176
177
178
179
180 static int write_long(struct task_struct * tsk, unsigned long addr,
181 unsigned long data)
182 {
183 unsigned long low,high;
184
185 if (addr > TASK_SIZE-4)
186 return -EIO;
187 if ((addr & 0xfff) > PAGE_SIZE-4) {
188 low = get_long(tsk,addr & 0xfffffffc);
189 high = get_long(tsk,(addr+4) & 0xfffffffc);
190 switch (addr & 3) {
191 case 0:
192 low = data;
193 break;
194 case 1:
195 low &= 0x000000ff;
196 low |= data << 8;
197 high &= 0xffffff00;
198 high |= data >> 24;
199 break;
200 case 2:
201 low &= 0x0000ffff;
202 low |= data << 16;
203 high &= 0xffff0000;
204 high |= data >> 16;
205 break;
206 case 3:
207 low &= 0x00ffffff;
208 low |= data << 24;
209 high &= 0xff000000;
210 high |= data >> 8;
211 break;
212 }
213 put_long(tsk,addr & 0xfffffffc,low);
214 put_long(tsk,(addr+4) & 0xfffffffc,high);
215 } else
216 put_long(tsk,addr,data);
217 return 0;
218 }
219
220 int sys_ptrace(long request, long pid, long addr, long data)
221 {
222 struct task_struct *child;
223
224 if (request == PTRACE_TRACEME) {
225
226 if (current->flags & PF_PTRACED)
227 return -EPERM;
228
229 current->flags |= PF_PTRACED;
230 return 0;
231 }
232 if (!(child = get_task(pid)))
233 return -ESRCH;
234 if (request == PTRACE_ATTACH) {
235 long tmp;
236
237 if (child == current)
238 return -EPERM;
239 if ((!child->dumpable || (current->uid != child->euid) ||
240 (current->gid != child->egid)) && !suser())
241 return -EPERM;
242
243 if (child->flags & PF_PTRACED)
244 return -EPERM;
245 child->flags |= PF_PTRACED;
246 if (child->p_pptr != current) {
247 REMOVE_LINKS(child);
248 child->p_pptr = current;
249 SET_LINKS(child);
250 }
251 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
252 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
253 if (child->state == TASK_INTERRUPTIBLE ||
254 child->state == TASK_STOPPED)
255 child->state = TASK_RUNNING;
256 child->signal = 0;
257 return 0;
258 }
259 if (!(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
260 return -ESRCH;
261 if (child->p_pptr != current)
262 return -ESRCH;
263
264 switch (request) {
265
266 case PTRACE_PEEKTEXT:
267 case PTRACE_PEEKDATA: {
268 int tmp,res;
269
270 res = read_long(child, addr, &tmp);
271 if (res < 0)
272 return res;
273 verify_area((void *) data, 4);
274 put_fs_long(tmp,(unsigned long *) data);
275 return 0;
276 }
277
278
279 case PTRACE_PEEKUSR: {
280 int tmp;
281 addr = addr >> 2;
282 if (addr < 0 || addr >= 17)
283 return -EIO;
284 verify_area((void *) data, 4);
285 tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
286 put_fs_long(tmp,(unsigned long *) data);
287 return 0;
288 }
289
290
291 case PTRACE_POKETEXT:
292 case PTRACE_POKEDATA:
293 return write_long(child,addr,data);
294
295 case PTRACE_POKEUSR:
296 addr = addr >> 2;
297 if (addr < 0 || addr >= 17)
298 return -EIO;
299 if (addr == ORIG_EAX)
300 return -EIO;
301 if (addr == EFL) {
302 data &= FLAG_MASK;
303 data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
304 }
305 if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
306 return -EIO;
307 return 0;
308
309 case PTRACE_CONT: {
310 long tmp;
311
312 child->signal = 0;
313 if (data > 0 && data <= NSIG)
314 child->signal = 1<<(data-1);
315 child->state = TASK_RUNNING;
316
317 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
318 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
319 return 0;
320 }
321
322
323
324
325
326
327 case PTRACE_KILL: {
328 long tmp;
329
330 child->state = TASK_RUNNING;
331 child->signal = 1 << (SIGKILL-1);
332
333 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
334 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
335 return 0;
336 }
337
338 case PTRACE_SINGLESTEP: {
339 long tmp;
340
341 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
342 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
343 child->state = TASK_RUNNING;
344 child->signal = 0;
345 if (data > 0 && data <= NSIG)
346 child->signal= 1<<(data-1);
347
348 return 0;
349 }
350
351 case PTRACE_DETACH: {
352 long tmp;
353
354 child->flags &= ~PF_PTRACED;
355 child->signal=0;
356 child->state = 0;
357 REMOVE_LINKS(child);
358 child->p_pptr = child->p_opptr;
359 SET_LINKS(child);
360
361 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
362 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
363 return 0;
364 }
365
366 default:
367 return -EIO;
368 }
369 }