From 180945cb0f7cc129494bde7908dc5709fff7662c Mon Sep 17 00:00:00 2001 From: Aaron Merey Date: Sun, 7 Sep 2025 22:17:28 -0400 Subject: [PATCH] elf_begin.c: Use relative offset in archive size check Before creating an elf descriptor for an archive member, dup_elf verifies that the size of an archive is large enough to contain the member. This check uses the member's offset relative to the map_address of the top-level archive containing the member. This check can incorrectly fail when an archive contains another archive as a member. For members of the inner archive, their offset relative to the outer archive might be significantly larger than the max_size of the inner archive. This appears as if the offset and max_size values are inconsistent and the creation of the member's elf descriptor is stopped unnecessarily. Fix this by accounting for the inner archive's non-zero start_offset when judging whether the member can fit within it. Also perform this size check before creating a copy of the member's Elf_Arhdr to prevent leaking the header's ar_name and ar_rawname if the size check fails. Signed-off-by: Aaron Merey --- libelf/elf_begin.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index d3ab887d..a824893f 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -1107,22 +1107,24 @@ dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) /* Something went wrong. Maybe there is no member left. */ return NULL; - Elf_Arhdr ar_hdr = {0}; - if (copy_arhdr (&ar_hdr, ref) != 0) - /* Out of memory. */ - return NULL; - /* We have all the information we need about the next archive member. Now create a descriptor for it. Check parent size can contain member. */ + if (ref->state.ar.offset < ref->start_offset) + return NULL; size_t max_size = ref->maximum_size; - size_t offset = (size_t) ref->state.ar.offset; + size_t offset = (size_t) (ref->state.ar.offset - ref->start_offset); size_t hdr_size = sizeof (struct ar_hdr); size_t ar_size = (size_t) ref->state.ar.elf_ar_hdr.ar_size; - if (max_size - hdr_size < offset) + if (max_size < hdr_size || max_size - hdr_size < offset) return NULL; - else - result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), - MIN (max_size - hdr_size - offset, ar_size), cmd, ref); + + Elf_Arhdr ar_hdr = {0}; + if (copy_arhdr (&ar_hdr, ref) != 0) + /* Out of memory. */ + return NULL; + + result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), + MIN (max_size - hdr_size - offset, ar_size), cmd, ref); if (result != NULL) { -- 2.47.3