From: Yann Rouillard Date: Tue, 9 Jul 2013 18:22:27 +0000 (+0200) Subject: Correctly handle the "multiple string tables" case for string resolution in the dynam... X-Git-Tag: v0.22~10^2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4cbbf8bd5d4cfbb9269e9bca2a3eed2f04ce6c72;p=pyelftools.git Correctly handle the "multiple string tables" case for string resolution in the dynamic section The index of the string table section used to resolve various strings in the dynamic section is given by the sh_link field in the dynamic section header. As several string tables with the same name can co-exist in an elf file we must explicitely look for this specific string table instead of looking for the first string table in the file. --- diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py index 60fb450..e36598e 100644 --- a/elftools/elf/dynamic.py +++ b/elftools/elf/dynamic.py @@ -28,12 +28,11 @@ class DynamicTag(object): ['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH', 'DT_SONAME', 'DT_SUNW_FILTER']) - def __init__(self, entry, elffile): + def __init__(self, entry, stringtable): self.entry = entry if entry.d_tag in self._HANDLED_TAGS: - dynstr = elffile.get_section_by_name(b'.dynstr') setattr(self, entry.d_tag[3:].lower(), - dynstr.get_string(self.entry.d_val)) + stringtable.get_string(self.entry.d_val)) def __getitem__(self, name): """ Implement dict-like access to entries @@ -54,13 +53,14 @@ class DynamicTag(object): class Dynamic(object): """ Shared functionality between dynamic sections and segments. """ - def __init__(self, stream, elffile, position): + def __init__(self, stream, elffile, stringtable, position): self._stream = stream self._elffile = elffile self._elfstructs = elffile.structs self._num_tags = -1 self._offset = position self._tagsize = self._elfstructs.Elf_Dyn.sizeof() + self._stringtable = stringtable def iter_tags(self, type=None): """ Yield all tags (limit to |type| if specified) @@ -80,7 +80,7 @@ class Dynamic(object): self._elfstructs.Elf_Dyn, self._stream, stream_pos=offset) - return DynamicTag(entry, self._elffile) + return DynamicTag(entry, self._stringtable) def num_tags(self): """ Number of dynamic tags in the file @@ -100,12 +100,24 @@ class DynamicSection(Section, Dynamic): """ def __init__(self, header, name, stream, elffile): Section.__init__(self, header, name, stream) - Dynamic.__init__(self, stream, elffile, self['sh_offset']) + stringtable = elffile.get_section(header['sh_link']) + Dynamic.__init__(self, stream, elffile, stringtable, self['sh_offset']) class DynamicSegment(Segment, Dynamic): """ ELF dynamic table segment. Knows how to process the list of tags. """ def __init__(self, header, stream, elffile): + # The string table section to be used to resolve string names in + # the dynamic tag array is the one pointed at by the sh_link field + # of the dynamic section header. + # So we must look for the dynamic section contained in the dynamic + # segment, we do so by searching for the dynamic section whose content + # is located at the same offset as the dynamic segment + for section in elffile.iter_sections(): + if (isinstance(section, DynamicSection) and + section['sh_offset'] == header['p_offset']): + stringtable = elffile.get_section(section['sh_link']) + break Segment.__init__(self, header, stream) - Dynamic.__init__(self, stream, elffile, self['p_offset']) + Dynamic.__init__(self, stream, elffile, stringtable, self['p_offset']) diff --git a/test/test_double_dynstr_section.py b/test/test_double_dynstr_section.py new file mode 100644 index 0000000..c907928 --- /dev/null +++ b/test/test_double_dynstr_section.py @@ -0,0 +1,64 @@ +#------------------------------------------------------------------------------ +# elftools tests +# +# Yann Rouillard (yann@pleiades.fr.eu.org) +# This code is in the public domain +#------------------------------------------------------------------------------ +try: + import unittest2 as unittest +except ImportError: + import unittest +import os + +from utils import setup_syspath +setup_syspath() +from elftools.elf.elffile import ELFFile +from elftools.elf.dynamic import DynamicSection, DynamicTag + + +class TestDoubleDynstrSections(unittest.TestCase): + """ This test make sure than dynamic tags + are properly analyzed when two .dynstr + sections are present in an elf file + """ + + reference_data = [ + b'libz.so.1', + b'libc.so.6', + b'lib_versioned.so.1', + ] + + def _test_double_dynstr_section_generic(self, testfile): + + with open(os.path.join('test', 'testfiles_for_unittests', testfile), + 'rb') as f: + + elf = ELFFile(f) + for section in elf.iter_sections(): + if isinstance(section, DynamicSection): + d_tags = [getattr(x, x.entry.d_tag[3:].lower()) + for x in section.iter_tags() + if x.entry.d_tag in DynamicTag._HANDLED_TAGS] + self.assertListEqual( + TestDoubleDynstrSections.reference_data, + d_tags) + return + + self.fail('No dynamic section found !!') + + + def test_double_dynstr_section(self): + """ First test with the good dynstr section first + """ + self._test_double_dynstr_section_generic( + 'lib_with_two_dynstr_sections.so.1.elf') + + def test_double_dynstr_section_reverse(self): + """ Second test with the good dynstr section last + """ + self._test_double_dynstr_section_generic( + 'lib_with_two_dynstr_sections_reversed.so.1.elf') + + +if __name__ == '__main__': + unittest.main() diff --git a/test/testfiles_for_unittests/lib_with_two_dynstr_sections.so.1.elf b/test/testfiles_for_unittests/lib_with_two_dynstr_sections.so.1.elf new file mode 100755 index 0000000..661950b Binary files /dev/null and b/test/testfiles_for_unittests/lib_with_two_dynstr_sections.so.1.elf differ diff --git a/test/testfiles_for_unittests/lib_with_two_dynstr_sections_reversed.so.1.elf b/test/testfiles_for_unittests/lib_with_two_dynstr_sections_reversed.so.1.elf new file mode 100755 index 0000000..8d07de1 Binary files /dev/null and b/test/testfiles_for_unittests/lib_with_two_dynstr_sections_reversed.so.1.elf differ