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

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: repeat:
                     92:        page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
                     93:        page = *(unsigned long *) page;
                     94:        if (page & PAGE_PRESENT) {
                     95:                page &= 0xfffff000;
                     96:                page += (addr >> 10) & 0xffc;
                     97:                page = *((unsigned long *) page);
1.1.1.2   root       98:        }
                     99:        if (!(page & PAGE_PRESENT)) {
1.1.1.4   root      100:                do_no_page(0,addr,tsk,0);
1.1.1.3   root      101:                goto repeat;
1.1.1.2   root      102:        }
1.1.1.3   root      103:        page &= 0xfffff000;
                    104:        page += addr & 0xfff;
                    105:        return *(unsigned long *) page;
1.1       root      106: }
                    107: 
1.1.1.2   root      108: /*
1.1.1.3   root      109:  * This routine puts a long into any process space by following the page
                    110:  * tables. NOTE! You should check that the long isn't on a page boundary,
                    111:  * and that it is in the task area before calling this: this routine does
                    112:  * no checking.
1.1.1.2   root      113:  */
1.1.1.3   root      114: static void put_long(struct task_struct * tsk, unsigned long addr,
                    115:        unsigned long data)
1.1       root      116: {
1.1.1.2   root      117:        unsigned long page;
                    118: 
1.1.1.3   root      119: repeat:
                    120:        page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
                    121:        page = *(unsigned long *) page;
                    122:        if (page & PAGE_PRESENT) {
                    123:                page &= 0xfffff000;
                    124:                page += (addr >> 10) & 0xffc;
                    125:                page = *((unsigned long *) page);
                    126:        }
                    127:        if (!(page & PAGE_PRESENT)) {
1.1.1.4   root      128:                do_no_page(0,addr,tsk,0);
1.1.1.3   root      129:                goto repeat;
1.1.1.2   root      130:        }
1.1.1.3   root      131:        if (!(page & PAGE_RW)) {
1.1.1.6   root      132:                do_wp_page(0,addr,tsk,0);
1.1.1.3   root      133:                goto repeat;
1.1.1.2   root      134:        }
1.1.1.3   root      135:        page &= 0xfffff000;
                    136:        page += addr & 0xfff;
                    137:        *(unsigned long *) page = data;
                    138: }
1.1       root      139: 
1.1.1.3   root      140: /*
                    141:  * This routine checks the page boundaries, and that the offset is
                    142:  * within the task area. It then calls get_long() to read a long.
                    143:  */
                    144: static int read_long(struct task_struct * tsk, unsigned long addr,
                    145:        unsigned long * result)
                    146: {
                    147:        unsigned long low,high;
1.1       root      148: 
1.1.1.3   root      149:        if (addr > TASK_SIZE-4)
1.1.1.2   root      150:                return -EIO;
1.1.1.3   root      151:        if ((addr & 0xfff) > PAGE_SIZE-4) {
                    152:                low = get_long(tsk,addr & 0xfffffffc);
                    153:                high = get_long(tsk,(addr+4) & 0xfffffffc);
                    154:                switch (addr & 3) {
                    155:                        case 1:
                    156:                                low >>= 8;
                    157:                                low |= high << 24;
                    158:                                break;
                    159:                        case 2:
                    160:                                low >>= 16;
                    161:                                low |= high << 16;
                    162:                                break;
                    163:                        case 3:
                    164:                                low >>= 24;
                    165:                                low |= high << 8;
                    166:                                break;
                    167:                }
                    168:                *result = low;
                    169:        } else
                    170:                *result = get_long(tsk,addr);
                    171:        return 0;
                    172: }
1.1       root      173: 
1.1.1.3   root      174: /*
                    175:  * This routine checks the page boundaries, and that the offset is
                    176:  * within the task area. It then calls put_long() to write a long.
                    177:  */
                    178: static int write_long(struct task_struct * tsk, unsigned long addr,
                    179:        unsigned long data)
                    180: {
                    181:        unsigned long low,high;
1.1       root      182: 
1.1.1.3   root      183:        if (addr > TASK_SIZE-4)
                    184:                return -EIO;
                    185:        if ((addr & 0xfff) > PAGE_SIZE-4) {
                    186:                low = get_long(tsk,addr & 0xfffffffc);
                    187:                high = get_long(tsk,(addr+4) & 0xfffffffc);
                    188:                switch (addr & 3) {
                    189:                        case 0: /* shouldn't happen, but safety first */
                    190:                                low = data;
                    191:                                break;
                    192:                        case 1:
                    193:                                low &= 0x000000ff;
                    194:                                low |= data << 8;
                    195:                                high &= 0xffffff00;
                    196:                                high |= data >> 24;
                    197:                                break;
                    198:                        case 2:
                    199:                                low &= 0x0000ffff;
                    200:                                low |= data << 16;
                    201:                                high &= 0xffff0000;
                    202:                                high |= data >> 16;
                    203:                                break;
                    204:                        case 3:
                    205:                                low &= 0x00ffffff;
                    206:                                low |= data << 24;
                    207:                                high &= 0xff000000;
                    208:                                high |= data >> 8;
                    209:                                break;
                    210:                }
                    211:                put_long(tsk,addr & 0xfffffffc,low);
                    212:                put_long(tsk,(addr+4) & 0xfffffffc,high);
                    213:        } else
                    214:                put_long(tsk,addr,data);
1.1.1.2   root      215:        return 0;
1.1       root      216: }
                    217: 
1.1.1.4   root      218: int sys_ptrace(long request, long pid, long addr, long data)
1.1       root      219: {
1.1.1.2   root      220:        struct task_struct *child;
                    221: 
1.1.1.5   root      222:        if (request == PTRACE_TRACEME) {
                    223:                /* are we already being traced? */
                    224:                if (current->flags & PF_PTRACED)
                    225:                        return -EPERM;
1.1.1.2   root      226:                /* set the ptrace bit in the proccess flags. */
                    227:                current->flags |= PF_PTRACED;
                    228:                return 0;
                    229:        }
1.1.1.5   root      230:        if (!(child = get_task(pid)))
1.1.1.2   root      231:                return -ESRCH;
1.1.1.5   root      232:        if (request == PTRACE_ATTACH) {
                    233:                long tmp;
1.1.1.2   root      234: 
1.1.1.6   root      235:                if (child == current)
                    236:                        return -EPERM;
                    237:                if ((!child->dumpable || (current->uid != child->euid) ||
1.1.1.5   root      238:                    (current->gid != child->egid)) && !suser())
                    239:                        return -EPERM;
                    240:                /* the same process cannot be attached many times */
                    241:                if (child->flags & PF_PTRACED)
                    242:                        return -EPERM;
                    243:                child->flags |= PF_PTRACED;
                    244:                if (child->p_pptr != current) {
                    245:                        REMOVE_LINKS(child);
                    246:                        child->p_pptr = current;
                    247:                        SET_LINKS(child);
                    248:                }
                    249:                tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
                    250:                put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    251:                if (child->state == TASK_INTERRUPTIBLE ||
                    252:                    child->state == TASK_STOPPED)
                    253:                        child->state = TASK_RUNNING;
                    254:                child->signal = 0;
                    255:                return 0;
                    256:        }
                    257:        if (!(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
                    258:                return -ESRCH;
                    259:        if (child->p_pptr != current)
1.1.1.2   root      260:                return -ESRCH;
                    261: 
                    262:        switch (request) {
1.1       root      263:        /* when I and D space are seperate, these will need to be fixed. */
1.1.1.5   root      264:                case PTRACE_PEEKTEXT: /* read word at location addr. */ 
                    265:                case PTRACE_PEEKDATA: {
1.1.1.2   root      266:                        int tmp,res;
                    267: 
1.1.1.5   root      268:                        res = read_long(child, addr, &tmp);
1.1.1.2   root      269:                        if (res < 0)
                    270:                                return res;
                    271:                        verify_area((void *) data, 4);
                    272:                        put_fs_long(tmp,(unsigned long *) data);
                    273:                        return 0;
                    274:                }
                    275: 
                    276:        /* read the word at location addr in the USER area. */
1.1.1.5   root      277:                case PTRACE_PEEKUSR: {
1.1.1.2   root      278:                        int tmp;
                    279:                        addr = addr >> 2; /* temporary hack. */
                    280:                        if (addr < 0 || addr >= 17)
                    281:                                return -EIO;
                    282:                        verify_area((void *) data, 4);
                    283:                        tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
                    284:                        put_fs_long(tmp,(unsigned long *) data);
                    285:                        return 0;
                    286:                }
1.1       root      287: 
                    288:       /* when I and D space are seperate, this will have to be fixed. */
1.1.1.5   root      289:                case PTRACE_POKETEXT: /* write the word at location addr. */
                    290:                case PTRACE_POKEDATA:
                    291:                        return write_long(child,addr,data);
1.1.1.2   root      292: 
1.1.1.5   root      293:                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
1.1.1.2   root      294:                        addr = addr >> 2; /* temproary hack. */
                    295:                        if (addr < 0 || addr >= 17)
1.1.1.3   root      296:                                return -EIO;
1.1.1.2   root      297:                        if (addr == ORIG_EAX)
                    298:                                return -EIO;
                    299:                        if (addr == EFL) {   /* flags. */
                    300:                                data &= FLAG_MASK;
                    301:                                data |= get_stack_long(child, EFL*4-MAGICNUMBER)  & ~FLAG_MASK;
                    302:                        }
                    303:                        if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
                    304:                                return -EIO;
                    305:                        return 0;
                    306: 
1.1.1.5   root      307:                case PTRACE_CONT: { /* restart after signal. */
1.1.1.2   root      308:                        long tmp;
                    309: 
1.1.1.5   root      310:                        child->signal = 0;
1.1.1.2   root      311:                        if (data > 0 && data <= NSIG)
                    312:                                child->signal = 1<<(data-1);
1.1.1.5   root      313:                        child->state = TASK_RUNNING;
1.1       root      314:        /* make sure the single step bit is not set. */
1.1.1.2   root      315:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
                    316:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    317:                        return 0;
                    318:                }
                    319: 
                    320: /*
                    321:  * make the child exit.  Best I can do is send it a sigkill. 
                    322:  * perhaps it should be put in the status that it want's to 
                    323:  * exit.
                    324:  */
1.1.1.5   root      325:                case PTRACE_KILL: {
1.1.1.2   root      326:                        long tmp;
                    327: 
1.1.1.5   root      328:                        child->state = TASK_RUNNING;
1.1.1.2   root      329:                        child->signal = 1 << (SIGKILL-1);
1.1       root      330:        /* make sure the single step bit is not set. */
1.1.1.2   root      331:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
                    332:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    333:                        return 0;
                    334:                }
                    335: 
1.1.1.5   root      336:                case PTRACE_SINGLESTEP: {  /* set the trap flag. */
1.1.1.2   root      337:                        long tmp;
                    338: 
                    339:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
                    340:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
1.1.1.5   root      341:                        child->state = TASK_RUNNING;
1.1.1.2   root      342:                        child->signal = 0;
1.1.1.5   root      343:                        if (data > 0 && data <= NSIG)
1.1.1.2   root      344:                                child->signal= 1<<(data-1);
1.1       root      345:        /* give it a chance to run. */
1.1.1.2   root      346:                        return 0;
                    347:                }
1.1       root      348: 
1.1.1.5   root      349:                case PTRACE_DETACH: { /* detach a process that was attached. */
                    350:                        long tmp;
                    351: 
                    352:                        child->flags &= ~PF_PTRACED;
                    353:                        child->signal=0;
                    354:                        child->state = 0;
                    355:                        REMOVE_LINKS(child);
                    356:                        child->p_pptr = child->p_opptr;
                    357:                        SET_LINKS(child);
                    358:                        /* make sure the single step bit is not set. */
                    359:                        tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
                    360:                        put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
                    361:                        return 0;
                    362:                }
                    363: 
1.1.1.2   root      364:                default:
                    365:                        return -EIO;
                    366:        }
1.1       root      367: }

unix.superglobalmegacorp.com