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

1.1.1.4 ! root        1: 
        !             2: /*
        !             3:  *  linux/fs/exec.c
        !             4:  *
        !             5:  *  (C) 1991  Linus Torvalds
        !             6:  *  (C) 2007  Abdel Benamrouche : use elf binary instead of a.out
        !             7:  * 
        !             8:  */
        !             9: 
        !            10: 
1.1       root       11: #include <errno.h>
                     12: #include <sys/stat.h>
1.1.1.4 ! root       13: #include <elf.h>
1.1       root       14: 
                     15: #include <linux/fs.h>
                     16: #include <linux/sched.h>
                     17: #include <linux/kernel.h>
                     18: #include <linux/mm.h>
                     19: #include <asm/segment.h>
                     20: 
                     21: extern int sys_exit(int exit_code);
                     22: extern int sys_close(int fd);
                     23: 
                     24: /*
                     25:  * MAX_ARG_PAGES defines the number of pages allocated for arguments
                     26:  * and envelope for the new program. 32 should suffice, this gives
                     27:  * a maximum env+arg of 128kB !
                     28:  */
                     29: #define MAX_ARG_PAGES 32
                     30: 
1.1.1.4 ! root       31: inline void cp_block(const void * from,void * to, int size)
1.1.1.3   root       32: {
                     33: int d0,d1,d2;
                     34: __asm__ __volatile("pushl $0x10\n\t"
                     35:        "pushl $0x17\n\t"
                     36:        "pop %%es\n\t"
                     37:        "cld\n\t"
                     38:        "rep\n\t"
                     39:        "movsl\n\t"
                     40:        "pop %%es"
                     41:        :"=&c" (d0), "=&S" (d1), "=&D" (d2)
1.1.1.4 ! root       42:        :"0" (size/4),"1" (from),"2" (to)
1.1.1.3   root       43:        :"memory");
                     44: }
1.1       root       45: 
1.1.1.4 ! root       46: typedef struct
1.1       root       47: {
1.1.1.4 ! root       48:        unsigned long b_entry;
        !            49:        unsigned long b_size;                           //file size
        !            50: }bin_section;
1.1       root       51: 
                     52: 
1.1.1.4 ! root       53: #include <string.h>
1.1       root       54: 
                     55: /*
                     56:  * create_tables() parses the env- and arg-strings in new user
                     57:  * memory and creates the pointer tables from them, and puts their
                     58:  * addresses on the "stack", returning the new stack pointer value.
                     59:  */
                     60: static unsigned long * create_tables(char * p,int argc,int envc)
                     61: {
                     62:        unsigned long *argv,*envp;
                     63:        unsigned long * sp;
                     64: 
                     65:        sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
                     66:        sp -= envc+1;
                     67:        envp = sp;
                     68:        sp -= argc+1;
                     69:        argv = sp;
1.1.1.4 ! root       70:        //put_fs_long((unsigned long)envp,--sp);
        !            71:        //put_fs_long((unsigned long)argv,--sp);
1.1       root       72:        put_fs_long((unsigned long)argc,--sp);
                     73:        while (argc-->0) {
                     74:                put_fs_long((unsigned long) p,argv++);
                     75:                while (get_fs_byte(p++)) /* nothing */ ;
                     76:        }
                     77:        put_fs_long(0,argv);
                     78:        while (envc-->0) {
                     79:                put_fs_long((unsigned long) p,envp++);
                     80:                while (get_fs_byte(p++)) /* nothing */ ;
                     81:        }
                     82:        put_fs_long(0,envp);
                     83:        return sp;
                     84: }
                     85: 
                     86: /*
                     87:  * count() counts the number of arguments/envelopes
                     88:  */
                     89: static int count(char ** argv)
                     90: {
                     91:        int i=0;
                     92:        char ** tmp;
                     93: 
1.1.1.3   root       94:        if ((tmp = argv))
1.1       root       95:                while (get_fs_long((unsigned long *) (tmp++)))
                     96:                        i++;
                     97: 
                     98:        return i;
                     99: }
                    100: 
                    101: /*
                    102:  * 'copy_string()' copies argument/envelope strings from user
                    103:  * memory to free pages in kernel mem. These are in a format ready
                    104:  * to be put directly into the top of new user memory.
                    105:  */
                    106: static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
                    107:                unsigned long p)
                    108: {
                    109:        int len,i;
                    110:        char *tmp;
                    111: 
                    112:        while (argc-- > 0) {
                    113:                if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
                    114:                        panic("argc is wrong");
                    115:                len=0;          /* remember zero-padding */
                    116:                do {
                    117:                        len++;
                    118:                } while (get_fs_byte(tmp++));
                    119:                if (p-len < 0)          /* this shouldn't happen - 128kB */
                    120:                        return 0;
                    121:                i = ((unsigned) (p-len)) >> 12;
                    122:                while (i<MAX_ARG_PAGES && !page[i]) {
                    123:                        if (!(page[i]=get_free_page()))
                    124:                                return 0;
                    125:                        i++;
                    126:                }
                    127:                do {
                    128:                        --p;
                    129:                        if (!page[p/PAGE_SIZE])
                    130:                                panic("nonexistent page in exec.c");
                    131:                        ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
                    132:                                get_fs_byte(--tmp);
                    133:                } while (--len);
                    134:        }
                    135:        return p;
                    136: }
                    137: 
                    138: static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
                    139: {
                    140:        unsigned long code_limit,data_limit,code_base,data_base;
                    141:        int i;
                    142: 
                    143:        code_limit = text_size+PAGE_SIZE -1;
                    144:        code_limit &= 0xFFFFF000;
                    145:        data_limit = 0x4000000;
                    146:        code_base = get_base(current->ldt[1]);
                    147:        data_base = code_base;
                    148:        set_base(current->ldt[1],code_base);
                    149:        set_limit(current->ldt[1],code_limit);
                    150:        set_base(current->ldt[2],data_base);
                    151:        set_limit(current->ldt[2],data_limit);
                    152: /* make sure fs points to the NEW data segment */
                    153:        __asm__("pushl $0x17\n\tpop %%fs"::);
                    154:        data_base += data_limit;
                    155:        for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
                    156:                data_base -= PAGE_SIZE;
                    157:                if (page[i])
                    158:                        put_page(page[i],data_base);
                    159:        }
                    160:        return data_limit;
                    161: }
                    162: 
                    163: /*
1.1.1.4 ! root      164:  * return 1 if ex if a valid elf executable
        !           165:  * */
        !           166: int is_valid_elf(Elf32_Ehdr* ex)
        !           167: {
        !           168:        if (ex->e_ident[EI_MAG0]!=ELFMAG0 || ex->e_ident[EI_MAG1]!=ELFMAG1 ||
        !           169:                ex->e_ident[EI_MAG2]!=ELFMAG2 || ex->e_ident[EI_MAG3]!=ELFMAG3){
        !           170:                printk("not elf format\n");
        !           171:                return 0;       /*not elf format */
        !           172:        }
        !           173: 
        !           174:        if (ex->e_type != ET_EXEC || ex->e_machine != EM_386){
        !           175:                printk("bad elf binary\n");
        !           176:                return 0;
        !           177:        }
        !           178: 
        !           179:        return 1;
        !           180: }
        !           181: 
        !           182: /*
        !           183:  * bread(dev,ind) is an array of block index
        !           184:  * So we have to get from this array our wanted index ( variable block)
        !           185:  * */
        !           186: struct buffer_head* read_file_block_ind(int dev,int ind,int block_num)
        !           187: {
        !           188:        struct buffer_head * bh=NULL,*ih;
        !           189:        unsigned short block;
        !           190: 
        !           191:        if (!(ih=bread(dev,ind)))
        !           192:        {
        !           193:                printk("bad block tab\n");
        !           194:                return NULL;
        !           195:        }
        !           196: 
        !           197:        if ((block = *((unsigned short *) (ih->b_data) + block_num))){
        !           198:                if (!(bh=bread(dev,block))) {
        !           199:                        brelse(ih);
        !           200:                        printk("bad block file\n");
        !           201:                        return NULL;
        !           202:                }
        !           203:        }
        !           204: 
        !           205: 
        !           206:        brelse(ih);
        !           207:        return bh;
        !           208: }
        !           209: 
        !           210: /*
        !           211:  * if block_num=5, read file at position 5*1024.
        !           212:  * this work only for minix 1 fs 
        !           213:  */
        !           214: struct buffer_head* read_file_block(struct m_inode * inode,int block_num)
        !           215: {
        !           216:        struct buffer_head * dind;
        !           217:        int i;
        !           218:        unsigned short table;
        !           219: 
        !           220:         /* 7 1st block can be read directly */
        !           221:        if (block_num<=6)
        !           222:        {
        !           223:                return bread(inode->i_dev,inode->i_zone[block_num]);
        !           224:        }
        !           225: 
        !           226:        block_num-=7;
        !           227: 
        !           228:        if (block_num<512)
        !           229:        {
        !           230:                /* read block at i_zone[7] is an array of block index */
        !           231:                return read_file_block_ind(inode->i_dev,inode->i_zone[7],block_num);
        !           232:        }
        !           233: 
        !           234:        block_num-=512;
        !           235: 
        !           236:        if (block_num>512*512)
        !           237:        {
        !           238:                panic("Impossibly long executable");
        !           239:                return NULL;    //just to avoid warning compilation
        !           240:        }
        !           241: 
        !           242:        /* i_zone[8] => array of array block index */
        !           243:        if (!(i=inode->i_zone[8]))
        !           244:                return NULL;
        !           245:        if (!(dind = bread(inode->i_dev,i)))
        !           246:                return NULL;
        !           247:        
        !           248:        table = *((unsigned short *) dind->b_data+(block_num/512));
        !           249:        brelse(dind);
        !           250:        if (block_num>=512)
        !           251:                block_num-=(block_num-1)*512;
        !           252:        
        !           253:        return read_file_block_ind(inode->i_dev,table,block_num);
        !           254: }
        !           255: 
        !           256: 
        !           257: /*  
        !           258:  *  read an area into %fs:mem.
        !           259:  */
        !           260: int copy_section(struct m_inode * inode,Elf32_Off from, Elf32_Addr dest,Elf32_Word size)
        !           261: {
        !           262:        struct buffer_head * bh;
        !           263:        int block_num=from/BLOCK_SIZE;
        !           264:        int block_offset;                       //only for 1st block
        !           265:        int cp_size;                            
        !           266: 
        !           267:        //read fist block
        !           268:        block_offset=from%BLOCK_SIZE;
        !           269:        bh=read_file_block(inode,block_num);
        !           270:        if (!bh) return -1;
        !           271:        cp_size=(size<BLOCK_SIZE-block_offset)?size:BLOCK_SIZE-block_offset;
        !           272:        //note we add 3 to size to get it aligned to word boundary
        !           273:        cp_block(bh->b_data+block_offset,(void*)dest,cp_size+3);
        !           274:        brelse(bh);
        !           275:        dest+=cp_size;
        !           276:        size-=cp_size;
        !           277:        block_num++;
        !           278: 
        !           279:        //read others blocks
        !           280:        while(size)
        !           281:        {
        !           282:                bh=read_file_block(inode,block_num);
        !           283:                if (!bh) return -1;
        !           284:                cp_size=(size<BLOCK_SIZE)?size:BLOCK_SIZE;
        !           285:                cp_block(bh->b_data,(void*)dest,cp_size+3);
        !           286:                block_num++;
        !           287:                size-=cp_size;
        !           288:                dest+=cp_size;
        !           289:                brelse(bh);
        !           290:        };
        !           291: 
        !           292:        return 0;
        !           293: }
        !           294: 
        !           295: inline int create_bss_section(Elf32_Addr dest,Elf32_Word size)
        !           296: {
        !           297:        while (size--)
        !           298:                put_fs_byte(0,(char *)dest++);
        !           299:        return 0;
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * in linux 0.01 only a.out binary format was supported
        !           304:  * Today it's hard to compile some programs (like bach) in a.out format
        !           305:  * So this version of linux 0.01 support elf binary.
        !           306:  * nb : there is no support of shared library !
        !           307:  */
        !           308: int load_elf_binary(struct m_inode *inode, struct buffer_head* bh,
        !           309:                                         bin_section* bs)
        !           310: {
        !           311:        Elf32_Ehdr ex;
        !           312:        Elf32_Shdr sect;
        !           313:        long nsect;
        !           314:        int lb=0;
        !           315:        struct buffer_head* bht=NULL;
        !           316: 
        !           317:        ex = *((Elf32_Ehdr *) bh->b_data);      /* read exec-header */
        !           318: 
        !           319:        /* check header */
        !           320:        if (!is_valid_elf(&ex)) {
        !           321:                return -1;
        !           322:        }
        !           323: 
        !           324:        bs->b_entry=ex.e_entry;
        !           325:        nsect=ex.e_shnum;
        !           326:        bs->b_size=ex.e_ehsize+nsect*ex.e_shentsize;
        !           327:        
        !           328:        if (nsect<=1){
        !           329:                printk("bad nb of sections %d\n",nsect);
        !           330:                return -1;
        !           331:        }
        !           332:        
        !           333:        while(nsect--){
        !           334:        
        !           335:                /* load block where is our table section*/
        !           336:                if ((ex.e_shoff + nsect * ex.e_shentsize)/BLOCK_SIZE != lb)
        !           337:                {
        !           338:                        printk("");     // gcc  bug : removing this line = gcc not happy !!!
        !           339:                        lb = (ex.e_shoff + nsect * ex.e_shentsize)/BLOCK_SIZE;
        !           340:                        if (bht) brelse(bht);
        !           341:                        bht=read_file_block(inode,lb);
        !           342:                        if (!bht) return -1;
        !           343:                }
        !           344: 
        !           345:                /* copy this section fo %fs:mem */
        !           346:                sect=*((Elf32_Shdr *)(bht->b_data + (ex.e_shoff + 
        !           347:                                nsect * ex.e_shentsize)%BLOCK_SIZE ));
        !           348:        
        !           349:                if (!sect.sh_size || !sect.sh_addr) continue;
        !           350:                
        !           351:                switch(sect.sh_type)
        !           352:                {
        !           353:                        case SHT_PROGBITS:
        !           354:                                if (copy_section(inode,sect.sh_offset,sect.sh_addr,
        !           355:                                        sect.sh_size))
        !           356:                                {
        !           357:                                        if (bht) brelse(bht);
        !           358:                                        return -1;
        !           359:                                }
        !           360:                                break;
        !           361:                        
        !           362:                        case SHT_NOBITS:          
        !           363:                                create_bss_section(sect.sh_addr,sect.sh_size);
        !           364:                                break;
        !           365: 
        !           366:                        default:
        !           367:                        continue;         
        !           368:                }
        !           369: 
        !           370:                /* find binary size */
        !           371:                if (bs->b_size<sect.sh_addr + sect.sh_size)
        !           372:                        bs->b_size=sect.sh_addr + sect.sh_size; 
        !           373:        };
        !           374: 
        !           375:        if (bht) brelse(bht);
        !           376:        return 0;
        !           377: }
        !           378: 
        !           379: /*
1.1       root      380:  * 'do_execve()' executes a new program.
                    381:  */
                    382: int do_execve(unsigned long * eip,long tmp,char * filename,
                    383:        char ** argv, char ** envp)
                    384: {
                    385:        struct m_inode * inode;
                    386:        struct buffer_head * bh;
                    387:        unsigned long page[MAX_ARG_PAGES];
                    388:        int i,argc,envc;
                    389:        unsigned long p;
1.1.1.4 ! root      390:        bin_section bs;
1.1       root      391: 
                    392:        if ((0xffff & eip[1]) != 0x000f)
                    393:                panic("execve called from supervisor mode");
                    394:        for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
                    395:                page[i]=0;
                    396:        if (!(inode=namei(filename)))           /* get executables inode */
                    397:                return -ENOENT;
1.1.1.4 ! root      398:        if (!S_ISREG(inode->i_mode)) {          /* must be regular file */
1.1       root      399:                iput(inode);
                    400:                return -EACCES;
                    401:        }
                    402:        i = inode->i_mode;
                    403:        if (current->uid && current->euid) {
                    404:                if (current->euid == inode->i_uid)
                    405:                        i >>= 6;
                    406:                else if (current->egid == inode->i_gid)
                    407:                        i >>= 3;
                    408:        } else if (i & 0111)
                    409:                i=1;
                    410:        if (!(i & 1)) {
                    411:                iput(inode);
                    412:                return -ENOEXEC;
                    413:        }
                    414:        if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
                    415:                iput(inode);
                    416:                return -EACCES;
                    417:        }
1.1.1.4 ! root      418: 
1.1       root      419:        argc = count(argv);
                    420:        envc = count(envp);
1.1.1.2   root      421:        p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES);
1.1       root      422:        p = copy_strings(argc,argv,page,p);
                    423:        if (!p) {
                    424:                for (i=0 ; i<MAX_ARG_PAGES ; i++)
                    425:                        free_page(page[i]);
                    426:                iput(inode);
                    427:                return -1;
                    428:        }
                    429: /* OK, This is the point of no return */
                    430:        for (i=0 ; i<32 ; i++)
                    431:                current->sig_fn[i] = NULL;
                    432:        for (i=0 ; i<NR_OPEN ; i++)
                    433:                if ((current->close_on_exec>>i)&1)
                    434:                        sys_close(i);
                    435:        current->close_on_exec = 0;
1.1.1.4 ! root      436: 
1.1       root      437:        free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
                    438:        free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
1.1.1.4 ! root      439:        
        !           440:        if (load_elf_binary(inode,bh,&bs)){
        !           441:                brelse(bh);
        !           442:                iput(inode);
        !           443:                return -EACCES;
        !           444:        }
        !           445:        brelse(bh);
        !           446: 
1.1       root      447:        if (last_task_used_math == current)
                    448:                last_task_used_math = NULL;
                    449:        current->used_math = 0;
1.1.1.4 ! root      450:        p += change_ldt(bs.b_size,page)-MAX_ARG_PAGES*PAGE_SIZE;
1.1       root      451:        p = (unsigned long) create_tables((char *)p,argc,envc);
1.1.1.4 ! root      452:        current->brk = bs.b_size;
        !           453:        current->end_data = bs.b_size;
        !           454:        current->end_code = bs.b_size;
1.1       root      455:        current->start_stack = p & 0xfffff000;
                    456:        iput(inode);
1.1.1.4 ! root      457: 
        !           458:        i = bs.b_size;
1.1       root      459:        while (i&0xfff)
                    460:                put_fs_byte(0,(char *) (i++));
1.1.1.4 ! root      461:        
        !           462:        eip[0] = bs.b_entry;            /* eip, magic happens :-) */
        !           463:        eip[3] = p;                                     /* stack pointer */
        !           464: 
1.1       root      465:        return 0;
                    466: }

unix.superglobalmegacorp.com

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