Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/imgact_elf.c
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#define ELF_NOTE_ROUNDSIZE 4 | #define ELF_NOTE_ROUNDSIZE 4 | ||||
#define OLD_EI_BRAND 8 | #define OLD_EI_BRAND 8 | ||||
static int __elfN(check_header)(const Elf_Ehdr *hdr); | static int __elfN(check_header)(const Elf_Ehdr *hdr); | ||||
static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp, | static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp, | ||||
const char *interp, int interp_name_len, int32_t *osrel); | const char *interp, int interp_name_len, int32_t *osrel); | ||||
static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr, | static int __elfN(load_file)(struct proc *p, struct vnode *vp, u_long *addr, | ||||
u_long *entry, size_t pagesize); | u_long *entry, size_t pagesize); | ||||
static int __elfN(load_path)(struct proc *p, const char *path, u_long *addr, | |||||
u_long *entry, size_t pagesize); | |||||
static int __elfN(load_section)(struct image_params *imgp, vm_offset_t offset, | static int __elfN(load_section)(struct image_params *imgp, vm_offset_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, | ||||
size_t pagesize); | size_t pagesize); | ||||
static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); | static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); | ||||
static boolean_t __elfN(freebsd_trans_osrel)(const Elf_Note *note, | static boolean_t __elfN(freebsd_trans_osrel)(const Elf_Note *note, | ||||
int32_t *osrel); | int32_t *osrel); | ||||
static boolean_t kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel); | static boolean_t kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel); | ||||
static boolean_t __elfN(check_note)(struct image_params *imgp, | static boolean_t __elfN(check_note)(struct image_params *imgp, | ||||
▲ Show 20 Lines • Show All 511 Lines • ▼ Show 20 Lines | |||||
* the address where a shared object should be loaded. If the file is | * the address where a shared object should be loaded. If the file is | ||||
* an executable, this value is ignored. On exit, "addr" specifies | * an executable, this value is ignored. On exit, "addr" specifies | ||||
* where the file was actually loaded. | * where the file was actually loaded. | ||||
* | * | ||||
* The "entry" reference parameter is out only. On exit, it specifies | * The "entry" reference parameter is out only. On exit, it specifies | ||||
* the entry point for the loaded file. | * the entry point for the loaded file. | ||||
*/ | */ | ||||
static int | static int | ||||
__elfN(load_file)(struct proc *p, const char *file, u_long *addr, | __elfN(load_file)(struct proc *p, struct vnode *vp, u_long *addr, | ||||
u_long *entry, size_t pagesize) | u_long *entry, size_t pagesize) | ||||
{ | { | ||||
struct { | struct { | ||||
struct nameidata nd; | |||||
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 vattr *attr; | struct vattr *attr; | ||||
struct image_params *imgp; | struct image_params *imgp; | ||||
vm_prot_t prot; | vm_prot_t prot; | ||||
u_long rbase; | u_long rbase; | ||||
u_long base_addr = 0; | u_long base_addr = 0; | ||||
int error, i, numsegs; | int error, i, numsegs; | ||||
#ifdef CAPABILITY_MODE | |||||
/* | |||||
* XXXJA: This check can go away once we are sufficiently confident | |||||
* that the checks in namei() are correct. | |||||
*/ | |||||
if (IN_CAPABILITY_MODE(curthread)) | |||||
return (ECAPMODE); | |||||
#endif | |||||
tempdata = malloc(sizeof(*tempdata), M_TEMP, M_WAITOK); | tempdata = malloc(sizeof(*tempdata), M_TEMP, M_WAITOK); | ||||
nd = &tempdata->nd; | |||||
attr = &tempdata->attr; | attr = &tempdata->attr; | ||||
imgp = &tempdata->image_params; | imgp = &tempdata->image_params; | ||||
/* | /* | ||||
* Initialize part of the common data | * Initialize part of the common data | ||||
*/ | */ | ||||
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; | ||||
imgp->vp = vp; | |||||
NDINIT(nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE, file, curthread); | |||||
if ((error = namei(nd)) != 0) { | |||||
nd->ni_vp = NULL; | |||||
goto fail; | |||||
} | |||||
NDFREE(nd, NDF_ONLY_PNBUF); | |||||
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; | ||||
error = exec_map_first_page(imgp); | error = exec_map_first_page(imgp); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
/* | /* | ||||
* Also make certain that the interpreter stays the same, so set | * Also make certain that the interpreter stays the same, so set | ||||
* its VV_TEXT flag, too. | * its VV_TEXT flag, too. | ||||
*/ | */ | ||||
VOP_SET_TEXT(nd->ni_vp); | VOP_SET_TEXT(vp); | ||||
imgp->object = nd->ni_vp->v_object; | imgp->object = 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) | ||||
goto fail; | goto fail; | ||||
if (hdr->e_type == ET_DYN) | if (hdr->e_type == ET_DYN) | ||||
rbase = *addr; | rbase = *addr; | ||||
else if (hdr->e_type == ET_EXEC) | else if (hdr->e_type == ET_EXEC) | ||||
rbase = 0; | rbase = 0; | ||||
Show All 36 Lines | __elfN(load_file)(struct proc *p, struct vnode *vp, u_long *addr, | ||||
} | } | ||||
*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) | vput(vp); | ||||
vput(nd->ni_vp); | |||||
free(tempdata, M_TEMP); | free(tempdata, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* Load a file into memory as specified by a path. | |||||
*/ | |||||
static int | static int | ||||
__elfN(load_path)(struct proc *p, const char *path, u_long *addr, | |||||
u_long *entry, size_t pagesize) | |||||
{ | |||||
struct nameidata nd; | |||||
struct vnode *vp = NULL; | |||||
int error; | |||||
#ifdef CAPABILITY_MODE | |||||
/* | |||||
* XXXJA: This check can go away once we are sufficiently confident | |||||
* that the checks in namei() are correct. | |||||
*/ | |||||
if (IN_CAPABILITY_MODE(curthread)) | |||||
return (ECAPMODE); | |||||
#endif | |||||
NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE, path, curthread); | |||||
error = namei(&nd); | |||||
vp = nd.ni_vp; | |||||
NDFREE(&nd, NDF_ONLY_PNBUF); | |||||
if (error != 0) { | |||||
return (error); | |||||
} | |||||
return __elfN(load_file)(p, vp, addr, entry, pagesize); | |||||
} | |||||
static int | |||||
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) | __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) | ||||
{ | { | ||||
cap_rights_t rights; | |||||
struct thread *td; | struct thread *td; | ||||
const Elf_Ehdr *hdr; | const Elf_Ehdr *hdr; | ||||
const Elf_Phdr *phdr; | const Elf_Phdr *phdr; | ||||
Elf_Auxargs *elf_auxargs; | Elf_Auxargs *elf_auxargs; | ||||
struct vmspace *vmspace; | struct vmspace *vmspace; | ||||
const char *err_str, *newinterp; | const char *err_str, *newinterp; | ||||
char *interp, *interp_buf, *path; | char *interp, *interp_buf, *path; | ||||
Elf_Brandinfo *brand_info; | Elf_Brandinfo *brand_info; | ||||
struct sysentvec *sv; | struct sysentvec *sv; | ||||
vm_prot_t prot; | vm_prot_t prot; | ||||
u_long text_size, data_size, total_size, text_addr, data_addr; | u_long text_size, data_size, total_size, text_addr, data_addr; | ||||
u_long seg_size, seg_addr, addr, baddr, et_dyn_addr, entry, proghdr; | u_long seg_size, seg_addr, addr, baddr, et_dyn_addr, entry, proghdr; | ||||
int32_t osrel; | int32_t osrel; | ||||
int error, i, n, interp_name_len, have_interp; | int error, i, n, interp_fd, interp_name_len, have_interp; | ||||
hdr = (const Elf_Ehdr *)imgp->image_header; | hdr = (const Elf_Ehdr *)imgp->image_header; | ||||
/* | /* | ||||
* Do we have a valid ELF header ? | * Do we have a valid ELF header ? | ||||
* | * | ||||
* Only allow ET_EXEC & ET_DYN here, reject ET_DYN later | * Only allow ET_EXEC & ET_DYN here, reject ET_DYN later | ||||
* if particular brand doesn't support it. | * if particular brand doesn't support it. | ||||
Show All 33 Lines | for (i = 0; i < hdr->e_phnum; i++) { | ||||
switch (phdr[i].p_type) { | switch (phdr[i].p_type) { | ||||
case PT_LOAD: | case PT_LOAD: | ||||
if (n == 0) | if (n == 0) | ||||
baddr = phdr[i].p_vaddr; | baddr = phdr[i].p_vaddr; | ||||
n++; | n++; | ||||
break; | break; | ||||
case PT_INTERP: | case PT_INTERP: | ||||
/* Path to interpreter */ | /* Path to interpreter */ | ||||
if (interp != NULL) { | |||||
/* fldexec() is overriding the interpreter */ | |||||
break; | |||||
} | |||||
if (phdr[i].p_filesz > MAXPATHLEN) { | if (phdr[i].p_filesz > MAXPATHLEN) { | ||||
uprintf("Invalid PT_INTERP\n"); | uprintf("Invalid PT_INTERP\n"); | ||||
error = ENOEXEC; | error = ENOEXEC; | ||||
goto ret; | goto ret; | ||||
} | } | ||||
if (interp != NULL) { | if (interp != NULL) { | ||||
uprintf("Multiple PT_INTERP headers\n"); | uprintf("Multiple PT_INTERP headers\n"); | ||||
error = ENOEXEC; | error = ENOEXEC; | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(td, | ||||
RLIMIT_DATA)); | RLIMIT_DATA)); | ||||
PROC_UNLOCK(imgp->proc); | PROC_UNLOCK(imgp->proc); | ||||
imgp->entry_addr = entry; | imgp->entry_addr = entry; | ||||
if (interp != NULL) { | if (interp != NULL) { | ||||
have_interp = FALSE; | have_interp = FALSE; | ||||
VOP_UNLOCK(imgp->vp, 0); | VOP_UNLOCK(imgp->vp, 0); | ||||
if ((interp_fd = imgp->args->interpreter) != -1) { | |||||
/* fldexec() is overriding the interpreter */ | |||||
error = fgetvp_exec(td, interp_fd, | |||||
cap_rights_init(&rights, CAP_FEXECVE), &imgp->vp); | |||||
if (error) { | |||||
uprintf("failed getting interpreter from FD %d", | |||||
interp_fd); | |||||
goto ret; | |||||
} | |||||
error = vn_lock(imgp->vp, LK_SHARED | LK_RETRY); | |||||
if (error) { | |||||
goto ret; | |||||
} | |||||
error = __elfN(load_file)(imgp->proc, imgp->vp, &addr, | |||||
&imgp->entry_addr, sv->sv_pagesize); | |||||
if (error == 0) | |||||
have_interp = TRUE; | |||||
} | |||||
if (brand_info->emul_path != NULL && | if (brand_info->emul_path != NULL && | ||||
brand_info->emul_path[0] != '\0') { | brand_info->emul_path[0] != '\0') { | ||||
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); | path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); | ||||
snprintf(path, MAXPATHLEN, "%s%s", | snprintf(path, MAXPATHLEN, "%s%s", | ||||
brand_info->emul_path, interp); | brand_info->emul_path, interp); | ||||
error = __elfN(load_file)(imgp->proc, path, &addr, | error = __elfN(load_path)(imgp->proc, path, &addr, | ||||
&imgp->entry_addr, sv->sv_pagesize); | &imgp->entry_addr, sv->sv_pagesize); | ||||
free(path, M_TEMP); | free(path, M_TEMP); | ||||
if (error == 0) | if (error == 0) | ||||
have_interp = TRUE; | have_interp = TRUE; | ||||
} | } | ||||
if (!have_interp && newinterp != NULL && | if (!have_interp && newinterp != NULL && | ||||
(brand_info->interp_path == NULL || | (brand_info->interp_path == NULL || | ||||
strcmp(interp, brand_info->interp_path) == 0)) { | strcmp(interp, brand_info->interp_path) == 0)) { | ||||
error = __elfN(load_file)(imgp->proc, newinterp, &addr, | error = __elfN(load_path)(imgp->proc, newinterp, &addr, | ||||
&imgp->entry_addr, sv->sv_pagesize); | &imgp->entry_addr, sv->sv_pagesize); | ||||
if (error == 0) | if (error == 0) | ||||
have_interp = TRUE; | have_interp = TRUE; | ||||
} | } | ||||
if (!have_interp) { | if (!have_interp) { | ||||
error = __elfN(load_file)(imgp->proc, interp, &addr, | error = __elfN(load_path)(imgp->proc, interp, &addr, | ||||
&imgp->entry_addr, sv->sv_pagesize); | &imgp->entry_addr, sv->sv_pagesize); | ||||
} | } | ||||
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); | ||||
if (error != 0) { | if (error != 0) { | ||||
uprintf("ELF interpreter %s not found, error %d\n", | uprintf("ELF interpreter %s not found, error %d\n", | ||||
interp, error); | interp, error); | ||||
goto ret; | goto ret; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,349 Lines • Show Last 20 Lines |