diff options
-rw-r--r-- | sys/kern/exec_elf.c | 98 |
1 files changed, 85 insertions, 13 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index ca8a3b58b4d..982a43412db 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.44 2003/02/18 03:54:40 drahn Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.45 2003/04/16 21:17:52 drahn Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -111,6 +111,12 @@ extern char *syscallnames[]; #define ELF_TRUNC(a, b) ((a) & ~((b) - 1)) /* + * We limit the number of program headers to 32, this should + * be a reasonable limit for ELF, the most we have seen so far is 12 + */ +#define ELF_MAX_VALID_PHDR 32 + +/* * This is the basic elf emul. elf_probe_funcs may change to other emuls. */ struct emul ELFNAMEEND(emul) = { @@ -183,7 +189,7 @@ ELFNAME(check_header)(Elf_Ehdr *ehdr, int type) return (ENOEXEC); /* Don't allow an insane amount of sections. */ - if (ehdr->e_phnum > 128) + if (ehdr->e_phnum > ELF_MAX_VALID_PHDR) return (ENOEXEC); return (0); @@ -228,7 +234,7 @@ os_ok: return (ENOEXEC); /* Don't allow an insane amount of sections. */ - if (ehdr->e_phnum > 128) + if (ehdr->e_phnum > ELF_MAX_VALID_PHDR) return (ENOEXEC); *os = ehdr->e_ident[OI_OS]; @@ -349,6 +355,13 @@ ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp, 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); @@ -385,6 +398,75 @@ ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp, 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 */ @@ -626,16 +708,6 @@ native: } } -#if !defined(__mips__) - /* - * 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 = round_page(epp->ep_daddr + MAXDSIZ); -#endif - /* * Check if we found a dynamically linked binary and arrange to load * it's interpreter when the exec file is released. |