int ELFNAME(os_pt_note)(struct proc *p, struct exec_package *epp, Elf_Ehdr *eh, char *os_name, size_t name_size, size_t desc_size) { Elf_Phdr *hph, *ph; Elf_Note *np = NULL; size_t phsize; int error; phsize = eh->e_phnum * sizeof(Elf_Phdr); hph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, (caddr_t)hph, phsize)) != 0) goto out1; for (ph = hph; ph < &hph[eh->e_phnum]; ph++) { if (ph->p_type != PT_NOTE || ph->p_filesz > 1024 || ph->p_filesz < sizeof(Elf_Note) + name_size) continue; np = (Elf_Note *)malloc(ph->p_filesz, M_TEMP, M_WAITOK); if ((error = ELFNAME(read_from)(p, epp->ep_vp, ph->p_offset, (caddr_t)np, ph->p_filesz)) != 0) goto out2; #if 0 if (np->type != ELF_NOTE_TYPE_OSVERSION) { free(np, M_TEMP); np = NULL; continue; } #endif /* Check the name and description sizes. */ if (np->namesz != name_size || np->descsz != desc_size) goto out3; if (bcmp((np + 1), os_name, name_size)) goto out3; /* XXX: We could check for the specific emulation here */ /* All checks succeeded. */ error = 0; goto out2; } out3: error = ENOEXEC; out2: if (np) free(np, M_TEMP); out1: free(hph, M_TEMP); return error; }
int ELFNAME(find_rd_root_image)(char *file, int fd, Elf_Phdr *ph, int segment, long *prd_root_size_off, long *prd_root_image_off, off_t *pmmap_off, size_t *pmmap_size) { unsigned long kernel_start, kernel_size; uint64_t rd_root_size_off, rd_root_image_off; if (ELFNAME(nlist)(fd, ELFNAME(wantsyms))) { fprintf(stderr, "%s: no rd_root_image symbols?\n", file); exit(1); } kernel_start = ph->p_paddr; kernel_size = ph->p_filesz; rd_root_size_off = ELFNAME(wantsyms)[0].n_value - kernel_start; rd_root_size_off -= (ph->p_vaddr - ph->p_paddr); rd_root_image_off = ELFNAME(wantsyms)[1].n_value - kernel_start; rd_root_image_off -= (ph->p_vaddr - ph->p_paddr); if (debug) { fprintf(stderr, "segment %d rd_root_size_off = 0x%x\n", segment, rd_root_size_off); if ((ph->p_vaddr - ph->p_paddr) != 0) fprintf(stderr, "root_off v %x p %x, diff %x altered %x\n", ph->p_vaddr, ph->p_paddr, (ph->p_vaddr - ph->p_paddr), rd_root_size_off - (ph->p_vaddr - ph->p_paddr)); fprintf(stderr, "rd_root_image_off = 0x%x\n", rd_root_image_off); } /* * Sanity check locations of db_* symbols */ if (rd_root_image_off < 0 || rd_root_image_off >= kernel_size) return (0); if (rd_root_size_off < 0 || rd_root_size_off >= kernel_size) { fprintf(stderr, "%s: rd_root_size not in data segment?\n", file); return (0); } *pmmap_off = ph->p_offset; *pmmap_size = kernel_size; *prd_root_size_off = rd_root_size_off; *prd_root_image_off = rd_root_image_off; return (1); }
/* * Check header for validity; return 0 for ok, ENOEXEC if error. * Remember OS tag for callers sake. */ int ELFNAME(olf_check_header)(Elf_Ehdr *ehdr, int type, u_int8_t *os) { int i; /* * We need to check magic, class size, endianess, version, and OS * before we look at the rest of the Elf_Ehdr structure. These few * elements are represented in a machine independant fashion. */ if (!IS_OLF(*ehdr) || ehdr->e_ident[OI_CLASS] != ELF_TARG_CLASS || ehdr->e_ident[OI_DATA] != ELF_TARG_DATA || ehdr->e_ident[OI_VERSION] != ELF_TARG_VER) return (ENOEXEC); for (i = 0; i < sizeof(ELFNAME(probes)) / sizeof(ELFNAME(probes)[0]); i++) { if ((1 << ehdr->e_ident[OI_OS]) & ELFNAME(probes)[i].os_mask) goto os_ok; } return (ENOEXEC); os_ok: /* Now check the machine dependant header */ if (ehdr->e_machine != ELF_TARG_MACH || ehdr->e_version != ELF_TARG_VER) return (ENOEXEC); /* Check the type */ if (ehdr->e_type != type) return (ENOEXEC); /* Don't allow an insane amount of sections. */ if (ehdr->e_phnum > ELF_MAX_VALID_PHDR) return (ENOEXEC); *os = ehdr->e_ident[OI_OS]; return (0); }
int linux_elf_probe(struct proc *p, struct exec_package *epp, char *itp, u_long *pos, u_int8_t *os) { Elf32_Ehdr *eh = epp->ep_hdr; char *bp, *brand; int error; size_t len; if (!(emul_linux_elf.e_flags & EMUL_ENABLED)) return (ENOEXEC); /* * Modern Linux binaries carry an identification note. */ if (ELFNAME(os_pt_note)(p, epp, epp->ep_hdr, "GNU", 4, 0x10) == 0) { goto recognized; } brand = elf32_check_brand(eh); if (brand != NULL && strcmp(brand, "Linux") != 0) return (EINVAL); /* * If this is a static binary, do not allow it to run, as it * has not been identified. We'll give non-static binaries a * chance to run, as the Linux ld.so name is usually unique * enough to clear any amibiguity. */ if (itp == NULL) return (EINVAL); recognized: if (itp) { if ((error = emul_find(p, NULL, linux_emul_path, itp, &bp, 0))) return (error); if ((error = copystr(bp, itp, MAXPATHLEN, &len))) return (error); free(bp, M_TEMP); } epp->ep_emul = &emul_linux_elf; *pos = ELF32_NO_ADDR; if (*os == OOS_NULL) *os = OOS_LINUX; mtx_init(&futex_lock, IPL_NONE); futex_pool_init(); return (0); }
void * ELFNAME(locate_image)(int fd, struct elfhdr *ghead, char *file, long *prd_root_size_off, long *prd_root_image_off, off_t *pmmap_off, size_t *pmmap_size) { int n; int found = 0; size_t phsize; Elf_Ehdr head; Elf_Phdr *ph; /* elfhdr may not have the full header? */ lseek(fd, 0, SEEK_SET); if (read(fd, &head, sizeof(head)) != sizeof(head)) { fprintf(stderr, "%s: can't read phdr area\n", file); exit(1); } phsize = head.e_phnum * sizeof(Elf_Phdr); ph = malloc(phsize); lseek(fd, head.e_phoff, SEEK_SET); if (read(fd, ph, phsize) != phsize) { fprintf(stderr, "%s: can't read phdr area\n", file); exit(1); } for (n = 0; n < head.e_phnum && !found; n++) { if (ph[n].p_type == PT_LOAD) found = ELFNAME(find_rd_root_image)(file, fd, &ph[n], n, prd_root_size_off, prd_root_image_off, pmmap_off, pmmap_size); } if (!found) { fprintf(stderr, "%s: can't locate space for rd_root_image!\n", file); exit(1); } free(ph); }
extern char linux_sigcode[], linux_esigcode[]; extern struct sysent linux_sysent[]; extern char *linux_syscallnames[]; struct emul ELFNAMEEND(emul_linux) = { "linux", native_to_linux_errno, linux_sendsig, LINUX_SYS_syscall, LINUX_SYS_MAXSYSCALL, linux_sysent, linux_syscallnames, LINUX_ELF_AUX_ARGSIZ, ELFNAME(copyargs), linux_setregs, linux_sigcode, linux_esigcode, }; #ifdef LINUX_GCC_SIGNATURE /* * Take advantage of the fact that all the linux binaries are compiled * with gcc, and gcc sticks in the comment field a signature. Note that * on SVR4 binaries, the gcc signature will follow the OS name signature, * that will not be a problem. We don't bother to read in the string table, * but we check all the progbits headers. * * XXX This only works in the i386. On the alpha (at least)
/* * Phase II of load. It is now safe to load the interpreter. Info collected * when loading the program is available for setup of the interpreter. */ int ELFNAME2(exec,fixup)(struct proc *p, struct exec_package *epp) { char *interp; int error; struct elf_args *ap; AuxInfo ai[ELF_AUX_ENTRIES], *a; Elf_Addr pos = epp->ep_interp_pos; if (epp->ep_interp == NULL) { return (0); } interp = (char *)epp->ep_interp; ap = (struct elf_args *)epp->ep_emul_arg; if ((error = ELFNAME(load_file)(p, interp, epp, ap, &pos)) != 0) { free((char *)ap, M_TEMP); free((char *)interp, M_TEMP); kill_vmcmds(&epp->ep_vmcmds); return (error); } /* * We have to do this ourselves... */ error = exec_process_vmcmds(p, epp); /* * Push extra arguments on the stack needed by dynamically * linked binaries */ if (error == 0) { a = ai; a->au_id = AUX_phdr; a->au_v = ap->arg_phaddr; a++; a->au_id = AUX_phent; a->au_v = ap->arg_phentsize; a++; a->au_id = AUX_phnum; a->au_v = ap->arg_phnum; a++; a->au_id = AUX_pagesz; a->au_v = PAGE_SIZE; a++; a->au_id = AUX_base; a->au_v = ap->arg_interp; a++; a->au_id = AUX_flags; a->au_v = 0; a++; a->au_id = AUX_entry; a->au_v = ap->arg_entry; a++; a->au_id = AUX_null; a->au_v = 0; a++; error = copyout(ai, epp->ep_emul_argp, sizeof ai); } free((char *)ap, M_TEMP); free((char *)interp, M_TEMP); return (error); }
/* * Prepare an Elf binary's exec package * * First, set of the various offsets/lengths in the exec package. * * Then, mark the text image busy (so it can be demand paged) or error out if * this is not possible. Finally, set up vmcmds for the text, data, bss, and * stack segments. */ int ELFNAME2(exec,makecmds)(struct proc *p, struct exec_package *epp) { Elf_Ehdr *eh = epp->ep_hdr; Elf_Phdr *ph, *pp; Elf_Addr phdr = 0; int error, i; char interp[MAXPATHLEN]; u_long pos = 0, phsize; u_int8_t os = OOS_NULL; if (epp->ep_hdrvalid < sizeof(Elf_Ehdr)) return (ENOEXEC); if (ELFNAME(check_header)(eh, ET_EXEC) && ELFNAME(olf_check_header)(eh, ET_EXEC, &os)) return (ENOEXEC); /* * check if vnode is in open for writing, because we want to demand- * page out of it. if it is, don't do it, for various reasons. */ if (epp->ep_vp->v_writecount != 0) { #ifdef DIAGNOSTIC if (epp->ep_vp->v_flag & VTEXT) panic("exec: a VTEXT vnode has writecount != 0"); #endif return (ETXTBSY); } /* * Allocate space to hold all the program headers, and read them * from the file */ phsize = eh->e_phnum * sizeof(Elf_Phdr); ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, (caddr_t)ph, phsize)) != 0) goto bad; epp->ep_tsize = ELFDEFNNAME(NO_ADDR); epp->ep_dsize = ELFDEFNNAME(NO_ADDR); interp[0] = '\0'; for (i = 0; i < eh->e_phnum; i++) { pp = &ph[i]; if (pp->p_type == PT_INTERP) { if (pp->p_filesz >= sizeof(interp)) goto bad; if ((error = ELFNAME(read_from)(p, epp->ep_vp, pp->p_offset, (caddr_t)interp, pp->p_filesz)) != 0) goto bad; break; } } /* * OK, we want a slightly different twist of the * standard emulation package for "real" elf. */ epp->ep_emul = &ELFNAMEEND(emul); pos = ELFDEFNNAME(NO_ADDR); /* * On the same architecture, we may be emulating different systems. * See which one will accept this executable. * * Probe functions would normally see if the interpreter (if any) * exists. Emulation packages may possibly replace the interpreter in * interp[] with a changed path (/emul/xxx/<path>), and also * set the ep_emul field in the exec package structure. */ error = ENOEXEC; p->p_os = OOS_OPENBSD; #ifdef NATIVE_EXEC_ELF if (ELFNAME(os_pt_note)(p, epp, epp->ep_hdr, "OpenBSD", 8, 4) == 0) { goto native; } #endif for (i = 0; i < sizeof(ELFNAME(probes)) / sizeof(ELFNAME(probes)[0]) && error; i++) { if (os == OOS_NULL || ((1 << os) & ELFNAME(probes)[i].os_mask)) error = ELFNAME(probes)[i].func ? (*ELFNAME(probes)[i].func)(p, epp, interp, &pos, &os) : 0; } if (!error) p->p_os = os; #ifndef NATIVE_EXEC_ELF else goto bad; #else native: #endif /* NATIVE_EXEC_ELF */ /* * Load all the necessary sections */ for (i = 0; i < eh->e_phnum; i++) { Elf_Addr addr = ELFDEFNNAME(NO_ADDR), size = 0; int prot = 0; pp = &ph[i]; switch (ph[i].p_type) { case PT_LOAD: /* * Calcuates size of text and data segments * by starting at first and going to end of last. * 'rwx' sections are treated as data. * this is correct for BSS_PLT, but may not be * for DATA_PLT, is fine for TEXT_PLT. */ ELFNAME(load_psection)(&epp->ep_vmcmds, epp->ep_vp, &ph[i], &addr, &size, &prot, 0); /* * Decide whether it's text or data by looking * at the protection of the section */ if (prot & VM_PROT_WRITE) { /* data section */ if (epp->ep_dsize == ELFDEFNNAME(NO_ADDR)) { epp->ep_daddr = addr; epp->ep_dsize = size; } else { if (addr < epp->ep_daddr) { epp->ep_dsize = epp->ep_dsize + epp->ep_daddr - addr; epp->ep_daddr = addr; } else epp->ep_dsize = addr+size - epp->ep_daddr; } } else if (prot & VM_PROT_EXECUTE) { /* text section */ if (epp->ep_tsize == ELFDEFNNAME(NO_ADDR)) { epp->ep_taddr = addr; epp->ep_tsize = size; } else { if (addr < epp->ep_taddr) { epp->ep_tsize = epp->ep_tsize + epp->ep_taddr - addr; epp->ep_taddr = addr; } else epp->ep_tsize = addr+size - epp->ep_taddr; } } break; case PT_SHLIB: error = ENOEXEC; goto bad; case PT_INTERP: /* Already did this one */ case PT_DYNAMIC: case PT_NOTE: break; case PT_PHDR: /* Note address of program headers (in text segment) */ phdr = pp->p_vaddr; break; default: /* * Not fatal, we don't need to understand everything * :-) */ break; } } /* * Check if we found a dynamically linked binary and arrange to load * it's interpreter when the exec file is released. */ if (interp[0]) { char *ip; struct elf_args *ap; ip = (char *)malloc(MAXPATHLEN, M_TEMP, M_WAITOK); ap = (struct elf_args *) malloc(sizeof(struct elf_args), M_TEMP, M_WAITOK); bcopy(interp, ip, MAXPATHLEN); epp->ep_interp = ip; epp->ep_interp_pos = pos; ap->arg_phaddr = phdr; ap->arg_phentsize = eh->e_phentsize; ap->arg_phnum = eh->e_phnum; ap->arg_entry = eh->e_entry; ap->arg_os = os; epp->ep_emul_arg = ap; epp->ep_entry = eh->e_entry; /* keep check_exec() happy */ } else { epp->ep_interp = NULL; epp->ep_entry = eh->e_entry; } #if defined(COMPAT_SVR4) && defined(i386) #ifndef ELF_MAP_PAGE_ZERO /* Dell SVR4 maps page zero, yeuch! */ if (p->p_os == OOS_DELL) #endif NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, PAGE_SIZE, 0, epp->ep_vp, 0, VM_PROT_READ); #endif free((char *)ph, M_TEMP); vn_marktext(epp->ep_vp); return (exec_setup_stack(p, epp)); bad: free((char *)ph, M_TEMP); kill_vmcmds(&epp->ep_vmcmds); return (ENOEXEC); }
/* * Load a file (interpreter/library) pointed to by path [stolen from * coff_load_shlib()]. Made slightly generic so it might be used externally. */ int ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp, struct elf_args *ap, Elf_Addr *last) { int error, i; struct nameidata nd; Elf_Ehdr eh; Elf_Phdr *ph = NULL; u_long phsize; char *bp = NULL; Elf_Addr addr; struct vnode *vp; u_int8_t os; /* Just a dummy in this routine */ Elf_Phdr *base_ph = NULL; struct interp_ld_sec { Elf_Addr vaddr; u_long memsz; } loadmap[ELF_MAX_VALID_PHDR]; int nload, idx = 0; Elf_Addr pos = *last; int file_align; bp = path; NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p); if ((error = namei(&nd)) != 0) { return (error); } vp = nd.ni_vp; if (vp->v_type != VREG) { error = EACCES; goto bad; } if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 0) goto bad; if (vp->v_mount->mnt_flag & MNT_NOEXEC) { error = EACCES; goto bad; } if ((error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) != 0) goto bad1; if ((error = ELFNAME(read_from)(p, nd.ni_vp, 0, (caddr_t)&eh, sizeof(eh))) != 0) goto bad1; if (ELFNAME(check_header)(&eh, ET_DYN) && ELFNAME(olf_check_header)(&eh, ET_DYN, &os)) { error = ENOEXEC; goto bad1; } phsize = eh.e_phnum * sizeof(Elf_Phdr); ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); if ((error = ELFNAME(read_from)(p, nd.ni_vp, eh.e_phoff, (caddr_t)ph, phsize)) != 0) goto bad1; for (i = 0; i < eh.e_phnum; i++) { if (ph[i].p_type == PT_LOAD) { loadmap[idx].vaddr = trunc_page(ph[i].p_vaddr); loadmap[idx].memsz = round_page (ph[i].p_vaddr + ph[i].p_memsz - loadmap[idx].vaddr); file_align = ph[i].p_align; idx++; } } nload = idx; /* * If no position to load the interpreter was set by a probe * function, pick the same address that a non-fixed mmap(0, ..) * would (i.e. something safely out of the way). */ if (pos == ELFDEFNNAME(NO_ADDR)) { pos = uvm_map_hint(p, VM_PROT_EXECUTE); } pos = ELF_ROUND(pos, file_align); *last = epp->ep_interp_pos = pos; for (i = 0; i < nload;/**/) { vaddr_t addr; struct uvm_object *uobj; off_t uoff; size_t size; #ifdef this_needs_fixing if (i == 0) { uobj = &vp->v_uvm.u_obj; /* need to fix uoff */ } else { #endif uobj = NULL; uoff = 0; #ifdef this_needs_fixing } #endif addr = trunc_page(pos + loadmap[i].vaddr); size = round_page(addr + loadmap[i].memsz) - addr; /* CRAP - map_findspace does not avoid daddr+MAXDSIZ */ if ((addr + size > (vaddr_t)p->p_vmspace->vm_daddr) && (addr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)) addr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); if (uvm_map_findspace(&p->p_vmspace->vm_map, addr, size, &addr, uobj, uoff, 0, UVM_FLAG_FIXED) == NULL) { if (uvm_map_findspace(&p->p_vmspace->vm_map, addr, size, &addr, uobj, uoff, 0, 0) == NULL) { error = ENOMEM; /* XXX */ goto bad1; } } if (addr != pos + loadmap[i].vaddr) { /* base changed. */ pos = addr - trunc_page(loadmap[i].vaddr); pos = ELF_ROUND(pos,file_align); epp->ep_interp_pos = *last = pos; i = 0; continue; } i++; } /* * Load all the necessary sections */ for (i = 0; i < eh.e_phnum; i++) { Elf_Addr size = 0; int prot = 0; int flags; switch (ph[i].p_type) { case PT_LOAD: if (base_ph == NULL) { flags = VMCMD_BASE; addr = *last; base_ph = &ph[i]; } else { flags = VMCMD_RELATIVE; addr = ph[i].p_vaddr - base_ph->p_vaddr; } ELFNAME(load_psection)(&epp->ep_vmcmds, nd.ni_vp, &ph[i], &addr, &size, &prot, flags); /* If entry is within this section it must be text */ if (eh.e_entry >= ph[i].p_vaddr && eh.e_entry < (ph[i].p_vaddr + size)) { epp->ep_entry = addr + eh.e_entry - ELF_TRUNC(ph[i].p_vaddr,ph[i].p_align); ap->arg_interp = addr; } addr += size; break; case PT_DYNAMIC: case PT_PHDR: case PT_NOTE: break; default: break; } } vn_marktext(nd.ni_vp); bad1: VOP_CLOSE(nd.ni_vp, FREAD, p->p_ucred, p); bad: if (ph != NULL) free((char *)ph, M_TEMP); *last = addr; vput(nd.ni_vp); return (error); }
int ELFNAME(nlist)(int fd, struct nlist *list) { struct nlist *p; caddr_t strtab; Elf_Off symoff = 0, symstroff = 0; Elf_Word symsize = 0; long symstrsize = 0; Elf_Sword nent, cc, i; Elf_Sym sbuf[1024]; Elf_Sym *s; Elf_Ehdr ehdr; Elf_Shdr *shdr = NULL; size_t shdr_size; struct stat st; int usemalloc = 0; size_t left, len; /* Make sure obj is OK */ if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) || !ELFNAME(__elf_is_okay__)(&ehdr) || fstat(fd, &st) < 0) return (-1); /* calculate section header table size */ shdr_size = ehdr.e_shentsize * ehdr.e_shnum; /* Make sure it's not too big to mmap */ if (SIZE_MAX - ehdr.e_shoff < shdr_size || S_ISREG(st.st_mode) && ehdr.e_shoff + shdr_size > st.st_size) { errno = EFBIG; return (-1); } /* mmap section header table */ shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff); if (shdr == MAP_FAILED) { usemalloc = 1; if ((shdr = malloc(shdr_size)) == NULL) return (-1); if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) != shdr_size) { free(shdr); return (-1); } } /* * Find the symbol table entry and its corresponding * string table entry. Version 1.1 of the ABI states * that there is only one symbol table but that this * could change in the future. */ for (i = 0; i < ehdr.e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { if (shdr[i].sh_link >= ehdr.e_shnum) continue; symoff = shdr[i].sh_offset; symsize = shdr[i].sh_size; symstroff = shdr[shdr[i].sh_link].sh_offset; symstrsize = shdr[shdr[i].sh_link].sh_size; break; } } /* Flush the section header table */ if (usemalloc) free(shdr); else munmap((caddr_t)shdr, shdr_size); /* * clean out any left-over information for all valid entries. * Type and value defined to be 0 if not found; historical * versions cleared other and desc as well. Also figure out * the largest string length so don't read any more of the * string table than we have to. * * XXX clearing anything other than n_type and n_value violates * the semantics given in the man page. */ nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } /* Don't process any further if object is stripped. */ /* ELFism - dunno if stripped by looking at header */ if (symoff == 0) return nent; /* Check for files too large to mmap. */ if (SIZE_MAX - symstrsize < symstroff || S_ISREG(st.st_mode) && symstrsize + symstroff > st.st_size) { errno = EFBIG; return (-1); } /* * Map string table into our address space. This gives us * an easy way to randomly access all the strings, without * making the memory allocation permanent as with malloc/free * (i.e., munmap will return it to the system). */ if (usemalloc) { if ((strtab = malloc(symstrsize)) == NULL) return (-1); if (pread(fd, strtab, symstrsize, (off_t)symstroff) != symstrsize) { free(strtab); return (-1); } } else { strtab = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_SHARED|MAP_FILE, fd, (off_t) symstroff); if (strtab == MAP_FAILED) return (-1); } while (symsize >= sizeof(Elf_Sym)) { cc = MIN(symsize, sizeof(sbuf)); if (pread(fd, sbuf, cc, (off_t)symoff) != cc) break; symsize -= cc; symoff += cc; for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) { Elf_Word soff = s->st_name; if (soff == 0 || soff >= symstrsize) continue; left = symstrsize - soff; for (p = list; !ISLAST(p); p++) { char *sym; /* * First we check for the symbol as it was * provided by the user. If that fails * and the first char is an '_', skip over * the '_' and try again. * XXX - What do we do when the user really * wants '_foo' and there are symbols * for both 'foo' and '_foo' in the * table and 'foo' is first? */ sym = p->n_name; len = strlen(sym); if ((len >= left || strcmp(&strtab[soff], sym) != 0) && (sym[0] != '_' || len - 1 >= left || strcmp(&strtab[soff], sym + 1) != 0)) continue; p->n_value = s->st_value; /* XXX - type conversion */ /* is pretty rude. */ switch(ELF_ST_TYPE(s->st_info)) { case STT_NOTYPE: switch (s->st_shndx) { case SHN_UNDEF: p->n_type = N_UNDF; break; case SHN_ABS: p->n_type = N_ABS; break; case SHN_COMMON: p->n_type = N_COMM; break; default: p->n_type = N_COMM | N_EXT; break; } break; case STT_OBJECT: p->n_type = N_DATA; break; case STT_FUNC: p->n_type = N_TEXT; break; case STT_FILE: p->n_type = N_FN; break; } if (ELF_ST_BIND(s->st_info) == STB_LOCAL) p->n_type = N_EXT; p->n_desc = 0; p->n_other = 0; if (--nent <= 0) break; } } } elf_done: if (usemalloc) free(strtab); else munmap(strtab, symstrsize); return (nent); }
#include <limits.h> #include <sys/exec_elf.h> #include "elfrdsetroot.h" void * ELFNAME(locate_image)(int, struct elfhdr *, char *, long *, long *, off_t *, size_t *); int ELFNAME(find_rd_root_image)(char *, int, Elf_Phdr *, int, long *, long *, off_t *, size_t *); struct elf_fn ELFDEFNNAME(fn) = { ELFNAME(locate_image), ELFNAME(find_rd_root_image) }; void * ELFNAME(locate_image)(int fd, struct elfhdr *ghead, char *file, long *prd_root_size_off, long *prd_root_image_off, off_t *pmmap_off, size_t *pmmap_size) { int n; int found = 0; size_t phsize; Elf_Ehdr head; Elf_Phdr *ph;