Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jul 2026 17:50:11 +0000
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 475a72f75478 - releng/15.0 - coredump: Don't assume that the number of ELF segments is consistent
Message-ID:  <6a6a3d53.3bba2.1034761b@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch releng/15.0 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=475a72f754781d781ef3b48a4faf3c350a2e1cca

commit 475a72f754781d781ef3b48a4faf3c350a2e1cca
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-07-27 15:42:49 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-07-28 17:34:59 +0000

    coredump: Don't assume that the number of ELF segments is consistent
    
    In an ELF coredump, each dumped vm_map_entry is represented by a
    segment.  __elfN(coredump) first computes the number of segments by
    looping over the vm_map entries (in each_dumpable_segment()), then
    allocates a buffer to hold the ELF header and program headers, then
    loops over the entries again to populate the program headers.
    
    each_dumpable_segment() holds the vm_map read lock, but that lock is
    dropped between the two calls.  If the map is shared with another
    process, via rfork(), then the map can change.  cb_put_phdr() did not
    account for this, and so could write out of bounds.
    
    Add a check to prevent this; simply do not write out excess segments.
    
    Approved by:    so
    Security:       FreeBSD-SA-26:55.elf
    Security:       CVE-2026-58088
    Reported by:    Maik Muench of Secfault Security
    Reviewed by:    kib, emaste
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D58416
---
 sys/kern/imgact_elf.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index ca5066c634f8..c43993ef0667 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -1555,6 +1555,8 @@ typedef void (*segment_callback)(vm_map_entry_t, void *);
 struct phdr_closure {
 	Elf_Phdr *phdr;		/* Program header to fill in */
 	Elf_Off offset;		/* Offset of segment in core file */
+	int numsegs;		/* Maximum number of segments */
+	int nextseg;		/* Next segment to fill in */
 };
 
 struct note_info {
@@ -1671,10 +1673,15 @@ __elfN(coredump)(struct thread *td, struct coredump_writer *cdw, off_t limit, in
 	}
 
 	/*
-	 * Allocate memory for building the header, fill it up,
-	 * and write it out following the notes.
+	 * Allocate memory for building the header, fill it up, and write it out
+	 * following the notes.
+	 *
+	 * Note that a process sharing our vmspace might be concurrently
+	 * mutating the map, in which case we could populate fewer than
+	 * seginfo.count headers.  Zero the buffer to ensure that unpopulated
+	 * headers are still initialized.
 	 */
-	hdr = malloc(hdrsize, M_TEMP, M_WAITOK);
+	hdr = malloc(hdrsize, M_TEMP, M_WAITOK | M_ZERO);
 	error = __elfN(corehdr)(&params, seginfo.count, hdr, hdrsize, &notelst,
 	    notesz, flags);
 
@@ -1727,6 +1734,11 @@ cb_put_phdr(vm_map_entry_t entry, void *closure)
 	struct phdr_closure *phc = (struct phdr_closure *)closure;
 	Elf_Phdr *phdr = phc->phdr;
 
+	if (phc->nextseg >= phc->numsegs) {
+		/* Only write as many headers as we have space for. */
+		return;
+	}
+
 	phc->offset = round_page(phc->offset);
 
 	phdr->p_type = PT_LOAD;
@@ -1739,6 +1751,8 @@ cb_put_phdr(vm_map_entry_t entry, void *closure)
 
 	phc->offset += phdr->p_filesz;
 	phc->phdr++;
+
+	phc->nextseg++;
 }
 
 /*
@@ -2001,6 +2015,8 @@ __elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs,
 	/* All the writable segments from the program. */
 	phc.phdr = phdr;
 	phc.offset = round_page(hdrsize + notesz);
+	phc.numsegs = numsegs;
+	phc.nextseg = 0;
 	each_dumpable_segment(td, cb_put_phdr, &phc, flags);
 }
 


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a6a3d53.3bba2.1034761b>