Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/imgact_elf.c
Show First 20 Lines • Show All 443 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct sf_buf *sf; | struct sf_buf *sf; | ||||
int error; | int error; | ||||
vm_offset_t off; | vm_offset_t off; | ||||
/* | /* | ||||
* Create the page if it doesn't exist yet. Ignore errors. | * Create the page if it doesn't exist yet. Ignore errors. | ||||
*/ | */ | ||||
vm_map_fixed(map, NULL, 0, trunc_page(start), round_page(end) - | vm_map_fixed(map, NULL, 0, trunc_page(start), round_page(end) - | ||||
markj: A cast to void is better for explicitly ignoring errors, to avoid warnings from static… | |||||
Done Inline ActionsIt actually was changed more substantially in intermediate version, but now becomes a stray change. Reverted. kib: It actually was changed more substantially in intermediate version, but now becomes a stray… | |||||
trunc_page(start), VM_PROT_ALL, VM_PROT_ALL, MAP_CHECK_EXCL); | trunc_page(start), VM_PROT_ALL, VM_PROT_ALL, MAP_CHECK_EXCL); | ||||
/* | /* | ||||
* Find the page from the underlying object. | * Find the page from the underlying object. | ||||
*/ | */ | ||||
if (object != NULL) { | if (object != NULL) { | ||||
sf = vm_imgact_map_page(object, offset); | sf = vm_imgact_map_page(object, offset); | ||||
if (sf == NULL) | if (sf == NULL) | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | for (; start < end; start += sz) { | ||||
vm_imgact_unmap_page(sf); | vm_imgact_unmap_page(sf); | ||||
if (error != 0) | if (error != 0) | ||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
offset += sz; | offset += sz; | ||||
} | } | ||||
} else { | } else { | ||||
vm_object_reference(object); | vm_object_reference(object); | ||||
rv = vm_map_fixed(map, object, offset, start, end - start, | rv = vm_map_fixed(map, object, offset, start, end - start, | ||||
prot, VM_PROT_ALL, cow | MAP_CHECK_EXCL); | prot, VM_PROT_ALL, cow | MAP_CHECK_EXCL | | ||||
(object != NULL ? MAP_VN_EXEC : 0)); | |||||
if (rv != KERN_SUCCESS) { | if (rv != KERN_SUCCESS) { | ||||
locked = VOP_ISLOCKED(imgp->vp); | locked = VOP_ISLOCKED(imgp->vp); | ||||
VOP_UNLOCK(imgp->vp, 0); | VOP_UNLOCK(imgp->vp, 0); | ||||
vm_object_deallocate(object); | vm_object_deallocate(object); | ||||
vn_lock(imgp->vp, locked | LK_RETRY); | vn_lock(imgp->vp, locked | LK_RETRY); | ||||
return (rv); | return (rv); | ||||
} else if (object != NULL) { | |||||
MPASS(imgp->vp->v_object == object); | |||||
VOP_SET_TEXT_CHECKED(imgp->vp); | |||||
} | } | ||||
} | } | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
} | } | ||||
static int | static int | ||||
__elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset, | __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset, | ||||
caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) | caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) | ||||
Show All 40 Lines | __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset, | ||||
else | else | ||||
map_len = round_page(offset + filsz) - file_addr; | map_len = round_page(offset + filsz) - file_addr; | ||||
if (map_len != 0) { | if (map_len != 0) { | ||||
/* cow flags: don't dump readonly sections in core */ | /* cow flags: don't dump readonly sections in core */ | ||||
cow = MAP_COPY_ON_WRITE | MAP_PREFAULT | | cow = MAP_COPY_ON_WRITE | MAP_PREFAULT | | ||||
(prot & VM_PROT_WRITE ? 0 : MAP_DISABLE_COREDUMP); | (prot & VM_PROT_WRITE ? 0 : MAP_DISABLE_COREDUMP); | ||||
rv = __elfN(map_insert)(imgp, map, | rv = __elfN(map_insert)(imgp, map, object, file_addr, | ||||
object, | map_addr, map_addr + map_len, prot, cow); | ||||
file_addr, /* file offset */ | |||||
map_addr, /* virtual start */ | |||||
map_addr + map_len,/* virtual end */ | |||||
prot, | |||||
cow); | |||||
if (rv != KERN_SUCCESS) | if (rv != KERN_SUCCESS) | ||||
return (EINVAL); | return (EINVAL); | ||||
/* we can stop now if we've covered it all */ | /* we can stop now if we've covered it all */ | ||||
if (memsz == filsz) | if (memsz == filsz) | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | struct { | ||||
struct vattr attr; | struct vattr attr; | ||||
struct image_params image_params; | struct image_params image_params; | ||||
} *tempdata; | } *tempdata; | ||||
const Elf_Ehdr *hdr = NULL; | const Elf_Ehdr *hdr = NULL; | ||||
const Elf_Phdr *phdr = NULL; | const Elf_Phdr *phdr = NULL; | ||||
struct nameidata *nd; | struct nameidata *nd; | ||||
struct vattr *attr; | struct vattr *attr; | ||||
struct image_params *imgp; | struct image_params *imgp; | ||||
u_long flags, rbase; | u_long rbase; | ||||
u_long base_addr = 0; | u_long base_addr = 0; | ||||
int error; | int error; | ||||
#ifdef CAPABILITY_MODE | #ifdef CAPABILITY_MODE | ||||
/* | /* | ||||
* XXXJA: This check can go away once we are sufficiently confident | * XXXJA: This check can go away once we are sufficiently confident | ||||
* that the checks in namei() are correct. | * that the checks in namei() are correct. | ||||
*/ | */ | ||||
Show All 11 Lines | #endif | ||||
*/ | */ | ||||
imgp->proc = p; | imgp->proc = p; | ||||
imgp->attr = attr; | imgp->attr = attr; | ||||
imgp->firstpage = NULL; | imgp->firstpage = NULL; | ||||
imgp->image_header = NULL; | imgp->image_header = NULL; | ||||
imgp->object = NULL; | imgp->object = NULL; | ||||
imgp->execlabel = NULL; | imgp->execlabel = NULL; | ||||
flags = FOLLOW | LOCKSHARED | LOCKLEAF; | NDINIT(nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF, UIO_SYSSPACE, file, | ||||
curthread); | |||||
again: | |||||
NDINIT(nd, LOOKUP, flags, UIO_SYSSPACE, file, curthread); | |||||
if ((error = namei(nd)) != 0) { | if ((error = namei(nd)) != 0) { | ||||
nd->ni_vp = NULL; | nd->ni_vp = NULL; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
NDFREE(nd, NDF_ONLY_PNBUF); | NDFREE(nd, NDF_ONLY_PNBUF); | ||||
imgp->vp = nd->ni_vp; | imgp->vp = nd->ni_vp; | ||||
/* | /* | ||||
* Check permissions, modes, uid, etc on the file, and "open" it. | * Check permissions, modes, uid, etc on the file, and "open" it. | ||||
*/ | */ | ||||
error = exec_check_permissions(imgp); | error = exec_check_permissions(imgp); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
/* | |||||
* Also make certain that the interpreter stays the same, | |||||
* so set its VV_TEXT flag, too. Since this function is only | |||||
* used to load the interpreter, the VV_TEXT is almost always | |||||
* already set. | |||||
*/ | |||||
if (VOP_IS_TEXT(nd->ni_vp) == 0) { | |||||
if (VOP_ISLOCKED(nd->ni_vp) != LK_EXCLUSIVE) { | |||||
/* | |||||
* LK_UPGRADE could have resulted in dropping | |||||
* the lock. Just try again from the start, | |||||
* this time with exclusive vnode lock. | |||||
*/ | |||||
vput(nd->ni_vp); | |||||
flags &= ~LOCKSHARED; | |||||
goto again; | |||||
} | |||||
VOP_SET_TEXT(nd->ni_vp); | |||||
} | |||||
error = exec_map_first_page(imgp); | error = exec_map_first_page(imgp); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
imgp->object = nd->ni_vp->v_object; | imgp->object = nd->ni_vp->v_object; | ||||
hdr = (const Elf_Ehdr *)imgp->image_header; | hdr = (const Elf_Ehdr *)imgp->image_header; | ||||
if ((error = __elfN(check_header)(hdr)) != 0) | if ((error = __elfN(check_header)(hdr)) != 0) | ||||
Show All 26 Lines | #endif | ||||
*addr = base_addr; | *addr = base_addr; | ||||
*entry = (unsigned long)hdr->e_entry + rbase; | *entry = (unsigned long)hdr->e_entry + rbase; | ||||
fail: | fail: | ||||
if (imgp->firstpage) | if (imgp->firstpage) | ||||
exec_unmap_first_page(imgp); | exec_unmap_first_page(imgp); | ||||
if (nd->ni_vp) | if (nd->ni_vp) { | ||||
if (imgp->textset) | |||||
VOP_UNSET_TEXT_CHECKED(nd->ni_vp); | |||||
vput(nd->ni_vp); | vput(nd->ni_vp); | ||||
} | |||||
free(tempdata, M_TEMP); | free(tempdata, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
static u_long | static u_long | ||||
__CONCAT(rnd_, __elfN(base))(vm_map_t map __unused, u_long minv, u_long maxv, | __CONCAT(rnd_, __elfN(base))(vm_map_t map __unused, u_long minv, u_long maxv, | ||||
u_int align) | u_int align) | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | __elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr, | ||||
if (phdr->p_filesz < 2 || phdr->p_filesz > MAXPATHLEN) { | if (phdr->p_filesz < 2 || phdr->p_filesz > MAXPATHLEN) { | ||||
uprintf("Invalid PT_INTERP\n"); | uprintf("Invalid PT_INTERP\n"); | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
} | } | ||||
interp_name_len = phdr->p_filesz; | interp_name_len = phdr->p_filesz; | ||||
if (phdr->p_offset > PAGE_SIZE || | if (phdr->p_offset > PAGE_SIZE || | ||||
interp_name_len > PAGE_SIZE - phdr->p_offset) { | interp_name_len > PAGE_SIZE - phdr->p_offset) { | ||||
interp = malloc(interp_name_len + 1, M_TEMP, M_NOWAIT); | |||||
if (interp == NULL) { | |||||
VOP_UNLOCK(imgp->vp, 0); | VOP_UNLOCK(imgp->vp, 0); | ||||
interp = malloc(interp_name_len + 1, M_TEMP, M_WAITOK); | interp = malloc(interp_name_len + 1, M_TEMP, M_WAITOK); | ||||
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(imgp->vp, LK_SHARED | LK_RETRY); | ||||
} | |||||
Not Done Inline ActionsThis looks like something that should be committed separately; same with similar chunks below. trasz: This looks like something that should be committed separately; same with similar chunks below. | |||||
Done Inline ActionsThis could be, and I am now not convinced that I want such change. The reason is the M_NOWAIT is allowed to drain free queue deeper. For now I included them to see how the change pass over the Peter stress2. Then I will decide. kib: This could be, and I am now not convinced that I want such change. The reason is the M_NOWAIT… | |||||
Done Inline ActionsI don't understand the claim about M_NOWAIT. markj: I don't understand the claim about M_NOWAIT. | |||||
Done Inline ActionsI forgot that I changed it in r243040. Weird. kib: I forgot that I changed it in r243040. Weird. | |||||
error = vn_rdwr(UIO_READ, imgp->vp, interp, | error = vn_rdwr(UIO_READ, imgp->vp, interp, | ||||
interp_name_len, phdr->p_offset, | interp_name_len, phdr->p_offset, | ||||
UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, | UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, | ||||
NOCRED, NULL, td); | NOCRED, NULL, td); | ||||
if (error != 0) { | if (error != 0) { | ||||
free(interp, M_TEMP); | free(interp, M_TEMP); | ||||
uprintf("i/o error PT_INTERP %d\n", error); | uprintf("i/o error PT_INTERP %d\n", error); | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | if (et_dyn_addr == ET_DYN_ADDR_RAND) { | ||||
KASSERT((map->flags & MAP_ASLR) != 0, | KASSERT((map->flags & MAP_ASLR) != 0, | ||||
("ET_DYN_ADDR_RAND but !MAP_ASLR")); | ("ET_DYN_ADDR_RAND but !MAP_ASLR")); | ||||
et_dyn_addr = __CONCAT(rnd_, __elfN(base))(map, | et_dyn_addr = __CONCAT(rnd_, __elfN(base))(map, | ||||
vm_map_min(map) + mapsz + lim_max(td, RLIMIT_DATA), | vm_map_min(map) + mapsz + lim_max(td, RLIMIT_DATA), | ||||
/* reserve half of the address space to interpreter */ | /* reserve half of the address space to interpreter */ | ||||
maxv / 2, 1UL << flsl(maxalign)); | maxv / 2, 1UL << flsl(maxalign)); | ||||
} | } | ||||
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(imgp->vp, LK_SHARED | LK_RETRY); | ||||
if (error != 0) | if (error != 0) | ||||
goto ret; | goto ret; | ||||
error = __elfN(load_sections)(imgp, hdr, phdr, et_dyn_addr, NULL); | error = __elfN(load_sections)(imgp, hdr, phdr, et_dyn_addr, NULL); | ||||
if (error != 0) | if (error != 0) | ||||
goto ret; | goto ret; | ||||
error = __elfN(enforce_limits)(imgp, hdr, phdr, et_dyn_addr); | error = __elfN(enforce_limits)(imgp, hdr, phdr, et_dyn_addr); | ||||
Show All 27 Lines | if ((map->flags & MAP_ASLR) != 0) { | ||||
/* Assume that interpeter fits into 1/4 of AS */ | /* Assume that interpeter fits into 1/4 of AS */ | ||||
maxv1 = maxv / 2 + addr / 2; | maxv1 = maxv / 2 + addr / 2; | ||||
MPASS(maxv1 >= addr); /* No overflow */ | MPASS(maxv1 >= addr); /* No overflow */ | ||||
addr = __CONCAT(rnd_, __elfN(base))(map, addr, | addr = __CONCAT(rnd_, __elfN(base))(map, addr, | ||||
maxv1, PAGE_SIZE); | maxv1, PAGE_SIZE); | ||||
} | } | ||||
error = __elfN(load_interp)(imgp, brand_info, interp, &addr, | error = __elfN(load_interp)(imgp, brand_info, interp, &addr, | ||||
&imgp->entry_addr); | &imgp->entry_addr); | ||||
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(imgp->vp, LK_SHARED | LK_RETRY); | ||||
if (error != 0) | if (error != 0) | ||||
goto ret; | goto ret; | ||||
} else | } else | ||||
addr = et_dyn_addr; | addr = et_dyn_addr; | ||||
/* | /* | ||||
* Construct auxargs table (used by the fixup routine) | * Construct auxargs table (used by the fixup routine) | ||||
*/ | */ | ||||
elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_NOWAIT); | |||||
if (elf_auxargs == NULL) { | |||||
VOP_UNLOCK(imgp->vp, 0); | |||||
elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); | elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); | ||||
vn_lock(imgp->vp, LK_SHARED | LK_RETRY); | |||||
} | |||||
elf_auxargs->execfd = -1; | elf_auxargs->execfd = -1; | ||||
elf_auxargs->phdr = proghdr + et_dyn_addr; | elf_auxargs->phdr = proghdr + et_dyn_addr; | ||||
elf_auxargs->phent = hdr->e_phentsize; | elf_auxargs->phent = hdr->e_phentsize; | ||||
elf_auxargs->phnum = hdr->e_phnum; | elf_auxargs->phnum = hdr->e_phnum; | ||||
elf_auxargs->pagesz = PAGE_SIZE; | elf_auxargs->pagesz = PAGE_SIZE; | ||||
elf_auxargs->base = addr; | elf_auxargs->base = addr; | ||||
elf_auxargs->flags = 0; | elf_auxargs->flags = 0; | ||||
elf_auxargs->entry = entry; | elf_auxargs->entry = entry; | ||||
▲ Show 20 Lines • Show All 1,263 Lines • ▼ Show 20 Lines | __elfN(parse_notes)(struct image_params *imgp, Elf_Note *checknote, | ||||
boolean_t res; | boolean_t res; | ||||
/* We need some limit, might as well use PAGE_SIZE. */ | /* We need some limit, might as well use PAGE_SIZE. */ | ||||
if (pnote == NULL || pnote->p_filesz > PAGE_SIZE) | if (pnote == NULL || pnote->p_filesz > PAGE_SIZE) | ||||
return (FALSE); | return (FALSE); | ||||
ASSERT_VOP_LOCKED(imgp->vp, "parse_notes"); | ASSERT_VOP_LOCKED(imgp->vp, "parse_notes"); | ||||
if (pnote->p_offset > PAGE_SIZE || | if (pnote->p_offset > PAGE_SIZE || | ||||
pnote->p_filesz > PAGE_SIZE - pnote->p_offset) { | pnote->p_filesz > PAGE_SIZE - pnote->p_offset) { | ||||
buf = malloc(pnote->p_filesz, M_TEMP, M_NOWAIT); | |||||
if (buf == NULL) { | |||||
VOP_UNLOCK(imgp->vp, 0); | VOP_UNLOCK(imgp->vp, 0); | ||||
buf = malloc(pnote->p_filesz, M_TEMP, M_WAITOK); | buf = malloc(pnote->p_filesz, M_TEMP, M_WAITOK); | ||||
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(imgp->vp, LK_SHARED | LK_RETRY); | ||||
} | |||||
error = vn_rdwr(UIO_READ, imgp->vp, buf, pnote->p_filesz, | error = vn_rdwr(UIO_READ, imgp->vp, buf, pnote->p_filesz, | ||||
pnote->p_offset, UIO_SYSSPACE, IO_NODELOCKED, | pnote->p_offset, UIO_SYSSPACE, IO_NODELOCKED, | ||||
curthread->td_ucred, NOCRED, NULL, curthread); | curthread->td_ucred, NOCRED, NULL, curthread); | ||||
if (error != 0) { | if (error != 0) { | ||||
uprintf("i/o error PT_NOTE\n"); | uprintf("i/o error PT_NOTE\n"); | ||||
goto retf; | goto retf; | ||||
} | } | ||||
note = note0 = (const Elf_Note *)buf; | note = note0 = (const Elf_Note *)buf; | ||||
▲ Show 20 Lines • Show All 167 Lines • Show Last 20 Lines |
A cast to void is better for explicitly ignoring errors, to avoid warnings from static analyzers.