Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/link_elf.c
Show All 34 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#ifdef GPROF | #ifdef GPROF | ||||
#include <sys/gmon.h> | #include <sys/gmon.h> | ||||
#endif | #endif | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#ifdef SPARSE_MAPPING | |||||
#include <sys/mman.h> | |||||
#endif | |||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
#include <sys/pcpu.h> | #include <sys/pcpu.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/namei.h> | #include <sys/namei.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/linker.h> | #include <sys/linker.h> | ||||
▲ Show 20 Lines • Show All 363 Lines • ▼ Show 20 Lines | link_elf_init(void* arg) | ||||
ef = (elf_file_t) linker_kernel_file; | ef = (elf_file_t) linker_kernel_file; | ||||
ef->preloaded = 1; | ef->preloaded = 1; | ||||
#ifdef __powerpc__ | #ifdef __powerpc__ | ||||
ef->address = (caddr_t) (__startkernel - KERNBASE); | ef->address = (caddr_t) (__startkernel - KERNBASE); | ||||
#else | #else | ||||
ef->address = 0; | ef->address = 0; | ||||
#endif | #endif | ||||
#ifdef SPARSE_MAPPING | #ifdef SPARSE_MAPPING | ||||
ef->object = 0; | ef->object = NULL; | ||||
#endif | #endif | ||||
ef->dynamic = dp; | ef->dynamic = dp; | ||||
if (dp != NULL) | if (dp != NULL) | ||||
parse_dynamic(ef); | parse_dynamic(ef); | ||||
#ifdef __powerpc__ | #ifdef __powerpc__ | ||||
linker_kernel_file->address = (caddr_t)__startkernel; | linker_kernel_file->address = (caddr_t)__startkernel; | ||||
linker_kernel_file->size = (intptr_t)(__endkernel - __startkernel); | linker_kernel_file->size = (intptr_t)(__endkernel - __startkernel); | ||||
▲ Show 20 Lines • Show All 336 Lines • ▼ Show 20 Lines | link_elf_link_preload(linker_class_t cls, | ||||
if (lf == NULL) | if (lf == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
ef = (elf_file_t) lf; | ef = (elf_file_t) lf; | ||||
ef->preloaded = 1; | ef->preloaded = 1; | ||||
ef->modptr = modptr; | ef->modptr = modptr; | ||||
ef->address = *(caddr_t *)baseptr; | ef->address = *(caddr_t *)baseptr; | ||||
#ifdef SPARSE_MAPPING | #ifdef SPARSE_MAPPING | ||||
ef->object = 0; | ef->object = NULL; | ||||
#endif | #endif | ||||
dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; | dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; | ||||
ef->dynamic = (Elf_Dyn *)dp; | ef->dynamic = (Elf_Dyn *)dp; | ||||
lf->address = ef->address; | lf->address = ef->address; | ||||
lf->size = *(size_t *)sizeptr; | lf->size = *(size_t *)sizeptr; | ||||
ctors_addrp = (Elf_Addr *)preload_search_info(modptr, | ctors_addrp = (Elf_Addr *)preload_search_info(modptr, | ||||
MODINFO_METADATA | MODINFOMD_CTORS_ADDR); | MODINFO_METADATA | MODINFOMD_CTORS_ADDR); | ||||
Show All 37 Lines | |||||
static int | static int | ||||
link_elf_load_file(linker_class_t cls, const char* filename, | link_elf_load_file(linker_class_t cls, const char* filename, | ||||
linker_file_t* result) | linker_file_t* result) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
struct thread* td = curthread; /* XXX */ | struct thread* td = curthread; /* XXX */ | ||||
Elf_Ehdr *hdr; | Elf_Ehdr *hdr; | ||||
caddr_t firstpage; | caddr_t firstpage, segbase; | ||||
int nbytes, i; | int nbytes, i; | ||||
Elf_Phdr *phdr; | Elf_Phdr *phdr; | ||||
Elf_Phdr *phlimit; | Elf_Phdr *phlimit; | ||||
Elf_Phdr *segs[MAXSEGS]; | Elf_Phdr *segs[MAXSEGS]; | ||||
int nsegs; | int nsegs; | ||||
Elf_Phdr *phdyn; | Elf_Phdr *phdyn; | ||||
caddr_t mapbase; | caddr_t mapbase; | ||||
size_t mapsize; | size_t mapsize; | ||||
▲ Show 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | #endif | ||||
lf = linker_make_file(filename, &link_elf_class); | lf = linker_make_file(filename, &link_elf_class); | ||||
if (lf == NULL) { | if (lf == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto out; | goto out; | ||||
} | } | ||||
ef = (elf_file_t) lf; | ef = (elf_file_t) lf; | ||||
#ifdef SPARSE_MAPPING | #ifdef SPARSE_MAPPING | ||||
ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); | ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); | ||||
markj: I am not sure why we cannot just use kernel_object here. OBJT_DEFAULT doesn't make a lot of… | |||||
if (ef->object == NULL) { | if (ef->object == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto out; | goto out; | ||||
} | } | ||||
ef->address = (caddr_t) vm_map_min(kernel_map); | #ifdef __amd64__ | ||||
mapbase = (caddr_t)KERNBASE; | |||||
#else | |||||
mapbase = (caddr_t)vm_map_min(kernel_map); | |||||
#endif | |||||
/* | |||||
* Mapping protections are downgraded after relocation processing. | |||||
*/ | |||||
error = vm_map_find(kernel_map, ef->object, 0, | error = vm_map_find(kernel_map, ef->object, 0, | ||||
(vm_offset_t *) &ef->address, mapsize, 0, VMFS_OPTIMAL_SPACE, | (vm_offset_t *)&mapbase, mapsize, 0, VMFS_OPTIMAL_SPACE, | ||||
VM_PROT_ALL, VM_PROT_ALL, 0); | VM_PROT_ALL, VM_PROT_ALL, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
vm_object_deallocate(ef->object); | vm_object_deallocate(ef->object); | ||||
ef->object = 0; | ef->object = NULL; | ||||
goto out; | goto out; | ||||
} | } | ||||
#else | #else | ||||
ef->address = malloc(mapsize, M_LINKER, M_EXEC | M_WAITOK); | mapbase = malloc(mapsize, M_LINKER, M_EXEC | M_WAITOK); | ||||
#endif | #endif | ||||
mapbase = ef->address; | ef->address = mapbase; | ||||
/* | /* | ||||
* Read the text and data sections and zero the bss. | * Read the text and data sections and zero the bss. | ||||
*/ | */ | ||||
for (i = 0; i < nsegs; i++) { | for (i = 0; i < nsegs; i++) { | ||||
caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; | segbase = mapbase + segs[i]->p_vaddr - base_vaddr; | ||||
error = vn_rdwr(UIO_READ, nd.ni_vp, | |||||
segbase, segs[i]->p_filesz, segs[i]->p_offset, | |||||
UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, | |||||
&resid, td); | |||||
if (error != 0) | |||||
goto out; | |||||
bzero(segbase + segs[i]->p_filesz, | |||||
segs[i]->p_memsz - segs[i]->p_filesz); | |||||
#ifdef SPARSE_MAPPING | #ifdef SPARSE_MAPPING | ||||
/* | /* | ||||
* Wire down the pages | * Consecutive segments may have different mapping permissions, | ||||
* so be strict and verify that their mappings do not overlap. | |||||
*/ | */ | ||||
if (((vm_offset_t)segbase & PAGE_MASK) != 0) { | |||||
error = EINVAL; | |||||
goto out; | |||||
} | |||||
error = vm_map_wire(kernel_map, | error = vm_map_wire(kernel_map, | ||||
(vm_offset_t) segbase, | (vm_offset_t)segbase, | ||||
(vm_offset_t) segbase + segs[i]->p_memsz, | (vm_offset_t)segbase + round_page(segs[i]->p_memsz), | ||||
VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES); | VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES); | ||||
if (error != KERN_SUCCESS) { | if (error != KERN_SUCCESS) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto out; | goto out; | ||||
} | } | ||||
#endif | #endif | ||||
error = vn_rdwr(UIO_READ, nd.ni_vp, | |||||
segbase, segs[i]->p_filesz, segs[i]->p_offset, | |||||
UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, | |||||
&resid, td); | |||||
if (error != 0) | |||||
goto out; | |||||
bzero(segbase + segs[i]->p_filesz, | |||||
segs[i]->p_memsz - segs[i]->p_filesz); | |||||
} | } | ||||
#ifdef GPROF | #ifdef GPROF | ||||
/* Update profiling information with the new text segment. */ | /* Update profiling information with the new text segment. */ | ||||
mtx_lock(&Giant); | mtx_lock(&Giant); | ||||
kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr + | kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr + | ||||
segs[0]->p_memsz)); | segs[0]->p_memsz)); | ||||
mtx_unlock(&Giant); | mtx_unlock(&Giant); | ||||
Show All 20 Lines | #endif | ||||
VOP_UNLOCK(nd.ni_vp, 0); | VOP_UNLOCK(nd.ni_vp, 0); | ||||
error = linker_load_dependencies(lf); | error = linker_load_dependencies(lf); | ||||
vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
error = relocate_file(ef); | error = relocate_file(ef); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
#ifdef SPARSE_MAPPING | |||||
/* | |||||
* Downgrade permissions on text segment mappings now that relocation | |||||
* processing is complete. Restrict permissions on read-only segments. | |||||
*/ | |||||
for (i = 0; i < nsegs; i++) { | |||||
vm_prot_t prot; | |||||
if (segs[i]->p_type != PT_LOAD) | |||||
continue; | |||||
prot = VM_PROT_READ; | |||||
if ((segs[i]->p_flags & PF_W) != 0) | |||||
prot |= VM_PROT_WRITE; | |||||
if ((segs[i]->p_flags & PF_X) != 0) | |||||
prot |= VM_PROT_EXECUTE; | |||||
segbase = mapbase + segs[i]->p_vaddr - base_vaddr; | |||||
error = vm_map_protect(kernel_map, | |||||
(vm_offset_t)segbase, | |||||
(vm_offset_t)segbase + round_page(segs[i]->p_memsz), | |||||
Done Inline ActionsI suspect this is too rough. In principle, the segments need not be page-aligned, and you might remove W or X from a neighbor segment that shares the page with us. I think the easiest would be to refuse loading such objects. kib: I suspect this is too rough. In principle, the segments need not be page-aligned, and you… | |||||
prot, FALSE); | |||||
if (error != KERN_SUCCESS) { | |||||
error = ENOMEM; | |||||
goto out; | |||||
} | |||||
} | |||||
#endif | |||||
/* | /* | ||||
* Try and load the symbol table if it's present. (you can | * Try and load the symbol table if it's present. (you can | ||||
* strip it!) | * strip it!) | ||||
*/ | */ | ||||
nbytes = hdr->e_shnum * hdr->e_shentsize; | nbytes = hdr->e_shnum * hdr->e_shentsize; | ||||
if (nbytes == 0 || hdr->e_shoff == 0) | if (nbytes == 0 || hdr->e_shoff == 0) | ||||
goto nosyms; | goto nosyms; | ||||
▲ Show 20 Lines • Show All 676 Lines • Show Last 20 Lines |
I am not sure why we cannot just use kernel_object here. OBJT_DEFAULT doesn't make a lot of sense, since the memory will not be pageable.