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