|
|
1.1 root 1: /* ptrace.c */
2: /* By Ross Biro 1/23/92 */
1.1.1.3 root 3: /* edited by Linus Torvalds */
1.1 root 4:
5: #include <linux/head.h>
6: #include <linux/kernel.h>
7: #include <linux/sched.h>
8: #include <linux/mm.h>
1.1.1.6 root 9: #include <linux/errno.h>
10: #include <linux/ptrace.h>
1.1.1.5 root 11:
1.1 root 12: #include <asm/segment.h>
13: #include <asm/system.h>
1.1.1.5 root 14:
1.1.1.2 root 15: /*
16: * does not yet catch signals sent when the child dies.
17: * in exit.c or in signal.c.
18: */
1.1 root 19:
20: /* determines which flags the user has access to. */
21: /* 1 = access 0 = no access */
22: #define FLAG_MASK 0x00000dd9
23:
24: /* set's the trap flag. */
25: #define TRAP_FLAG 0x100
26:
1.1.1.2 root 27: /*
28: * this is the number to subtract from the top of the stack. To find
29: * the local frame.
30: */
1.1 root 31: #define MAGICNUMBER 68
32:
33: /* change a pid into a task struct. */
1.1.1.5 root 34: static inline struct task_struct * get_task(int pid)
1.1 root 35: {
1.1.1.2 root 36: int i;
37:
1.1.1.6 root 38: for (i = 1; i < NR_TASKS; i++) {
1.1.1.2 root 39: if (task[i] != NULL && (task[i]->pid == pid))
1.1.1.5 root 40: return task[i];
1.1.1.2 root 41: }
1.1.1.5 root 42: return NULL;
1.1 root 43: }
44:
1.1.1.2 root 45: /*
46: * this routine will get a word off of the processes priviledged stack.
47: * the offset is how far from the base addr as stored in the TSS.
48: * this routine assumes that all the priviledged stacks are in our
49: * data space.
1.1.1.3 root 50: */
1.1.1.2 root 51: static inline int get_stack_long(struct task_struct *task, int offset)
1.1 root 52: {
1.1.1.2 root 53: unsigned char *stack;
1.1 root 54:
1.1.1.2 root 55: stack = (unsigned char *)task->tss.esp0;
56: stack += offset;
57: return (*((int *)stack));
1.1 root 58: }
59:
1.1.1.2 root 60: /*
61: * this routine will put a word on the processes priviledged stack.
62: * the offset is how far from the base addr as stored in the TSS.
63: * this routine assumes that all the priviledged stacks are in our
64: * data space.
65: */
66: static inline int put_stack_long(struct task_struct *task, int offset,
1.1.1.3 root 67: unsigned long data)
1.1 root 68: {
1.1.1.2 root 69: unsigned char * stack;
1.1 root 70:
1.1.1.2 root 71: stack = (unsigned char *) task->tss.esp0;
72: stack += offset;
1.1.1.3 root 73: *(unsigned long *) stack = data;
1.1.1.2 root 74: return 0;
1.1 root 75: }
76:
1.1.1.2 root 77: /*
1.1.1.3 root 78: * This routine gets a long from any process space by following the page
79: * tables. NOTE! You should check that the long isn't on a page boundary,
80: * and that it is in the task area before calling this: this routine does
81: * no checking.
82: *
83: * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
84: * zero. This routine shouldn't have to change when we make a better mm.
1.1.1.2 root 85: */
1.1.1.3 root 86: static unsigned long get_long(struct task_struct * tsk,
87: unsigned long addr)
1.1 root 88: {
1.1.1.2 root 89: unsigned long page;
90:
1.1.1.3 root 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);
1.1.1.2 root 98: }
99: if (!(page & PAGE_PRESENT)) {
1.1.1.4 root 100: do_no_page(0,addr,tsk,0);
1.1.1.3 root 101: goto repeat;
1.1.1.2 root 102: }
1.1.1.3 root 103: page &= 0xfffff000;
104: page += addr & 0xfff;
105: return *(unsigned long *) page;
1.1 root 106: }
107:
1.1.1.2 root 108: /*
1.1.1.3 root 109: * This routine puts a long into any process space by following the page
110: * tables. NOTE! You should check that the long isn't on a page boundary,
111: * and that it is in the task area before calling this: this routine does
112: * no checking.
1.1.1.2 root 113: */
1.1.1.3 root 114: static void put_long(struct task_struct * tsk, unsigned long addr,
115: unsigned long data)
1.1 root 116: {
1.1.1.2 root 117: unsigned long page;
118:
1.1.1.3 root 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)) {
1.1.1.4 root 128: do_no_page(0,addr,tsk,0);
1.1.1.3 root 129: goto repeat;
1.1.1.2 root 130: }
1.1.1.3 root 131: if (!(page & PAGE_RW)) {
1.1.1.6 root 132: do_wp_page(0,addr,tsk,0);
1.1.1.3 root 133: goto repeat;
1.1.1.2 root 134: }
1.1.1.3 root 135: page &= 0xfffff000;
136: page += addr & 0xfff;
137: *(unsigned long *) page = data;
138: }
1.1 root 139:
1.1.1.3 root 140: /*
141: * This routine checks the page boundaries, and that the offset is
142: * within the task area. It then calls get_long() to read a long.
143: */
144: static int read_long(struct task_struct * tsk, unsigned long addr,
145: unsigned long * result)
146: {
147: unsigned long low,high;
1.1 root 148:
1.1.1.3 root 149: if (addr > TASK_SIZE-4)
1.1.1.2 root 150: return -EIO;
1.1.1.3 root 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: }
1.1 root 173:
1.1.1.3 root 174: /*
175: * This routine checks the page boundaries, and that the offset is
176: * within the task area. It then calls put_long() to write a long.
177: */
178: static int write_long(struct task_struct * tsk, unsigned long addr,
179: unsigned long data)
180: {
181: unsigned long low,high;
1.1 root 182:
1.1.1.3 root 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: /* shouldn't happen, but safety first */
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);
1.1.1.2 root 215: return 0;
1.1 root 216: }
217:
1.1.1.4 root 218: int sys_ptrace(long request, long pid, long addr, long data)
1.1 root 219: {
1.1.1.2 root 220: struct task_struct *child;
221:
1.1.1.5 root 222: if (request == PTRACE_TRACEME) {
223: /* are we already being traced? */
224: if (current->flags & PF_PTRACED)
225: return -EPERM;
1.1.1.2 root 226: /* set the ptrace bit in the proccess flags. */
227: current->flags |= PF_PTRACED;
228: return 0;
229: }
1.1.1.5 root 230: if (!(child = get_task(pid)))
1.1.1.2 root 231: return -ESRCH;
1.1.1.5 root 232: if (request == PTRACE_ATTACH) {
233: long tmp;
1.1.1.2 root 234:
1.1.1.6 root 235: if (child == current)
236: return -EPERM;
237: if ((!child->dumpable || (current->uid != child->euid) ||
1.1.1.5 root 238: (current->gid != child->egid)) && !suser())
239: return -EPERM;
240: /* the same process cannot be attached many times */
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)
1.1.1.2 root 260: return -ESRCH;
261:
262: switch (request) {
1.1 root 263: /* when I and D space are seperate, these will need to be fixed. */
1.1.1.5 root 264: case PTRACE_PEEKTEXT: /* read word at location addr. */
265: case PTRACE_PEEKDATA: {
1.1.1.2 root 266: int tmp,res;
267:
1.1.1.5 root 268: res = read_long(child, addr, &tmp);
1.1.1.2 root 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: /* read the word at location addr in the USER area. */
1.1.1.5 root 277: case PTRACE_PEEKUSR: {
1.1.1.2 root 278: int tmp;
279: addr = addr >> 2; /* temporary hack. */
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: }
1.1 root 287:
288: /* when I and D space are seperate, this will have to be fixed. */
1.1.1.5 root 289: case PTRACE_POKETEXT: /* write the word at location addr. */
290: case PTRACE_POKEDATA:
291: return write_long(child,addr,data);
1.1.1.2 root 292:
1.1.1.5 root 293: case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
1.1.1.2 root 294: addr = addr >> 2; /* temproary hack. */
295: if (addr < 0 || addr >= 17)
1.1.1.3 root 296: return -EIO;
1.1.1.2 root 297: if (addr == ORIG_EAX)
298: return -EIO;
299: if (addr == EFL) { /* flags. */
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:
1.1.1.5 root 307: case PTRACE_CONT: { /* restart after signal. */
1.1.1.2 root 308: long tmp;
309:
1.1.1.5 root 310: child->signal = 0;
1.1.1.2 root 311: if (data > 0 && data <= NSIG)
312: child->signal = 1<<(data-1);
1.1.1.5 root 313: child->state = TASK_RUNNING;
1.1 root 314: /* make sure the single step bit is not set. */
1.1.1.2 root 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: * make the child exit. Best I can do is send it a sigkill.
322: * perhaps it should be put in the status that it want's to
323: * exit.
324: */
1.1.1.5 root 325: case PTRACE_KILL: {
1.1.1.2 root 326: long tmp;
327:
1.1.1.5 root 328: child->state = TASK_RUNNING;
1.1.1.2 root 329: child->signal = 1 << (SIGKILL-1);
1.1 root 330: /* make sure the single step bit is not set. */
1.1.1.2 root 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:
1.1.1.5 root 336: case PTRACE_SINGLESTEP: { /* set the trap flag. */
1.1.1.2 root 337: long tmp;
338:
339: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
340: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
1.1.1.5 root 341: child->state = TASK_RUNNING;
1.1.1.2 root 342: child->signal = 0;
1.1.1.5 root 343: if (data > 0 && data <= NSIG)
1.1.1.2 root 344: child->signal= 1<<(data-1);
1.1 root 345: /* give it a chance to run. */
1.1.1.2 root 346: return 0;
347: }
1.1 root 348:
1.1.1.5 root 349: case PTRACE_DETACH: { /* detach a process that was attached. */
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: /* make sure the single step bit is not set. */
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:
1.1.1.2 root 364: default:
365: return -EIO;
366: }
1.1 root 367: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.