zdump: Fix handling of PT_LOAD segments with p_filesz < p_memsz in ELF DFI

According to the ELF specification, the file size of a PT_LOAD
memory segment might be less than its memory size. In that case,
the remaining bytes must be filled with zeros. The ELF DFI implementation
didn't handle this case correctly. Such ELF core files might be produced
by the makedumpfile tool.

From elf.5 man page:
------------------------------------------------------
PT_LOAD
       The array element specifies a loadable segment,
       described by p_filesz and p_memsz.  The bytes
       from the file are mapped to the beginning of the
       memory segment.  If the segment's memory size
       p_memsz is larger than the file size p_filesz,
       the "extra" bytes are defined to hold the value
       0 and to follow the segment's initialized area.
       The file size may not be larger than the memory
       size.  Loadable segment entries in the program
       header table appear in ascending order, sorted
       on the p_vaddr member.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Alexander Egorenkov
2021-08-19 12:31:42 +02:00
committed by Jan Höppner
parent 735d8f5493
commit 4043137cd7

View File

@@ -47,16 +47,20 @@ static int pt_load_add(Elf64_Phdr *phdr)
return -EINVAL;
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
if (phdr->p_filesz == 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
dfi_mem_chunk_read_zero, NULL);
} else {
if (phdr->p_filesz > phdr->p_memsz)
return -EINVAL;
if (phdr->p_filesz > 0) {
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = phdr->p_offset;
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_filesz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
}
if (phdr->p_memsz - phdr->p_filesz > 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr + phdr->p_filesz,
phdr->p_memsz - phdr->p_filesz, NULL,
dfi_mem_chunk_read_zero, NULL);
}
return 0;
}