__libelf_readall reads an entire image into memory and sets ELF_F_MALLOCED for the associated elf descriptor. For ELF_K_AR descriptors, member/child descriptors do not have ELF_F_MALLOCED set even though their image is in a malloced buffer.
This causes an assert failure in elf32_getshdr.c:load_shdr_wrlock when attempting to read an shdr from an archive member. The function asserts that ELF_F_MALLOCED is set because the member descriptor's map_address is non-NULL. Fix this by introducing a new internal flag ELF_F_PARENT_MALLOCED to indicate that this descriptor's image has been allocated but the memory is owned by a parent descriptor. Signed-off-by: Aaron Merey <[email protected]> --- libelf/elf32_getshdr.c | 7 ++++--- libelf/elf_readall.c | 4 ++++ libelf/libelfP.h | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libelf/elf32_getshdr.c b/libelf/elf32_getshdr.c index e4bebe18..7c6c2acb 100644 --- a/libelf/elf32_getshdr.c +++ b/libelf/elf32_getshdr.c @@ -91,11 +91,12 @@ load_shdr_wrlock (Elf_Scn *scn) /* All the data is already mapped. If we could use it directly this would already have happened. Unless we allocated the memory ourselves and the ELF_F_MALLOCED - flag is set. */ + flag is set, or a parent archive allocated the memory + and ELF_F_PARENT_MALLOCED is set. */ void *file_shdr = ((char *) elf->map_address + elf->start_offset + ehdr->e_shoff); - assert ((elf->flags & ELF_F_MALLOCED) + assert ((elf->flags & (ELF_F_MALLOCED | ELF_F_PARENT_MALLOCED)) || ehdr->e_ident[EI_DATA] != MY_ELFDATA || elf->cmd == ELF_C_READ_MMAP || (! ALLOW_UNALIGNED @@ -105,7 +106,7 @@ load_shdr_wrlock (Elf_Scn *scn) /* Now copy the data and at the same time convert the byte order. */ if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) { - assert ((elf->flags & ELF_F_MALLOCED) + assert ((elf->flags & (ELF_F_MALLOCED | ELF_F_PARENT_MALLOCED)) || elf->cmd == ELF_C_READ_MMAP || ! ALLOW_UNALIGNED); memcpy (shdr, file_shdr, size); diff --git a/libelf/elf_readall.c b/libelf/elf_readall.c index 4ef8fe97..2e3a3c6f 100644 --- a/libelf/elf_readall.c +++ b/libelf/elf_readall.c @@ -49,8 +49,12 @@ set_address (Elf *elf, size_t offset) { if (child->map_address == NULL) { + /* The archive image is malloced but owned by the parent + archive, so the child must not free it. */ + child->flags |= ELF_F_PARENT_MALLOCED; child->map_address = elf->map_address; child->start_offset -= offset; + if (child->kind == ELF_K_AR) child->state.ar.offset -= offset; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index 2403d796..3f351553 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -83,7 +83,8 @@ enum { ELF_F_MMAPPED = 0x40, ELF_F_MALLOCED = 0x80, - ELF_F_FILEDATA = 0x100 + ELF_F_FILEDATA = 0x100, + ELF_F_PARENT_MALLOCED = 0x200 }; -- 2.55.0
