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

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

unix.superglobalmegacorp.com

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