Hi Matej,
On Fri, Jul 03, 2026 at 05:20:55PM +0200, Matej Smycka wrote:
> 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.
Right pread_retry is unable to read "beyond" the end of the fd.
> 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.
Ah, missed that in the review. Thanks for catching that.
> 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.
And lets add that to the testcase:
https://sourceware.org/cgit/elfutils/commit/?id=7dacdb1ddb46
> Signed-off-by: Matej Smycka <[email protected]>
> ---
> libelf/elf_getarsym.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> 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;
Looks good. Pushed as:
https://sourceware.org/cgit/elfutils/commit/?id=3a122a068285
Thanks,
Mark