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

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.4 ! root       32: void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned long);
1.1.1.2   root       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.4 ! root      103:                do_no_page(0,addr,tsk,0);
1.1.1.3   root      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)) {
1.1.1.4 ! root      132:                do_no_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:        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: 
1.1.1.4 ! root      222: int sys_ptrace(long request, long pid, long addr, long data)
1.1       root      223: {
1.1.1.2   root      224:        struct task_struct *child;
                    225:        int childno;
                    226: 
                    227:        if (request == 0) {
                    228:                /* set the ptrace bit in the proccess flags. */
                    229:                current->flags |= PF_PTRACED;
                    230:                return 0;
                    231:        }
                    232: 
                    233:        childno = get_task(pid);
1.1       root      234: 
1.1.1.2   root      235:        if (childno < 0)
                    236:                return -ESRCH;
                    237:        else
                    238:                child = task[childno];
                    239: 
                    240:        if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
                    241:            child->state != TASK_STOPPED)
                    242:                return -ESRCH;
                    243: 
                    244:        switch (request) {
1.1       root      245:        /* when I and D space are seperate, these will need to be fixed. */
1.1.1.2   root      246:                case 1: /* read word at location addr. */ 
                    247:                case 2: {
                    248:                        int tmp,res;
                    249: 
1.1.1.3   root      250:                        res = read_long(task[childno], addr, &tmp);
1.1.1.2   root      251:                        if (res < 0)
                    252:                                return res;
                    253:                        verify_area((void *) data, 4);
                    254:                        put_fs_long(tmp,(unsigned long *) data);
                    255:                        return 0;
                    256:                }
                    257: 
                    258:        /* read the word at location addr in the USER area. */
                    259:                case 3: {
                    260:                        int tmp;
                    261:                        addr = addr >> 2; /* temporary hack. */
                    262:                        if (addr < 0 || addr >= 17)
                    263:                                return -EIO;
                    264:                        verify_area((void *) data, 4);
                    265:                        tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
                    266:                        put_fs_long(tmp,(unsigned long *) data);
                    267:                        return 0;
                    268:                }
1.1       root      269: 
                    270:       /* when I and D space are seperate, this will have to be fixed. */
1.1.1.2   root      271:                case 4: /* write the word at location addr. */
                    272:                case 5:
1.1.1.3   root      273:                        return write_long(task[childno],addr,data);
1.1.1.2   root      274: 
                    275:                case 6: /* write the word at location addr in the USER area */
                    276:                        addr = addr >> 2; /* temproary hack. */
                    277:                        if (addr < 0 || addr >= 17)
1.1.1.3   root      278:                                return -EIO;
1.1.1.2   root      279:                        if (addr == ORIG_EAX)
                    280:                                return -EIO;
                    281:                        if (addr == EFL) {   /* flags. */
                    282:                                data &= FLAG_MASK;
                    283:                                data |= get_stack_long(child, EFL*4-MAGICNUMBER)  & ~FLAG_MASK;
                    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.