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);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to