Annotation of linux/kernel/ptrace.c, revision 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.