From: Matej Smycka Date: Fri, 3 Jul 2026 15:20:55 +0000 (+0200) Subject: libelf: Bounds-check archive symbol index count on the mmap path X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3a122a068285b5f64ee8324a7a425f3b632bbc78;p=thirdparty%2Felfutils.git libelf: Bounds-check archive symbol index count on the mmap path read_number_entries () reads the archive symbol index entry count. On the mmap path it copied w (4 or 8) bytes from the mapping without checking that those bytes are present: if (elf->map_address != NULL) memcpy (&u, elf->map_address + *offp, w); else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w) return -1; The pread path rejects a short read, but the mmap path does not. The only preceding size check (SARMAG + sizeof (struct ar_hdr) > maximum_size) covers the 68-byte index-member header; the count field sits immediately after it and index_size (the member's real size) is only validated later. A mmap'd archive truncated to exactly the index header (a "/" member with no content) therefore passes the header check, and read_number_entries () reads w bytes past the end of the mapping. This is the same defect addressed for the over-wide read in commit 8b192160 ("libelf: fix OOB read in elf_getarsym 32-bit archive index count"), which narrowed the read from 8 to w bytes but did not add a bounds check, so a sufficiently truncated archive still over-reads. Reject the read when the count field lies outside the mapping, matching the guarantee the pread path already provides. Reproduced with a guard page: a 68-byte header-only archive built with elf_memory () and placed at the end of a mapping with an inaccessible page following it crashes on an unfixed build and returns ELF_E_NO_INDEX on a fixed build. Signed-off-by: Matej Smycka --- diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c index 346596d7..79aa3bbe 100644 --- a/libelf/elf_getarsym.c +++ b/libelf/elf_getarsym.c @@ -53,9 +53,13 @@ read_number_entries (uint64_t *nump, Elf *elf, size_t *offp, bool index64_p) size_t w = index64_p ? 8 : 4; if (elf->map_address != NULL) - /* Use memcpy instead of pointer dereference so as not to assume the - field is naturally aligned within the file. */ - memcpy (&u, elf->map_address + *offp, w); + { + if (*offp + w > elf->start_offset + elf->maximum_size) + return -1; + /* Use memcpy instead of pointer dereference so as not to assume the + field is naturally aligned within the file. */ + memcpy (&u, elf->map_address + *offp, w); + } else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w) return -1;