|
|
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: 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);
1.1.1.2 root 99: }
100: if (!(page & PAGE_PRESENT)) {
1.1.1.4 root 101: do_no_page(0,addr,tsk,0);
1.1.1.3 root 102: goto repeat;
1.1.1.2 root 103: }
1.1.1.3 root 104: page &= 0xfffff000;
105: page += addr & 0xfff;
106: return *(unsigned long *) page;
1.1 root 107: }
108:
1.1.1.2 root 109: /*
1.1.1.3 root 110: * This routine puts a long into any process space by following the page
111: * tables. NOTE! You should check that the long isn't on a page boundary,
112: * and that it is in the task area before calling this: this routine does
113: * no checking.
1.1.1.2 root 114: */
1.1.1.3 root 115: static void put_long(struct task_struct * tsk, unsigned long addr,
116: unsigned long data)
1.1 root 117: {
1.1.1.2 root 118: unsigned long page;
119:
1.1.1.3 root 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)) {
1.1.1.4 root 130: do_no_page(0,addr,tsk,0);
1.1.1.3 root 131: goto repeat;
1.1.1.2 root 132: }
1.1.1.3 root 133: if (!(page & PAGE_RW)) {
1.1.1.6 ! root 134: do_wp_page(0,addr,tsk,0);
1.1.1.3 root 135: goto repeat;
1.1.1.2 root 136: }
1.1.1.3 root 137: page &= 0xfffff000;
138: page += addr & 0xfff;
139: *(unsigned long *) page = data;
140: }
1.1 root 141:
1.1.1.3 root 142: /*
143: * This routine checks the page boundaries, and that the offset is
144: * within the task area. It then calls get_long() to read a long.
145: */
146: static int read_long(struct task_struct * tsk, unsigned long addr,
147: unsigned long * result)
148: {
149: unsigned long low,high;
1.1 root 150:
1.1.1.3 root 151: if (addr > TASK_SIZE-4)
1.1.1.2 root 152: return -EIO;
1.1.1.3 root 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: }
1.1 root 175:
1.1.1.3 root 176: /*
177: * This routine checks the page boundaries, and that the offset is
178: * within the task area. It then calls put_long() to write a long.
179: */
180: static int write_long(struct task_struct * tsk, unsigned long addr,
181: unsigned long data)
182: {
183: unsigned long low,high;
1.1 root 184:
1.1.1.3 root 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: /* shouldn't happen, but safety first */
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);
1.1.1.2 root 217: return 0;
1.1 root 218: }
219:
1.1.1.4 root 220: int sys_ptrace(long request, long pid, long addr, long data)
1.1 root 221: {
1.1.1.2 root 222: struct task_struct *child;
223:
1.1.1.5 root 224: if (request == PTRACE_TRACEME) {
225: /* are we already being traced? */
226: if (current->flags & PF_PTRACED)
227: return -EPERM;
1.1.1.2 root 228: /* set the ptrace bit in the proccess flags. */
229: current->flags |= PF_PTRACED;
230: return 0;
231: }
1.1.1.5 root 232: if (!(child = get_task(pid)))
1.1.1.2 root 233: return -ESRCH;
1.1.1.5 root 234: if (request == PTRACE_ATTACH) {
235: long tmp;
1.1.1.2 root 236:
1.1.1.6 ! root 237: if (child == current)
! 238: return -EPERM;
! 239: if ((!child->dumpable || (current->uid != child->euid) ||
1.1.1.5 root 240: (current->gid != child->egid)) && !suser())
241: return -EPERM;
242: /* the same process cannot be attached many times */
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)
1.1.1.2 root 262: return -ESRCH;
263:
264: switch (request) {
1.1 root 265: /* when I and D space are seperate, these will need to be fixed. */
1.1.1.5 root 266: case PTRACE_PEEKTEXT: /* read word at location addr. */
267: case PTRACE_PEEKDATA: {
1.1.1.2 root 268: int tmp,res;
269:
1.1.1.5 root 270: res = read_long(child, addr, &tmp);
1.1.1.2 root 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: /* read the word at location addr in the USER area. */
1.1.1.5 root 279: case PTRACE_PEEKUSR: {
1.1.1.2 root 280: int tmp;
281: addr = addr >> 2; /* temporary hack. */
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: }
1.1 root 289:
290: /* when I and D space are seperate, this will have to be fixed. */
1.1.1.5 root 291: case PTRACE_POKETEXT: /* write the word at location addr. */
292: case PTRACE_POKEDATA:
293: return write_long(child,addr,data);
1.1.1.2 root 294:
1.1.1.5 root 295: case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
1.1.1.2 root 296: addr = addr >> 2; /* temproary hack. */
297: if (addr < 0 || addr >= 17)
1.1.1.3 root 298: return -EIO;
1.1.1.2 root 299: if (addr == ORIG_EAX)
300: return -EIO;
301: if (addr == EFL) { /* flags. */
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:
1.1.1.5 root 309: case PTRACE_CONT: { /* restart after signal. */
1.1.1.2 root 310: long tmp;
311:
1.1.1.5 root 312: child->signal = 0;
1.1.1.2 root 313: if (data > 0 && data <= NSIG)
314: child->signal = 1<<(data-1);
1.1.1.5 root 315: child->state = TASK_RUNNING;
1.1 root 316: /* make sure the single step bit is not set. */
1.1.1.2 root 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: * make the child exit. Best I can do is send it a sigkill.
324: * perhaps it should be put in the status that it want's to
325: * exit.
326: */
1.1.1.5 root 327: case PTRACE_KILL: {
1.1.1.2 root 328: long tmp;
329:
1.1.1.5 root 330: child->state = TASK_RUNNING;
1.1.1.2 root 331: child->signal = 1 << (SIGKILL-1);
1.1 root 332: /* make sure the single step bit is not set. */
1.1.1.2 root 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:
1.1.1.5 root 338: case PTRACE_SINGLESTEP: { /* set the trap flag. */
1.1.1.2 root 339: long tmp;
340:
341: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
342: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
1.1.1.5 root 343: child->state = TASK_RUNNING;
1.1.1.2 root 344: child->signal = 0;
1.1.1.5 root 345: if (data > 0 && data <= NSIG)
1.1.1.2 root 346: child->signal= 1<<(data-1);
1.1 root 347: /* give it a chance to run. */
1.1.1.2 root 348: return 0;
349: }
1.1 root 350:
1.1.1.5 root 351: case PTRACE_DETACH: { /* detach a process that was attached. */
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: /* make sure the single step bit is not set. */
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:
1.1.1.2 root 366: default:
367: return -EIO;
368: }
1.1 root 369: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.