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