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>
