131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */ 231e31b8aSbellard 331e31b8aSbellard #include <stdio.h> 431e31b8aSbellard #include <sys/types.h> 531e31b8aSbellard #include <fcntl.h> 631e31b8aSbellard #include <sys/stat.h> 731e31b8aSbellard #include <errno.h> 831e31b8aSbellard #include <unistd.h> 931e31b8aSbellard #include <sys/mman.h> 1031e31b8aSbellard #include <stdlib.h> 1131e31b8aSbellard #include <string.h> 1231e31b8aSbellard 133ef693a0Sbellard #include "qemu.h" 1431e31b8aSbellard 1531e31b8aSbellard #include "linux_bin.h" 1631e31b8aSbellard #include "elf.h" 1731e31b8aSbellard #include "segment.h" 1831e31b8aSbellard 1931e31b8aSbellard /* Necessary parameters */ 2031e31b8aSbellard #define ALPHA_PAGE_SIZE 4096 2131e31b8aSbellard #define X86_PAGE_SIZE 4096 2231e31b8aSbellard 2331e31b8aSbellard #define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1)) 2431e31b8aSbellard #define X86_PAGE_MASK (~(X86_PAGE_SIZE-1)) 2531e31b8aSbellard 2631e31b8aSbellard #define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK) 2731e31b8aSbellard #define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK) 2831e31b8aSbellard 2931e31b8aSbellard #define NGROUPS 32 3031e31b8aSbellard 3131e31b8aSbellard #define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE 3231e31b8aSbellard #define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1)) 3331e31b8aSbellard #define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1)) 3431e31b8aSbellard 3531e31b8aSbellard #define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1)) 3631e31b8aSbellard #define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1)) 3731e31b8aSbellard 3831e31b8aSbellard #define INTERPRETER_NONE 0 3931e31b8aSbellard #define INTERPRETER_AOUT 1 4031e31b8aSbellard #define INTERPRETER_ELF 2 4131e31b8aSbellard 4231e31b8aSbellard #define DLINFO_ITEMS 12 4331e31b8aSbellard 4431e31b8aSbellard /* Where we find X86 libraries... */ 45d691f669Sbellard 4631e31b8aSbellard 4731e31b8aSbellard //extern void * mmap4k(); 4831e31b8aSbellard #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) 4931e31b8aSbellard 5031e31b8aSbellard extern unsigned long x86_stack_size; 5131e31b8aSbellard 5231e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd); 5331e31b8aSbellard 5431e31b8aSbellard #ifdef BSWAP_NEEDED 5531e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr) 5631e31b8aSbellard { 5731e31b8aSbellard bswap16s(&ehdr->e_type); /* Object file type */ 5831e31b8aSbellard bswap16s(&ehdr->e_machine); /* Architecture */ 5931e31b8aSbellard bswap32s(&ehdr->e_version); /* Object file version */ 6031e31b8aSbellard bswap32s(&ehdr->e_entry); /* Entry point virtual address */ 6131e31b8aSbellard bswap32s(&ehdr->e_phoff); /* Program header table file offset */ 6231e31b8aSbellard bswap32s(&ehdr->e_shoff); /* Section header table file offset */ 6331e31b8aSbellard bswap32s(&ehdr->e_flags); /* Processor-specific flags */ 6431e31b8aSbellard bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ 6531e31b8aSbellard bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ 6631e31b8aSbellard bswap16s(&ehdr->e_phnum); /* Program header table entry count */ 6731e31b8aSbellard bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ 6831e31b8aSbellard bswap16s(&ehdr->e_shnum); /* Section header table entry count */ 6931e31b8aSbellard bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ 7031e31b8aSbellard } 7131e31b8aSbellard 7231e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr) 7331e31b8aSbellard { 7431e31b8aSbellard bswap32s(&phdr->p_type); /* Segment type */ 7531e31b8aSbellard bswap32s(&phdr->p_offset); /* Segment file offset */ 7631e31b8aSbellard bswap32s(&phdr->p_vaddr); /* Segment virtual address */ 7731e31b8aSbellard bswap32s(&phdr->p_paddr); /* Segment physical address */ 7831e31b8aSbellard bswap32s(&phdr->p_filesz); /* Segment size in file */ 7931e31b8aSbellard bswap32s(&phdr->p_memsz); /* Segment size in memory */ 8031e31b8aSbellard bswap32s(&phdr->p_flags); /* Segment flags */ 8131e31b8aSbellard bswap32s(&phdr->p_align); /* Segment alignment */ 8231e31b8aSbellard } 8331e31b8aSbellard #endif 8431e31b8aSbellard 8531e31b8aSbellard static void * get_free_page(void) 8631e31b8aSbellard { 8731e31b8aSbellard void * retval; 8831e31b8aSbellard 8931e31b8aSbellard /* User-space version of kernel get_free_page. Returns a page-aligned 9031e31b8aSbellard * page-sized chunk of memory. 9131e31b8aSbellard */ 9231e31b8aSbellard retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE, 9331e31b8aSbellard MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 9431e31b8aSbellard 9531e31b8aSbellard if((long)retval == -1) { 9631e31b8aSbellard perror("get_free_page"); 9731e31b8aSbellard exit(-1); 9831e31b8aSbellard } 9931e31b8aSbellard else { 10031e31b8aSbellard return(retval); 10131e31b8aSbellard } 10231e31b8aSbellard } 10331e31b8aSbellard 10431e31b8aSbellard static void free_page(void * pageaddr) 10531e31b8aSbellard { 10631e31b8aSbellard (void)munmap(pageaddr, ALPHA_PAGE_SIZE); 10731e31b8aSbellard } 10831e31b8aSbellard 10931e31b8aSbellard /* 11031e31b8aSbellard * 'copy_string()' copies argument/envelope strings from user 11131e31b8aSbellard * memory to free pages in kernel mem. These are in a format ready 11231e31b8aSbellard * to be put directly into the top of new user memory. 11331e31b8aSbellard * 11431e31b8aSbellard */ 11531e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, 11631e31b8aSbellard unsigned long p) 11731e31b8aSbellard { 11831e31b8aSbellard char *tmp, *tmp1, *pag = NULL; 11931e31b8aSbellard int len, offset = 0; 12031e31b8aSbellard 12131e31b8aSbellard if (!p) { 12231e31b8aSbellard return 0; /* bullet-proofing */ 12331e31b8aSbellard } 12431e31b8aSbellard while (argc-- > 0) { 12531e31b8aSbellard if (!(tmp1 = tmp = get_user(argv+argc))) { 12631e31b8aSbellard fprintf(stderr, "VFS: argc is wrong"); 12731e31b8aSbellard exit(-1); 12831e31b8aSbellard } 12931e31b8aSbellard while (get_user(tmp++)); 13031e31b8aSbellard len = tmp - tmp1; 13131e31b8aSbellard if (p < len) { /* this shouldn't happen - 128kB */ 13231e31b8aSbellard return 0; 13331e31b8aSbellard } 13431e31b8aSbellard while (len) { 13531e31b8aSbellard --p; --tmp; --len; 13631e31b8aSbellard if (--offset < 0) { 13731e31b8aSbellard offset = p % X86_PAGE_SIZE; 13831e31b8aSbellard if (!(pag = (char *) page[p/X86_PAGE_SIZE]) && 13931e31b8aSbellard !(pag = (char *) page[p/X86_PAGE_SIZE] = 14031e31b8aSbellard (unsigned long *) get_free_page())) { 14131e31b8aSbellard return 0; 14231e31b8aSbellard } 14331e31b8aSbellard } 14431e31b8aSbellard if (len == 0 || offset == 0) { 14531e31b8aSbellard *(pag + offset) = get_user(tmp); 14631e31b8aSbellard } 14731e31b8aSbellard else { 14831e31b8aSbellard int bytes_to_copy = (len > offset) ? offset : len; 14931e31b8aSbellard tmp -= bytes_to_copy; 15031e31b8aSbellard p -= bytes_to_copy; 15131e31b8aSbellard offset -= bytes_to_copy; 15231e31b8aSbellard len -= bytes_to_copy; 15331e31b8aSbellard memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); 15431e31b8aSbellard } 15531e31b8aSbellard } 15631e31b8aSbellard } 15731e31b8aSbellard return p; 15831e31b8aSbellard } 15931e31b8aSbellard 16031e31b8aSbellard static int in_group_p(gid_t g) 16131e31b8aSbellard { 16231e31b8aSbellard /* return TRUE if we're in the specified group, FALSE otherwise */ 16331e31b8aSbellard int ngroup; 16431e31b8aSbellard int i; 16531e31b8aSbellard gid_t grouplist[NGROUPS]; 16631e31b8aSbellard 16731e31b8aSbellard ngroup = getgroups(NGROUPS, grouplist); 16831e31b8aSbellard for(i = 0; i < ngroup; i++) { 16931e31b8aSbellard if(grouplist[i] == g) { 17031e31b8aSbellard return 1; 17131e31b8aSbellard } 17231e31b8aSbellard } 17331e31b8aSbellard return 0; 17431e31b8aSbellard } 17531e31b8aSbellard 17631e31b8aSbellard static int count(char ** vec) 17731e31b8aSbellard { 17831e31b8aSbellard int i; 17931e31b8aSbellard 18031e31b8aSbellard for(i = 0; *vec; i++) { 18131e31b8aSbellard vec++; 18231e31b8aSbellard } 18331e31b8aSbellard 18431e31b8aSbellard return(i); 18531e31b8aSbellard } 18631e31b8aSbellard 18731e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm) 18831e31b8aSbellard { 18931e31b8aSbellard struct stat st; 19031e31b8aSbellard int mode; 19131e31b8aSbellard int retval, id_change; 19231e31b8aSbellard 19331e31b8aSbellard if(fstat(bprm->fd, &st) < 0) { 19431e31b8aSbellard return(-errno); 19531e31b8aSbellard } 19631e31b8aSbellard 19731e31b8aSbellard mode = st.st_mode; 19831e31b8aSbellard if(!S_ISREG(mode)) { /* Must be regular file */ 19931e31b8aSbellard return(-EACCES); 20031e31b8aSbellard } 20131e31b8aSbellard if(!(mode & 0111)) { /* Must have at least one execute bit set */ 20231e31b8aSbellard return(-EACCES); 20331e31b8aSbellard } 20431e31b8aSbellard 20531e31b8aSbellard bprm->e_uid = geteuid(); 20631e31b8aSbellard bprm->e_gid = getegid(); 20731e31b8aSbellard id_change = 0; 20831e31b8aSbellard 20931e31b8aSbellard /* Set-uid? */ 21031e31b8aSbellard if(mode & S_ISUID) { 21131e31b8aSbellard bprm->e_uid = st.st_uid; 21231e31b8aSbellard if(bprm->e_uid != geteuid()) { 21331e31b8aSbellard id_change = 1; 21431e31b8aSbellard } 21531e31b8aSbellard } 21631e31b8aSbellard 21731e31b8aSbellard /* Set-gid? */ 21831e31b8aSbellard /* 21931e31b8aSbellard * If setgid is set but no group execute bit then this 22031e31b8aSbellard * is a candidate for mandatory locking, not a setgid 22131e31b8aSbellard * executable. 22231e31b8aSbellard */ 22331e31b8aSbellard if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 22431e31b8aSbellard bprm->e_gid = st.st_gid; 22531e31b8aSbellard if (!in_group_p(bprm->e_gid)) { 22631e31b8aSbellard id_change = 1; 22731e31b8aSbellard } 22831e31b8aSbellard } 22931e31b8aSbellard 23031e31b8aSbellard memset(bprm->buf, 0, sizeof(bprm->buf)); 23131e31b8aSbellard retval = lseek(bprm->fd, 0L, SEEK_SET); 23231e31b8aSbellard if(retval >= 0) { 23331e31b8aSbellard retval = read(bprm->fd, bprm->buf, 128); 23431e31b8aSbellard } 23531e31b8aSbellard if(retval < 0) { 23631e31b8aSbellard perror("prepare_binprm"); 23731e31b8aSbellard exit(-1); 23831e31b8aSbellard /* return(-errno); */ 23931e31b8aSbellard } 24031e31b8aSbellard else { 24131e31b8aSbellard return(retval); 24231e31b8aSbellard } 24331e31b8aSbellard } 24431e31b8aSbellard 24531e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, 24631e31b8aSbellard struct image_info * info) 24731e31b8aSbellard { 24831e31b8aSbellard unsigned long stack_base; 24931e31b8aSbellard int i; 25031e31b8aSbellard extern unsigned long stktop; 25131e31b8aSbellard 25231e31b8aSbellard stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE; 25331e31b8aSbellard 25431e31b8aSbellard p += stack_base; 25531e31b8aSbellard if (bprm->loader) { 25631e31b8aSbellard bprm->loader += stack_base; 25731e31b8aSbellard } 25831e31b8aSbellard bprm->exec += stack_base; 25931e31b8aSbellard 26031e31b8aSbellard /* Create enough stack to hold everything. If we don't use 26131e31b8aSbellard * it for args, we'll use it for something else... 26231e31b8aSbellard */ 2639de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so 2649de5e440Sbellard we allocate a bigger stack. Need a better solution, for example 2659de5e440Sbellard by remapping the process stack directly at the right place */ 26631e31b8aSbellard if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { 26731e31b8aSbellard if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, 26831e31b8aSbellard PROT_READ | PROT_WRITE, 26931e31b8aSbellard MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 27031e31b8aSbellard perror("stk mmap"); 27131e31b8aSbellard exit(-1); 27231e31b8aSbellard } 27331e31b8aSbellard } 27431e31b8aSbellard else { 27531e31b8aSbellard if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE, 27631e31b8aSbellard PROT_READ | PROT_WRITE, 27731e31b8aSbellard MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 27831e31b8aSbellard perror("stk mmap"); 27931e31b8aSbellard exit(-1); 28031e31b8aSbellard } 28131e31b8aSbellard } 28231e31b8aSbellard 28331e31b8aSbellard stktop = stack_base; 28431e31b8aSbellard 28531e31b8aSbellard for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 28631e31b8aSbellard if (bprm->page[i]) { 28731e31b8aSbellard info->rss++; 28831e31b8aSbellard 28931e31b8aSbellard memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE); 29031e31b8aSbellard free_page((void *)bprm->page[i]); 29131e31b8aSbellard } 29231e31b8aSbellard stack_base += X86_PAGE_SIZE; 29331e31b8aSbellard } 29431e31b8aSbellard return p; 29531e31b8aSbellard } 29631e31b8aSbellard 29731e31b8aSbellard static void set_brk(unsigned long start, unsigned long end) 29831e31b8aSbellard { 29931e31b8aSbellard /* page-align the start and end addresses... */ 30031e31b8aSbellard start = ALPHA_PAGE_ALIGN(start); 30131e31b8aSbellard end = ALPHA_PAGE_ALIGN(end); 30231e31b8aSbellard if (end <= start) 30331e31b8aSbellard return; 30431e31b8aSbellard if((long)mmap4k(start, end - start, 30531e31b8aSbellard PROT_READ | PROT_WRITE | PROT_EXEC, 30631e31b8aSbellard MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 30731e31b8aSbellard perror("cannot mmap brk"); 30831e31b8aSbellard exit(-1); 30931e31b8aSbellard } 31031e31b8aSbellard } 31131e31b8aSbellard 31231e31b8aSbellard 31331e31b8aSbellard /* We need to explicitly zero any fractional pages 31431e31b8aSbellard after the data section (i.e. bss). This would 31531e31b8aSbellard contain the junk from the file that should not 31631e31b8aSbellard be in memory */ 31731e31b8aSbellard 31831e31b8aSbellard 31931e31b8aSbellard static void padzero(unsigned long elf_bss) 32031e31b8aSbellard { 32131e31b8aSbellard unsigned long nbyte; 32231e31b8aSbellard char * fpnt; 32331e31b8aSbellard 32431e31b8aSbellard nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */ 32531e31b8aSbellard if (nbyte) { 32631e31b8aSbellard nbyte = ALPHA_PAGE_SIZE - nbyte; 32731e31b8aSbellard fpnt = (char *) elf_bss; 32831e31b8aSbellard do { 32931e31b8aSbellard *fpnt++ = 0; 33031e31b8aSbellard } while (--nbyte); 33131e31b8aSbellard } 33231e31b8aSbellard } 33331e31b8aSbellard 33431e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc, 33531e31b8aSbellard struct elfhdr * exec, 33631e31b8aSbellard unsigned long load_addr, 33731e31b8aSbellard unsigned long interp_load_addr, int ibcs, 33831e31b8aSbellard struct image_info *info) 33931e31b8aSbellard { 340b17780d5Sbellard target_ulong *argv, *envp, *dlinfo; 341b17780d5Sbellard target_ulong *sp; 34231e31b8aSbellard 34331e31b8aSbellard /* 34431e31b8aSbellard * Force 16 byte alignment here for generality. 34531e31b8aSbellard */ 34631e31b8aSbellard sp = (unsigned int *) (~15UL & (unsigned long) p); 34731e31b8aSbellard sp -= exec ? DLINFO_ITEMS*2 : 2; 34831e31b8aSbellard dlinfo = sp; 34931e31b8aSbellard sp -= envc+1; 35031e31b8aSbellard envp = sp; 35131e31b8aSbellard sp -= argc+1; 35231e31b8aSbellard argv = sp; 35331e31b8aSbellard if (!ibcs) { 354b17780d5Sbellard put_user(tswapl((target_ulong)envp),--sp); 355b17780d5Sbellard put_user(tswapl((target_ulong)argv),--sp); 35631e31b8aSbellard } 35731e31b8aSbellard 35831e31b8aSbellard #define NEW_AUX_ENT(id, val) \ 359b17780d5Sbellard put_user (tswapl(id), dlinfo++); \ 360b17780d5Sbellard put_user (tswapl(val), dlinfo++) 36131e31b8aSbellard 36231e31b8aSbellard if (exec) { /* Put this here for an ELF program interpreter */ 36331e31b8aSbellard NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff)); 36431e31b8aSbellard NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); 36531e31b8aSbellard NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); 36631e31b8aSbellard NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE)); 36731e31b8aSbellard NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr)); 36831e31b8aSbellard NEW_AUX_ENT (AT_FLAGS, (unsigned int)0); 36931e31b8aSbellard NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry); 37031e31b8aSbellard NEW_AUX_ENT (AT_UID, (unsigned int) getuid()); 37131e31b8aSbellard NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid()); 37231e31b8aSbellard NEW_AUX_ENT (AT_GID, (unsigned int) getgid()); 37331e31b8aSbellard NEW_AUX_ENT (AT_EGID, (unsigned int) getegid()); 37431e31b8aSbellard } 37531e31b8aSbellard NEW_AUX_ENT (AT_NULL, 0); 37631e31b8aSbellard #undef NEW_AUX_ENT 377b17780d5Sbellard put_user(tswapl(argc),--sp); 37831e31b8aSbellard info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); 37931e31b8aSbellard while (argc-->0) { 380b17780d5Sbellard put_user(tswapl((target_ulong)p),argv++); 38131e31b8aSbellard while (get_user(p++)) /* nothing */ ; 38231e31b8aSbellard } 38331e31b8aSbellard put_user(0,argv); 38431e31b8aSbellard info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); 38531e31b8aSbellard while (envc-->0) { 386b17780d5Sbellard put_user(tswapl((target_ulong)p),envp++); 38731e31b8aSbellard while (get_user(p++)) /* nothing */ ; 38831e31b8aSbellard } 38931e31b8aSbellard put_user(0,envp); 39031e31b8aSbellard info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); 39131e31b8aSbellard return sp; 39231e31b8aSbellard } 39331e31b8aSbellard 39431e31b8aSbellard 39531e31b8aSbellard 39631e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, 39731e31b8aSbellard int interpreter_fd, 39831e31b8aSbellard unsigned long *interp_load_addr) 39931e31b8aSbellard { 40031e31b8aSbellard struct elf_phdr *elf_phdata = NULL; 40131e31b8aSbellard struct elf_phdr *eppnt; 40231e31b8aSbellard unsigned long load_addr; 40331e31b8aSbellard int load_addr_set = 0; 40431e31b8aSbellard int retval; 40531e31b8aSbellard unsigned long last_bss, elf_bss; 40631e31b8aSbellard unsigned long error; 40731e31b8aSbellard int i; 40831e31b8aSbellard 40931e31b8aSbellard elf_bss = 0; 41031e31b8aSbellard last_bss = 0; 41131e31b8aSbellard error = 0; 41231e31b8aSbellard 41331e31b8aSbellard /* We put this here so that mmap will search for the *first* 41431e31b8aSbellard * available memory... 41531e31b8aSbellard */ 41631e31b8aSbellard load_addr = INTERP_LOADADDR; 41731e31b8aSbellard 418*644c433cSbellard #ifdef BSWAP_NEEDED 419*644c433cSbellard bswap_ehdr(interp_elf_ex); 420*644c433cSbellard #endif 42131e31b8aSbellard /* First of all, some simple consistency checks */ 42231e31b8aSbellard if ((interp_elf_ex->e_type != ET_EXEC && 42331e31b8aSbellard interp_elf_ex->e_type != ET_DYN) || 42431e31b8aSbellard !elf_check_arch(interp_elf_ex->e_machine)) { 42531e31b8aSbellard return ~0UL; 42631e31b8aSbellard } 42731e31b8aSbellard 428*644c433cSbellard 42931e31b8aSbellard /* Now read in all of the header information */ 43031e31b8aSbellard 43131e31b8aSbellard if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) 43231e31b8aSbellard return ~0UL; 43331e31b8aSbellard 43431e31b8aSbellard elf_phdata = (struct elf_phdr *) 43531e31b8aSbellard malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 43631e31b8aSbellard 43731e31b8aSbellard if (!elf_phdata) 43831e31b8aSbellard return ~0UL; 43931e31b8aSbellard 44031e31b8aSbellard /* 44131e31b8aSbellard * If the size of this structure has changed, then punt, since 44231e31b8aSbellard * we will be doing the wrong thing. 44331e31b8aSbellard */ 44431e31b8aSbellard if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) 44531e31b8aSbellard { 44631e31b8aSbellard free(elf_phdata); 44731e31b8aSbellard return ~0UL; 44831e31b8aSbellard } 44931e31b8aSbellard 45031e31b8aSbellard retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); 45131e31b8aSbellard if(retval >= 0) { 45231e31b8aSbellard retval = read(interpreter_fd, 45331e31b8aSbellard (char *) elf_phdata, 45431e31b8aSbellard sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 45531e31b8aSbellard } 45631e31b8aSbellard if (retval < 0) { 45731e31b8aSbellard perror("load_elf_interp"); 45831e31b8aSbellard exit(-1); 45931e31b8aSbellard free (elf_phdata); 46031e31b8aSbellard return retval; 46131e31b8aSbellard } 46231e31b8aSbellard #ifdef BSWAP_NEEDED 46331e31b8aSbellard eppnt = elf_phdata; 46431e31b8aSbellard for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { 46531e31b8aSbellard bswap_phdr(eppnt); 46631e31b8aSbellard } 46731e31b8aSbellard #endif 46831e31b8aSbellard eppnt = elf_phdata; 46931e31b8aSbellard for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) 47031e31b8aSbellard if (eppnt->p_type == PT_LOAD) { 47131e31b8aSbellard int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 47231e31b8aSbellard int elf_prot = 0; 47331e31b8aSbellard unsigned long vaddr = 0; 47431e31b8aSbellard unsigned long k; 47531e31b8aSbellard 47631e31b8aSbellard if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; 47731e31b8aSbellard if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 47831e31b8aSbellard if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 47931e31b8aSbellard if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { 48031e31b8aSbellard elf_type |= MAP_FIXED; 48131e31b8aSbellard vaddr = eppnt->p_vaddr; 48231e31b8aSbellard } 48331e31b8aSbellard error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr), 48431e31b8aSbellard eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr), 48531e31b8aSbellard elf_prot, 48631e31b8aSbellard elf_type, 48731e31b8aSbellard interpreter_fd, 48831e31b8aSbellard eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr)); 48931e31b8aSbellard 49031e31b8aSbellard if (error > -1024UL) { 49131e31b8aSbellard /* Real error */ 49231e31b8aSbellard close(interpreter_fd); 49331e31b8aSbellard free(elf_phdata); 49431e31b8aSbellard return ~0UL; 49531e31b8aSbellard } 49631e31b8aSbellard 49731e31b8aSbellard if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { 49831e31b8aSbellard load_addr = error; 49931e31b8aSbellard load_addr_set = 1; 50031e31b8aSbellard } 50131e31b8aSbellard 50231e31b8aSbellard /* 50331e31b8aSbellard * Find the end of the file mapping for this phdr, and keep 50431e31b8aSbellard * track of the largest address we see for this. 50531e31b8aSbellard */ 50631e31b8aSbellard k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 50731e31b8aSbellard if (k > elf_bss) elf_bss = k; 50831e31b8aSbellard 50931e31b8aSbellard /* 51031e31b8aSbellard * Do the same thing for the memory mapping - between 51131e31b8aSbellard * elf_bss and last_bss is the bss section. 51231e31b8aSbellard */ 51331e31b8aSbellard k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 51431e31b8aSbellard if (k > last_bss) last_bss = k; 51531e31b8aSbellard } 51631e31b8aSbellard 51731e31b8aSbellard /* Now use mmap to map the library into memory. */ 51831e31b8aSbellard 51931e31b8aSbellard close(interpreter_fd); 52031e31b8aSbellard 52131e31b8aSbellard /* 52231e31b8aSbellard * Now fill out the bss section. First pad the last page up 52331e31b8aSbellard * to the page boundary, and then perform a mmap to make sure 52431e31b8aSbellard * that there are zeromapped pages up to and including the last 52531e31b8aSbellard * bss page. 52631e31b8aSbellard */ 52731e31b8aSbellard padzero(elf_bss); 52831e31b8aSbellard elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */ 52931e31b8aSbellard 53031e31b8aSbellard /* Map the last of the bss segment */ 53131e31b8aSbellard if (last_bss > elf_bss) { 53231e31b8aSbellard mmap4k(elf_bss, last_bss-elf_bss, 53331e31b8aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 53431e31b8aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 53531e31b8aSbellard } 53631e31b8aSbellard free(elf_phdata); 53731e31b8aSbellard 53831e31b8aSbellard *interp_load_addr = load_addr; 53931e31b8aSbellard return ((unsigned long) interp_elf_ex->e_entry) + load_addr; 54031e31b8aSbellard } 54131e31b8aSbellard 54231e31b8aSbellard 54331e31b8aSbellard 544b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 54531e31b8aSbellard struct image_info * info) 54631e31b8aSbellard { 54731e31b8aSbellard struct elfhdr elf_ex; 54831e31b8aSbellard struct elfhdr interp_elf_ex; 54931e31b8aSbellard struct exec interp_ex; 55031e31b8aSbellard int interpreter_fd = -1; /* avoid warning */ 55131e31b8aSbellard unsigned long load_addr; 55231e31b8aSbellard int load_addr_set = 0; 55331e31b8aSbellard unsigned int interpreter_type = INTERPRETER_NONE; 55431e31b8aSbellard unsigned char ibcs2_interpreter; 55531e31b8aSbellard int i; 55631e31b8aSbellard void * mapped_addr; 55731e31b8aSbellard struct elf_phdr * elf_ppnt; 55831e31b8aSbellard struct elf_phdr *elf_phdata; 55931e31b8aSbellard unsigned long elf_bss, k, elf_brk; 56031e31b8aSbellard int retval; 56131e31b8aSbellard char * elf_interpreter; 56231e31b8aSbellard unsigned long elf_entry, interp_load_addr = 0; 56331e31b8aSbellard int status; 56431e31b8aSbellard unsigned long start_code, end_code, end_data; 56531e31b8aSbellard unsigned long elf_stack; 56631e31b8aSbellard char passed_fileno[6]; 56731e31b8aSbellard 56831e31b8aSbellard ibcs2_interpreter = 0; 56931e31b8aSbellard status = 0; 57031e31b8aSbellard load_addr = 0; 57131e31b8aSbellard elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ 57231e31b8aSbellard #ifdef BSWAP_NEEDED 57331e31b8aSbellard bswap_ehdr(&elf_ex); 57431e31b8aSbellard #endif 57531e31b8aSbellard 57631e31b8aSbellard if (elf_ex.e_ident[0] != 0x7f || 57731e31b8aSbellard strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { 57831e31b8aSbellard return -ENOEXEC; 57931e31b8aSbellard } 58031e31b8aSbellard 58131e31b8aSbellard /* First of all, some simple consistency checks */ 58231e31b8aSbellard if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 58331e31b8aSbellard (! elf_check_arch(elf_ex.e_machine))) { 58431e31b8aSbellard return -ENOEXEC; 58531e31b8aSbellard } 58631e31b8aSbellard 58731e31b8aSbellard /* Now read in all of the header information */ 58831e31b8aSbellard 58931e31b8aSbellard elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); 59031e31b8aSbellard if (elf_phdata == NULL) { 59131e31b8aSbellard return -ENOMEM; 59231e31b8aSbellard } 59331e31b8aSbellard 59431e31b8aSbellard retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); 59531e31b8aSbellard if(retval > 0) { 59631e31b8aSbellard retval = read(bprm->fd, (char *) elf_phdata, 59731e31b8aSbellard elf_ex.e_phentsize * elf_ex.e_phnum); 59831e31b8aSbellard } 59931e31b8aSbellard 60031e31b8aSbellard if (retval < 0) { 60131e31b8aSbellard perror("load_elf_binary"); 60231e31b8aSbellard exit(-1); 60331e31b8aSbellard free (elf_phdata); 60431e31b8aSbellard return -errno; 60531e31b8aSbellard } 60631e31b8aSbellard 607b17780d5Sbellard #ifdef BSWAP_NEEDED 608b17780d5Sbellard elf_ppnt = elf_phdata; 609b17780d5Sbellard for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { 610b17780d5Sbellard bswap_phdr(elf_ppnt); 611b17780d5Sbellard } 612b17780d5Sbellard #endif 61331e31b8aSbellard elf_ppnt = elf_phdata; 61431e31b8aSbellard 61531e31b8aSbellard elf_bss = 0; 61631e31b8aSbellard elf_brk = 0; 61731e31b8aSbellard 61831e31b8aSbellard 61931e31b8aSbellard elf_stack = ~0UL; 62031e31b8aSbellard elf_interpreter = NULL; 62131e31b8aSbellard start_code = ~0UL; 62231e31b8aSbellard end_code = 0; 62331e31b8aSbellard end_data = 0; 62431e31b8aSbellard 62531e31b8aSbellard for(i=0;i < elf_ex.e_phnum; i++) { 62631e31b8aSbellard if (elf_ppnt->p_type == PT_INTERP) { 62731e31b8aSbellard if ( elf_interpreter != NULL ) 62831e31b8aSbellard { 62931e31b8aSbellard free (elf_phdata); 63031e31b8aSbellard free(elf_interpreter); 63131e31b8aSbellard close(bprm->fd); 63231e31b8aSbellard return -EINVAL; 63331e31b8aSbellard } 63431e31b8aSbellard 63531e31b8aSbellard /* This is the program interpreter used for 63631e31b8aSbellard * shared libraries - for now assume that this 63731e31b8aSbellard * is an a.out format binary 63831e31b8aSbellard */ 63931e31b8aSbellard 640d691f669Sbellard elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+ 641d691f669Sbellard strlen(bprm->interp_prefix)); 64231e31b8aSbellard 64331e31b8aSbellard if (elf_interpreter == NULL) { 64431e31b8aSbellard free (elf_phdata); 64531e31b8aSbellard close(bprm->fd); 64631e31b8aSbellard return -ENOMEM; 64731e31b8aSbellard } 64831e31b8aSbellard 649d691f669Sbellard strcpy(elf_interpreter, bprm->interp_prefix); 65031e31b8aSbellard retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); 65131e31b8aSbellard if(retval >= 0) { 65231e31b8aSbellard retval = read(bprm->fd, 653d691f669Sbellard elf_interpreter+strlen(bprm->interp_prefix), 65431e31b8aSbellard elf_ppnt->p_filesz); 65531e31b8aSbellard } 65631e31b8aSbellard if(retval < 0) { 65731e31b8aSbellard perror("load_elf_binary2"); 65831e31b8aSbellard exit(-1); 65931e31b8aSbellard } 66031e31b8aSbellard 66131e31b8aSbellard /* If the program interpreter is one of these two, 66231e31b8aSbellard then assume an iBCS2 image. Otherwise assume 66331e31b8aSbellard a native linux image. */ 66431e31b8aSbellard 66531e31b8aSbellard /* JRP - Need to add X86 lib dir stuff here... */ 66631e31b8aSbellard 66731e31b8aSbellard if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || 66831e31b8aSbellard strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { 66931e31b8aSbellard ibcs2_interpreter = 1; 67031e31b8aSbellard } 67131e31b8aSbellard 67231e31b8aSbellard #if 0 67331e31b8aSbellard printf("Using ELF interpreter %s\n", elf_interpreter); 67431e31b8aSbellard #endif 67531e31b8aSbellard if (retval >= 0) { 67631e31b8aSbellard retval = open(elf_interpreter, O_RDONLY); 67731e31b8aSbellard if(retval >= 0) { 67831e31b8aSbellard interpreter_fd = retval; 67931e31b8aSbellard } 68031e31b8aSbellard else { 68131e31b8aSbellard perror(elf_interpreter); 68231e31b8aSbellard exit(-1); 68331e31b8aSbellard /* retval = -errno; */ 68431e31b8aSbellard } 68531e31b8aSbellard } 68631e31b8aSbellard 68731e31b8aSbellard if (retval >= 0) { 68831e31b8aSbellard retval = lseek(interpreter_fd, 0, SEEK_SET); 68931e31b8aSbellard if(retval >= 0) { 69031e31b8aSbellard retval = read(interpreter_fd,bprm->buf,128); 69131e31b8aSbellard } 69231e31b8aSbellard } 69331e31b8aSbellard if (retval >= 0) { 69431e31b8aSbellard interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ 69531e31b8aSbellard interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ 69631e31b8aSbellard } 69731e31b8aSbellard if (retval < 0) { 69831e31b8aSbellard perror("load_elf_binary3"); 69931e31b8aSbellard exit(-1); 70031e31b8aSbellard free (elf_phdata); 70131e31b8aSbellard free(elf_interpreter); 70231e31b8aSbellard close(bprm->fd); 70331e31b8aSbellard return retval; 70431e31b8aSbellard } 70531e31b8aSbellard } 70631e31b8aSbellard elf_ppnt++; 70731e31b8aSbellard } 70831e31b8aSbellard 70931e31b8aSbellard /* Some simple consistency checks for the interpreter */ 71031e31b8aSbellard if (elf_interpreter){ 71131e31b8aSbellard interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; 71231e31b8aSbellard 71331e31b8aSbellard /* Now figure out which format our binary is */ 71431e31b8aSbellard if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && 71531e31b8aSbellard (N_MAGIC(interp_ex) != QMAGIC)) { 71631e31b8aSbellard interpreter_type = INTERPRETER_ELF; 71731e31b8aSbellard } 71831e31b8aSbellard 71931e31b8aSbellard if (interp_elf_ex.e_ident[0] != 0x7f || 72031e31b8aSbellard strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { 72131e31b8aSbellard interpreter_type &= ~INTERPRETER_ELF; 72231e31b8aSbellard } 72331e31b8aSbellard 72431e31b8aSbellard if (!interpreter_type) { 72531e31b8aSbellard free(elf_interpreter); 72631e31b8aSbellard free(elf_phdata); 72731e31b8aSbellard close(bprm->fd); 72831e31b8aSbellard return -ELIBBAD; 72931e31b8aSbellard } 73031e31b8aSbellard } 73131e31b8aSbellard 73231e31b8aSbellard /* OK, we are done with that, now set up the arg stuff, 73331e31b8aSbellard and then start this sucker up */ 73431e31b8aSbellard 73531e31b8aSbellard if (!bprm->sh_bang) { 73631e31b8aSbellard char * passed_p; 73731e31b8aSbellard 73831e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) { 73931e31b8aSbellard sprintf(passed_fileno, "%d", bprm->fd); 74031e31b8aSbellard passed_p = passed_fileno; 74131e31b8aSbellard 74231e31b8aSbellard if (elf_interpreter) { 74331e31b8aSbellard bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); 74431e31b8aSbellard bprm->argc++; 74531e31b8aSbellard } 74631e31b8aSbellard } 74731e31b8aSbellard if (!bprm->p) { 74831e31b8aSbellard if (elf_interpreter) { 74931e31b8aSbellard free(elf_interpreter); 75031e31b8aSbellard } 75131e31b8aSbellard free (elf_phdata); 75231e31b8aSbellard close(bprm->fd); 75331e31b8aSbellard return -E2BIG; 75431e31b8aSbellard } 75531e31b8aSbellard } 75631e31b8aSbellard 75731e31b8aSbellard /* OK, This is the point of no return */ 75831e31b8aSbellard info->end_data = 0; 75931e31b8aSbellard info->end_code = 0; 76031e31b8aSbellard info->start_mmap = (unsigned long)ELF_START_MMAP; 76131e31b8aSbellard info->mmap = 0; 76231e31b8aSbellard elf_entry = (unsigned long) elf_ex.e_entry; 76331e31b8aSbellard 76431e31b8aSbellard /* Do this so that we can load the interpreter, if need be. We will 76531e31b8aSbellard change some of these later */ 76631e31b8aSbellard info->rss = 0; 76731e31b8aSbellard bprm->p = setup_arg_pages(bprm->p, bprm, info); 76831e31b8aSbellard info->start_stack = bprm->p; 76931e31b8aSbellard 77031e31b8aSbellard /* Now we do a little grungy work by mmaping the ELF image into 77131e31b8aSbellard * the correct location in memory. At this point, we assume that 77231e31b8aSbellard * the image should be loaded at fixed address, not at a variable 77331e31b8aSbellard * address. 77431e31b8aSbellard */ 77531e31b8aSbellard 77631e31b8aSbellard 77731e31b8aSbellard 77831e31b8aSbellard for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { 77931e31b8aSbellard if (elf_ppnt->p_type == PT_LOAD) { 78031e31b8aSbellard int elf_prot = 0; 78131e31b8aSbellard if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; 78231e31b8aSbellard if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 78331e31b8aSbellard if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 78431e31b8aSbellard 78531e31b8aSbellard mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr), 78631e31b8aSbellard (elf_ppnt->p_filesz + 78731e31b8aSbellard X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), 78831e31b8aSbellard elf_prot, 78931e31b8aSbellard (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), 79031e31b8aSbellard bprm->fd, 79131e31b8aSbellard (elf_ppnt->p_offset - 79231e31b8aSbellard X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); 79331e31b8aSbellard 79431e31b8aSbellard if((unsigned long)mapped_addr == 0xffffffffffffffff) { 79531e31b8aSbellard perror("mmap"); 79631e31b8aSbellard exit(-1); 79731e31b8aSbellard } 79831e31b8aSbellard 79931e31b8aSbellard 80031e31b8aSbellard 80131e31b8aSbellard #ifdef LOW_ELF_STACK 80231e31b8aSbellard if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 80331e31b8aSbellard elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); 80431e31b8aSbellard #endif 80531e31b8aSbellard 80631e31b8aSbellard if (!load_addr_set) { 80731e31b8aSbellard load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; 80831e31b8aSbellard load_addr_set = 1; 80931e31b8aSbellard } 81031e31b8aSbellard k = elf_ppnt->p_vaddr; 81131e31b8aSbellard if (k < start_code) start_code = k; 81231e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 81331e31b8aSbellard if (k > elf_bss) elf_bss = k; 81431e31b8aSbellard #if 1 81531e31b8aSbellard if ((elf_ppnt->p_flags & PF_X) && end_code < k) 81631e31b8aSbellard #else 81731e31b8aSbellard if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) 81831e31b8aSbellard #endif 81931e31b8aSbellard end_code = k; 82031e31b8aSbellard if (end_data < k) end_data = k; 82131e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 82231e31b8aSbellard if (k > elf_brk) elf_brk = k; 82331e31b8aSbellard } 82431e31b8aSbellard } 82531e31b8aSbellard 82631e31b8aSbellard if (elf_interpreter) { 82731e31b8aSbellard if (interpreter_type & 1) { 82831e31b8aSbellard elf_entry = load_aout_interp(&interp_ex, interpreter_fd); 82931e31b8aSbellard } 83031e31b8aSbellard else if (interpreter_type & 2) { 83131e31b8aSbellard elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, 83231e31b8aSbellard &interp_load_addr); 83331e31b8aSbellard } 83431e31b8aSbellard 83531e31b8aSbellard close(interpreter_fd); 83631e31b8aSbellard free(elf_interpreter); 83731e31b8aSbellard 83831e31b8aSbellard if (elf_entry == ~0UL) { 83931e31b8aSbellard printf("Unable to load interpreter\n"); 84031e31b8aSbellard free(elf_phdata); 84131e31b8aSbellard exit(-1); 84231e31b8aSbellard return 0; 84331e31b8aSbellard } 84431e31b8aSbellard } 84531e31b8aSbellard 84631e31b8aSbellard free(elf_phdata); 84731e31b8aSbellard 84831e31b8aSbellard if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); 84931e31b8aSbellard info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); 85031e31b8aSbellard 85131e31b8aSbellard #ifdef LOW_ELF_STACK 85231e31b8aSbellard info->start_stack = bprm->p = elf_stack - 4; 85331e31b8aSbellard #endif 85431e31b8aSbellard bprm->p = (unsigned long) 85531e31b8aSbellard create_elf_tables((char *)bprm->p, 85631e31b8aSbellard bprm->argc, 85731e31b8aSbellard bprm->envc, 85831e31b8aSbellard (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), 85931e31b8aSbellard load_addr, 86031e31b8aSbellard interp_load_addr, 86131e31b8aSbellard (interpreter_type == INTERPRETER_AOUT ? 0 : 1), 86231e31b8aSbellard info); 86331e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) 86431e31b8aSbellard info->arg_start += strlen(passed_fileno) + 1; 86531e31b8aSbellard info->start_brk = info->brk = elf_brk; 86631e31b8aSbellard info->end_code = end_code; 86731e31b8aSbellard info->start_code = start_code; 86831e31b8aSbellard info->end_data = end_data; 86931e31b8aSbellard info->start_stack = bprm->p; 87031e31b8aSbellard 87131e31b8aSbellard /* Calling set_brk effectively mmaps the pages that we need for the bss and break 87231e31b8aSbellard sections */ 87331e31b8aSbellard set_brk(elf_bss, elf_brk); 87431e31b8aSbellard 87531e31b8aSbellard padzero(elf_bss); 87631e31b8aSbellard 87731e31b8aSbellard #if 0 87831e31b8aSbellard printf("(start_brk) %x\n" , info->start_brk); 87931e31b8aSbellard printf("(end_code) %x\n" , info->end_code); 88031e31b8aSbellard printf("(start_code) %x\n" , info->start_code); 88131e31b8aSbellard printf("(end_data) %x\n" , info->end_data); 88231e31b8aSbellard printf("(start_stack) %x\n" , info->start_stack); 88331e31b8aSbellard printf("(brk) %x\n" , info->brk); 88431e31b8aSbellard #endif 88531e31b8aSbellard 88631e31b8aSbellard if ( info->personality == PER_SVR4 ) 88731e31b8aSbellard { 88831e31b8aSbellard /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 88931e31b8aSbellard and some applications "depend" upon this behavior. 89031e31b8aSbellard Since we do not have the power to recompile these, we 89131e31b8aSbellard emulate the SVr4 behavior. Sigh. */ 89231e31b8aSbellard mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC, 89331e31b8aSbellard MAP_FIXED | MAP_PRIVATE, -1, 0); 89431e31b8aSbellard } 89531e31b8aSbellard 89631e31b8aSbellard #ifdef ELF_PLAT_INIT 89731e31b8aSbellard /* 89831e31b8aSbellard * The ABI may specify that certain registers be set up in special 89931e31b8aSbellard * ways (on i386 %edx is the address of a DT_FINI function, for 90031e31b8aSbellard * example. This macro performs whatever initialization to 90131e31b8aSbellard * the regs structure is required. 90231e31b8aSbellard */ 90331e31b8aSbellard ELF_PLAT_INIT(regs); 90431e31b8aSbellard #endif 90531e31b8aSbellard 90631e31b8aSbellard 90731e31b8aSbellard info->entry = elf_entry; 90831e31b8aSbellard 90931e31b8aSbellard return 0; 91031e31b8aSbellard } 91131e31b8aSbellard 91231e31b8aSbellard 91331e31b8aSbellard 914d691f669Sbellard int elf_exec(const char *interp_prefix, 915d691f669Sbellard const char * filename, char ** argv, char ** envp, 916b17780d5Sbellard struct target_pt_regs * regs, struct image_info *infop) 91731e31b8aSbellard { 91831e31b8aSbellard struct linux_binprm bprm; 91931e31b8aSbellard int retval; 92031e31b8aSbellard int i; 92131e31b8aSbellard 92231e31b8aSbellard bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); 92331e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ 92431e31b8aSbellard bprm.page[i] = 0; 92531e31b8aSbellard retval = open(filename, O_RDONLY); 92631e31b8aSbellard if (retval == -1) { 92731e31b8aSbellard perror(filename); 92831e31b8aSbellard exit(-1); 92931e31b8aSbellard /* return retval; */ 93031e31b8aSbellard } 93131e31b8aSbellard else { 93231e31b8aSbellard bprm.fd = retval; 93331e31b8aSbellard } 934d691f669Sbellard bprm.interp_prefix = (char *)interp_prefix; 93531e31b8aSbellard bprm.filename = (char *)filename; 93631e31b8aSbellard bprm.sh_bang = 0; 93731e31b8aSbellard bprm.loader = 0; 93831e31b8aSbellard bprm.exec = 0; 93931e31b8aSbellard bprm.dont_iput = 0; 94031e31b8aSbellard bprm.argc = count(argv); 94131e31b8aSbellard bprm.envc = count(envp); 94231e31b8aSbellard 94331e31b8aSbellard retval = prepare_binprm(&bprm); 94431e31b8aSbellard 94531e31b8aSbellard if(retval>=0) { 94631e31b8aSbellard bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); 94731e31b8aSbellard bprm.exec = bprm.p; 94831e31b8aSbellard bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); 94931e31b8aSbellard bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); 95031e31b8aSbellard if (!bprm.p) { 95131e31b8aSbellard retval = -E2BIG; 95231e31b8aSbellard } 95331e31b8aSbellard } 95431e31b8aSbellard 95531e31b8aSbellard if(retval>=0) { 95631e31b8aSbellard retval = load_elf_binary(&bprm,regs,infop); 95731e31b8aSbellard } 95831e31b8aSbellard if(retval>=0) { 95931e31b8aSbellard /* success. Initialize important registers */ 96031e31b8aSbellard regs->esp = infop->start_stack; 96131e31b8aSbellard regs->eip = infop->entry; 96231e31b8aSbellard return retval; 96331e31b8aSbellard } 96431e31b8aSbellard 96531e31b8aSbellard /* Something went wrong, return the inode and free the argument pages*/ 96631e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) { 96731e31b8aSbellard free_page((void *)bprm.page[i]); 96831e31b8aSbellard } 96931e31b8aSbellard return(retval); 97031e31b8aSbellard } 97131e31b8aSbellard 97231e31b8aSbellard 97331e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd) 97431e31b8aSbellard { 97531e31b8aSbellard printf("a.out interpreter not yet supported\n"); 97631e31b8aSbellard return(0); 97731e31b8aSbellard } 97831e31b8aSbellard 979