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 1530ac07d4Sbellard #ifdef TARGET_I386 1630ac07d4Sbellard 1730ac07d4Sbellard #define ELF_START_MMAP 0x80000000 1830ac07d4Sbellard 1930ac07d4Sbellard typedef uint32_t elf_greg_t; 2030ac07d4Sbellard 2130ac07d4Sbellard #define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t)) 2230ac07d4Sbellard typedef elf_greg_t elf_gregset_t[ELF_NGREG]; 2330ac07d4Sbellard 2430ac07d4Sbellard typedef struct user_i387_struct elf_fpregset_t; 2530ac07d4Sbellard 2630ac07d4Sbellard /* 2730ac07d4Sbellard * This is used to ensure we don't load something for the wrong architecture. 2830ac07d4Sbellard */ 2930ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) 3030ac07d4Sbellard 3130ac07d4Sbellard /* 3230ac07d4Sbellard * These are used to set parameters in the core dumps. 3330ac07d4Sbellard */ 3430ac07d4Sbellard #define ELF_CLASS ELFCLASS32 3530ac07d4Sbellard #define ELF_DATA ELFDATA2LSB 3630ac07d4Sbellard #define ELF_ARCH EM_386 3730ac07d4Sbellard 3830ac07d4Sbellard /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program 3930ac07d4Sbellard starts %edx contains a pointer to a function which might be 4030ac07d4Sbellard registered using `atexit'. This provides a mean for the 4130ac07d4Sbellard dynamic linker to call DT_FINI functions for shared libraries 4230ac07d4Sbellard that have been loaded before the code runs. 4330ac07d4Sbellard 4430ac07d4Sbellard A value of 0 tells we have no such handler. */ 4530ac07d4Sbellard #define ELF_PLAT_INIT(_r) _r->edx = 0 4630ac07d4Sbellard 4730ac07d4Sbellard #define USE_ELF_CORE_DUMP 4830ac07d4Sbellard #define ELF_EXEC_PAGESIZE 4096 4930ac07d4Sbellard 5030ac07d4Sbellard #endif 5130ac07d4Sbellard 5231e31b8aSbellard #include "elf.h" 5309bfb054Sbellard 5409bfb054Sbellard /* 5509bfb054Sbellard * MAX_ARG_PAGES defines the number of pages allocated for arguments 5609bfb054Sbellard * and envelope for the new program. 32 should suffice, this gives 5709bfb054Sbellard * a maximum env+arg of 128kB w/4KB pages! 5809bfb054Sbellard */ 5909bfb054Sbellard #define MAX_ARG_PAGES 32 6009bfb054Sbellard 6109bfb054Sbellard /* 6209bfb054Sbellard * This structure is used to hold the arguments that are 6309bfb054Sbellard * used when loading binaries. 6409bfb054Sbellard */ 6509bfb054Sbellard struct linux_binprm { 6609bfb054Sbellard char buf[128]; 6709bfb054Sbellard unsigned long page[MAX_ARG_PAGES]; 6809bfb054Sbellard unsigned long p; 6909bfb054Sbellard int sh_bang; 7009bfb054Sbellard int fd; 7109bfb054Sbellard int e_uid, e_gid; 7209bfb054Sbellard int argc, envc; 7309bfb054Sbellard char * filename; /* Name of binary */ 7409bfb054Sbellard unsigned long loader, exec; 7509bfb054Sbellard int dont_iput; /* binfmt handler has put inode */ 7609bfb054Sbellard }; 7709bfb054Sbellard 7809bfb054Sbellard struct exec 7909bfb054Sbellard { 8009bfb054Sbellard unsigned int a_info; /* Use macros N_MAGIC, etc for access */ 8109bfb054Sbellard unsigned int a_text; /* length of text, in bytes */ 8209bfb054Sbellard unsigned int a_data; /* length of data, in bytes */ 8309bfb054Sbellard unsigned int a_bss; /* length of uninitialized data area, in bytes */ 8409bfb054Sbellard unsigned int a_syms; /* length of symbol table data in file, in bytes */ 8509bfb054Sbellard unsigned int a_entry; /* start address */ 8609bfb054Sbellard unsigned int a_trsize; /* length of relocation info for text, in bytes */ 8709bfb054Sbellard unsigned int a_drsize; /* length of relocation info for data, in bytes */ 8809bfb054Sbellard }; 8909bfb054Sbellard 9009bfb054Sbellard 9109bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff) 9209bfb054Sbellard #define OMAGIC 0407 9309bfb054Sbellard #define NMAGIC 0410 9409bfb054Sbellard #define ZMAGIC 0413 9509bfb054Sbellard #define QMAGIC 0314 9609bfb054Sbellard 9709bfb054Sbellard #define X86_STACK_TOP 0x7d000000 9809bfb054Sbellard 9909bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */ 10009bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024) 10109bfb054Sbellard 10209bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */ 10309bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) 10409bfb054Sbellard 10509bfb054Sbellard /* from personality.h */ 10609bfb054Sbellard 10709bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */ 10809bfb054Sbellard #define STICKY_TIMEOUTS 0x4000000 10909bfb054Sbellard #define WHOLE_SECONDS 0x2000000 11009bfb054Sbellard 11109bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit, 11209bfb054Sbellard * it will conflict with error returns. 11309bfb054Sbellard */ 11409bfb054Sbellard #define PER_MASK (0x00ff) 11509bfb054Sbellard #define PER_LINUX (0x0000) 11609bfb054Sbellard #define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) 11709bfb054Sbellard #define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) 11809bfb054Sbellard #define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) 11909bfb054Sbellard #define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) 12009bfb054Sbellard #define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) 12109bfb054Sbellard #define PER_BSD (0x0006) 12209bfb054Sbellard #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) 12331e31b8aSbellard 12431e31b8aSbellard /* Necessary parameters */ 12531e31b8aSbellard #define ALPHA_PAGE_SIZE 4096 12631e31b8aSbellard #define X86_PAGE_SIZE 4096 12731e31b8aSbellard 12831e31b8aSbellard #define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1)) 12931e31b8aSbellard #define X86_PAGE_MASK (~(X86_PAGE_SIZE-1)) 13031e31b8aSbellard 13131e31b8aSbellard #define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK) 13231e31b8aSbellard #define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK) 13331e31b8aSbellard 13431e31b8aSbellard #define NGROUPS 32 13531e31b8aSbellard 13631e31b8aSbellard #define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE 13731e31b8aSbellard #define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1)) 13831e31b8aSbellard #define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1)) 13931e31b8aSbellard 14031e31b8aSbellard #define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1)) 14131e31b8aSbellard #define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1)) 14231e31b8aSbellard 14331e31b8aSbellard #define INTERPRETER_NONE 0 14431e31b8aSbellard #define INTERPRETER_AOUT 1 14531e31b8aSbellard #define INTERPRETER_ELF 2 14631e31b8aSbellard 14731e31b8aSbellard #define DLINFO_ITEMS 12 14831e31b8aSbellard 14909bfb054Sbellard #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) 15009bfb054Sbellard #define get_user(ptr) (typeof(*ptr))(*(ptr)) 151d691f669Sbellard 15209bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) 15309bfb054Sbellard { 15409bfb054Sbellard memcpy(to, from, n); 15509bfb054Sbellard } 15609bfb054Sbellard 15709bfb054Sbellard static inline void memcpy_tofs(void * to, const void * from, unsigned long n) 15809bfb054Sbellard { 15909bfb054Sbellard memcpy(to, from, n); 16009bfb054Sbellard } 16131e31b8aSbellard 16231e31b8aSbellard //extern void * mmap4k(); 16331e31b8aSbellard #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) 16431e31b8aSbellard 16531e31b8aSbellard extern unsigned long x86_stack_size; 16631e31b8aSbellard 16731e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd); 16831e31b8aSbellard 16931e31b8aSbellard #ifdef BSWAP_NEEDED 17031e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr) 17131e31b8aSbellard { 17231e31b8aSbellard bswap16s(&ehdr->e_type); /* Object file type */ 17331e31b8aSbellard bswap16s(&ehdr->e_machine); /* Architecture */ 17431e31b8aSbellard bswap32s(&ehdr->e_version); /* Object file version */ 17531e31b8aSbellard bswap32s(&ehdr->e_entry); /* Entry point virtual address */ 17631e31b8aSbellard bswap32s(&ehdr->e_phoff); /* Program header table file offset */ 17731e31b8aSbellard bswap32s(&ehdr->e_shoff); /* Section header table file offset */ 17831e31b8aSbellard bswap32s(&ehdr->e_flags); /* Processor-specific flags */ 17931e31b8aSbellard bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ 18031e31b8aSbellard bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ 18131e31b8aSbellard bswap16s(&ehdr->e_phnum); /* Program header table entry count */ 18231e31b8aSbellard bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ 18331e31b8aSbellard bswap16s(&ehdr->e_shnum); /* Section header table entry count */ 18431e31b8aSbellard bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ 18531e31b8aSbellard } 18631e31b8aSbellard 18731e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr) 18831e31b8aSbellard { 18931e31b8aSbellard bswap32s(&phdr->p_type); /* Segment type */ 19031e31b8aSbellard bswap32s(&phdr->p_offset); /* Segment file offset */ 19131e31b8aSbellard bswap32s(&phdr->p_vaddr); /* Segment virtual address */ 19231e31b8aSbellard bswap32s(&phdr->p_paddr); /* Segment physical address */ 19331e31b8aSbellard bswap32s(&phdr->p_filesz); /* Segment size in file */ 19431e31b8aSbellard bswap32s(&phdr->p_memsz); /* Segment size in memory */ 19531e31b8aSbellard bswap32s(&phdr->p_flags); /* Segment flags */ 19631e31b8aSbellard bswap32s(&phdr->p_align); /* Segment alignment */ 19731e31b8aSbellard } 19831e31b8aSbellard #endif 19931e31b8aSbellard 20031e31b8aSbellard static void * get_free_page(void) 20131e31b8aSbellard { 20231e31b8aSbellard void * retval; 20331e31b8aSbellard 20431e31b8aSbellard /* User-space version of kernel get_free_page. Returns a page-aligned 20531e31b8aSbellard * page-sized chunk of memory. 20631e31b8aSbellard */ 20731e31b8aSbellard retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE, 20831e31b8aSbellard MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 20931e31b8aSbellard 21031e31b8aSbellard if((long)retval == -1) { 21131e31b8aSbellard perror("get_free_page"); 21231e31b8aSbellard exit(-1); 21331e31b8aSbellard } 21431e31b8aSbellard else { 21531e31b8aSbellard return(retval); 21631e31b8aSbellard } 21731e31b8aSbellard } 21831e31b8aSbellard 21931e31b8aSbellard static void free_page(void * pageaddr) 22031e31b8aSbellard { 22131e31b8aSbellard (void)munmap(pageaddr, ALPHA_PAGE_SIZE); 22231e31b8aSbellard } 22331e31b8aSbellard 22431e31b8aSbellard /* 22531e31b8aSbellard * 'copy_string()' copies argument/envelope strings from user 22631e31b8aSbellard * memory to free pages in kernel mem. These are in a format ready 22731e31b8aSbellard * to be put directly into the top of new user memory. 22831e31b8aSbellard * 22931e31b8aSbellard */ 23031e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, 23131e31b8aSbellard unsigned long p) 23231e31b8aSbellard { 23331e31b8aSbellard char *tmp, *tmp1, *pag = NULL; 23431e31b8aSbellard int len, offset = 0; 23531e31b8aSbellard 23631e31b8aSbellard if (!p) { 23731e31b8aSbellard return 0; /* bullet-proofing */ 23831e31b8aSbellard } 23931e31b8aSbellard while (argc-- > 0) { 24031e31b8aSbellard if (!(tmp1 = tmp = get_user(argv+argc))) { 24131e31b8aSbellard fprintf(stderr, "VFS: argc is wrong"); 24231e31b8aSbellard exit(-1); 24331e31b8aSbellard } 24431e31b8aSbellard while (get_user(tmp++)); 24531e31b8aSbellard len = tmp - tmp1; 24631e31b8aSbellard if (p < len) { /* this shouldn't happen - 128kB */ 24731e31b8aSbellard return 0; 24831e31b8aSbellard } 24931e31b8aSbellard while (len) { 25031e31b8aSbellard --p; --tmp; --len; 25131e31b8aSbellard if (--offset < 0) { 25231e31b8aSbellard offset = p % X86_PAGE_SIZE; 25331e31b8aSbellard if (!(pag = (char *) page[p/X86_PAGE_SIZE]) && 25431e31b8aSbellard !(pag = (char *) page[p/X86_PAGE_SIZE] = 25531e31b8aSbellard (unsigned long *) get_free_page())) { 25631e31b8aSbellard return 0; 25731e31b8aSbellard } 25831e31b8aSbellard } 25931e31b8aSbellard if (len == 0 || offset == 0) { 26031e31b8aSbellard *(pag + offset) = get_user(tmp); 26131e31b8aSbellard } 26231e31b8aSbellard else { 26331e31b8aSbellard int bytes_to_copy = (len > offset) ? offset : len; 26431e31b8aSbellard tmp -= bytes_to_copy; 26531e31b8aSbellard p -= bytes_to_copy; 26631e31b8aSbellard offset -= bytes_to_copy; 26731e31b8aSbellard len -= bytes_to_copy; 26831e31b8aSbellard memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); 26931e31b8aSbellard } 27031e31b8aSbellard } 27131e31b8aSbellard } 27231e31b8aSbellard return p; 27331e31b8aSbellard } 27431e31b8aSbellard 27531e31b8aSbellard static int in_group_p(gid_t g) 27631e31b8aSbellard { 27731e31b8aSbellard /* return TRUE if we're in the specified group, FALSE otherwise */ 27831e31b8aSbellard int ngroup; 27931e31b8aSbellard int i; 28031e31b8aSbellard gid_t grouplist[NGROUPS]; 28131e31b8aSbellard 28231e31b8aSbellard ngroup = getgroups(NGROUPS, grouplist); 28331e31b8aSbellard for(i = 0; i < ngroup; i++) { 28431e31b8aSbellard if(grouplist[i] == g) { 28531e31b8aSbellard return 1; 28631e31b8aSbellard } 28731e31b8aSbellard } 28831e31b8aSbellard return 0; 28931e31b8aSbellard } 29031e31b8aSbellard 29131e31b8aSbellard static int count(char ** vec) 29231e31b8aSbellard { 29331e31b8aSbellard int i; 29431e31b8aSbellard 29531e31b8aSbellard for(i = 0; *vec; i++) { 29631e31b8aSbellard vec++; 29731e31b8aSbellard } 29831e31b8aSbellard 29931e31b8aSbellard return(i); 30031e31b8aSbellard } 30131e31b8aSbellard 30231e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm) 30331e31b8aSbellard { 30431e31b8aSbellard struct stat st; 30531e31b8aSbellard int mode; 30631e31b8aSbellard int retval, id_change; 30731e31b8aSbellard 30831e31b8aSbellard if(fstat(bprm->fd, &st) < 0) { 30931e31b8aSbellard return(-errno); 31031e31b8aSbellard } 31131e31b8aSbellard 31231e31b8aSbellard mode = st.st_mode; 31331e31b8aSbellard if(!S_ISREG(mode)) { /* Must be regular file */ 31431e31b8aSbellard return(-EACCES); 31531e31b8aSbellard } 31631e31b8aSbellard if(!(mode & 0111)) { /* Must have at least one execute bit set */ 31731e31b8aSbellard return(-EACCES); 31831e31b8aSbellard } 31931e31b8aSbellard 32031e31b8aSbellard bprm->e_uid = geteuid(); 32131e31b8aSbellard bprm->e_gid = getegid(); 32231e31b8aSbellard id_change = 0; 32331e31b8aSbellard 32431e31b8aSbellard /* Set-uid? */ 32531e31b8aSbellard if(mode & S_ISUID) { 32631e31b8aSbellard bprm->e_uid = st.st_uid; 32731e31b8aSbellard if(bprm->e_uid != geteuid()) { 32831e31b8aSbellard id_change = 1; 32931e31b8aSbellard } 33031e31b8aSbellard } 33131e31b8aSbellard 33231e31b8aSbellard /* Set-gid? */ 33331e31b8aSbellard /* 33431e31b8aSbellard * If setgid is set but no group execute bit then this 33531e31b8aSbellard * is a candidate for mandatory locking, not a setgid 33631e31b8aSbellard * executable. 33731e31b8aSbellard */ 33831e31b8aSbellard if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 33931e31b8aSbellard bprm->e_gid = st.st_gid; 34031e31b8aSbellard if (!in_group_p(bprm->e_gid)) { 34131e31b8aSbellard id_change = 1; 34231e31b8aSbellard } 34331e31b8aSbellard } 34431e31b8aSbellard 34531e31b8aSbellard memset(bprm->buf, 0, sizeof(bprm->buf)); 34631e31b8aSbellard retval = lseek(bprm->fd, 0L, SEEK_SET); 34731e31b8aSbellard if(retval >= 0) { 34831e31b8aSbellard retval = read(bprm->fd, bprm->buf, 128); 34931e31b8aSbellard } 35031e31b8aSbellard if(retval < 0) { 35131e31b8aSbellard perror("prepare_binprm"); 35231e31b8aSbellard exit(-1); 35331e31b8aSbellard /* return(-errno); */ 35431e31b8aSbellard } 35531e31b8aSbellard else { 35631e31b8aSbellard return(retval); 35731e31b8aSbellard } 35831e31b8aSbellard } 35931e31b8aSbellard 36031e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, 36131e31b8aSbellard struct image_info * info) 36231e31b8aSbellard { 36309bfb054Sbellard unsigned long stack_base, size, error; 36431e31b8aSbellard int i; 36531e31b8aSbellard 36631e31b8aSbellard /* Create enough stack to hold everything. If we don't use 36731e31b8aSbellard * it for args, we'll use it for something else... 36831e31b8aSbellard */ 36909bfb054Sbellard size = x86_stack_size; 37009bfb054Sbellard if (size < MAX_ARG_PAGES*X86_PAGE_SIZE) 37109bfb054Sbellard size = MAX_ARG_PAGES*X86_PAGE_SIZE; 37209bfb054Sbellard error = (unsigned long)mmap4k(NULL, 37309bfb054Sbellard size + X86_PAGE_SIZE, 37431e31b8aSbellard PROT_READ | PROT_WRITE, 37509bfb054Sbellard MAP_PRIVATE | MAP_ANONYMOUS, 37609bfb054Sbellard -1, 0); 37709bfb054Sbellard if (error == -1) { 37831e31b8aSbellard perror("stk mmap"); 37931e31b8aSbellard exit(-1); 38031e31b8aSbellard } 38109bfb054Sbellard /* we reserve one extra page at the top of the stack as guard */ 38209bfb054Sbellard mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE); 38331e31b8aSbellard 38409bfb054Sbellard stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE; 38509bfb054Sbellard p += stack_base; 38609bfb054Sbellard 38709bfb054Sbellard if (bprm->loader) { 38809bfb054Sbellard bprm->loader += stack_base; 38909bfb054Sbellard } 39009bfb054Sbellard bprm->exec += stack_base; 39131e31b8aSbellard 39231e31b8aSbellard for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 39331e31b8aSbellard if (bprm->page[i]) { 39431e31b8aSbellard info->rss++; 39531e31b8aSbellard 39631e31b8aSbellard memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE); 39731e31b8aSbellard free_page((void *)bprm->page[i]); 39831e31b8aSbellard } 39931e31b8aSbellard stack_base += X86_PAGE_SIZE; 40031e31b8aSbellard } 40131e31b8aSbellard return p; 40231e31b8aSbellard } 40331e31b8aSbellard 40431e31b8aSbellard static void set_brk(unsigned long start, unsigned long end) 40531e31b8aSbellard { 40631e31b8aSbellard /* page-align the start and end addresses... */ 40731e31b8aSbellard start = ALPHA_PAGE_ALIGN(start); 40831e31b8aSbellard end = ALPHA_PAGE_ALIGN(end); 40931e31b8aSbellard if (end <= start) 41031e31b8aSbellard return; 41131e31b8aSbellard if((long)mmap4k(start, end - start, 41231e31b8aSbellard PROT_READ | PROT_WRITE | PROT_EXEC, 41331e31b8aSbellard MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 41431e31b8aSbellard perror("cannot mmap brk"); 41531e31b8aSbellard exit(-1); 41631e31b8aSbellard } 41731e31b8aSbellard } 41831e31b8aSbellard 41931e31b8aSbellard 42031e31b8aSbellard /* We need to explicitly zero any fractional pages 42131e31b8aSbellard after the data section (i.e. bss). This would 42231e31b8aSbellard contain the junk from the file that should not 42331e31b8aSbellard be in memory */ 42431e31b8aSbellard 42531e31b8aSbellard 42631e31b8aSbellard static void padzero(unsigned long elf_bss) 42731e31b8aSbellard { 42831e31b8aSbellard unsigned long nbyte; 42931e31b8aSbellard char * fpnt; 43031e31b8aSbellard 43131e31b8aSbellard nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */ 43231e31b8aSbellard if (nbyte) { 43331e31b8aSbellard nbyte = ALPHA_PAGE_SIZE - nbyte; 43431e31b8aSbellard fpnt = (char *) elf_bss; 43531e31b8aSbellard do { 43631e31b8aSbellard *fpnt++ = 0; 43731e31b8aSbellard } while (--nbyte); 43831e31b8aSbellard } 43931e31b8aSbellard } 44031e31b8aSbellard 44131e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc, 44231e31b8aSbellard struct elfhdr * exec, 44331e31b8aSbellard unsigned long load_addr, 44409bfb054Sbellard unsigned long load_bias, 44531e31b8aSbellard unsigned long interp_load_addr, int ibcs, 44631e31b8aSbellard struct image_info *info) 44731e31b8aSbellard { 448b17780d5Sbellard target_ulong *argv, *envp, *dlinfo; 449b17780d5Sbellard target_ulong *sp; 45031e31b8aSbellard 45131e31b8aSbellard /* 45231e31b8aSbellard * Force 16 byte alignment here for generality. 45331e31b8aSbellard */ 45431e31b8aSbellard sp = (unsigned int *) (~15UL & (unsigned long) p); 45531e31b8aSbellard sp -= exec ? DLINFO_ITEMS*2 : 2; 45631e31b8aSbellard dlinfo = sp; 45731e31b8aSbellard sp -= envc+1; 45831e31b8aSbellard envp = sp; 45931e31b8aSbellard sp -= argc+1; 46031e31b8aSbellard argv = sp; 46131e31b8aSbellard if (!ibcs) { 462b17780d5Sbellard put_user(tswapl((target_ulong)envp),--sp); 463b17780d5Sbellard put_user(tswapl((target_ulong)argv),--sp); 46431e31b8aSbellard } 46531e31b8aSbellard 46631e31b8aSbellard #define NEW_AUX_ENT(id, val) \ 467b17780d5Sbellard put_user (tswapl(id), dlinfo++); \ 468b17780d5Sbellard put_user (tswapl(val), dlinfo++) 46931e31b8aSbellard 47031e31b8aSbellard if (exec) { /* Put this here for an ELF program interpreter */ 47109bfb054Sbellard NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); 47209bfb054Sbellard NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); 47309bfb054Sbellard NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); 47409bfb054Sbellard NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE)); 47509bfb054Sbellard NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); 47609bfb054Sbellard NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); 47709bfb054Sbellard NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); 47809bfb054Sbellard NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); 47909bfb054Sbellard NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); 48009bfb054Sbellard NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); 48109bfb054Sbellard NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); 48231e31b8aSbellard } 48331e31b8aSbellard NEW_AUX_ENT (AT_NULL, 0); 48431e31b8aSbellard #undef NEW_AUX_ENT 485b17780d5Sbellard put_user(tswapl(argc),--sp); 48631e31b8aSbellard info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); 48731e31b8aSbellard while (argc-->0) { 488b17780d5Sbellard put_user(tswapl((target_ulong)p),argv++); 48931e31b8aSbellard while (get_user(p++)) /* nothing */ ; 49031e31b8aSbellard } 49131e31b8aSbellard put_user(0,argv); 49231e31b8aSbellard info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); 49331e31b8aSbellard while (envc-->0) { 494b17780d5Sbellard put_user(tswapl((target_ulong)p),envp++); 49531e31b8aSbellard while (get_user(p++)) /* nothing */ ; 49631e31b8aSbellard } 49731e31b8aSbellard put_user(0,envp); 49831e31b8aSbellard info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); 49931e31b8aSbellard return sp; 50031e31b8aSbellard } 50131e31b8aSbellard 50231e31b8aSbellard 50331e31b8aSbellard 50431e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, 50531e31b8aSbellard int interpreter_fd, 50631e31b8aSbellard unsigned long *interp_load_addr) 50731e31b8aSbellard { 50831e31b8aSbellard struct elf_phdr *elf_phdata = NULL; 50931e31b8aSbellard struct elf_phdr *eppnt; 51009bfb054Sbellard unsigned long load_addr = 0; 51131e31b8aSbellard int load_addr_set = 0; 51231e31b8aSbellard int retval; 51331e31b8aSbellard unsigned long last_bss, elf_bss; 51431e31b8aSbellard unsigned long error; 51531e31b8aSbellard int i; 51631e31b8aSbellard 51731e31b8aSbellard elf_bss = 0; 51831e31b8aSbellard last_bss = 0; 51931e31b8aSbellard error = 0; 52031e31b8aSbellard 521644c433cSbellard #ifdef BSWAP_NEEDED 522644c433cSbellard bswap_ehdr(interp_elf_ex); 523644c433cSbellard #endif 52431e31b8aSbellard /* First of all, some simple consistency checks */ 52531e31b8aSbellard if ((interp_elf_ex->e_type != ET_EXEC && 52631e31b8aSbellard interp_elf_ex->e_type != ET_DYN) || 52731e31b8aSbellard !elf_check_arch(interp_elf_ex->e_machine)) { 52831e31b8aSbellard return ~0UL; 52931e31b8aSbellard } 53031e31b8aSbellard 531644c433cSbellard 53231e31b8aSbellard /* Now read in all of the header information */ 53331e31b8aSbellard 53431e31b8aSbellard if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) 53531e31b8aSbellard return ~0UL; 53631e31b8aSbellard 53731e31b8aSbellard elf_phdata = (struct elf_phdr *) 53831e31b8aSbellard malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 53931e31b8aSbellard 54031e31b8aSbellard if (!elf_phdata) 54131e31b8aSbellard return ~0UL; 54231e31b8aSbellard 54331e31b8aSbellard /* 54431e31b8aSbellard * If the size of this structure has changed, then punt, since 54531e31b8aSbellard * we will be doing the wrong thing. 54631e31b8aSbellard */ 54709bfb054Sbellard if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { 54831e31b8aSbellard free(elf_phdata); 54931e31b8aSbellard return ~0UL; 55031e31b8aSbellard } 55131e31b8aSbellard 55231e31b8aSbellard retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); 55331e31b8aSbellard if(retval >= 0) { 55431e31b8aSbellard retval = read(interpreter_fd, 55531e31b8aSbellard (char *) elf_phdata, 55631e31b8aSbellard sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 55731e31b8aSbellard } 55831e31b8aSbellard if (retval < 0) { 55931e31b8aSbellard perror("load_elf_interp"); 56031e31b8aSbellard exit(-1); 56131e31b8aSbellard free (elf_phdata); 56231e31b8aSbellard return retval; 56331e31b8aSbellard } 56431e31b8aSbellard #ifdef BSWAP_NEEDED 56531e31b8aSbellard eppnt = elf_phdata; 56631e31b8aSbellard for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { 56731e31b8aSbellard bswap_phdr(eppnt); 56831e31b8aSbellard } 56931e31b8aSbellard #endif 57009bfb054Sbellard 57109bfb054Sbellard if (interp_elf_ex->e_type == ET_DYN) { 57209bfb054Sbellard /* in order to avoid harcoding the interpreter load 57309bfb054Sbellard address in qemu, we allocate a big enough memory zone */ 57409bfb054Sbellard error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE, 57509bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 57609bfb054Sbellard -1, 0); 57709bfb054Sbellard if (error == -1) { 57809bfb054Sbellard perror("mmap"); 57909bfb054Sbellard exit(-1); 58009bfb054Sbellard } 58109bfb054Sbellard load_addr = error; 58209bfb054Sbellard load_addr_set = 1; 58309bfb054Sbellard } 58409bfb054Sbellard 58531e31b8aSbellard eppnt = elf_phdata; 58631e31b8aSbellard for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) 58731e31b8aSbellard if (eppnt->p_type == PT_LOAD) { 58831e31b8aSbellard int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 58931e31b8aSbellard int elf_prot = 0; 59031e31b8aSbellard unsigned long vaddr = 0; 59131e31b8aSbellard unsigned long k; 59231e31b8aSbellard 59331e31b8aSbellard if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; 59431e31b8aSbellard if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 59531e31b8aSbellard if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 59631e31b8aSbellard if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { 59731e31b8aSbellard elf_type |= MAP_FIXED; 59831e31b8aSbellard vaddr = eppnt->p_vaddr; 59931e31b8aSbellard } 60031e31b8aSbellard error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr), 60131e31b8aSbellard eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr), 60231e31b8aSbellard elf_prot, 60331e31b8aSbellard elf_type, 60431e31b8aSbellard interpreter_fd, 60531e31b8aSbellard eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr)); 60631e31b8aSbellard 60731e31b8aSbellard if (error > -1024UL) { 60831e31b8aSbellard /* Real error */ 60931e31b8aSbellard close(interpreter_fd); 61031e31b8aSbellard free(elf_phdata); 61131e31b8aSbellard return ~0UL; 61231e31b8aSbellard } 61331e31b8aSbellard 61431e31b8aSbellard if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { 61531e31b8aSbellard load_addr = error; 61631e31b8aSbellard load_addr_set = 1; 61731e31b8aSbellard } 61831e31b8aSbellard 61931e31b8aSbellard /* 62031e31b8aSbellard * Find the end of the file mapping for this phdr, and keep 62131e31b8aSbellard * track of the largest address we see for this. 62231e31b8aSbellard */ 62331e31b8aSbellard k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 62431e31b8aSbellard if (k > elf_bss) elf_bss = k; 62531e31b8aSbellard 62631e31b8aSbellard /* 62731e31b8aSbellard * Do the same thing for the memory mapping - between 62831e31b8aSbellard * elf_bss and last_bss is the bss section. 62931e31b8aSbellard */ 63031e31b8aSbellard k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 63131e31b8aSbellard if (k > last_bss) last_bss = k; 63231e31b8aSbellard } 63331e31b8aSbellard 63431e31b8aSbellard /* Now use mmap to map the library into memory. */ 63531e31b8aSbellard 63631e31b8aSbellard close(interpreter_fd); 63731e31b8aSbellard 63831e31b8aSbellard /* 63931e31b8aSbellard * Now fill out the bss section. First pad the last page up 64031e31b8aSbellard * to the page boundary, and then perform a mmap to make sure 64131e31b8aSbellard * that there are zeromapped pages up to and including the last 64231e31b8aSbellard * bss page. 64331e31b8aSbellard */ 64431e31b8aSbellard padzero(elf_bss); 64531e31b8aSbellard elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */ 64631e31b8aSbellard 64731e31b8aSbellard /* Map the last of the bss segment */ 64831e31b8aSbellard if (last_bss > elf_bss) { 64931e31b8aSbellard mmap4k(elf_bss, last_bss-elf_bss, 65031e31b8aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 65131e31b8aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 65231e31b8aSbellard } 65331e31b8aSbellard free(elf_phdata); 65431e31b8aSbellard 65531e31b8aSbellard *interp_load_addr = load_addr; 65631e31b8aSbellard return ((unsigned long) interp_elf_ex->e_entry) + load_addr; 65731e31b8aSbellard } 65831e31b8aSbellard 65931e31b8aSbellard 66031e31b8aSbellard 661b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 66231e31b8aSbellard struct image_info * info) 66331e31b8aSbellard { 66431e31b8aSbellard struct elfhdr elf_ex; 66531e31b8aSbellard struct elfhdr interp_elf_ex; 66631e31b8aSbellard struct exec interp_ex; 66731e31b8aSbellard int interpreter_fd = -1; /* avoid warning */ 66809bfb054Sbellard unsigned long load_addr, load_bias; 66931e31b8aSbellard int load_addr_set = 0; 67031e31b8aSbellard unsigned int interpreter_type = INTERPRETER_NONE; 67131e31b8aSbellard unsigned char ibcs2_interpreter; 67231e31b8aSbellard int i; 67331e31b8aSbellard void * mapped_addr; 67431e31b8aSbellard struct elf_phdr * elf_ppnt; 67531e31b8aSbellard struct elf_phdr *elf_phdata; 67631e31b8aSbellard unsigned long elf_bss, k, elf_brk; 67731e31b8aSbellard int retval; 67831e31b8aSbellard char * elf_interpreter; 67931e31b8aSbellard unsigned long elf_entry, interp_load_addr = 0; 68031e31b8aSbellard int status; 68131e31b8aSbellard unsigned long start_code, end_code, end_data; 68231e31b8aSbellard unsigned long elf_stack; 68331e31b8aSbellard char passed_fileno[6]; 68431e31b8aSbellard 68531e31b8aSbellard ibcs2_interpreter = 0; 68631e31b8aSbellard status = 0; 68731e31b8aSbellard load_addr = 0; 68809bfb054Sbellard load_bias = 0; 68931e31b8aSbellard elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ 69031e31b8aSbellard #ifdef BSWAP_NEEDED 69131e31b8aSbellard bswap_ehdr(&elf_ex); 69231e31b8aSbellard #endif 69331e31b8aSbellard 69431e31b8aSbellard if (elf_ex.e_ident[0] != 0x7f || 69531e31b8aSbellard strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { 69631e31b8aSbellard return -ENOEXEC; 69731e31b8aSbellard } 69831e31b8aSbellard 69931e31b8aSbellard /* First of all, some simple consistency checks */ 70031e31b8aSbellard if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 70131e31b8aSbellard (! elf_check_arch(elf_ex.e_machine))) { 70231e31b8aSbellard return -ENOEXEC; 70331e31b8aSbellard } 70431e31b8aSbellard 70531e31b8aSbellard /* Now read in all of the header information */ 70631e31b8aSbellard 70731e31b8aSbellard elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); 70831e31b8aSbellard if (elf_phdata == NULL) { 70931e31b8aSbellard return -ENOMEM; 71031e31b8aSbellard } 71131e31b8aSbellard 71231e31b8aSbellard retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); 71331e31b8aSbellard if(retval > 0) { 71431e31b8aSbellard retval = read(bprm->fd, (char *) elf_phdata, 71531e31b8aSbellard elf_ex.e_phentsize * elf_ex.e_phnum); 71631e31b8aSbellard } 71731e31b8aSbellard 71831e31b8aSbellard if (retval < 0) { 71931e31b8aSbellard perror("load_elf_binary"); 72031e31b8aSbellard exit(-1); 72131e31b8aSbellard free (elf_phdata); 72231e31b8aSbellard return -errno; 72331e31b8aSbellard } 72431e31b8aSbellard 725b17780d5Sbellard #ifdef BSWAP_NEEDED 726b17780d5Sbellard elf_ppnt = elf_phdata; 727b17780d5Sbellard for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { 728b17780d5Sbellard bswap_phdr(elf_ppnt); 729b17780d5Sbellard } 730b17780d5Sbellard #endif 73131e31b8aSbellard elf_ppnt = elf_phdata; 73231e31b8aSbellard 73331e31b8aSbellard elf_bss = 0; 73431e31b8aSbellard elf_brk = 0; 73531e31b8aSbellard 73631e31b8aSbellard 73731e31b8aSbellard elf_stack = ~0UL; 73831e31b8aSbellard elf_interpreter = NULL; 73931e31b8aSbellard start_code = ~0UL; 74031e31b8aSbellard end_code = 0; 74131e31b8aSbellard end_data = 0; 74231e31b8aSbellard 74331e31b8aSbellard for(i=0;i < elf_ex.e_phnum; i++) { 74431e31b8aSbellard if (elf_ppnt->p_type == PT_INTERP) { 74531e31b8aSbellard if ( elf_interpreter != NULL ) 74631e31b8aSbellard { 74731e31b8aSbellard free (elf_phdata); 74831e31b8aSbellard free(elf_interpreter); 74931e31b8aSbellard close(bprm->fd); 75031e31b8aSbellard return -EINVAL; 75131e31b8aSbellard } 75231e31b8aSbellard 75331e31b8aSbellard /* This is the program interpreter used for 75431e31b8aSbellard * shared libraries - for now assume that this 75531e31b8aSbellard * is an a.out format binary 75631e31b8aSbellard */ 75731e31b8aSbellard 758*32ce6337Sbellard elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); 75931e31b8aSbellard 76031e31b8aSbellard if (elf_interpreter == NULL) { 76131e31b8aSbellard free (elf_phdata); 76231e31b8aSbellard close(bprm->fd); 76331e31b8aSbellard return -ENOMEM; 76431e31b8aSbellard } 76531e31b8aSbellard 76631e31b8aSbellard retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); 76731e31b8aSbellard if(retval >= 0) { 768*32ce6337Sbellard retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); 76931e31b8aSbellard } 77031e31b8aSbellard if(retval < 0) { 77131e31b8aSbellard perror("load_elf_binary2"); 77231e31b8aSbellard exit(-1); 77331e31b8aSbellard } 77431e31b8aSbellard 77531e31b8aSbellard /* If the program interpreter is one of these two, 77631e31b8aSbellard then assume an iBCS2 image. Otherwise assume 77731e31b8aSbellard a native linux image. */ 77831e31b8aSbellard 77931e31b8aSbellard /* JRP - Need to add X86 lib dir stuff here... */ 78031e31b8aSbellard 78131e31b8aSbellard if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || 78231e31b8aSbellard strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { 78331e31b8aSbellard ibcs2_interpreter = 1; 78431e31b8aSbellard } 78531e31b8aSbellard 78631e31b8aSbellard #if 0 78731e31b8aSbellard printf("Using ELF interpreter %s\n", elf_interpreter); 78831e31b8aSbellard #endif 78931e31b8aSbellard if (retval >= 0) { 790*32ce6337Sbellard retval = open(path(elf_interpreter), O_RDONLY); 79131e31b8aSbellard if(retval >= 0) { 79231e31b8aSbellard interpreter_fd = retval; 79331e31b8aSbellard } 79431e31b8aSbellard else { 79531e31b8aSbellard perror(elf_interpreter); 79631e31b8aSbellard exit(-1); 79731e31b8aSbellard /* retval = -errno; */ 79831e31b8aSbellard } 79931e31b8aSbellard } 80031e31b8aSbellard 80131e31b8aSbellard if (retval >= 0) { 80231e31b8aSbellard retval = lseek(interpreter_fd, 0, SEEK_SET); 80331e31b8aSbellard if(retval >= 0) { 80431e31b8aSbellard retval = read(interpreter_fd,bprm->buf,128); 80531e31b8aSbellard } 80631e31b8aSbellard } 80731e31b8aSbellard if (retval >= 0) { 80831e31b8aSbellard interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ 80931e31b8aSbellard interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ 81031e31b8aSbellard } 81131e31b8aSbellard if (retval < 0) { 81231e31b8aSbellard perror("load_elf_binary3"); 81331e31b8aSbellard exit(-1); 81431e31b8aSbellard free (elf_phdata); 81531e31b8aSbellard free(elf_interpreter); 81631e31b8aSbellard close(bprm->fd); 81731e31b8aSbellard return retval; 81831e31b8aSbellard } 81931e31b8aSbellard } 82031e31b8aSbellard elf_ppnt++; 82131e31b8aSbellard } 82231e31b8aSbellard 82331e31b8aSbellard /* Some simple consistency checks for the interpreter */ 82431e31b8aSbellard if (elf_interpreter){ 82531e31b8aSbellard interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; 82631e31b8aSbellard 82731e31b8aSbellard /* Now figure out which format our binary is */ 82831e31b8aSbellard if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && 82931e31b8aSbellard (N_MAGIC(interp_ex) != QMAGIC)) { 83031e31b8aSbellard interpreter_type = INTERPRETER_ELF; 83131e31b8aSbellard } 83231e31b8aSbellard 83331e31b8aSbellard if (interp_elf_ex.e_ident[0] != 0x7f || 83431e31b8aSbellard strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { 83531e31b8aSbellard interpreter_type &= ~INTERPRETER_ELF; 83631e31b8aSbellard } 83731e31b8aSbellard 83831e31b8aSbellard if (!interpreter_type) { 83931e31b8aSbellard free(elf_interpreter); 84031e31b8aSbellard free(elf_phdata); 84131e31b8aSbellard close(bprm->fd); 84231e31b8aSbellard return -ELIBBAD; 84331e31b8aSbellard } 84431e31b8aSbellard } 84531e31b8aSbellard 84631e31b8aSbellard /* OK, we are done with that, now set up the arg stuff, 84731e31b8aSbellard and then start this sucker up */ 84831e31b8aSbellard 84931e31b8aSbellard if (!bprm->sh_bang) { 85031e31b8aSbellard char * passed_p; 85131e31b8aSbellard 85231e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) { 85331e31b8aSbellard sprintf(passed_fileno, "%d", bprm->fd); 85431e31b8aSbellard passed_p = passed_fileno; 85531e31b8aSbellard 85631e31b8aSbellard if (elf_interpreter) { 85731e31b8aSbellard bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); 85831e31b8aSbellard bprm->argc++; 85931e31b8aSbellard } 86031e31b8aSbellard } 86131e31b8aSbellard if (!bprm->p) { 86231e31b8aSbellard if (elf_interpreter) { 86331e31b8aSbellard free(elf_interpreter); 86431e31b8aSbellard } 86531e31b8aSbellard free (elf_phdata); 86631e31b8aSbellard close(bprm->fd); 86731e31b8aSbellard return -E2BIG; 86831e31b8aSbellard } 86931e31b8aSbellard } 87031e31b8aSbellard 87131e31b8aSbellard /* OK, This is the point of no return */ 87231e31b8aSbellard info->end_data = 0; 87331e31b8aSbellard info->end_code = 0; 87431e31b8aSbellard info->start_mmap = (unsigned long)ELF_START_MMAP; 87531e31b8aSbellard info->mmap = 0; 87631e31b8aSbellard elf_entry = (unsigned long) elf_ex.e_entry; 87731e31b8aSbellard 87831e31b8aSbellard /* Do this so that we can load the interpreter, if need be. We will 87931e31b8aSbellard change some of these later */ 88031e31b8aSbellard info->rss = 0; 88131e31b8aSbellard bprm->p = setup_arg_pages(bprm->p, bprm, info); 88231e31b8aSbellard info->start_stack = bprm->p; 88331e31b8aSbellard 88431e31b8aSbellard /* Now we do a little grungy work by mmaping the ELF image into 88531e31b8aSbellard * the correct location in memory. At this point, we assume that 88631e31b8aSbellard * the image should be loaded at fixed address, not at a variable 88731e31b8aSbellard * address. 88831e31b8aSbellard */ 88931e31b8aSbellard 89031e31b8aSbellard for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { 89131e31b8aSbellard int elf_prot = 0; 89209bfb054Sbellard int elf_flags = 0; 89309bfb054Sbellard unsigned long error; 89409bfb054Sbellard 89509bfb054Sbellard if (elf_ppnt->p_type != PT_LOAD) 89609bfb054Sbellard continue; 89709bfb054Sbellard 89831e31b8aSbellard if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; 89931e31b8aSbellard if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 90031e31b8aSbellard if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 90109bfb054Sbellard elf_flags = MAP_PRIVATE | MAP_DENYWRITE; 90209bfb054Sbellard if (elf_ex.e_type == ET_EXEC || load_addr_set) { 90309bfb054Sbellard elf_flags |= MAP_FIXED; 90409bfb054Sbellard } else if (elf_ex.e_type == ET_DYN) { 90509bfb054Sbellard /* Try and get dynamic programs out of the way of the default mmap 90609bfb054Sbellard base, as well as whatever program they might try to exec. This 90709bfb054Sbellard is because the brk will follow the loader, and is not movable. */ 90809bfb054Sbellard /* NOTE: for qemu, we do a big mmap to get enough space 90909bfb054Sbellard without harcoding any address */ 91009bfb054Sbellard error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE, 91109bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 91209bfb054Sbellard -1, 0); 91309bfb054Sbellard if (error == -1) { 91409bfb054Sbellard perror("mmap"); 91509bfb054Sbellard exit(-1); 91609bfb054Sbellard } 91709bfb054Sbellard load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr); 91809bfb054Sbellard } 91931e31b8aSbellard 92009bfb054Sbellard error = (unsigned long)mmap4k( 92109bfb054Sbellard X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), 92231e31b8aSbellard (elf_ppnt->p_filesz + 92331e31b8aSbellard X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), 92431e31b8aSbellard elf_prot, 92531e31b8aSbellard (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), 92631e31b8aSbellard bprm->fd, 92731e31b8aSbellard (elf_ppnt->p_offset - 92831e31b8aSbellard X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); 92909bfb054Sbellard if (error == -1) { 93031e31b8aSbellard perror("mmap"); 93131e31b8aSbellard exit(-1); 93231e31b8aSbellard } 93331e31b8aSbellard 93431e31b8aSbellard #ifdef LOW_ELF_STACK 93531e31b8aSbellard if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 93631e31b8aSbellard elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); 93731e31b8aSbellard #endif 93831e31b8aSbellard 93931e31b8aSbellard if (!load_addr_set) { 94031e31b8aSbellard load_addr_set = 1; 94109bfb054Sbellard load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; 94209bfb054Sbellard if (elf_ex.e_type == ET_DYN) { 94309bfb054Sbellard load_bias += error - 94409bfb054Sbellard X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); 94509bfb054Sbellard load_addr += load_bias; 94609bfb054Sbellard } 94731e31b8aSbellard } 94831e31b8aSbellard k = elf_ppnt->p_vaddr; 94909bfb054Sbellard if (k < start_code) 95009bfb054Sbellard start_code = k; 95131e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 95209bfb054Sbellard if (k > elf_bss) 95309bfb054Sbellard elf_bss = k; 95431e31b8aSbellard if ((elf_ppnt->p_flags & PF_X) && end_code < k) 95531e31b8aSbellard end_code = k; 95609bfb054Sbellard if (end_data < k) 95709bfb054Sbellard end_data = k; 95831e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 95931e31b8aSbellard if (k > elf_brk) elf_brk = k; 96031e31b8aSbellard } 96109bfb054Sbellard 96209bfb054Sbellard elf_entry += load_bias; 96309bfb054Sbellard elf_bss += load_bias; 96409bfb054Sbellard elf_brk += load_bias; 96509bfb054Sbellard start_code += load_bias; 96609bfb054Sbellard end_code += load_bias; 96709bfb054Sbellard // start_data += load_bias; 96809bfb054Sbellard end_data += load_bias; 96931e31b8aSbellard 97031e31b8aSbellard if (elf_interpreter) { 97131e31b8aSbellard if (interpreter_type & 1) { 97231e31b8aSbellard elf_entry = load_aout_interp(&interp_ex, interpreter_fd); 97331e31b8aSbellard } 97431e31b8aSbellard else if (interpreter_type & 2) { 97531e31b8aSbellard elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, 97631e31b8aSbellard &interp_load_addr); 97731e31b8aSbellard } 97831e31b8aSbellard 97931e31b8aSbellard close(interpreter_fd); 98031e31b8aSbellard free(elf_interpreter); 98131e31b8aSbellard 98231e31b8aSbellard if (elf_entry == ~0UL) { 98331e31b8aSbellard printf("Unable to load interpreter\n"); 98431e31b8aSbellard free(elf_phdata); 98531e31b8aSbellard exit(-1); 98631e31b8aSbellard return 0; 98731e31b8aSbellard } 98831e31b8aSbellard } 98931e31b8aSbellard 99031e31b8aSbellard free(elf_phdata); 99131e31b8aSbellard 99231e31b8aSbellard if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); 99331e31b8aSbellard info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); 99431e31b8aSbellard 99531e31b8aSbellard #ifdef LOW_ELF_STACK 99631e31b8aSbellard info->start_stack = bprm->p = elf_stack - 4; 99731e31b8aSbellard #endif 99831e31b8aSbellard bprm->p = (unsigned long) 99931e31b8aSbellard create_elf_tables((char *)bprm->p, 100031e31b8aSbellard bprm->argc, 100131e31b8aSbellard bprm->envc, 100231e31b8aSbellard (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), 100309bfb054Sbellard load_addr, load_bias, 100431e31b8aSbellard interp_load_addr, 100531e31b8aSbellard (interpreter_type == INTERPRETER_AOUT ? 0 : 1), 100631e31b8aSbellard info); 100731e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) 100831e31b8aSbellard info->arg_start += strlen(passed_fileno) + 1; 100931e31b8aSbellard info->start_brk = info->brk = elf_brk; 101031e31b8aSbellard info->end_code = end_code; 101131e31b8aSbellard info->start_code = start_code; 101231e31b8aSbellard info->end_data = end_data; 101331e31b8aSbellard info->start_stack = bprm->p; 101431e31b8aSbellard 101531e31b8aSbellard /* Calling set_brk effectively mmaps the pages that we need for the bss and break 101631e31b8aSbellard sections */ 101731e31b8aSbellard set_brk(elf_bss, elf_brk); 101831e31b8aSbellard 101931e31b8aSbellard padzero(elf_bss); 102031e31b8aSbellard 102131e31b8aSbellard #if 0 102231e31b8aSbellard printf("(start_brk) %x\n" , info->start_brk); 102331e31b8aSbellard printf("(end_code) %x\n" , info->end_code); 102431e31b8aSbellard printf("(start_code) %x\n" , info->start_code); 102531e31b8aSbellard printf("(end_data) %x\n" , info->end_data); 102631e31b8aSbellard printf("(start_stack) %x\n" , info->start_stack); 102731e31b8aSbellard printf("(brk) %x\n" , info->brk); 102831e31b8aSbellard #endif 102931e31b8aSbellard 103031e31b8aSbellard if ( info->personality == PER_SVR4 ) 103131e31b8aSbellard { 103231e31b8aSbellard /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 103331e31b8aSbellard and some applications "depend" upon this behavior. 103431e31b8aSbellard Since we do not have the power to recompile these, we 103531e31b8aSbellard emulate the SVr4 behavior. Sigh. */ 103631e31b8aSbellard mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC, 103731e31b8aSbellard MAP_FIXED | MAP_PRIVATE, -1, 0); 103831e31b8aSbellard } 103931e31b8aSbellard 104031e31b8aSbellard #ifdef ELF_PLAT_INIT 104131e31b8aSbellard /* 104231e31b8aSbellard * The ABI may specify that certain registers be set up in special 104331e31b8aSbellard * ways (on i386 %edx is the address of a DT_FINI function, for 104431e31b8aSbellard * example. This macro performs whatever initialization to 104531e31b8aSbellard * the regs structure is required. 104631e31b8aSbellard */ 104731e31b8aSbellard ELF_PLAT_INIT(regs); 104831e31b8aSbellard #endif 104931e31b8aSbellard 105031e31b8aSbellard 105131e31b8aSbellard info->entry = elf_entry; 105231e31b8aSbellard 105331e31b8aSbellard return 0; 105431e31b8aSbellard } 105531e31b8aSbellard 105631e31b8aSbellard 105731e31b8aSbellard 1058*32ce6337Sbellard int elf_exec(const char * filename, char ** argv, char ** envp, 1059b17780d5Sbellard struct target_pt_regs * regs, struct image_info *infop) 106031e31b8aSbellard { 106131e31b8aSbellard struct linux_binprm bprm; 106231e31b8aSbellard int retval; 106331e31b8aSbellard int i; 106431e31b8aSbellard 106531e31b8aSbellard bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); 106631e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ 106731e31b8aSbellard bprm.page[i] = 0; 106831e31b8aSbellard retval = open(filename, O_RDONLY); 106931e31b8aSbellard if (retval == -1) { 107031e31b8aSbellard perror(filename); 107131e31b8aSbellard exit(-1); 107231e31b8aSbellard /* return retval; */ 107331e31b8aSbellard } 107431e31b8aSbellard else { 107531e31b8aSbellard bprm.fd = retval; 107631e31b8aSbellard } 107731e31b8aSbellard bprm.filename = (char *)filename; 107831e31b8aSbellard bprm.sh_bang = 0; 107931e31b8aSbellard bprm.loader = 0; 108031e31b8aSbellard bprm.exec = 0; 108131e31b8aSbellard bprm.dont_iput = 0; 108231e31b8aSbellard bprm.argc = count(argv); 108331e31b8aSbellard bprm.envc = count(envp); 108431e31b8aSbellard 108531e31b8aSbellard retval = prepare_binprm(&bprm); 108631e31b8aSbellard 108731e31b8aSbellard if(retval>=0) { 108831e31b8aSbellard bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); 108931e31b8aSbellard bprm.exec = bprm.p; 109031e31b8aSbellard bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); 109131e31b8aSbellard bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); 109231e31b8aSbellard if (!bprm.p) { 109331e31b8aSbellard retval = -E2BIG; 109431e31b8aSbellard } 109531e31b8aSbellard } 109631e31b8aSbellard 109731e31b8aSbellard if(retval>=0) { 109831e31b8aSbellard retval = load_elf_binary(&bprm,regs,infop); 109931e31b8aSbellard } 110031e31b8aSbellard if(retval>=0) { 110131e31b8aSbellard /* success. Initialize important registers */ 110231e31b8aSbellard regs->esp = infop->start_stack; 110331e31b8aSbellard regs->eip = infop->entry; 110431e31b8aSbellard return retval; 110531e31b8aSbellard } 110631e31b8aSbellard 110731e31b8aSbellard /* Something went wrong, return the inode and free the argument pages*/ 110831e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) { 110931e31b8aSbellard free_page((void *)bprm.page[i]); 111031e31b8aSbellard } 111131e31b8aSbellard return(retval); 111231e31b8aSbellard } 111331e31b8aSbellard 111431e31b8aSbellard 111531e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd) 111631e31b8aSbellard { 111731e31b8aSbellard printf("a.out interpreter not yet supported\n"); 111831e31b8aSbellard return(0); 111931e31b8aSbellard } 112031e31b8aSbellard 1121