> On Aug 26, 2021, at 3:11 PM, imp@bsdimp.com wrote: > > From: Warner Losh > > Factor out load_elf_sections and is_target_elf_binary out of > load_elf_interp. > > Signed-off-by: Mikaƫl Urankar > Signed-off-by: Stacey Son > Signed-off-by: Warner Losh > --- > bsd-user/elfload.c | 350 +++++++++++++++++++++------------------------ > 1 file changed, 164 insertions(+), 186 deletions(-) > > diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c > index bdf18f3dce..aed28f2f73 100644 > --- a/bsd-user/elfload.c > +++ b/bsd-user/elfload.c > @@ -36,6 +36,8 @@ abi_ulong target_stksiz; > abi_ulong target_stkbas; > > static int elf_core_dump(int signr, CPUArchState *env); > +static int load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr, > + int fd, abi_ulong rbase, abi_ulong *baddrp); > > static inline void memcpy_fromfs(void *to, const void *from, unsigned long n) > { > @@ -271,16 +273,10 @@ static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, > abi_ulong *interp_load_addr) > { > struct elf_phdr *elf_phdata = NULL; > - struct elf_phdr *eppnt; > - abi_ulong load_addr = 0; > - int load_addr_set = 0; > + abi_ulong rbase; > int retval; > - abi_ulong last_bss, elf_bss; > - abi_ulong error; > - int i; > + abi_ulong baddr, error; > > - elf_bss = 0; > - last_bss = 0; > error = 0; > > bswap_ehdr(interp_elf_ex); > @@ -325,6 +321,7 @@ static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, > } > bswap_phdr(elf_phdata, interp_elf_ex->e_phnum); > > + rbase = 0; > if (interp_elf_ex->e_type == ET_DYN) { > /* > * In order to avoid hardcoding the interpreter load > @@ -332,86 +329,25 @@ static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, > */ > error = target_mmap(0, INTERP_MAP_SIZE, PROT_NONE, > MAP_PRIVATE | MAP_ANON, -1, 0); s/error = /rbase = / so that the test below worked properly. > - if (error == -1) { > + if (rbase == -1) { > perror("mmap"); > exit(-1); > } > - load_addr = error; > - load_addr_set = 1; > - } > - > - eppnt = elf_phdata; > - for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) > - if (eppnt->p_type == PT_LOAD) { > - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; > - int elf_prot = 0; > - abi_ulong vaddr = 0; > - abi_ulong k; > - > - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; > - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; > - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; > - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { > - elf_type |= MAP_FIXED; > - vaddr = eppnt->p_vaddr; > - } > - error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr), > - eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), > - elf_prot, > - elf_type, > - interpreter_fd, > - eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); > - > - if (error == -1) { > - /* Real error */ > - close(interpreter_fd); > - free(elf_phdata); > - return ~((abi_ulong)0UL); > - } > - > - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { > - load_addr = error; > - load_addr_set = 1; > - } > - > - /* > - * Find the end of the file mapping for this phdr, and keep > - * track of the largest address we see for this. > - */ > - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; > - if (k > elf_bss) elf_bss = k; > + } > > - /* > - * Do the same thing for the memory mapping - between > - * elf_bss and last_bss is the bss section. > - */ > - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; > - if (k > last_bss) last_bss = k; > - } > + error = load_elf_sections(interp_elf_ex, elf_phdata, interpreter_fd, rbase, > + &baddr); > + if (error != 0) { > + perror("load_elf_sections"); > + exit(-1); > + } > > /* Now use mmap to map the library into memory. */ > - > close(interpreter_fd); > - > - /* > - * Now fill out the bss section. First pad the last page up > - * to the page boundary, and then perform a mmap to make sure > - * that there are zeromapped pages up to and including the last > - * bss page. > - */ > - padzero(elf_bss, last_bss); > - elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ > - > - /* Map the last of the bss segment */ > - if (last_bss > elf_bss) { > - target_mmap(elf_bss, last_bss - elf_bss, > - PROT_READ | PROT_WRITE | PROT_EXEC, > - MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); > - } > free(elf_phdata); > > - *interp_load_addr = load_addr; > - return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; > + *interp_load_addr = baddr; > + return ((abi_ulong) interp_elf_ex->e_entry) + rbase; > } > > static int symfind(const void *s0, const void *s1) > @@ -521,6 +457,10 @@ found: > } > continue; > } > +#if defined(TARGET_ARM) || defined(TARGET_MIPS) > + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ > + syms[i].st_value &= ~(target_ulong)1; > +#endif > i++; > } > > @@ -560,26 +500,119 @@ found: > syminfos = s; > } > > +/* Check the elf header and see if this a target elf binary. */ > +int is_target_elf_binary(int fd) > +{ > + uint8_t buf[128]; > + struct elfhdr elf_ex; > + > + if (lseek(fd, 0L, SEEK_SET) < 0) { > + return 0; > + } > + if (read(fd, buf, sizeof(buf)) < 0) { > + return 0; > + } > + > + elf_ex = *((struct elfhdr *)buf); > + bswap_ehdr(&elf_ex); > + > + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || > + (!elf_check_arch(elf_ex.e_machine))) { > + return 0; > + } else { > + return 1; > + } > +} > + > +static int > +load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr, int fd, > + abi_ulong rbase, abi_ulong *baddrp) > +{ > + struct elf_phdr *elf_ppnt; > + abi_ulong baddr; > + int i; > + bool first; > + > + /* > + * 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. > + */ > + first = true; > + for (i = 0, elf_ppnt = phdr; i < hdr->e_phnum; i++, elf_ppnt++) { > + int elf_prot = 0; > + abi_ulong error; > + > + /* XXX Skip memsz == 0. */ > + 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; > + } > + > + error = target_mmap(TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr), > + (elf_ppnt->p_filesz + > + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), > + elf_prot, > + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), > + fd, > + (elf_ppnt->p_offset - > + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); > + if (error == -1) { > + perror("mmap"); > + exit(-1); > + } else if (elf_ppnt->p_memsz != elf_ppnt->p_filesz) { > + abi_ulong start_bss, end_bss; > + > + start_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_filesz; > + end_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_memsz; > + > + /* > + * Calling set_brk effectively mmaps the pages that we need for the > + * bss and break sections. > + */ > + set_brk(start_bss, end_bss); > + padzero(start_bss, end_bss); > + } > + > + if (first) { > + baddr = TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr); > + first = false; > + } > + } > + > + if (baddrp != NULL) { > + *baddrp = baddr; > + } > + return 0; > +} > + > int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, > struct image_info *info) > { > struct elfhdr elf_ex; > struct elfhdr interp_elf_ex; > int interpreter_fd = -1; /* avoid warning */ > - abi_ulong load_addr, load_bias; > - int load_addr_set = 0; > + abi_ulong load_addr; > int i; > - struct elf_phdr * elf_ppnt; > + struct elf_phdr *elf_ppnt; > struct elf_phdr *elf_phdata; > - abi_ulong elf_bss, k, elf_brk; > - int retval; > - char * elf_interpreter; > - abi_ulong elf_entry, interp_load_addr = 0; > - abi_ulong start_code, end_code, start_data, end_data; > + abi_ulong elf_brk; > + int error, retval; > + char *elf_interpreter; > + abi_ulong baddr, elf_entry, et_dyn_addr, interp_load_addr = 0; > abi_ulong reloc_func_desc = 0; > > load_addr = 0; > - load_bias = 0; > elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ > bswap_ehdr(&elf_ex); > > @@ -618,16 +651,10 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, > bswap_phdr(elf_phdata, elf_ex.e_phnum); > elf_ppnt = elf_phdata; > > - elf_bss = 0; > elf_brk = 0; > > > elf_interpreter = NULL; > - start_code = ~((abi_ulong)0UL); > - end_code = 0; > - start_data = 0; > - end_data = 0; > - > for (i = 0; i < elf_ex.e_phnum; i++) { > if (elf_ppnt->p_type == PT_INTERP) { > if (elf_interpreter != NULL) { > @@ -714,94 +741,45 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, > info->mmap = 0; > elf_entry = (abi_ulong) elf_ex.e_entry; > > - /* Do this so that we can load the interpreter, if need be. We will > - change some of these later */ > + /* XXX Join this with PT_INTERP search? */ > + baddr = 0; > + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { > + if (elf_ppnt->p_type != PT_LOAD) { > + continue; > + } > + baddr = elf_ppnt->p_vaddr; > + break; > + } > + > + et_dyn_addr = 0; > + if (elf_ex.e_type == ET_DYN && baddr == 0) { > + et_dyn_addr = ELF_ET_DYN_LOAD_ADDR; > + } > + > + /* > + * Do this so that we can load the interpreter, if need be. We will > + * change some of these later > + */ > info->rss = 0; > setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp); > 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. > - */ > + info->elf_flags = elf_ex.e_flags; > > + error = load_elf_sections(&elf_ex, elf_phdata, bprm->fd, et_dyn_addr, > + &load_addr); > 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) > + 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); > - } > - > - 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; > - reloc_func_desc = 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 (k > elf_bss) > - elf_bss = k; > - 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 = k; > - } > - > - elf_entry += load_bias; > - elf_bss += load_bias; > - elf_brk += load_bias; > - start_code += load_bias; > - end_code += load_bias; > - start_data += load_bias; > - end_data += load_bias; > + if (elf_ppnt->p_memsz > elf_ppnt->p_filesz) > + elf_brk = MAX(elf_brk, et_dyn_addr + elf_ppnt->p_vaddr + > + elf_ppnt->p_memsz); > + } > + if (error != 0) { > + perror("load_elf_sections"); > + exit(-1); > + } > > if (elf_interpreter) { > elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, > @@ -817,6 +795,9 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, > exit(-1); > return 0; > } > + } else { > + interp_load_addr = et_dyn_addr; > + elf_entry += interp_load_addr; > } > > free(elf_phdata); > @@ -827,21 +808,18 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, > > close(bprm->fd); > > - bprm->p = target_create_elf_tables(bprm->p, bprm->argc, bprm->envc, bprm->stringp, > - &elf_ex, load_addr, load_bias, interp_load_addr, info); > + bprm->p = target_create_elf_tables(bprm->p, > + bprm->argc, > + bprm->envc, > + bprm->stringp, > + &elf_ex, > + load_addr, et_dyn_addr, > + interp_load_addr, > + info); > info->load_addr = reloc_func_desc; > 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->start_stack = bprm->p; > - > - /* Calling set_brk effectively mmaps the pages that we need for the bss and break > - sections */ > - set_brk(elf_bss, elf_brk); > - > - padzero(elf_bss, elf_brk); > + info->load_bias = 0; > > info->entry = elf_entry; > > -- > 2.32.0 >