|
|
1.1 root 1: /* ptrace.c */
2: /* By Ross Biro 1/23/92 */
3:
4: #include <linux/head.h>
5: #include <linux/kernel.h>
6: #include <linux/sched.h>
7: #include <linux/mm.h>
8: #include <errno.h>
9: #include <asm/segment.h>
10: #include <asm/system.h>
11: #include <sys/ptrace.h>
1.1.1.2 ! root 12:
! 13: /*
! 14: * does not yet catch signals sent when the child dies.
! 15: * in exit.c or in signal.c.
! 16: */
1.1 root 17:
18: /* determines which flags the user has access to. */
19: /* 1 = access 0 = no access */
20: #define FLAG_MASK 0x00000dd9
21:
22: /* set's the trap flag. */
23: #define TRAP_FLAG 0x100
24:
25: /* check's for granularity. */
26: #define GRANULARITY 0x00800000
27:
1.1.1.2 ! root 28: /*
! 29: * this is the number to subtract from the top of the stack. To find
! 30: * the local frame.
! 31: */
1.1 root 32: #define MAGICNUMBER 68
33:
1.1.1.2 ! root 34: void do_no_page(unsigned long, unsigned long, struct task_struct *);
! 35: void write_verify(unsigned long);
1.1 root 36:
37: /* change a pid into a task struct. */
38: static inline int get_task(int pid)
39: {
1.1.1.2 ! root 40: int i;
! 41:
! 42: for (i = 0; i < NR_TASKS; i++) {
! 43: if (task[i] != NULL && (task[i]->pid == pid))
! 44: return i;
! 45: }
! 46: return -1;
1.1 root 47: }
48:
1.1.1.2 ! root 49: /*
! 50: * this routine will get a word off of the processes priviledged stack.
! 51: * the offset is how far from the base addr as stored in the TSS.
! 52: * this routine assumes that all the priviledged stacks are in our
! 53: * data space.
! 54: */
1.1 root 55:
1.1.1.2 ! root 56: static inline int get_stack_long(struct task_struct *task, int offset)
1.1 root 57: {
1.1.1.2 ! root 58: unsigned char *stack;
1.1 root 59:
1.1.1.2 ! root 60: stack = (unsigned char *)task->tss.esp0;
! 61: stack += offset;
! 62: return (*((int *)stack));
1.1 root 63: }
64:
1.1.1.2 ! root 65: /*
! 66: * this routine will put a word on the processes priviledged stack.
! 67: * the offset is how far from the base addr as stored in the TSS.
! 68: * this routine assumes that all the priviledged stacks are in our
! 69: * data space.
! 70: */
! 71: static inline int put_stack_long(struct task_struct *task, int offset,
! 72: unsigned short data)
1.1 root 73: {
1.1.1.2 ! root 74: unsigned char * stack;
1.1 root 75:
1.1.1.2 ! root 76: stack = (unsigned char *) task->tss.esp0;
! 77: stack += offset;
! 78: *(int *) stack = data;
! 79: return 0;
1.1 root 80: }
81:
1.1.1.2 ! root 82: /*
! 83: * this routine will get a word out of an arbitrary
! 84: * tasks data space. It likes to have the task number
! 85: * rather than the task pointer. Perhaps the number
! 86: * should be included in the pointer.
! 87: */
1.1 root 88: /* seg = 0 if I space */
1.1.1.2 ! root 89: static inline int get_long(int tsk, long addr, unsigned seg, int *data)
1.1 root 90: {
1.1.1.2 ! root 91: int i;
! 92: int limit;
! 93: int cur;
! 94: unsigned long address;
! 95: unsigned long page;
! 96: unsigned oldfs;
! 97:
1.1 root 98: /* find the task number of the current task. */
1.1.1.2 ! root 99: for (i = 0; i < NR_TASKS ; i ++) {
! 100: if (task[i] == current) break;
! 101: }
! 102: if (i == NR_TASKS) {
! 103: printk("PTRACE: Can't find current task\n");
! 104: do_exit(SIGSEGV);
! 105: }
! 106: cur = i;
1.1 root 107:
1.1.1.2 ! root 108: /* we will need to check the readability of the segment
1.1 root 109: and then the byte in order to avoid segment violations. */
1.1.1.2 ! root 110: seg++;
! 111: limit = (task[tsk]->ldt[seg].a) & 0xffff;
1.1 root 112: /* this should be constant amound all of our segments, but we
113: had better check anyway. */
1.1.1.2 ! root 114: if (task[tsk]->ldt[seg].b & GRANULARITY)
! 115: limit = limit << 12;
1.1 root 116:
1.1.1.2 ! root 117: if (limit <= addr+4)
! 118: return -EIO;
1.1 root 119:
120: /* Now compute the address, and make sure that it is present. */
1.1.1.2 ! root 121: address = task[tsk]->start_code + addr;
1.1 root 122:
1.1.1.2 ! root 123: page = *((unsigned long*) ((address >> 20) & 0xffc));
1.1 root 124: /* see if it is present. */
1.1.1.2 ! root 125: if (!(page & PAGE_PRESENT)) {
! 126: do_no_page(0, address, task[tsk]);
! 127: }
1.1 root 128:
1.1.1.2 ! root 129: oldfs = get_fs();
1.1 root 130: /* now convert seg to the right format. */
1.1.1.2 ! root 131: seg = (seg << 3) | 0x4;
1.1 root 132:
1.1.1.2 ! root 133: cli(); /* we are about to change our ldt, we better do it
1.1 root 134: with interrupts off. Perhaps we should call schedule
135: first so that we won't be taking too much extra time. */
1.1.1.2 ! root 136: lldt(tsk);
! 137: set_fs(seg);
! 138: *data = get_fs_long((void *)addr); /* we are assuming kernel space
! 139: is in the gdt here. */
! 140: lldt(cur);
! 141: set_fs(oldfs);
! 142: sti();
! 143: return 0;
1.1 root 144: }
145:
1.1.1.2 ! root 146: /*
! 147: * this routine will get a word out of an arbitrary
! 148: * tasks data space. It likes to have the task number
! 149: * rather than the task pointer. Perhaps the number
! 150: * should be included in the pointer.
! 151: */
1.1 root 152: /* seg = 0 if I space */
1.1.1.2 ! root 153: static inline int put_long(int tsk, long addr, int data, unsigned seg)
1.1 root 154: {
1.1.1.2 ! root 155: int i;
! 156: int limit;
! 157: unsigned oldfs;
! 158: unsigned long address;
! 159: unsigned long page;
! 160: int cur;
! 161:
1.1 root 162: /* find the task number of the current task. */
1.1.1.2 ! root 163: for (i = 0; i < NR_TASKS ; i++) {
! 164: if (task[i] == current) break;
! 165: }
! 166: if (i == NR_TASKS) {
! 167: printk("PTRACE: Can't find current task\n");
! 168: do_exit(SIGSEGV);
! 169: }
! 170: cur = i;
1.1 root 171:
172: /* we will need to check the readability of the segment
173: and then the byte in order to avoid segment violations. */
1.1.1.2 ! root 174: seg++;
! 175: limit = (task[tsk]->ldt[seg].a) & 0xffff;
1.1 root 176: /* this should be constant amound all of our segments, but we
177: had better check anyway. */
1.1.1.2 ! root 178: if (task[tsk]->ldt[seg].b & GRANULARITY)
! 179: limit = limit << 12;
1.1 root 180:
1.1.1.2 ! root 181: if (limit <= addr+4)
! 182: return -EIO;
1.1 root 183:
184: /* Now compute the address, and make sure that it is present. */
1.1.1.2 ! root 185: address = task[tsk]->start_code + addr;
1.1 root 186:
1.1.1.2 ! root 187: page = *((unsigned long*) ((address >> 20) & 0xffc));
1.1 root 188: /* see if it is present. */
1.1.1.2 ! root 189: if (!(page & PAGE_PRESENT)) {
! 190: do_no_page(0, address, task[tsk]);
! 191: }
! 192: write_verify(address);
1.1 root 193:
1.1.1.2 ! root 194: oldfs=get_fs();
1.1 root 195: /* now convert seg to the right format. */
1.1.1.2 ! root 196: seg = (seg << 3) | 0x4;
1.1 root 197:
1.1.1.2 ! root 198: cli(); /* we are about to change our ldt, we better do it
1.1 root 199: with interrupts off. Perhaps we should call schedule
200: first so that we won't be taking too much extra time. */
1.1.1.2 ! root 201: lldt(tsk);
! 202: set_fs(seg);
! 203: put_fs_long(data,(void *)addr);
! 204: lldt(cur);
! 205: set_fs(oldfs);
! 206: sti();
! 207: return 0;
1.1 root 208: }
209:
210:
211: /* Perform ptrace(request, pid, addr, data) syscall */
1.1.1.2 ! root 212: int sys_ptrace(unsigned long *buffer)
1.1 root 213: {
1.1.1.2 ! root 214: long request, pid, data;
! 215: long addr;
! 216: struct task_struct *child;
! 217: int childno;
! 218:
! 219: request = get_fs_long(buffer++);
! 220: pid = get_fs_long(buffer++);
! 221: addr = get_fs_long(buffer++); /* assume long = void * */
! 222: data = get_fs_long(buffer++);
! 223:
! 224: if (request == 0) {
! 225: /* set the ptrace bit in the proccess flags. */
! 226: current->flags |= PF_PTRACED;
! 227: return 0;
! 228: }
! 229:
! 230: childno = get_task(pid);
1.1 root 231:
1.1.1.2 ! root 232: if (childno < 0)
! 233: return -ESRCH;
! 234: else
! 235: child = task[childno];
! 236:
! 237: if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
! 238: child->state != TASK_STOPPED)
! 239: return -ESRCH;
! 240:
! 241: switch (request) {
1.1 root 242: /* when I and D space are seperate, these will need to be fixed. */
1.1.1.2 ! root 243: case 1: /* read word at location addr. */
! 244: case 2: {
! 245: int tmp,res;
! 246:
! 247: res = get_long(childno, addr, 1, &tmp);
! 248: if (res < 0)
! 249: return res;
! 250: verify_area((void *) data, 4);
! 251: put_fs_long(tmp,(unsigned long *) data);
! 252: return 0;
! 253: }
! 254:
! 255: /* read the word at location addr in the USER area. */
! 256: case 3: {
! 257: int tmp;
! 258: addr = addr >> 2; /* temporary hack. */
! 259: if (addr < 0 || addr >= 17)
! 260: return -EIO;
! 261: verify_area((void *) data, 4);
! 262: tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
! 263: put_fs_long(tmp,(unsigned long *) data);
! 264: return 0;
! 265: }
1.1 root 266:
267: /* when I and D space are seperate, this will have to be fixed. */
1.1.1.2 ! root 268: case 4: /* write the word at location addr. */
! 269: case 5:
! 270: if (put_long(childno, addr, data, 1))
! 271: return -EIO;
! 272: return 0;
! 273:
! 274: case 6: /* write the word at location addr in the USER area */
! 275: addr = addr >> 2; /* temproary hack. */
! 276: if (addr < 0 || addr >= 17)
! 277: return -EIO;
! 278: if (addr == ORIG_EAX)
! 279: return -EIO;
! 280: if (addr == EFL) { /* flags. */
! 281: data &= FLAG_MASK;
! 282: data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
! 283: }
! 284:
! 285: if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
! 286: return -EIO;
! 287: return 0;
! 288:
! 289: case 7: { /* restart after signal. */
! 290: long tmp;
! 291:
! 292: child->signal=0;
! 293: if (data > 0 && data <= NSIG)
! 294: child->signal = 1<<(data-1);
! 295: child->state = 0;
1.1 root 296: /* make sure the single step bit is not set. */
1.1.1.2 ! root 297: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
! 298: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
! 299: return 0;
! 300: }
! 301:
! 302: /*
! 303: * make the child exit. Best I can do is send it a sigkill.
! 304: * perhaps it should be put in the status that it want's to
! 305: * exit.
! 306: */
! 307: case 8: {
! 308: long tmp;
! 309:
! 310: child->state = 0;
! 311: child->signal = 1 << (SIGKILL-1);
1.1 root 312: /* make sure the single step bit is not set. */
1.1.1.2 ! root 313: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
! 314: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
! 315: return 0;
! 316: }
! 317:
! 318: case 9: { /* set the trap flag. */
! 319: long tmp;
! 320:
! 321: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
! 322: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
! 323: child->state = 0;
! 324: child->signal = 0;
! 325: if (data > 0 && data <NSIG)
! 326: child->signal= 1<<(data-1);
1.1 root 327: /* give it a chance to run. */
1.1.1.2 ! root 328: return 0;
! 329: }
1.1 root 330:
1.1.1.2 ! root 331: default:
! 332: return -EIO;
! 333: }
1.1 root 334: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.