Annotation of linux/kernel/ptrace.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.