|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.