svn commit: r345661 - head/sys/kern
Edward Tomasz Napierala
trasz at FreeBSD.org
Thu Mar 28 21:43:02 UTC 2019
Author: trasz
Date: Thu Mar 28 21:43:01 2019
New Revision: 345661
URL: https://svnweb.freebsd.org/changeset/base/345661
Log:
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
Modified:
head/sys/kern/imgact_elf.c
Modified: head/sys/kern/imgact_elf.c
==============================================================================
--- head/sys/kern/imgact_elf.c Thu Mar 28 21:22:28 2019 (r345660)
+++ head/sys/kern/imgact_elf.c Thu Mar 28 21:43:01 2019 (r345661)
@@ -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,13 +272,15 @@ __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
* that SCO added to the ELF spec, (2) FreeBSD 3.x's traditional string
@@ -889,6 +891,60 @@ __elfN(enforce_limits)(struct image_params *imgp, cons
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 *i
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 *i
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 *i
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 *i
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 *i
}
}
- 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 *i
imgp->proc->p_elf_flags = hdr->e_flags;
ret:
- free(interp_buf, M_TEMP);
+ if (free_interp)
+ free(interp, M_TEMP);
return (error);
}
More information about the svn-src-all
mailing list