Hi Aaron, Hi Constantine, On Mon, 2025-05-05 at 10:44 -0400, Aaron Merey wrote: > 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); > +
All looks good. > 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; > + } The last && addrs[i_verneednum] != 0 is ok, but redundant because of the i < addrs[i_verneednum] (which would immediately succeed and so also skips the loop). But if we are going to make this robust then there is another (pre- existing) issue. We keep reading the data from the d_buf as a GElf_Verneed and use verneed->vn_next to give us the next offset. We need to check if that is sane. First we need to check verneed_data- >d_size is at least sizeof (GElf_Verneed) and then vn_next_offset must always be smaller than verneed_data->d_size - sizeof (GElf_Verneed). > /* 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); > + Looks good. > 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; > + } Same as above, but now for sizeof (GElf_Verdef). > /* 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, Looks good. Cheers, Mark