svn commit: r345661 - head/sys/kern

Edward Tomasz Napierala trasz at FreeBSD.org
Tue Sep 3 14:05:55 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-head mailing list