From: Aaron Merey Date: Mon, 8 Sep 2025 02:17:28 +0000 (-0400) Subject: elf_begin.c: Use relative offset in archive size check X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=180945cb0f7cc129494bde7908dc5709fff7662c;p=thirdparty%2Felfutils.git 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 --- 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) {