handle_dynamic_symtab can attempt to read symbol and version data from file offset of 0 or address of 0 if the associated DT_ tags aren't found.
Fix this by only reading symbol and version data when non-zero file offsets/addresses have been found. https://sourceware.org/bugzilla/show_bug.cgi?id=32864 Suggested-by: Constantine Bytensky <cbyten...@gmail.com> Signed-off-by: Aaron Merey <ame...@redhat.com> --- v2 changes: Added checks for unset addrs and missing symbol version data. src/readelf.c | 82 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/src/readelf.c b/src/readelf.c index 8603b3c4..e9df0344 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -3047,53 +3047,69 @@ handle_dynamic_symtab (Ebl *ebl) Elf_Data *verdef_data = NULL; Elf_Data *verneed_data = NULL; - symdata = elf_getdata_rawchunk ( - ebl->elf, offs[i_symtab], - gelf_fsize (ebl->elf, ELF_T_SYM, syments, EV_CURRENT), ELF_T_SYM); - symstrdata = elf_getdata_rawchunk (ebl->elf, offs[i_strtab], addrs[i_strsz], - ELF_T_BYTE); - versym_data = elf_getdata_rawchunk ( - ebl->elf, offs[i_versym], syments * sizeof (Elf64_Half), ELF_T_HALF); + if (offs[i_symtab] != 0) + symdata = elf_getdata_rawchunk ( + ebl->elf, offs[i_symtab], + gelf_fsize (ebl->elf, ELF_T_SYM, syments, EV_CURRENT), ELF_T_SYM); + + if (offs[i_strtab] != 0 && addrs[i_strsz] != 0) + symstrdata = elf_getdata_rawchunk (ebl->elf, offs[i_strtab], addrs[i_strsz], + ELF_T_BYTE); + + if (offs[i_versym] != 0) + versym_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_versym], syments * sizeof (Elf64_Half), ELF_T_HALF); /* Get the verneed_data without vernaux. */ - verneed_data = elf_getdata_rawchunk ( - ebl->elf, offs[i_verneed], addrs[i_verneednum] * sizeof (Elf64_Verneed), - ELF_T_VNEED); + if (offs[i_verneed] != 0 && addrs[i_verneednum] != 0) + verneed_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verneed], addrs[i_verneednum] * sizeof (Elf64_Verneed), + ELF_T_VNEED); + size_t vernauxnum = 0; size_t vn_next_offset = 0; - for (size_t i = 0; i < addrs[i_verneednum]; i++) - { - GElf_Verneed *verneed - = (GElf_Verneed *)(verneed_data->d_buf + vn_next_offset); - vernauxnum += verneed->vn_cnt; - vn_next_offset += verneed->vn_next; - } + if (verneed_data != NULL && verneed_data->d_buf != NULL + && addrs[i_verneednum] != 0) + for (size_t i = 0; i < addrs[i_verneednum]; i++) + { + GElf_Verneed *verneed + = (GElf_Verneed *)(verneed_data->d_buf + vn_next_offset); + vernauxnum += verneed->vn_cnt; + vn_next_offset += verneed->vn_next; + } /* Update the verneed_data to include the vernaux. */ - verneed_data = elf_getdata_rawchunk ( - ebl->elf, offs[i_verneed], - (addrs[i_verneednum] + vernauxnum) * sizeof (GElf_Verneed), ELF_T_VNEED); + if (offs[i_verneed] != 0 && addrs[i_verneednum] != 0) + verneed_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verneed], + (addrs[i_verneednum] + vernauxnum) * sizeof (GElf_Verneed), + ELF_T_VNEED); /* Get the verdef_data without verdaux. */ - verdef_data = elf_getdata_rawchunk ( - ebl->elf, offs[i_verdef], addrs[i_verdefnum] * sizeof (Elf64_Verdef), - ELF_T_VDEF); + if (offs[i_verdef] != 0 && addrs[i_verdefnum] != 0) + verdef_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verdef], addrs[i_verdefnum] * sizeof (Elf64_Verdef), + ELF_T_VDEF); + size_t verdauxnum = 0; size_t vd_next_offset = 0; - for (size_t i = 0; i < addrs[i_verdefnum]; i++) - { - GElf_Verdef *verdef - = (GElf_Verdef *)(verdef_data->d_buf + vd_next_offset); - verdauxnum += verdef->vd_cnt; - vd_next_offset += verdef->vd_next; - } + if (verdef_data != NULL && verdef_data->d_buf != NULL + && addrs[i_verdefnum] != 0) + for (size_t i = 0; i < addrs[i_verdefnum]; i++) + { + GElf_Verdef *verdef + = (GElf_Verdef *)(verdef_data->d_buf + vd_next_offset); + verdauxnum += verdef->vd_cnt; + vd_next_offset += verdef->vd_next; + } /* Update the verdef_data to include the verdaux. */ - verdef_data = elf_getdata_rawchunk ( - ebl->elf, offs[i_verdef], - (addrs[i_verdefnum] + verdauxnum) * sizeof (GElf_Verdef), ELF_T_VDEF); + if (offs[i_verdef] != 0 && addrs[i_verdefnum] != 0) + verdef_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verdef], + (addrs[i_verdefnum] + verdauxnum) * sizeof (GElf_Verdef), ELF_T_VDEF); unsigned int nsyms = (unsigned int)syments; process_symtab (ebl, nsyms, 0, 0, 0, symdata, versym_data, symstrdata, -- 2.49.0