Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elf: fix parsing of notes after patchelf mangling #3111

Merged
merged 2 commits into from
May 11, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 11 additions & 2 deletions snapcraft/internal/elf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was curious about what the best canonical way of determining the build ID is. I think this is the relevant part of the GDB source code:

https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=bfd/opncls.c;h=99097a9e39989e377af70e9450a970b009439e70;hb=HEAD#l1797

It seems to use the following process:

  1. Find the section named .note.gnu.build-id
  2. Read the contents of the section (this presumably makes sure its not a SHT_NOBITS section).
  3. Look for a note with name "GNU" and type "NT_GNU_BUILD_ID". The description field of that note is the build ID.

So you are right to switch over to checking sections, but I think we can switch this to section = elf.get_section_by_name('.note.gnu-build-id'), and work from there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, will do! Thanks!

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)

Expand Down