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

1.1.1.2 ! root        1: /*
        !             2:  *  linux/fs/exec.c
        !             3:  *
        !             4:  *  (C) 1991  Linus Torvalds
        !             5:  */
        !             6: 
1.1       root        7: #include <errno.h>
1.1.1.2 ! root        8: #include <string.h>
1.1       root        9: #include <sys/stat.h>
                     10: #include <a.out.h>
                     11: 
                     12: #include <linux/fs.h>
                     13: #include <linux/sched.h>
                     14: #include <linux/kernel.h>
                     15: #include <linux/mm.h>
                     16: #include <asm/segment.h>
                     17: 
                     18: extern int sys_exit(int exit_code);
                     19: extern int sys_close(int fd);
                     20: 
                     21: /*
                     22:  * MAX_ARG_PAGES defines the number of pages allocated for arguments
                     23:  * and envelope for the new program. 32 should suffice, this gives
                     24:  * a maximum env+arg of 128kB !
                     25:  */
                     26: #define MAX_ARG_PAGES 32
                     27: 
                     28: #define cp_block(from,to) \
                     29: __asm__("pushl $0x10\n\t" \
                     30:        "pushl $0x17\n\t" \
                     31:        "pop %%es\n\t" \
                     32:        "cld\n\t" \
                     33:        "rep\n\t" \
                     34:        "movsl\n\t" \
                     35:        "pop %%es" \
                     36:        ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
                     37:        :"cx","di","si")
                     38: 
                     39: /*
                     40:  * read_head() reads blocks 1-6 (not 0). Block 0 has already been
                     41:  * read for header information.
                     42:  */
                     43: int read_head(struct m_inode * inode,int blocks)
                     44: {
                     45:        struct buffer_head * bh;
                     46:        int count;
                     47: 
                     48:        if (blocks>6)
                     49:                blocks=6;
                     50:        for(count = 0 ; count<blocks ; count++) {
                     51:                if (!inode->i_zone[count+1])
                     52:                        continue;
                     53:                if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
                     54:                        return -1;
                     55:                cp_block(bh->b_data,count*BLOCK_SIZE);
                     56:                brelse(bh);
                     57:        }
                     58:        return 0;
                     59: }
                     60: 
                     61: int read_ind(int dev,int ind,long size,unsigned long offset)
                     62: {
                     63:        struct buffer_head * ih, * bh;
                     64:        unsigned short * table,block;
                     65: 
                     66:        if (size<=0)
                     67:                panic("size<=0 in read_ind");
                     68:        if (size>512*BLOCK_SIZE)
                     69:                size=512*BLOCK_SIZE;
                     70:        if (!ind)
                     71:                return 0;
                     72:        if (!(ih=bread(dev,ind)))
                     73:                return -1;
                     74:        table = (unsigned short *) ih->b_data;
                     75:        while (size>0) {
                     76:                if (block=*(table++))
                     77:                        if (!(bh=bread(dev,block))) {
                     78:                                brelse(ih);
                     79:                                return -1;
                     80:                        } else {
                     81:                                cp_block(bh->b_data,offset);
                     82:                                brelse(bh);
                     83:                        }
                     84:                size -= BLOCK_SIZE;
                     85:                offset += BLOCK_SIZE;
                     86:        }
                     87:        brelse(ih);
                     88:        return 0;
                     89: }
                     90: 
                     91: /*
                     92:  * read_area() reads an area into %fs:mem.
                     93:  */
                     94: int read_area(struct m_inode * inode,long size)
                     95: {
                     96:        struct buffer_head * dind;
                     97:        unsigned short * table;
                     98:        int i,count;
                     99: 
                    100:        if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
                    101:            (size -= BLOCK_SIZE*6)<=0)
                    102:                return i;
                    103:        if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
                    104:            (size -= BLOCK_SIZE*512)<=0)
                    105:                return i;
                    106:        if (!(i=inode->i_zone[8]))
                    107:                return 0;
                    108:        if (!(dind = bread(inode->i_dev,i)))
                    109:                return -1;
                    110:        table = (unsigned short *) dind->b_data;
                    111:        for(count=0 ; count<512 ; count++)
                    112:                if ((i=read_ind(inode->i_dev,*(table++),size,
                    113:                    BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
                    114:                        return i;
                    115:        panic("Impossibly long executable");
                    116: }
                    117: 
                    118: /*
                    119:  * create_tables() parses the env- and arg-strings in new user
                    120:  * memory and creates the pointer tables from them, and puts their
                    121:  * addresses on the "stack", returning the new stack pointer value.
                    122:  */
                    123: static unsigned long * create_tables(char * p,int argc,int envc)
                    124: {
                    125:        unsigned long *argv,*envp;
                    126:        unsigned long * sp;
                    127: 
                    128:        sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
                    129:        sp -= envc+1;
                    130:        envp = sp;
                    131:        sp -= argc+1;
                    132:        argv = sp;
                    133:        put_fs_long((unsigned long)envp,--sp);
                    134:        put_fs_long((unsigned long)argv,--sp);
                    135:        put_fs_long((unsigned long)argc,--sp);
                    136:        while (argc-->0) {
                    137:                put_fs_long((unsigned long) p,argv++);
                    138:                while (get_fs_byte(p++)) /* nothing */ ;
                    139:        }
                    140:        put_fs_long(0,argv);
                    141:        while (envc-->0) {
                    142:                put_fs_long((unsigned long) p,envp++);
                    143:                while (get_fs_byte(p++)) /* nothing */ ;
                    144:        }
                    145:        put_fs_long(0,envp);
                    146:        return sp;
                    147: }
                    148: 
                    149: /*
                    150:  * count() counts the number of arguments/envelopes
                    151:  */
                    152: static int count(char ** argv)
                    153: {
                    154:        int i=0;
                    155:        char ** tmp;
                    156: 
                    157:        if (tmp = argv)
                    158:                while (get_fs_long((unsigned long *) (tmp++)))
                    159:                        i++;
                    160: 
                    161:        return i;
                    162: }
                    163: 
                    164: /*
                    165:  * 'copy_string()' copies argument/envelope strings from user
                    166:  * memory to free pages in kernel mem. These are in a format ready
                    167:  * to be put directly into the top of new user memory.
1.1.1.2 ! root      168:  *
        !           169:  * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
        !           170:  * whether the string and the string array are from user or kernel segments:
        !           171:  * 
        !           172:  * from_kmem     argv *        argv **
        !           173:  *    0          user space    user space
        !           174:  *    1          kernel space  user space
        !           175:  *    2          kernel space  kernel space
        !           176:  * 
        !           177:  * We do this by playing games with the fs segment register.  Since it
        !           178:  * it is expensive to load a segment register, we try to avoid calling
        !           179:  * set_fs() unless we absolutely have to.
1.1       root      180:  */
                    181: static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
1.1.1.2 ! root      182:                unsigned long p, int from_kmem)
1.1       root      183: {
1.1.1.2 ! root      184:        char *tmp, *pag;
        !           185:        int len, offset = 0;
        !           186:        unsigned long old_fs, new_fs;
        !           187: 
        !           188:        if (!p)
        !           189:                return 0;       /* bullet-proofing */
        !           190:        new_fs = get_ds();
        !           191:        old_fs = get_fs();
        !           192:        if (from_kmem==2)
        !           193:                set_fs(new_fs);
1.1       root      194:        while (argc-- > 0) {
1.1.1.2 ! root      195:                if (from_kmem == 1)
        !           196:                        set_fs(new_fs);
        !           197:                if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
1.1       root      198:                        panic("argc is wrong");
1.1.1.2 ! root      199:                if (from_kmem == 1)
        !           200:                        set_fs(old_fs);
1.1       root      201:                len=0;          /* remember zero-padding */
                    202:                do {
                    203:                        len++;
                    204:                } while (get_fs_byte(tmp++));
1.1.1.2 ! root      205:                if (p-len < 0) {        /* this shouldn't happen - 128kB */
        !           206:                        set_fs(old_fs);
1.1       root      207:                        return 0;
                    208:                }
1.1.1.2 ! root      209:                while (len) {
        !           210:                        --p; --tmp; --len;
        !           211:                        if (--offset < 0) {
        !           212:                                offset = p % PAGE_SIZE;
        !           213:                                if (from_kmem==2)
        !           214:                                        set_fs(old_fs);
        !           215:                                if (!(pag = (char *) page[p/PAGE_SIZE]) &&
        !           216:                                    !(pag = (char *) page[p/PAGE_SIZE] =
        !           217:                                      (unsigned long *) get_free_page())) 
        !           218:                                        return 0;
        !           219:                                if (from_kmem==2)
        !           220:                                        set_fs(new_fs);
        !           221: 
        !           222:                        }
        !           223:                        *(pag + offset) = get_fs_byte(tmp);
        !           224:                }
1.1       root      225:        }
1.1.1.2 ! root      226:        if (from_kmem==2)
        !           227:                set_fs(old_fs);
1.1       root      228:        return p;
                    229: }
                    230: 
                    231: static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
                    232: {
                    233:        unsigned long code_limit,data_limit,code_base,data_base;
                    234:        int i;
                    235: 
                    236:        code_limit = text_size+PAGE_SIZE -1;
                    237:        code_limit &= 0xFFFFF000;
                    238:        data_limit = 0x4000000;
                    239:        code_base = get_base(current->ldt[1]);
                    240:        data_base = code_base;
                    241:        set_base(current->ldt[1],code_base);
                    242:        set_limit(current->ldt[1],code_limit);
                    243:        set_base(current->ldt[2],data_base);
                    244:        set_limit(current->ldt[2],data_limit);
                    245: /* make sure fs points to the NEW data segment */
                    246:        __asm__("pushl $0x17\n\tpop %%fs"::);
                    247:        data_base += data_limit;
                    248:        for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
                    249:                data_base -= PAGE_SIZE;
                    250:                if (page[i])
                    251:                        put_page(page[i],data_base);
                    252:        }
                    253:        return data_limit;
                    254: }
                    255: 
                    256: /*
                    257:  * 'do_execve()' executes a new program.
                    258:  */
                    259: int do_execve(unsigned long * eip,long tmp,char * filename,
                    260:        char ** argv, char ** envp)
                    261: {
                    262:        struct m_inode * inode;
                    263:        struct buffer_head * bh;
                    264:        struct exec ex;
                    265:        unsigned long page[MAX_ARG_PAGES];
                    266:        int i,argc,envc;
1.1.1.2 ! root      267:        int e_uid, e_gid;
        !           268:        int retval;
        !           269:        int sh_bang = 0;
        !           270:        char    *buf = 0;
        !           271:        unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
1.1       root      272: 
                    273:        if ((0xffff & eip[1]) != 0x000f)
                    274:                panic("execve called from supervisor mode");
                    275:        for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
                    276:                page[i]=0;
                    277:        if (!(inode=namei(filename)))           /* get executables inode */
                    278:                return -ENOENT;
1.1.1.2 ! root      279:        argc = count(argv);
        !           280:        envc = count(envp);
        !           281:        
        !           282: restart_interp:
1.1       root      283:        if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
1.1.1.2 ! root      284:                retval = -EACCES;
        !           285:                goto exec_error2;
1.1       root      286:        }
                    287:        i = inode->i_mode;
1.1.1.2 ! root      288:        e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
        !           289:        e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
        !           290:        if (current->euid == inode->i_uid)
        !           291:                i >>= 6;
        !           292:        else if (current->egid == inode->i_gid)
        !           293:                i >>= 3;
        !           294:        if (!(i & 1) &&
        !           295:            !((inode->i_mode & 0111) && suser())) {
        !           296:                retval = -ENOEXEC;
        !           297:                goto exec_error2;
1.1       root      298:        }
                    299:        if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
1.1.1.2 ! root      300:                retval = -EACCES;
        !           301:                goto exec_error2;
1.1       root      302:        }
                    303:        ex = *((struct exec *) bh->b_data);     /* read exec-header */
1.1.1.2 ! root      304:        if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
        !           305:                /*
        !           306:                 * This section does the #! interpretation.
        !           307:                 * Sorta complicated, but hopefully it will work.  -TYT
        !           308:                 */
        !           309: 
        !           310:                char *cp, *interp, *i_name, *i_arg;
        !           311:                unsigned long old_fs;
        !           312: 
        !           313:                if (!buf)
        !           314:                        buf = malloc(1024);
        !           315:                strncpy(buf, bh->b_data+2, 1022);
        !           316:                brelse(bh);
        !           317:                iput(inode);
        !           318:                buf[1022] = '\0';
        !           319:                if (cp = strchr(buf, '\n')) {
        !           320:                        *cp = '\0';
        !           321:                        for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
        !           322:                }
        !           323:                if (!cp || *cp == '\0') {
        !           324:                        retval = -ENOEXEC; /* No interpreter name found */
        !           325:                        goto exec_error1;
        !           326:                }
        !           327:                interp = i_name = cp;
        !           328:                i_arg = 0;
        !           329:                for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
        !           330:                        if (*cp == '/')
        !           331:                                i_name = cp+1;
        !           332:                }
        !           333:                if (*cp) {
        !           334:                        *cp++ = '\0';
        !           335:                        i_arg = cp;
        !           336:                }
        !           337:                /*
        !           338:                 * OK, we've parsed out the interpreter name and
        !           339:                 * (optional) argument.
        !           340:                 */
        !           341:                if (sh_bang++ == 0) {
        !           342:                        p = copy_strings(envc, envp, page, p, 0);
        !           343:                        p = copy_strings(--argc, argv+1, page, p, 0);
        !           344:                }
        !           345:                /*
        !           346:                 * Splice in (1) the interpreter's name for argv[0]
        !           347:                 *           (2) (optional) argument to interpreter
        !           348:                 *           (3) filename of shell script
        !           349:                 *
        !           350:                 * This is done in reverse order, because of how the
        !           351:                 * user environment and arguments are stored.
        !           352:                 */
        !           353:                p = copy_strings(1, &filename, page, p, 1);
        !           354:                argc++;
        !           355:                if (i_arg) {
        !           356:                        p = copy_strings(1, &i_arg, page, p, 2);
        !           357:                        argc++;
        !           358:                }
        !           359:                p = copy_strings(1, &i_name, page, p, 2);
        !           360:                argc++;
        !           361:                if (!p) {
        !           362:                        retval = -ENOMEM;
        !           363:                        goto exec_error1;
        !           364:                }
        !           365:                /*
        !           366:                 * OK, now restart the process with the interpreter's inode.
        !           367:                 */
        !           368:                old_fs = get_fs();
        !           369:                set_fs(get_ds());
        !           370:                if (!(inode=namei(interp))) { /* get executables inode */
        !           371:                        set_fs(old_fs);
        !           372:                        retval = -ENOENT;
        !           373:                        goto exec_error1;
        !           374:                }
        !           375:                set_fs(old_fs);
        !           376:                goto restart_interp;
        !           377:        }
1.1       root      378:        brelse(bh);
                    379:        if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
                    380:                ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
                    381:                inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
1.1.1.2 ! root      382:                retval = -ENOEXEC;
        !           383:                goto exec_error2;
1.1       root      384:        }
1.1.1.2 ! root      385:        if (N_TXTOFF(ex) != BLOCK_SIZE) {
        !           386:                printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
        !           387:                retval = -ENOEXEC;
        !           388:                goto exec_error2;
        !           389:        }
        !           390:        if (!sh_bang) {
        !           391:                p = copy_strings(envc,envp,page,p,0);
        !           392:                p = copy_strings(argc,argv,page,p,0);
        !           393:                if (!p) {
        !           394:                        retval = -ENOMEM;
        !           395:                        goto exec_error2;
        !           396:                }
1.1       root      397:        }
                    398: /* OK, This is the point of no return */
1.1.1.2 ! root      399:        if (buf)
        !           400:                free_s(buf, 1024);
1.1       root      401:        for (i=0 ; i<32 ; i++)
1.1.1.2 ! root      402:                current->sigaction[i].sa_handler = NULL;
1.1       root      403:        for (i=0 ; i<NR_OPEN ; i++)
                    404:                if ((current->close_on_exec>>i)&1)
                    405:                        sys_close(i);
                    406:        current->close_on_exec = 0;
                    407:        free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
                    408:        free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
                    409:        if (last_task_used_math == current)
                    410:                last_task_used_math = NULL;
                    411:        current->used_math = 0;
                    412:        p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
                    413:        p = (unsigned long) create_tables((char *)p,argc,envc);
                    414:        current->brk = ex.a_bss +
                    415:                (current->end_data = ex.a_data +
                    416:                (current->end_code = ex.a_text));
                    417:        current->start_stack = p & 0xfffff000;
1.1.1.2 ! root      418:        current->euid = e_uid;
        !           419:        current->egid = e_gid;
1.1       root      420:        i = read_area(inode,ex.a_text+ex.a_data);
                    421:        iput(inode);
                    422:        if (i<0)
                    423:                sys_exit(-1);
                    424:        i = ex.a_text+ex.a_data;
                    425:        while (i&0xfff)
                    426:                put_fs_byte(0,(char *) (i++));
                    427:        eip[0] = ex.a_entry;            /* eip, magic happens :-) */
                    428:        eip[3] = p;                     /* stack pointer */
                    429:        return 0;
1.1.1.2 ! root      430: exec_error2:
        !           431:        iput(inode);
        !           432: exec_error1:
        !           433:        if (buf)
        !           434:                free(buf);
        !           435:        for (i=0 ; i<MAX_ARG_PAGES ; i++)
        !           436:                free_page(page[i]);
        !           437:        return(retval);
1.1       root      438: }

unix.superglobalmegacorp.com

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