Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 May 2026 20:59:51 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 804daf166406 - main - imgact_elf: read program headers if not contained in the first page
Message-ID:  <6a18acc7.32ef9.6a0db43@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=804daf166406a1b0e22f93b9417b90ed7d3aa1ae

commit 804daf166406a1b0e22f93b9417b90ed7d3aa1ae
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-05-28 09:06:33 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-05-28 20:59:26 +0000

    imgact_elf: read program headers if not contained in the first page
    
    PR:     295629
    Reviewed by:    markj
    Tested by:      Alex S <iwtcex@gmail.com>
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D57294
---
 sys/kern/imgact_elf.c | 91 +++++++++++++++++++++++++++++++++++----------------
 1 file changed, 62 insertions(+), 29 deletions(-)

diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 42cdfa08f19b..e3969223c170 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -84,6 +84,8 @@
 #define ELF_NOTE_ROUNDSIZE	4
 #define OLD_EI_BRAND	8
 
+#define	ELF_OFFPAGE_PHNUM	128
+
 /*
  * ELF_ABI_NAME is a string name of the ELF ABI.  ELF_ABI_ID is used
  * to build variable names.
@@ -93,7 +95,7 @@
 
 static int __elfN(check_header)(const Elf_Ehdr *hdr);
 static const Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp,
-    const char *interp, int32_t *osrel, uint32_t *fctl0);
+    const Elf_Phdr *phdr, const char *interp, int32_t *osrel, uint32_t *fctl0);
 static int __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
     u_long *entry);
 static int __elfN(load_section)(const struct image_params *imgp,
@@ -103,7 +105,7 @@ static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp);
 static bool __elfN(freebsd_trans_osrel)(const Elf_Note *note,
     int32_t *osrel);
 static bool kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel);
-static bool __elfN(check_note)(struct image_params *imgp,
+static bool __elfN(check_note)(struct image_params *imgp, const Elf_Phdr *phdr,
     const Elf_Brandnote *checknote, int32_t *osrel, bool *has_fctl0,
     uint32_t *fctl0);
 static vm_prot_t __elfN(trans_prot)(Elf_Word);
@@ -339,8 +341,8 @@ __elfN(brand_inuse)(const Elf_Brandinfo *entry)
 }
 
 static const Elf_Brandinfo *
-__elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
-    int32_t *osrel, uint32_t *fctl0)
+__elfN(get_brandinfo)(struct image_params *imgp, const Elf_Phdr *phdr,
+    const char *interp, int32_t *osrel, uint32_t *fctl0)
 {
 	const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
 	const Elf_Brandinfo *bi, *bi_m;
@@ -369,8 +371,8 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
 			has_fctl0 = false;
 			*fctl0 = 0;
 			*osrel = 0;
-			ret = __elfN(check_note)(imgp, bi->brand_note, osrel,
-			    &has_fctl0, fctl0);
+			ret = __elfN(check_note)(imgp, phdr, bi->brand_note,
+			    osrel, &has_fctl0, fctl0);
 			/* Give brand a chance to veto check_note's guess */
 			if (ret && bi->header_supported) {
 				ret = bi->header_supported(imgp, osrel,
@@ -787,12 +789,13 @@ __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
 		struct nameidata nd;
 		struct vattr attr;
 		struct image_params image_params;
-	} *tempdata;
+	} *tempdata = NULL;
 	const Elf_Ehdr *hdr = NULL;
 	const Elf_Phdr *phdr = NULL;
 	struct nameidata *nd;
 	struct vattr *attr;
 	struct image_params *imgp;
+	void *m_phdrs = NULL;
 	u_long rbase;
 	u_long base_addr = 0;
 	int error;
@@ -852,16 +855,27 @@ __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
 		goto fail;
 	}
 
-	/* Only support headers that fit within first page for now      */
-	if (!__elfN(phdr_in_zero_page)(hdr)) {
+	if (!aligned(imgp->image_header + hdr->e_phoff, Elf_Addr)) {
 		error = ENOEXEC;
 		goto fail;
 	}
-
-	phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
-	if (!aligned(phdr, Elf_Addr)) {
-		error = ENOEXEC;
-		goto fail;
+	if (__elfN(phdr_in_zero_page)(hdr)) {
+		phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
+	} else {
+		if (hdr->e_phnum > ELF_OFFPAGE_PHNUM) {
+			error = ENOEXEC;
+			goto fail;
+		}
+		VOP_UNLOCK(imgp->vp);
+		phdr = m_phdrs = malloc(hdr->e_phnum * sizeof(Elf_Phdr),
+		    M_TEMP, M_WAITOK | M_ZERO);
+		vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
+		error = vn_rdwr(UIO_READ, imgp->vp, m_phdrs,
+		    hdr->e_phnum * sizeof(Elf_Phdr), hdr->e_phoff,
+		    UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred,
+		    NOCRED, NULL, imgp->td);
+		if (error != 0)
+			goto fail;
 	}
 
 	error = __elfN(load_sections)(imgp, hdr, phdr, rbase, &base_addr);
@@ -883,6 +897,7 @@ fail:
 			VOP_UNSET_TEXT_CHECKED(nd->ni_vp);
 		vput(nd->ni_vp);
 	}
+	free(m_phdrs, M_TEMP);
 	free(tempdata, M_TEMP);
 
 	return (error);
@@ -1108,6 +1123,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 	char *interp;
 	const Elf_Brandinfo *brand_info;
 	struct sysentvec *sv;
+	void *m_phdrs;
 	u_long addr, baddr, entry, proghdr;
 	u_long maxalign, maxsalign, mapsz, maxv, maxv1, anon_loc;
 	uint32_t fctl0;
@@ -1132,16 +1148,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 	 * detected an ELF file.
 	 */
 
-	if (!__elfN(phdr_in_zero_page)(hdr)) {
-		uprintf("Program headers not in the first page\n");
-		return (ENOEXEC);
-	}
-	phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 
-	if (!aligned(phdr, Elf_Addr)) {
-		uprintf("Unaligned program headers\n");
-		return (ENOEXEC);
-	}
-
 	n = error = 0;
 	baddr = 0;
 	osrel = 0;
@@ -1149,6 +1155,33 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 	entry = proghdr = 0;
 	interp = NULL;
 	free_interp = false;
+	m_phdrs = NULL;
+
+	if (!aligned(imgp->image_header + hdr->e_phoff, Elf_Addr)) {
+		uprintf("Unaligned program headers\n");
+		return (ENOEXEC);
+	}
+	if (hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize < hdr->e_phoff) {
+		uprintf("PHDRS wrap\n");
+		return (ENOEXEC);
+	}
+	if (__elfN(phdr_in_zero_page)(hdr)) {
+		phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
+	} else if (hdr->e_phnum > ELF_OFFPAGE_PHNUM) {
+		uprintf("Too many program headers\n");
+		return (ENOEXEC);
+	} else {
+		VOP_UNLOCK(imgp->vp);
+		phdr = m_phdrs = malloc(hdr->e_phnum * sizeof(Elf_Phdr),
+		    M_TEMP, M_WAITOK | M_ZERO);
+		vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
+		error = vn_rdwr(UIO_READ, imgp->vp, m_phdrs,
+		    hdr->e_phnum * sizeof(Elf_Phdr), hdr->e_phoff,
+		    UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred,
+		    NOCRED, NULL, imgp->td);
+		if (error != 0)
+			goto ret;
+	}
 
 	/*
 	 * Somewhat arbitrary, limit accepted max alignment for the
@@ -1230,7 +1263,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 		}
 	}
 
-	brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0);
+	brand_info = __elfN(get_brandinfo)(imgp, phdr, interp, &osrel, &fctl0);
 	if (brand_info == NULL) {
 		uprintf("ELF binary type \"%u\" not known.\n",
 		    hdr->e_ident[EI_OSABI]);
@@ -1434,6 +1467,7 @@ ret:
 	ASSERT_VOP_LOCKED(imgp->vp, "skipped relock");
 	if (free_interp)
 		free(interp, M_TEMP);
+	free(m_phdrs, M_TEMP);
 	return (error);
 }
 
@@ -2914,17 +2948,16 @@ note_fctl_cb(const Elf_Note *note, void *arg0, bool *res)
  * as for headers.
  */
 static bool
-__elfN(check_note)(struct image_params *imgp, const Elf_Brandnote *brandnote,
-    int32_t *osrel, bool *has_fctl0, uint32_t *fctl0)
+__elfN(check_note)(struct image_params *imgp, const Elf_Phdr *phdr,
+    const Elf_Brandnote *brandnote, int32_t *osrel, bool *has_fctl0,
+    uint32_t *fctl0)
 {
-	const Elf_Phdr *phdr;
 	const Elf_Ehdr *hdr;
 	struct brandnote_cb_arg b_arg;
 	struct fctl_cb_arg f_arg;
 	int i, j;
 
 	hdr = (const Elf_Ehdr *)imgp->image_header;
-	phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
 	b_arg.brandnote = brandnote;
 	b_arg.osrel = osrel;
 	f_arg.has_fctl0 = has_fctl0;


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a18acc7.32ef9.6a0db43>