On Mon, 5 Apr 2010, Richard Henderson wrote: > This requires moving the PT_INTERP extraction and GUEST_BASE > handling into load_elf_image. Key this off a non-null pointer > argument to receive the interpreter name. > > Signed-off-by: Richard Henderson <r...@twiddle.net> > --- > linux-user/elfload.c | 269 > ++++++++++---------------------------------------- > 1 files changed, 53 insertions(+), 216 deletions(-) > > diff --git a/linux-user/elfload.c b/linux-user/elfload.c > index c58387a..100efdc 100644 > --- a/linux-user/elfload.c > +++ b/linux-user/elfload.c > @@ -829,9 +829,6 @@ struct exec > #define ZMAGIC 0413 > #define QMAGIC 0314 > > -/* max code+data+bss+brk space allocated to ET_DYN executables */ > -#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) > - > /* Necessary parameters */ > #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE > #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned > long)(TARGET_ELF_EXEC_PAGESIZE-1)) > @@ -1168,7 +1165,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int > argc, int envc, > On return: INFO values will be filled in, as necessary or available. */ > > static void load_elf_image(const char *image_name, int image_fd, > - struct image_info *info, > + struct image_info *info, char **pinterp_name, > char bprm_buf[BPRM_BUF_SIZE]) > { > struct elfhdr *ehdr = (struct elfhdr *)bprm_buf; > @@ -1228,6 +1225,20 @@ static void load_elf_image(const char *image_name, int > image_fd, > if (load_addr == -1) { > goto exit_perror; > } > + } else if (pinterp_name != NULL) { > + /* This is the main executable. Make sure that the low > + address does not conflict with MMAP_MIN_ADDR. */ > + /* ??? Ideally, we'd check against more than just the > + minimum mmap address, but also against the QEMU program > + image itself. I.e. find a range that does not conflict > + with PAGE_RESERVED entries. Except that we havn't read > + those in yet, since that code uses the guest_base that > + we set up here. Blah. */ > +#if defined(CONFIG_USE_GUEST_BASE) > + if (HOST_PAGE_ALIGN(loaddr) < mmap_min_addr) { > + guest_base = HOST_PAGE_ALIGN(mmap_min_addr); > + } > +#endif > } > load_bias = load_addr - loaddr; > > @@ -1289,6 +1300,30 @@ static void load_elf_image(const char *image_name, int > image_fd, > info->brk = vaddr_em; > } > } > + } else if (eppnt->p_type == PT_INTERP && pinterp_name) { > + char *interp_name; > + > + if (*pinterp_name) { > + errmsg = "Multiple PT_INTERP entries"; > + goto exit_errmsg; > + } > + interp_name = malloc(eppnt->p_filesz);
malloc can fail > + > + if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) { > + memcpy(interp_name, bprm_buf + eppnt->p_offset, > + eppnt->p_filesz); > + } else { > + retval = pread(image_fd, interp_name, eppnt->p_filesz, Indentation seems off. > + eppnt->p_offset); > + if (retval != eppnt->p_filesz) { > + goto exit_perror; > + } > + } > + if (interp_name[eppnt->p_filesz - 1] != 0) { > + errmsg = "Invalid PT_INTERP entry"; > + goto exit_errmsg; > + } > + *pinterp_name = interp_name; > } > } > > @@ -1335,7 +1370,7 @@ static void load_elf_interp(const char *filename, > struct image_info *info, > memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval); > } > > - load_elf_image(filename, fd, info, bprm_buf); > + load_elf_image(filename, fd, info, NULL, bprm_buf); > return; > > exit_perror: > @@ -1479,230 +1514,31 @@ int load_elf_binary(struct linux_binprm * bprm, > struct target_pt_regs * regs, > { > struct image_info interp_info; > struct elfhdr elf_ex; > - abi_ulong load_addr, load_bias; > - int load_addr_set = 0; > - int i; > - struct elf_phdr * elf_ppnt; > - struct elf_phdr *elf_phdata; > - abi_ulong k, elf_brk; > - int retval; > char *elf_interpreter = NULL; > - abi_ulong elf_entry; > - int status; > - abi_ulong start_code, end_code, start_data, end_data; > - abi_ulong elf_stack; > > - status = 0; > - load_addr = 0; > - load_bias = 0; > - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ > + info->start_mmap = (abi_ulong)ELF_START_MMAP; > + info->mmap = 0; > + info->rss = 0; > + > + load_elf_image(bprm->filename, bprm->fd, info, > + &elf_interpreter, bprm->buf); > > - /* First of all, some simple consistency checks */ > - if (!elf_check_ident(&elf_ex)) { > - return -ENOEXEC; > - } > - bswap_ehdr(&elf_ex); > - if (!elf_check_ehdr(&elf_ex)) { > - return -ENOEXEC; > - } > + /* ??? We need a copy of the elf header for passing to create_elf_tables. > + If we do nothing, we'll have overwritten this when we re-use bprm->buf > + when we load the interpreter. */ > + elf_ex = *(struct elfhdr *)bprm->buf; > > bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); > bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); > bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); > if (!bprm->p) { > - retval = -E2BIG; > - } > - > - /* Now read in all of the header information */ > - elf_phdata = (struct elf_phdr *) > - malloc(elf_ex.e_phnum * sizeof(struct elf_phdr)); > - if (elf_phdata == NULL) { > - return -ENOMEM; > - } > - > - i = elf_ex.e_phnum * sizeof(struct elf_phdr); > - if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) { > - memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i); > - } else { > - retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff); > - if (retval != i) { > - perror("load_elf_binary"); > - exit(-1); > - } > - } > - bswap_phdr(elf_phdata, elf_ex.e_phnum); > - > - elf_brk = 0; > - elf_stack = ~((abi_ulong)0UL); > - start_code = ~((abi_ulong)0UL); > - end_code = 0; > - start_data = 0; > - end_data = 0; > - > - elf_ppnt = elf_phdata; > - for(i=0;i < elf_ex.e_phnum; i++) { > - if (elf_ppnt->p_type == PT_INTERP) { > - if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) { > - elf_interpreter = bprm->buf + elf_ppnt->p_offset; > - } else { > - elf_interpreter = alloca(elf_ppnt->p_filesz); > - retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz, > - elf_ppnt->p_offset); > - if (retval != elf_ppnt->p_filesz) { > - perror("load_elf_binary"); > - exit(-1); > - } > - } > - } > - elf_ppnt++; > - } > - > - /* OK, This is the point of no return */ > - info->end_data = 0; > - info->end_code = 0; > - info->start_mmap = (abi_ulong)ELF_START_MMAP; > - info->mmap = 0; > - elf_entry = (abi_ulong) elf_ex.e_entry; > - > -#if defined(CONFIG_USE_GUEST_BASE) > - /* > - * In case where user has not explicitly set the guest_base, we > - * probe here that should we set it automatically. > - */ > - if (!have_guest_base) { > - /* > - * Go through ELF program header table and find out whether > - * any of the segments drop below our current mmap_min_addr and > - * in that case set guest_base to corresponding address. > - */ > - for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; > - i++, elf_ppnt++) { > - if (elf_ppnt->p_type != PT_LOAD) > - continue; > - if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) { > - guest_base = HOST_PAGE_ALIGN(mmap_min_addr); > - break; > - } > - } > + fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG)); > + exit(-1); > } > -#endif /* CONFIG_USE_GUEST_BASE */ > > /* Do this so that we can load the interpreter, if need be. We will > change some of these later */ > - info->rss = 0; > bprm->p = setup_arg_pages(bprm->p, bprm, info); > - info->start_stack = bprm->p; > - > - /* Now we do a little grungy work by mmaping the ELF image into > - * the correct location in memory. At this point, we assume that > - * the image should be loaded at fixed address, not at a variable > - * address. > - */ > - > - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { > - int elf_prot = 0; > - int elf_flags = 0; > - abi_ulong error; > - > - if (elf_ppnt->p_type != PT_LOAD) > - continue; > - > - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; > - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; > - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; > - elf_flags = MAP_PRIVATE | MAP_DENYWRITE; > - if (elf_ex.e_type == ET_EXEC || load_addr_set) { > - elf_flags |= MAP_FIXED; > - } else if (elf_ex.e_type == ET_DYN) { > - /* Try and get dynamic programs out of the way of the default > mmap > - base, as well as whatever program they might try to exec. > This > - is because the brk will follow the loader, and is not > movable. */ > - /* NOTE: for qemu, we do a big mmap to get enough space > - without hardcoding any address */ > - error = target_mmap(0, ET_DYN_MAP_SIZE, > - PROT_NONE, MAP_PRIVATE | MAP_ANON, > - -1, 0); > - if (error == -1) { > - perror("mmap"); > - exit(-1); > - } > - load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); > - } > - > - error = target_mmap(TARGET_ELF_PAGESTART(load_bias + > elf_ppnt->p_vaddr), > - (elf_ppnt->p_filesz + > - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), > - elf_prot, > - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), > - bprm->fd, > - (elf_ppnt->p_offset - > - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); > - if (error == -1) { > - perror("mmap"); > - exit(-1); > - } > - > -#ifdef LOW_ELF_STACK > - if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) > - elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); > -#endif > - > - if (!load_addr_set) { > - load_addr_set = 1; > - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; > - if (elf_ex.e_type == ET_DYN) { > - load_bias += error - > - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); > - load_addr += load_bias; > - } > - } > - k = elf_ppnt->p_vaddr; > - if (k < start_code) > - start_code = k; > - if (start_data < k) > - start_data = k; > - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; > - if ((elf_ppnt->p_flags & PF_X) && end_code < k) > - end_code = k; > - if (end_data < k) > - end_data = k; > - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; > - if (k > elf_brk) { > - elf_brk = TARGET_PAGE_ALIGN(k); > - } > - > - /* If the load segment requests extra zeros (e.g. bss), map it. */ > - if (elf_ppnt->p_filesz < elf_ppnt->p_memsz) { > - abi_ulong base = load_bias + elf_ppnt->p_vaddr; > - zero_bss(base + elf_ppnt->p_filesz, > - base + elf_ppnt->p_memsz, elf_prot); > - } > - } > - > - elf_entry += load_bias; > - elf_brk += load_bias; > - start_code += load_bias; > - end_code += load_bias; > - start_data += load_bias; > - end_data += load_bias; > - > - info->load_bias = load_bias; > - info->load_addr = load_addr; > - info->entry = elf_entry; > - info->start_brk = info->brk = elf_brk; > - info->end_code = end_code; > - info->start_code = start_code; > - info->start_data = start_data; > - info->end_data = end_data; > - info->personality = PER_LINUX; > - > - free(elf_phdata); > - > - if (qemu_log_enabled()) { > - load_symbols(&elf_ex, bprm->fd, load_bias); > - } > - > - close(bprm->fd); > > if (elf_interpreter) { > load_elf_interp(elf_interpreter, &interp_info, bprm->buf); > @@ -1734,6 +1570,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct > target_pt_regs * regs, > if (elf_interpreter) { > info->load_addr = interp_info.load_addr; > info->entry = interp_info.entry; > + free(elf_interpreter); > } > > #ifdef USE_ELF_CORE_DUMP > -- mailto:av1...@comtv.ru