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

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

unix.superglobalmegacorp.com

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