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