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

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

unix.superglobalmegacorp.com

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