summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/imgact_elf.c271
1 files changed, 108 insertions, 163 deletions
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index c33c6be..e049b52 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -26,7 +26,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: imgact_elf.c,v 1.39 1998/10/15 09:52:19 dfr Exp $
+ * $Id: imgact_elf.c,v 1.40 1998/10/16 03:55:00 peter Exp $
*/
#include "opt_rlimit.h"
@@ -63,40 +63,25 @@
#include <vm/vm_prot.h>
#include <vm/vm_extern.h>
+#include <machine/elf.h>
#include <machine/md_var.h>
-#define MAX_PHDR 32 /* XXX enough ? */
-
-#if ELF_TARG_CLASS == ELFCLASS32
-
-#define Elf_Ehdr Elf32_Ehdr
-#define Elf_Phdr Elf32_Phdr
-#define Elf_Auxargs Elf32_Auxargs
-#define Elf_Brandinfo Elf32_Brandinfo
-
-#else
-
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Phdr Elf64_Phdr
-#define Elf_Auxargs Elf64_Auxargs
-#define Elf_Brandinfo Elf64_Brandinfo
-
-#endif
-
+__ElfType(Brandinfo);
+__ElfType(Auxargs);
static int elf_check_header __P((const Elf_Ehdr *hdr, int type));
static int elf_freebsd_fixup __P((long **stack_base,
struct image_params *imgp));
static int elf_load_file __P((struct proc *p, char *file, u_long *addr,
u_long *entry));
-static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp,
+static int elf_load_section __P((struct proc *p,
+ struct vmspace *vmspace, struct vnode *vp,
vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz,
vm_prot_t prot));
static int exec_elf_imgact __P((struct image_params *imgp));
static int elf_trace = 0;
SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, "");
-#define UPRINTF if (elf_trace) uprintf
static struct sysentvec elf_freebsd_sysvec = {
SYS_MAXSYSCALL,
@@ -163,86 +148,124 @@ elf_remove_brand_entry(Elf_Brandinfo *entry)
static int
elf_check_header(const Elf_Ehdr *hdr, int type)
{
- if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 &&
- hdr->e_ident[EI_MAG1] == ELFMAG1 &&
- hdr->e_ident[EI_MAG2] == ELFMAG2 &&
- hdr->e_ident[EI_MAG3] == ELFMAG3))
+ if (!IS_ELF(*hdr) ||
+ hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+ hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
+ hdr->e_ident[EI_VERSION] != EV_CURRENT)
return ENOEXEC;
-#ifdef __i386__
- if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486)
-#endif
-#ifdef __alpha__
- if (hdr->e_machine != EM_ALPHA)
-#endif
+ if (!ELF_MACHINE_OK(hdr->e_machine))
return ENOEXEC;
-
- if (hdr->e_type != type)
+ if (hdr->e_type != type || hdr->e_version != ELF_TARG_VER)
return ENOEXEC;
return 0;
}
static int
-elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)
+elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)
{
size_t map_len;
vm_offset_t map_addr;
- int error;
- unsigned char *data_buf = 0;
+ int error, rv;
size_t copy_len;
+ vm_object_t object;
+ vm_offset_t file_addr;
+ vm_offset_t data_buf = 0;
+
+ object = vp->v_object;
+ error = 0;
map_addr = trunc_page((vm_offset_t)vmaddr);
+ file_addr = trunc_page(offset);
+ /*
+ * We have two choices. We can either clear the data in the last page
+ * of an oversized mapping, or we can start the anon mapping a page
+ * early and copy the initialized data into that first page. We
+ * choose the second..
+ */
if (memsz > filsz)
- map_len = trunc_page(offset+filsz) - trunc_page(offset);
+ map_len = trunc_page(offset+filsz) - file_addr;
else
- map_len = round_page(offset+filsz) - trunc_page(offset);
-
- if (error = vm_mmap (&vmspace->vm_map,
- &map_addr,
- map_len,
- prot,
- VM_PROT_ALL,
- MAP_PRIVATE | MAP_FIXED,
- (caddr_t)vp,
- trunc_page(offset)))
- return error;
+ map_len = round_page(offset+filsz) - file_addr;
+
+ if (map_len != 0) {
+ vm_object_reference(object);
+ vm_map_lock(&vmspace->vm_map);
+ rv = vm_map_insert(&vmspace->vm_map,
+ object,
+ file_addr, /* file offset */
+ map_addr, /* virtual start */
+ map_addr + map_len,/* virtual end */
+ prot,
+ VM_PROT_ALL,
+ MAP_COPY_NEEDED | MAP_COPY_ON_WRITE);
+ vm_map_unlock(&vmspace->vm_map);
+ if (rv != KERN_SUCCESS)
+ return EINVAL;
+
+ /* prefault the page tables */
+ pmap_object_init_pt(&vmspace->vm_pmap,
+ map_addr,
+ object,
+ (vm_pindex_t) OFF_TO_IDX(file_addr),
+ map_len,
+ 0);
+
+ /* we can stop now if we've covered it all */
+ if (memsz == filsz)
+ return 0;
+ }
- if (memsz == filsz)
- return 0;
/*
- * We have to map the remaining bit of the file into the kernel's
- * memory map, allocate some anonymous memory, and copy that last
- * bit into it. The remaining space should be .bss...
+ * We have to get the remaining bit of the file into the first part
+ * of the oversized map segment. This is normally because the .data
+ * segment in the file is extended to provide bss. It's a neat idea
+ * to try and save a page, but it's a pain in the behind to implement.
*/
copy_len = (offset + filsz) - trunc_page(offset + filsz);
map_addr = trunc_page((vm_offset_t)vmaddr + filsz);
map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr;
+ /* This had damn well better be true! */
if (map_len != 0) {
- if (error = vm_map_find(&vmspace->vm_map, NULL, 0,
- &map_addr, map_len, FALSE,
- VM_PROT_ALL, VM_PROT_ALL,0))
- return error;
+ vm_map_lock(&vmspace->vm_map);
+ rv = vm_map_insert(&vmspace->vm_map, NULL, 0,
+ map_addr, map_addr + map_len,
+ VM_PROT_ALL, VM_PROT_ALL, 0);
+ vm_map_unlock(&vmspace->vm_map);
+ if (rv != KERN_SUCCESS)
+ return EINVAL;
}
- if (error = vm_mmap(exec_map,
- (vm_offset_t *)&data_buf,
- PAGE_SIZE,
- VM_PROT_READ,
- VM_PROT_READ,
- 0,
- (caddr_t)vp,
- trunc_page(offset + filsz)))
- return error;
-
- error = copyout(data_buf, (caddr_t)map_addr, copy_len);
-
- vm_map_remove(exec_map, (vm_offset_t)data_buf,
- (vm_offset_t)data_buf + PAGE_SIZE);
+ if (copy_len != 0) {
+ vm_object_reference(object);
+ rv = vm_map_find(exec_map,
+ object,
+ trunc_page(offset + filsz),
+ &data_buf,
+ PAGE_SIZE,
+ TRUE,
+ VM_PROT_READ,
+ VM_PROT_ALL,
+ MAP_COPY_ON_WRITE | MAP_COPY_NEEDED);
+ if (rv != KERN_SUCCESS) {
+ vm_object_deallocate(object);
+ return EINVAL;
+ }
+ pmap_object_init_pt(exec_map->pmap, data_buf, object,
+ (vm_pindex_t) OFF_TO_IDX(trunc_page(offset + filsz)),
+ PAGE_SIZE, 1);
+
+ /* send the page fragment to user space */
+ error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len);
+ vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE);
+ if (error)
+ return (error);
+ }
/*
* set it to the specified protection
@@ -250,7 +273,6 @@ elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset,
vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot,
FALSE);
- UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len);
return error;
}
@@ -263,10 +285,9 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
struct vmspace *vmspace = p->p_vmspace;
struct vattr attr;
struct image_params image_params, *imgp;
- vm_prot_t prot = 0;
+ vm_prot_t prot;
unsigned long text_size = 0, data_size = 0;
unsigned long text_addr = 0, data_addr = 0;
- int header_size = 0;
int error, i;
imgp = &image_params;
@@ -312,19 +333,9 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
if (error = elf_check_header(hdr, ET_DYN))
goto fail;
- /*
- * ouch, need to bounds check in case user gives us a corrupted
- * file with an insane header size
- */
- if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */
- error = ENOEXEC;
- goto fail;
- }
-
- header_size = hdr->e_phentsize * hdr->e_phnum;
-
/* Only support headers that fit within first page for now */
- if (header_size + hdr->e_phoff > PAGE_SIZE) {
+ if ((hdr->e_phoff > PAGE_SIZE) ||
+ (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) {
error = ENOEXEC;
goto fail;
}
@@ -332,14 +343,8 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
for (i = 0; i < hdr->e_phnum; i++) {
- switch(phdr[i].p_type) {
-
- case PT_NULL: /* NULL section */
- UPRINTF ("ELF(file) PT_NULL section\n");
- break;
- case PT_LOAD: /* Loadable segment */
- {
- UPRINTF ("ELF(file) PT_LOAD section ");
+ if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */
+ prot = 0;
if (phdr[i].p_flags & PF_X)
prot |= VM_PROT_EXECUTE;
if (phdr[i].p_flags & PF_W)
@@ -347,7 +352,7 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
if (phdr[i].p_flags & PF_R)
prot |= VM_PROT_READ;
- if (error = elf_load_section(vmspace, nd.ni_vp,
+ if (error = elf_load_section(p, vmspace, nd.ni_vp,
phdr[i].p_offset,
(caddr_t)phdr[i].p_vaddr +
(*addr),
@@ -367,37 +372,13 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
phdr[i].p_vaddr -
trunc_page(phdr[i].p_vaddr));
*entry=(unsigned long)hdr->e_entry+(*addr);
- UPRINTF(".text <%08lx,%08lx> entry=%08lx\n",
- text_addr, text_size, *entry);
} else {
data_addr = trunc_page(phdr[i].p_vaddr+(*addr));
data_size = round_page(phdr[i].p_memsz +
phdr[i].p_vaddr -
trunc_page(phdr[i].p_vaddr));
- UPRINTF(".data <%08lx,%08lx>\n",
- data_addr, data_size);
}
}
- break;
-
- case PT_DYNAMIC:/* Dynamic link information */
- UPRINTF ("ELF(file) PT_DYNAMIC section\n");
- break;
- case PT_INTERP: /* Path to interpreter */
- UPRINTF ("ELF(file) PT_INTERP section\n");
- break;
- case PT_NOTE: /* Note section */
- UPRINTF ("ELF(file) PT_NOTE section\n");
- break;
- case PT_SHLIB: /* Shared lib section */
- UPRINTF ("ELF(file) PT_SHLIB section\n");
- break;
- case PT_PHDR: /* Program header table info */
- UPRINTF ("ELF(file) PT_PHDR section\n");
- break;
- default:
- UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type );
- }
}
fail:
@@ -419,11 +400,11 @@ exec_elf_imgact(struct image_params *imgp)
const Elf_Phdr *phdr, *mapped_phdr = NULL;
Elf_Auxargs *elf_auxargs = NULL;
struct vmspace *vmspace;
- vm_prot_t prot = 0;
+ vm_prot_t prot;
u_long text_size = 0, data_size = 0;
u_long text_addr = 0, data_addr = 0;
u_long addr, entry = 0, proghdr = 0;
- int error, i, header_size = 0;
+ int error, i;
const char *interp = NULL;
Elf_Brandinfo *brand_info;
char *brand;
@@ -440,24 +421,12 @@ exec_elf_imgact(struct image_params *imgp)
* detected an ELF file.
*/
- /*
- * ouch, need to bounds check in case user gives us a corrupted
- * file with an insane header size
- */
- if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */
- return ENOEXEC;
- }
-
- header_size = hdr->e_phentsize * hdr->e_phnum;
-
if ((hdr->e_phoff > PAGE_SIZE) ||
- (hdr->e_phoff + header_size) > PAGE_SIZE) {
+ (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) {
/* Only support headers in first page for now */
return ENOEXEC;
- } else {
- phdr = (const Elf_Phdr*)
- ((const char *)imgp->image_header + hdr->e_phoff);
}
+ phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff);
/*
* From this point on, we may have resources that need to be freed.
@@ -472,12 +441,8 @@ exec_elf_imgact(struct image_params *imgp)
for (i = 0; i < hdr->e_phnum; i++) {
switch(phdr[i].p_type) {
- case PT_NULL: /* NULL section */
- UPRINTF ("ELF PT_NULL section\n");
- break;
case PT_LOAD: /* Loadable segment */
- {
- UPRINTF ("ELF PT_LOAD section ");
+ prot = 0;
if (phdr[i].p_flags & PF_X)
prot |= VM_PROT_EXECUTE;
if (phdr[i].p_flags & PF_W)
@@ -485,7 +450,8 @@ exec_elf_imgact(struct image_params *imgp)
if (phdr[i].p_flags & PF_R)
prot |= VM_PROT_READ;
- if (error = elf_load_section(vmspace, imgp->vp,
+ if (error = elf_load_section(imgp->proc,
+ vmspace, imgp->vp,
phdr[i].p_offset,
(caddr_t)phdr[i].p_vaddr,
phdr[i].p_memsz,
@@ -504,44 +470,26 @@ exec_elf_imgact(struct image_params *imgp)
phdr[i].p_vaddr -
text_addr);
entry = (u_long)hdr->e_entry;
- UPRINTF(".text <%08lx,%08lx> entry=%08lx\n",
- text_addr, text_size, entry);
} else {
data_addr = trunc_page(phdr[i].p_vaddr);
data_size = round_page(phdr[i].p_memsz +
phdr[i].p_vaddr -
data_addr);
- UPRINTF(".data <%08lx,%08lx>\n",
- data_addr, data_size);
}
- }
- break;
-
- case PT_DYNAMIC:/* Dynamic link information */
- UPRINTF ("ELF PT_DYNAMIC section ??\n");
break;
case PT_INTERP: /* Path to interpreter */
- UPRINTF ("ELF PT_INTERP section ");
if (phdr[i].p_filesz > MAXPATHLEN ||
phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) {
error = ENOEXEC;
goto fail;
}
interp = imgp->image_header + phdr[i].p_offset;
- UPRINTF("<%s>\n", interp);
- break;
- case PT_NOTE: /* Note section */
- UPRINTF ("ELF PT_NOTE section\n");
- break;
- case PT_SHLIB: /* Shared lib section */
- UPRINTF ("ELF PT_SHLIB section\n");
break;
case PT_PHDR: /* Program header table info */
- UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr);
proghdr = phdr[i].p_vaddr;
break;
default:
- UPRINTF ("ELF %d section ??\n", phdr[i].p_type);
+ break;
}
}
@@ -602,7 +550,6 @@ exec_elf_imgact(struct image_params *imgp)
if (interp != NULL) {
strcpy(path, brand_info->emul_path);
strcat(path, interp);
- UPRINTF("interpreter=<%s> %s\n", interp, brand_info->emul_path);
if ((error = elf_load_file(imgp->proc, path, &addr,
&imgp->entry_addr)) != 0) {
uprintf("ELF interpreter %s not found\n", path);
@@ -610,8 +557,6 @@ exec_elf_imgact(struct image_params *imgp)
}
}
- UPRINTF("Executing %s binary\n", brand_info->brand);
-
/*
* Construct auxargs table (used by the fixup routine)
*/
OpenPOWER on IntegriCloud