1 /* ptrace.c */
2 /* By Ross Biro 1/23/92 */
3 /* edited by Linus Torvalds */
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 * does not yet catch signals sent when the child dies.
19 * in exit.c or in signal.c.
20 */
21
22 /* determines which flags the user has access to. */
23 /* 1 = access 0 = no access */
24 #define FLAG_MASK 0x00044dd5
25
26 /* set's the trap flag. */
27 #define TRAP_FLAG 0x100
28
29 /*
30 * this is the number to subtract from the top of the stack. To find
31 * the local frame.
32 */
33 #define MAGICNUMBER 68
34
35 /* change a pid into a task struct. */
36 static inline struct task_struct * get_task(int pid)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 * this routine will get a word off of the processes priviledged stack.
49 * the offset is how far from the base addr as stored in the TSS.
50 * this routine assumes that all the priviledged stacks are in our
51 * data space.
52 */
53 static inline int get_stack_long(struct task_struct *task, int offset)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
54 {
55 unsigned char *stack;
56
57 stack = (unsigned char *)task->tss.esp0;
58 stack += offset;
59 return (*((int *)stack));
60 }
61
62 /*
63 * this routine will put a word on the processes priviledged stack.
64 * the offset is how far from the base addr as stored in the TSS.
65 * this routine assumes that all the priviledged stacks are in our
66 * data space.
67 */
68 static inline int put_stack_long(struct task_struct *task, int offset,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 * This routine gets a long from any process space by following the page
81 * tables. NOTE! You should check that the long isn't on a page boundary,
82 * and that it is in the task area before calling this: this routine does
83 * no checking.
84 *
85 * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
86 * zero. This routine shouldn't have to change when we make a better mm.
87 */
88 static unsigned long get_long(struct task_struct * tsk,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 /* this is a hack for non-kernel-mapped video buffers and similar */
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 * This routine puts a long into any process space by following the page
114 * tables. NOTE! You should check that the long isn't on a page boundary,
115 * and that it is in the task area before calling this: this routine does
116 * no checking.
117 *
118 * Now keeps R/W state of page so that a text page stays readonly
119 * even if a debugger scribbles breakpoints into it. -M.U-
120 */
121 static void put_long(struct task_struct * tsk, unsigned long addr,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 /* PAGE_RW */ ,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 /* this is a hack for non-kernel-mapped video buffers and similar */
146 if (page >= high_memory)
147 return;
148 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
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 * This routine checks the page boundaries, and that the offset is
161 * within the task area. It then calls get_long() to read a long.
162 */
163 static int read_long(struct task_struct * tsk, unsigned long addr,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 * This routine checks the page boundaries, and that the offset is
195 * within the task area. It then calls put_long() to write a long.
196 */
197 static int write_long(struct task_struct * tsk, unsigned long addr,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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: /* shouldn't happen, but safety first */
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)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
238 {
239 struct task_struct *child;
240 struct user * dummy;
241 int i;
242
243 dummy = NULL;
244
245 if (request == PTRACE_TRACEME) {
246 /* are we already being traced? */
247 if (current->flags & PF_PTRACED)
248 return -EPERM;
249 /* set the ptrace bit in the proccess flags. */
250 current->flags |= PF_PTRACED;
251 return 0;
252 }
253 if (pid == 1) /* you may not mess with init */
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 /* the same process cannot be attached many times */
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 /* when I and D space are seperate, these will need to be fixed. */
286 case PTRACE_PEEKTEXT: /* read word at location addr. */
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 /* read the word at location addr in the USER area. */
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; /* Default return condition */
313 if(addr < 17*sizeof(long)) {
314 addr = addr >> 2; /* temporary hack. */
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 /* when I and D space are seperate, this will have to be fixed. */
333 case PTRACE_POKETEXT: /* write the word at location addr. */
334 case PTRACE_POKEDATA:
335 return write_long(child,addr,data);
336
337 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
338 if ((addr & 3) || addr < 0 ||
339 addr > sizeof(struct user) - 3)
340 return -EIO;
341
342 addr = addr >> 2; /* temproary hack. */
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) { /* flags. */
354 data &= FLAG_MASK;
355 data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
356 }
357 /* Do not allow the user to set the debug register for kernel
358 address space */
359 if(addr < 17){
360 if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
361 return -EIO;
362 return 0;
363 };
364
365 /* We need to be very careful here. We implicitly
366 want to modify a portion of the task_struct, and we
367 have to be selective about what portions we allow someone
368 to modify. */
369
370 addr = addr << 2; /* Convert back again */
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: /* continue and stop at next (return from) syscall */
394 case PTRACE_CONT: { /* restart after signal. */
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 /* make sure the single step bit is not set. */
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 * make the child exit. Best I can do is send it a sigkill.
413 * perhaps it should be put in the status that it want's to
414 * exit.
415 */
416 case PTRACE_KILL: {
417 long tmp;
418
419 child->state = TASK_RUNNING;
420 child->exit_code = SIGKILL;
421 /* make sure the single step bit is not set. */
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: { /* set the trap flag. */
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 /* give it a chance to run. */
438 return 0;
439 }
440
441 case PTRACE_DETACH: { /* detach a process that was attached. */
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 /* make sure the single step bit is not set. */
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)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 * this isn't the same as continuing with a signal, but it will do
474 * for normal use. strace only continues with a signal if the
475 * stopping signal is not SIGTRAP. -brl
476 */
477 if (current->exit_code)
478 current->signal |= (1 << (current->exit_code - 1));
479 current->exit_code = 0;
480 }