Annotation of linux/fs/exec.c, revision 1.1

1.1     ! root        1: #include <errno.h>
        !             2: #include <sys/stat.h>
        !             3: #include <a.out.h>
        !             4: 
        !             5: #include <linux/fs.h>
        !             6: #include <linux/sched.h>
        !             7: #include <linux/kernel.h>
        !             8: #include <linux/mm.h>
        !             9: #include <asm/segment.h>
        !            10: 
        !            11: extern int sys_exit(int exit_code);
        !            12: extern int sys_close(int fd);
        !            13: 
        !            14: /*
        !            15:  * MAX_ARG_PAGES defines the number of pages allocated for arguments
        !            16:  * and envelope for the new program. 32 should suffice, this gives
        !            17:  * a maximum env+arg of 128kB !
        !            18:  */
        !            19: #define MAX_ARG_PAGES 32
        !            20: 
        !            21: #define cp_block(from,to) \
        !            22: __asm__("pushl $0x10\n\t" \
        !            23:        "pushl $0x17\n\t" \
        !            24:        "pop %%es\n\t" \
        !            25:        "cld\n\t" \
        !            26:        "rep\n\t" \
        !            27:        "movsl\n\t" \
        !            28:        "pop %%es" \
        !            29:        ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
        !            30:        :"cx","di","si")
        !            31: 
        !            32: /*
        !            33:  * read_head() reads blocks 1-6 (not 0). Block 0 has already been
        !            34:  * read for header information.
        !            35:  */
        !            36: int read_head(struct m_inode * inode,int blocks)
        !            37: {
        !            38:        struct buffer_head * bh;
        !            39:        int count;
        !            40: 
        !            41:        if (blocks>6)
        !            42:                blocks=6;
        !            43:        for(count = 0 ; count<blocks ; count++) {
        !            44:                if (!inode->i_zone[count+1])
        !            45:                        continue;
        !            46:                if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
        !            47:                        return -1;
        !            48:                cp_block(bh->b_data,count*BLOCK_SIZE);
        !            49:                brelse(bh);
        !            50:        }
        !            51:        return 0;
        !            52: }
        !            53: 
        !            54: int read_ind(int dev,int ind,long size,unsigned long offset)
        !            55: {
        !            56:        struct buffer_head * ih, * bh;
        !            57:        unsigned short * table,block;
        !            58: 
        !            59:        if (size<=0)
        !            60:                panic("size<=0 in read_ind");
        !            61:        if (size>512*BLOCK_SIZE)
        !            62:                size=512*BLOCK_SIZE;
        !            63:        if (!ind)
        !            64:                return 0;
        !            65:        if (!(ih=bread(dev,ind)))
        !            66:                return -1;
        !            67:        table = (unsigned short *) ih->b_data;
        !            68:        while (size>0) {
        !            69:                if (block=*(table++))
        !            70:                        if (!(bh=bread(dev,block))) {
        !            71:                                brelse(ih);
        !            72:                                return -1;
        !            73:                        } else {
        !            74:                                cp_block(bh->b_data,offset);
        !            75:                                brelse(bh);
        !            76:                        }
        !            77:                size -= BLOCK_SIZE;
        !            78:                offset += BLOCK_SIZE;
        !            79:        }
        !            80:        brelse(ih);
        !            81:        return 0;
        !            82: }
        !            83: 
        !            84: /*
        !            85:  * read_area() reads an area into %fs:mem.
        !            86:  */
        !            87: int read_area(struct m_inode * inode,long size)
        !            88: {
        !            89:        struct buffer_head * dind;
        !            90:        unsigned short * table;
        !            91:        int i,count;
        !            92: 
        !            93:        if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
        !            94:            (size -= BLOCK_SIZE*6)<=0)
        !            95:                return i;
        !            96:        if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
        !            97:            (size -= BLOCK_SIZE*512)<=0)
        !            98:                return i;
        !            99:        if (!(i=inode->i_zone[8]))
        !           100:                return 0;
        !           101:        if (!(dind = bread(inode->i_dev,i)))
        !           102:                return -1;
        !           103:        table = (unsigned short *) dind->b_data;
        !           104:        for(count=0 ; count<512 ; count++)
        !           105:                if ((i=read_ind(inode->i_dev,*(table++),size,
        !           106:                    BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
        !           107:                        return i;
        !           108:        panic("Impossibly long executable");
        !           109: }
        !           110: 
        !           111: /*
        !           112:  * create_tables() parses the env- and arg-strings in new user
        !           113:  * memory and creates the pointer tables from them, and puts their
        !           114:  * addresses on the "stack", returning the new stack pointer value.
        !           115:  */
        !           116: static unsigned long * create_tables(char * p,int argc,int envc)
        !           117: {
        !           118:        unsigned long *argv,*envp;
        !           119:        unsigned long * sp;
        !           120: 
        !           121:        sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
        !           122:        sp -= envc+1;
        !           123:        envp = sp;
        !           124:        sp -= argc+1;
        !           125:        argv = sp;
        !           126:        put_fs_long((unsigned long)envp,--sp);
        !           127:        put_fs_long((unsigned long)argv,--sp);
        !           128:        put_fs_long((unsigned long)argc,--sp);
        !           129:        while (argc-->0) {
        !           130:                put_fs_long((unsigned long) p,argv++);
        !           131:                while (get_fs_byte(p++)) /* nothing */ ;
        !           132:        }
        !           133:        put_fs_long(0,argv);
        !           134:        while (envc-->0) {
        !           135:                put_fs_long((unsigned long) p,envp++);
        !           136:                while (get_fs_byte(p++)) /* nothing */ ;
        !           137:        }
        !           138:        put_fs_long(0,envp);
        !           139:        return sp;
        !           140: }
        !           141: 
        !           142: /*
        !           143:  * count() counts the number of arguments/envelopes
        !           144:  */
        !           145: static int count(char ** argv)
        !           146: {
        !           147:        int i=0;
        !           148:        char ** tmp;
        !           149: 
        !           150:        if (tmp = argv)
        !           151:                while (get_fs_long((unsigned long *) (tmp++)))
        !           152:                        i++;
        !           153: 
        !           154:        return i;
        !           155: }
        !           156: 
        !           157: /*
        !           158:  * 'copy_string()' copies argument/envelope strings from user
        !           159:  * memory to free pages in kernel mem. These are in a format ready
        !           160:  * to be put directly into the top of new user memory.
        !           161:  */
        !           162: static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
        !           163:                unsigned long p)
        !           164: {
        !           165:        int len,i;
        !           166:        char *tmp;
        !           167: 
        !           168:        while (argc-- > 0) {
        !           169:                if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
        !           170:                        panic("argc is wrong");
        !           171:                len=0;          /* remember zero-padding */
        !           172:                do {
        !           173:                        len++;
        !           174:                } while (get_fs_byte(tmp++));
        !           175:                if (p-len < 0)          /* this shouldn't happen - 128kB */
        !           176:                        return 0;
        !           177:                i = ((unsigned) (p-len)) >> 12;
        !           178:                while (i<MAX_ARG_PAGES && !page[i]) {
        !           179:                        if (!(page[i]=get_free_page()))
        !           180:                                return 0;
        !           181:                        i++;
        !           182:                }
        !           183:                do {
        !           184:                        --p;
        !           185:                        if (!page[p/PAGE_SIZE])
        !           186:                                panic("nonexistent page in exec.c");
        !           187:                        ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
        !           188:                                get_fs_byte(--tmp);
        !           189:                } while (--len);
        !           190:        }
        !           191:        return p;
        !           192: }
        !           193: 
        !           194: static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
        !           195: {
        !           196:        unsigned long code_limit,data_limit,code_base,data_base;
        !           197:        int i;
        !           198: 
        !           199:        code_limit = text_size+PAGE_SIZE -1;
        !           200:        code_limit &= 0xFFFFF000;
        !           201:        data_limit = 0x4000000;
        !           202:        code_base = get_base(current->ldt[1]);
        !           203:        data_base = code_base;
        !           204:        set_base(current->ldt[1],code_base);
        !           205:        set_limit(current->ldt[1],code_limit);
        !           206:        set_base(current->ldt[2],data_base);
        !           207:        set_limit(current->ldt[2],data_limit);
        !           208: /* make sure fs points to the NEW data segment */
        !           209:        __asm__("pushl $0x17\n\tpop %%fs"::);
        !           210:        data_base += data_limit;
        !           211:        for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
        !           212:                data_base -= PAGE_SIZE;
        !           213:                if (page[i])
        !           214:                        put_page(page[i],data_base);
        !           215:        }
        !           216:        return data_limit;
        !           217: }
        !           218: 
        !           219: /*
        !           220:  * 'do_execve()' executes a new program.
        !           221:  */
        !           222: int do_execve(unsigned long * eip,long tmp,char * filename,
        !           223:        char ** argv, char ** envp)
        !           224: {
        !           225:        struct m_inode * inode;
        !           226:        struct buffer_head * bh;
        !           227:        struct exec ex;
        !           228:        unsigned long page[MAX_ARG_PAGES];
        !           229:        int i,argc,envc;
        !           230:        unsigned long p;
        !           231: 
        !           232:        if ((0xffff & eip[1]) != 0x000f)
        !           233:                panic("execve called from supervisor mode");
        !           234:        for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
        !           235:                page[i]=0;
        !           236:        if (!(inode=namei(filename)))           /* get executables inode */
        !           237:                return -ENOENT;
        !           238:        if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
        !           239:                iput(inode);
        !           240:                return -EACCES;
        !           241:        }
        !           242:        i = inode->i_mode;
        !           243:        if (current->uid && current->euid) {
        !           244:                if (current->euid == inode->i_uid)
        !           245:                        i >>= 6;
        !           246:                else if (current->egid == inode->i_gid)
        !           247:                        i >>= 3;
        !           248:        } else if (i & 0111)
        !           249:                i=1;
        !           250:        if (!(i & 1)) {
        !           251:                iput(inode);
        !           252:                return -ENOEXEC;
        !           253:        }
        !           254:        if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
        !           255:                iput(inode);
        !           256:                return -EACCES;
        !           257:        }
        !           258:        ex = *((struct exec *) bh->b_data);     /* read exec-header */
        !           259:        brelse(bh);
        !           260:        if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
        !           261:                ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
        !           262:                inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
        !           263:                iput(inode);
        !           264:                return -ENOEXEC;
        !           265:        }
        !           266:        if (N_TXTOFF(ex) != BLOCK_SIZE)
        !           267:                panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
        !           268:        argc = count(argv);
        !           269:        envc = count(envp);
        !           270:        p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
        !           271:        p = copy_strings(argc,argv,page,p);
        !           272:        if (!p) {
        !           273:                for (i=0 ; i<MAX_ARG_PAGES ; i++)
        !           274:                        free_page(page[i]);
        !           275:                iput(inode);
        !           276:                return -1;
        !           277:        }
        !           278: /* OK, This is the point of no return */
        !           279:        for (i=0 ; i<32 ; i++)
        !           280:                current->sig_fn[i] = NULL;
        !           281:        for (i=0 ; i<NR_OPEN ; i++)
        !           282:                if ((current->close_on_exec>>i)&1)
        !           283:                        sys_close(i);
        !           284:        current->close_on_exec = 0;
        !           285:        free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
        !           286:        free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
        !           287:        if (last_task_used_math == current)
        !           288:                last_task_used_math = NULL;
        !           289:        current->used_math = 0;
        !           290:        p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
        !           291:        p = (unsigned long) create_tables((char *)p,argc,envc);
        !           292:        current->brk = ex.a_bss +
        !           293:                (current->end_data = ex.a_data +
        !           294:                (current->end_code = ex.a_text));
        !           295:        current->start_stack = p & 0xfffff000;
        !           296:        i = read_area(inode,ex.a_text+ex.a_data);
        !           297:        iput(inode);
        !           298:        if (i<0)
        !           299:                sys_exit(-1);
        !           300:        i = ex.a_text+ex.a_data;
        !           301:        while (i&0xfff)
        !           302:                put_fs_byte(0,(char *) (i++));
        !           303:        eip[0] = ex.a_entry;            /* eip, magic happens :-) */
        !           304:        eip[3] = p;                     /* stack pointer */
        !           305:        return 0;
        !           306: }

unix.superglobalmegacorp.com

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