From b9d005177a31be1e548c90afc9e86507a842f966 Mon Sep 17 00:00:00 2001 From: Chris Patterson Date: Fri, 8 May 2020 12:14:14 +0000 Subject: [PATCH 1/2] elf: fix parsing of notes after patchelf mangling We cannot rely on iterating on the notes via the note segment. Patchelf may move note sections into other segments, and worse yet, possibly leave the note segment standing with invalid data. Here we instead iterate over each section and (more) reliably gather the note information. There is some improvement that should be done on the patchelf side, as `readelf` complains on these binaries, and other issues have surfaced in the past (e.g. mesa in classic snaps). However, this will hopefully address snapcraft build-time issues with not only our patched files for classic snaps, but externally patched binaries that are being packaged. Add a couple of developer logs to indicate when we are parsing an ELF, so future investigations are easier when something explodes. Signed-off-by: Chris Patterson --- snapcraft/internal/elf.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/snapcraft/internal/elf.py b/snapcraft/internal/elf.py index 98de6ba89a..327ac9e4d2 100644 --- a/snapcraft/internal/elf.py +++ b/snapcraft/internal/elf.py @@ -298,8 +298,10 @@ def __init__(self, *, path: str) -> None: self.elf_type: str = "ET_NONE" try: + logger.debug("Extracting ELF attributes:", path) self._extract_attributes() except (UnicodeDecodeError, AttributeError, ConstructError) as exception: + logger.debug("Extracting ELF attributes exception: ", str(exception)) raise errors.CorruptedElfFileError(path, exception) def _extract_attributes(self) -> None: # noqa: C901 @@ -335,8 +337,15 @@ def _extract_attributes(self) -> None: # noqa: C901 self.execstack_set = True elif isinstance(segment, elftools.elf.segments.InterpSegment): self.interp = segment.get_interp_name() - elif isinstance(segment, elftools.elf.segments.NoteSegment): - for note in segment.iter_notes(): + + # We cannot rely on iterating on the notes via the note segment. + # Patchelf may move note sections into other segments, and worse + # yet, possibly leave the note segment standing with invalid data. + # Here we instead iterate over each section and (more) reliably + # gather the note information. + for section in elf.iter_sections(): + if isinstance(section, elftools.elf.sections.NoteSection): + for note in section.iter_notes(): if note.n_name == "GNU" and note.n_type == "NT_GNU_BUILD_ID": self.build_id = _ensure_str(note.n_desc) From ed0a3b71e71703096c791b5dc4c73db85294613c Mon Sep 17 00:00:00 2001 From: Chris Patterson Date: Mon, 11 May 2020 11:40:47 +0000 Subject: [PATCH 2/2] get section by name and check for SHT_NOBITS Signed-off-by: Chris Patterson --- snapcraft/internal/elf.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/snapcraft/internal/elf.py b/snapcraft/internal/elf.py index 327ac9e4d2..b3bdb51473 100644 --- a/snapcraft/internal/elf.py +++ b/snapcraft/internal/elf.py @@ -338,16 +338,14 @@ def _extract_attributes(self) -> None: # noqa: C901 elif isinstance(segment, elftools.elf.segments.InterpSegment): self.interp = segment.get_interp_name() - # We cannot rely on iterating on the notes via the note segment. - # Patchelf may move note sections into other segments, and worse - # yet, possibly leave the note segment standing with invalid data. - # Here we instead iterate over each section and (more) reliably - # gather the note information. - for section in elf.iter_sections(): - if isinstance(section, elftools.elf.sections.NoteSection): - for note in section.iter_notes(): - if note.n_name == "GNU" and note.n_type == "NT_GNU_BUILD_ID": - self.build_id = _ensure_str(note.n_desc) + build_id_section = elf.get_section_by_name(".note.gnu.build-id") + if ( + isinstance(build_id_section, elftools.elf.sections.NoteSection) + and build_id_section.header["sh_type"] != "SHT_NOBITS" + ): + for note in build_id_section.iter_notes(): + if note.n_name == "GNU" and note.n_type == "NT_GNU_BUILD_ID": + self.build_id = _ensure_str(note.n_desc) # If we are processing a detached debug info file, these # sections will be present but empty.