Factor out retrieving the interpreter path from the main ELF

loader routine.

Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D19715
This commit is contained in:
Edward Tomasz Napierala 2019-03-28 21:43:01 +00:00
parent dd3b96ecec
commit 09c78d53bf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345661

View File

@ -88,7 +88,7 @@ __FBSDID("$FreeBSD$");
static int __elfN(check_header)(const Elf_Ehdr *hdr);
static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp,
const char *interp, int interp_name_len, int32_t *osrel, uint32_t *fctl0);
const char *interp, int32_t *osrel, uint32_t *fctl0);
static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr,
u_long *entry);
static int __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset,
@ -272,12 +272,14 @@ __elfN(brand_inuse)(Elf_Brandinfo *entry)
static Elf_Brandinfo *
__elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
int interp_name_len, int32_t *osrel, uint32_t *fctl0)
int32_t *osrel, uint32_t *fctl0)
{
const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
Elf_Brandinfo *bi, *bi_m;
boolean_t ret;
int i;
int i, interp_name_len;
interp_name_len = interp != NULL ? strlen(interp) : 0;
/*
* We support four types of branding -- (1) the ELF EI_OSABI field
@ -889,6 +891,60 @@ __elfN(enforce_limits)(struct image_params *imgp, const Elf_Ehdr *hdr,
return (0);
}
static int
__elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr,
char **interpp, bool *free_interpp)
{
struct thread *td;
char *interp;
int error, interp_name_len;
KASSERT(phdr->p_type == PT_INTERP,
("%s: p_type %u != PT_INTERP", __func__, phdr->p_type));
KASSERT(VOP_ISLOCKED(imgp->vp),
("%s: vp %p is not locked", __func__, imgp->vp));
td = curthread;
/* Path to interpreter */
if (phdr->p_filesz < 2 || phdr->p_filesz > MAXPATHLEN) {
uprintf("Invalid PT_INTERP\n");
return (ENOEXEC);
}
interp_name_len = phdr->p_filesz;
if (phdr->p_offset > PAGE_SIZE ||
interp_name_len > PAGE_SIZE - phdr->p_offset) {
VOP_UNLOCK(imgp->vp, 0);
interp = malloc(interp_name_len + 1, M_TEMP, M_WAITOK);
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
error = vn_rdwr(UIO_READ, imgp->vp, interp,
interp_name_len, phdr->p_offset,
UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
NOCRED, NULL, td);
if (error != 0) {
free(interp, M_TEMP);
uprintf("i/o error PT_INTERP %d\n", error);
return (error);
}
interp[interp_name_len] = '\0';
*interpp = interp;
*free_interpp = true;
return (0);
}
interp = __DECONST(char *, imgp->image_header) + phdr->p_offset;
if (interp[interp_name_len - 1] != '\0') {
uprintf("Invalid PT_INTERP\n");
return (ENOEXEC);
}
*interpp = interp;
*free_interpp = false;
return (0);
}
/*
* Impossible et_dyn_addr initial value indicating that the real base
* must be calculated later with some randomization applied.
@ -905,7 +961,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
struct vmspace *vmspace;
vm_map_t map;
const char *newinterp;
char *interp, *interp_buf, *path;
char *interp, *path;
Elf_Brandinfo *brand_info;
struct sysentvec *sv;
vm_prot_t prot;
@ -913,7 +969,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
u_long maxalign, mapsz, maxv, maxv1;
uint32_t fctl0;
int32_t osrel;
int error, i, n, interp_name_len, have_interp;
bool free_interp;
int error, i, n, have_interp;
hdr = (const Elf_Ehdr *)imgp->image_header;
@ -949,9 +1006,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
osrel = 0;
fctl0 = 0;
entry = proghdr = 0;
interp_name_len = 0;
newinterp = NULL;
interp = interp_buf = NULL;
newinterp = interp = NULL;
free_interp = false;
td = curthread;
maxalign = PAGE_SIZE;
mapsz = 0;
@ -968,44 +1024,15 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
break;
case PT_INTERP:
/* Path to interpreter */
if (phdr[i].p_filesz < 2 ||
phdr[i].p_filesz > MAXPATHLEN) {
uprintf("Invalid PT_INTERP\n");
error = ENOEXEC;
goto ret;
}
if (interp != NULL) {
uprintf("Multiple PT_INTERP headers\n");
error = ENOEXEC;
goto ret;
}
interp_name_len = phdr[i].p_filesz;
if (phdr[i].p_offset > PAGE_SIZE ||
interp_name_len > PAGE_SIZE - phdr[i].p_offset) {
VOP_UNLOCK(imgp->vp, 0);
interp_buf = malloc(interp_name_len + 1, M_TEMP,
M_WAITOK);
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
error = vn_rdwr(UIO_READ, imgp->vp, interp_buf,
interp_name_len, phdr[i].p_offset,
UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
NOCRED, NULL, td);
if (error != 0) {
uprintf("i/o error PT_INTERP %d\n",
error);
goto ret;
}
interp_buf[interp_name_len] = '\0';
interp = interp_buf;
} else {
interp = __DECONST(char *, imgp->image_header) +
phdr[i].p_offset;
if (interp[interp_name_len - 1] != '\0') {
uprintf("Invalid PT_INTERP\n");
error = ENOEXEC;
goto ret;
}
}
error = __elfN(get_interp)(imgp, &phdr[i], &interp,
&free_interp);
if (error != 0)
goto ret;
break;
case PT_GNU_STACK:
if (__elfN(nxstack))
@ -1016,8 +1043,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
}
}
brand_info = __elfN(get_brandinfo)(imgp, interp, interp_name_len,
&osrel, &fctl0);
brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0);
if (brand_info == NULL) {
uprintf("ELF binary type \"%u\" not known.\n",
hdr->e_ident[EI_OSABI]);
@ -1238,7 +1264,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
imgp->proc->p_elf_flags = hdr->e_flags;
ret:
free(interp_buf, M_TEMP);
if (free_interp)
free(interp, M_TEMP);
return (error);
}