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

1.1       root        1: /* ptrace.c */
                      2: /* By Ross Biro 1/23/92 */
1.1.1.3 ! root        3: /* edited by Linus Torvalds */
1.1       root        4: 
                      5: #include <linux/head.h>
                      6: #include <linux/kernel.h>
                      7: #include <linux/sched.h>
                      8: #include <linux/mm.h>
                      9: #include <errno.h>
                     10: #include <asm/segment.h>
                     11: #include <asm/system.h>
                     12: #include <sys/ptrace.h>
1.1.1.2   root       13: 
                     14: /*
                     15:  * does not yet catch signals sent when the child dies.
                     16:  * in exit.c or in signal.c.
                     17:  */
1.1       root       18: 
                     19: /* determines which flags the user has access to. */
                     20: /* 1 = access 0 = no access */
                     21: #define FLAG_MASK 0x00000dd9
                     22: 
                     23: /* set's the trap flag. */
                     24: #define TRAP_FLAG 0x100
                     25: 
1.1.1.2   root       26: /*
                     27:  * this is the number to subtract from the top of the stack. To find
                     28:  * the local frame.
                     29:  */
1.1       root       30: #define MAGICNUMBER 68
                     31: 
1.1.1.2   root       32: void do_no_page(unsigned long, unsigned long, struct task_struct *);
                     33: void write_verify(unsigned long);
1.1       root       34: 
                     35: /* change a pid into a task struct. */
                     36: static inline int get_task(int pid)
                     37: {
1.1.1.2   root       38:        int i;
                     39: 
                     40:        for (i = 0; i < NR_TASKS; i++) {
                     41:                if (task[i] != NULL && (task[i]->pid == pid))
                     42:                        return i;
                     43:        }
                     44:        return -1;
1.1       root       45: }
                     46: 
1.1.1.2   root       47: /*
                     48:  * this routine will get a word off of the processes priviledged stack. 
                     49:  * the offset is how far from the base addr as stored in the TSS.  
                     50:  * this routine assumes that all the priviledged stacks are in our
                     51:  * data space.
1.1.1.3 ! root       52:  */   
1.1.1.2   root       53: static inline int get_stack_long(struct task_struct *task, int offset)
1.1       root       54: {
1.1.1.2   root       55:        unsigned char *stack;
1.1       root       56: 
1.1.1.2   root       57:        stack = (unsigned char *)task->tss.esp0;
                     58:        stack += offset;
                     59:        return (*((int *)stack));
1.1       root       60: }
                     61: 
1.1.1.2   root       62: /*
                     63:  * this routine will put a word on the processes priviledged stack. 
                     64:  * the offset is how far from the base addr as stored in the TSS.  
                     65:  * this routine assumes that all the priviledged stacks are in our
                     66:  * data space.
                     67:  */
                     68: static inline int put_stack_long(struct task_struct *task, int offset,
1.1.1.3 ! root       69:        unsigned long data)
1.1       root       70: {
1.1.1.2   root       71:        unsigned char * stack;
1.1       root       72: 
1.1.1.2   root       73:        stack = (unsigned char *) task->tss.esp0;
                     74:        stack += offset;
1.1.1.3 ! root       75:        *(unsigned long *) stack = data;
1.1.1.2   root       76:        return 0;
1.1       root       77: }
                     78: 
1.1.1.2   root       79: /*
1.1.1.3 ! root       80:  * This routine gets a long from any process space by following the page
        !            81:  * tables. NOTE! You should check that the long isn't on a page boundary,
        !            82:  * and that it is in the task area before calling this: this routine does
        !            83:  * no checking.
        !            84:  *
        !            85:  * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
        !            86:  * zero. This routine shouldn't have to change when we make a better mm.
1.1.1.2   root       87:  */
1.1.1.3 ! root       88: static unsigned long get_long(struct task_struct * tsk,
        !            89:        unsigned long addr)
1.1       root       90: {
1.1.1.2   root       91:        unsigned long page;
                     92: 
1.1.1.3 ! root       93:        addr += tsk->start_code;
        !            94: repeat:
        !            95:        page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
        !            96:        page = *(unsigned long *) page;
        !            97:        if (page & PAGE_PRESENT) {
        !            98:                page &= 0xfffff000;
        !            99:                page += (addr >> 10) & 0xffc;
        !           100:                page = *((unsigned long *) page);
1.1.1.2   root      101:        }
                    102:        if (!(page & PAGE_PRESENT)) {
1.1.1.3 ! root      103:                do_no_page(0,addr,tsk);
        !           104:                goto repeat;
1.1.1.2   root      105:        }
1.1.1.3 ! root      106:        page &= 0xfffff000;
        !           107:        page += addr & 0xfff;
        !           108:        return *(unsigned long *) page;
1.1       root      109: }
                    110: 
1.1.1.2   root      111: /*
1.1.1.3 ! root      112:  * This routine puts a long into any process space by following the page
        !           113:  * tables. NOTE! You should check that the long isn't on a page boundary,
        !           114:  * and that it is in the task area before calling this: this routine does
        !           115:  * no checking.
1.1.1.2   root      116:  */
1.1.1.3 ! root      117: static void put_long(struct task_struct * tsk, unsigned long addr,
        !           118:        unsigned long data)
1.1       root      119: {
1.1.1.2   root      120:        unsigned long page;
                    121: 
1.1.1.3 ! root      122:        addr += tsk->start_code;
        !           123: repeat:
        !           124:        page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
        !           125:        page = *(unsigned long *) page;
        !           126:        if (page & PAGE_PRESENT) {
        !           127:                page &= 0xfffff000;
        !           128:                page += (addr >> 10) & 0xffc;
        !           129:                page = *((unsigned long *) page);
        !           130:        }
        !           131:        if (!(page & PAGE_PRESENT)) {
        !           132:                do_no_page(0,addr,tsk);
        !           133:                goto repeat;
1.1.1.2   root      134:        }
1.1.1.3 ! root      135:        if (!(page & PAGE_RW)) {
        !           136:                write_verify(addr);
        !           137:                goto repeat;
1.1.1.2   root      138:        }
1.1.1.3 ! root      139:        page &= 0xfffff000;
        !           140:        page += addr & 0xfff;
        !           141:        *(unsigned long *) page = data;
        !           142: }
1.1       root      143: 
1.1.1.3 ! root      144: /*
        !           145:  * This routine checks the page boundaries, and that the offset is
        !           146:  * within the task area. It then calls get_long() to read a long.
        !           147:  */
        !           148: static int read_long(struct task_struct * tsk, unsigned long addr,
        !           149:        unsigned long * result)
        !           150: {
        !           151:        unsigned long low,high;
1.1       root      152: 
1.1.1.3 ! root      153:        if (addr > TASK_SIZE-4)
1.1.1.2   root      154:                return -EIO;
1.1.1.3 ! root      155:        if ((addr & 0xfff) > PAGE_SIZE-4) {
        !           156:                low = get_long(tsk,addr & 0xfffffffc);
        !           157:                high = get_long(tsk,(addr+4) & 0xfffffffc);
        !           158:                switch (addr & 3) {
        !           159:                        case 1:
        !           160:                                low >>= 8;
        !           161:                                low |= high << 24;
        !           162:                                break;
        !           163:                        case 2:
        !           164:                                low >>= 16;
        !           165:                                low |= high << 16;
        !           166:                                break;
        !           167:                        case 3:
        !           168:                                low >>= 24;
        !           169:                                low |= high << 8;
        !           170:                                break;
        !           171:                }
        !           172:                *result = low;
        !           173:        } else
        !           174:                *result = get_long(tsk,addr);
        !           175:        return 0;
        !           176: }
1.1       root      177: 
1.1.1.3 ! root      178: /*
        !           179:  * This routine checks the page boundaries, and that the offset is
        !           180:  * within the task area. It then calls put_long() to write a long.
        !           181:  */
        !           182: static int write_long(struct task_struct * tsk, unsigned long addr,
        !           183:        unsigned long data)
        !           184: {
        !           185:        unsigned long low,high;
1.1       root      186: 
1.1.1.3 ! root      187:        if (addr > TASK_SIZE-4)
        !           188:                return -EIO;
        !           189:        if ((addr & 0xfff) > PAGE_SIZE-4) {
        !           190:                low = get_long(tsk,addr & 0xfffffffc);
        !           191:                high = get_long(tsk,(addr+4) & 0xfffffffc);
        !           192:                switch (addr & 3) {
        !           193:                        case 0: /* shouldn't happen, but safety first */
        !           194:                                low = data;
        !           195:                                break;
        !           196:                        case 1:
        !           197:                                low &= 0x000000ff;
        !           198:                                low |= data << 8;
        !           199:                                high &= 0xffffff00;
        !           200:                                high |= data >> 24;
        !           201:                                break;
        !           202:                        case 2:
        !           203:                                low &= 0x0000ffff;
        !           204:                                low |= data << 16;
        !           205:                                high &= 0xffff0000;
        !           206:                                high |= data >> 16;
        !           207:                                break;
        !           208:                        case 3:
        !           209:                                low &= 0x00ffffff;
        !           210:                                low |= data << 24;
        !           211:                                high &= 0xff000000;
        !           212:                                high |= data >> 8;
        !           213:                                break;
        !           214:                }
        !           215:                put_long(tsk,addr & 0xfffffffc,low);
        !           216:                put_long(tsk,(addr+4) & 0xfffffffc,high);
        !           217:        } else
        !           218:                put_long(tsk,addr,data);
1.1.1.2   root      219:        return 0;
1.1       root      220: }
                    221: 
                    222: /* Perform ptrace(request, pid, addr, data) syscall */
1.1.1.2   root      223: int sys_ptrace(unsigned long *buffer)
1.1       root      224: {
1.1.1.2   root      225:        long request, pid, data;
                    226:        long addr;
                    227:        struct task_struct *child;
                    228:        int childno;
                    229: 
                    230:        request = get_fs_long(buffer++);
                    231:        pid = get_fs_long(buffer++);
                    232:        addr = get_fs_long(buffer++); /* assume long = void * */
                    233:        data = get_fs_long(buffer++);
                    234: 
                    235:        if (request == 0) {
                    236:                /* set the ptrace bit in the proccess flags. */
                    237:                current->flags |= PF_PTRACED;
                    238:                return 0;
                    239:        }
                    240: 
                    241:        childno = get_task(pid);
1.1       root      242: 
1.1.1.2   root      243:        if (childno < 0)
                    244:                return -ESRCH;
                    245:        else
                    246:                child = task[childno];
                    247: 
                    248:        if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
                    249:            child->state != TASK_STOPPED)
                    250:                return -ESRCH;
                    251: 
                    252:        switch (request) {
1.1       root      253:        /* when I and D space are seperate, these will need to be fixed. */
1.1.1.2   root      254:                case 1: /* read word at location addr. */ 
                    255:                case 2: {
                    256:                        int tmp,res;
                    257: 
1.1.1.3 ! root      258:                        res = read_long(task[childno], addr, &tmp);
1.1.1.2   root      259:                        if (res < 0)
                    260:                                return res;
                    261:                        verify_area((void *) data, 4);
                    262:                        put_fs_long(tmp,(unsigned long *) data);
                    263:                        return 0;
                    264:                }
                    265: 
                    266:        /* read the word at location addr in the USER area. */
                    267:                case 3: {
                    268:                        int tmp;
                    269:                        addr = addr >> 2; /* temporary hack. */
                    270:                        if (addr < 0 || addr >= 17)
                    271:                                return -EIO;
                    272:                        verify_area((void *) data, 4);
                    273:                        tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
                    274:                        put_fs_long(tmp,(unsigned long *) data);
                    275:                        return 0;
                    276:                }
1.1       root      277: 
                    278:       /* when I and D space are seperate, this will have to be fixed. */
1.1.1.2   root      279:                case 4: /* write the word at location addr. */
                    280:                case 5:
1.1.1.3 ! root      281:                        return write_long(task[childno],addr,data);
1.1.1.2   root      282: 
                    283:                case 6: /* write the word at location addr in the USER area */
                    284:                        addr = addr >> 2; /* temproary hack. */
                    285:                        if (addr < 0 || addr >= 17)
1.1.1.3 ! root      286:                                return -EIO;
1.1.1.2   root      287:                        if (addr == ORIG_EAX)
                    288:                                return -EIO;
                    289:                        if (addr == EFL) {   /* flags. */
                    290:                                data &= FLAG_MASK;
                    291:                                data |= get_stack_long(child, EFL*4-MAGICNUMBER)  & ~FLAG_MASK;
                    292:                        }
                    293:                        if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
                    294:                                return -EIO;
                    295:                        return 0;
                    296: 
                    297:                case 7: { /* restart after signal. */
                    298:                        long tmp;
                    299: 
                    300:                        child->signal=0;
                    301:                        if (data > 0 && data <= NSIG)
                    302:                                child->signal = 1<<(data-1);
                    303:                        child->state = 0;
1.1       root      304:        /* make sure the single step bit is not set. */
1.1.1.2   root      305:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
                    306:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    307:                        return 0;
                    308:                }
                    309: 
                    310: /*
                    311:  * make the child exit.  Best I can do is send it a sigkill. 
                    312:  * perhaps it should be put in the status that it want's to 
                    313:  * exit.
                    314:  */
                    315:                case 8: {
                    316:                        long tmp;
                    317: 
                    318:                        child->state = 0;
                    319:                        child->signal = 1 << (SIGKILL-1);
1.1       root      320:        /* make sure the single step bit is not set. */
1.1.1.2   root      321:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
                    322:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    323:                        return 0;
                    324:                }
                    325: 
                    326:                case 9: {  /* set the trap flag. */
                    327:                        long tmp;
                    328: 
                    329:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
                    330:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    331:                        child->state = 0;
                    332:                        child->signal = 0;
                    333:                        if (data > 0 && data <NSIG)
                    334:                                child->signal= 1<<(data-1);
1.1       root      335:        /* give it a chance to run. */
1.1.1.2   root      336:                        return 0;
                    337:                }
1.1       root      338: 
1.1.1.2   root      339:                default:
                    340:                        return -EIO;
                    341:        }
1.1       root      342: }

unix.superglobalmegacorp.com

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