-
Couldn't load subscription status.
- Fork 15k
[llvm][ELF]Add Shdr check for getBuildID #126537
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
Changes from 15 commits
a19e1a0
20f7214
169f9db
0c6d355
7105db4
40ff1ff
0a502cd
7193339
c388efa
9393e97
e07a49b
4e83f8a
2e8c6ba
6fa8919
b64f287
fece101
a1971c9
62ee98b
47b96a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -407,7 +407,8 @@ class ELFFile { | |
| Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const { | ||
| assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE"); | ||
| ErrorAsOutParameter ErrAsOutParam(Err); | ||
| if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) { | ||
| if (Phdr.p_offset + Phdr.p_filesz > getBufSize() || | ||
| Phdr.p_offset + Phdr.p_filesz < Phdr.p_offset) { | ||
| Err = | ||
| createError("invalid offset (0x" + Twine::utohexstr(Phdr.p_offset) + | ||
| ") or size (0x" + Twine::utohexstr(Phdr.p_filesz) + ")"); | ||
|
|
@@ -435,7 +436,8 @@ class ELFFile { | |
| Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const { | ||
| assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE"); | ||
| ErrorAsOutParameter ErrAsOutParam(Err); | ||
| if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) { | ||
| if (Shdr.sh_offset + Shdr.sh_size > getBufSize() || | ||
|
||
| Shdr.sh_offset + Shdr.sh_size < Shdr.sh_offset) { | ||
| Err = | ||
| createError("invalid offset (0x" + Twine::utohexstr(Shdr.sh_offset) + | ||
| ") or size (0x" + Twine::utohexstr(Shdr.sh_size) + ")"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| //===- BuildIDTest.cpp - Tests for getBuildID ----------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/Object/BuildID.h" | ||
| #include "llvm/ADT/SmallString.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/Object/ELFObjectFile.h" | ||
| #include "llvm/ObjectYAML/yaml2obj.h" | ||
| #include "llvm/Support/YAMLTraits.h" | ||
| #include "llvm/Testing/Support/Error.h" | ||
|
|
||
| #include "gtest/gtest.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace llvm::object; | ||
|
|
||
| template <class ELFT> | ||
| static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage, | ||
| StringRef Yaml) { | ||
| raw_svector_ostream OS(Storage); | ||
| yaml::Input YIn(Yaml); | ||
| if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {})) | ||
| return createStringError(std::errc::invalid_argument, | ||
| "unable to convert YAML"); | ||
| return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF")); | ||
| } | ||
|
|
||
| static StringRef getInvalidNoteELF(bool WithShdr) { | ||
| static std::string WithSection(R"( | ||
| --- !ELF | ||
| FileHeader: | ||
| Class: ELFCLASS64 | ||
| Data: ELFDATA2LSB | ||
| Type: ET_EXEC | ||
| Machine: EM_X86_64 | ||
| ProgramHeaders: | ||
| - Type: PT_NOTE | ||
| FileSize: 0xffffffffffffff88 | ||
|
||
| FirstSec: .note.gnu.build-id | ||
| LastSec: .note.gnu.build-id | ||
| Sections: | ||
| - Name: .note.gnu.build-id | ||
| Type: SHT_NOTE | ||
| AddressAlign: 0x04 | ||
| Notes: | ||
| - Name: "GNU" | ||
| Desc: "abb50d82b6bdc861" | ||
| Type: 3 | ||
| )"); | ||
| static std::string WithoutSection(WithSection + R"( | ||
| - Type: SectionHeaderTable | ||
| NoHeaders: true | ||
| )"); | ||
| if (WithShdr) | ||
| return WithSection; | ||
| return WithoutSection; | ||
| } | ||
|
|
||
| // The BuildID can be looked up from a section header, if there is no program header. | ||
| TEST(BuildIDTest, InvalidPhdrFileSizeWithShdrs) { | ||
| SmallString<0> Storage; | ||
| Expected<ELFObjectFile<ELF64LE>> ElfOrErr = | ||
| toBinary<ELF64LE>(Storage, getInvalidNoteELF(true)); | ||
| ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded()); | ||
| BuildIDRef BuildID = getBuildID(&ElfOrErr.get()); | ||
| EXPECT_EQ( | ||
| StringRef(reinterpret_cast<const char *>(BuildID.data()), BuildID.size()), | ||
| "\xAB\xB5\x0D\x82\xB6\xBD\xC8\x61"); | ||
| } | ||
|
|
||
| // The code handles a malformed program header that points at data outside the file. | ||
| TEST(BuildIDTest, InvalidPhdrFileSizeNoShdrs) { | ||
| SmallString<0> Storage; | ||
| Expected<ELFObjectFile<ELF64LE>> ElfOrErr = | ||
| toBinary<ELF64LE>(Storage, getInvalidNoteELF(false)); | ||
| ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded()); | ||
| BuildIDRef BuildID = getBuildID(&ElfOrErr.get()); | ||
| EXPECT_EQ( | ||
| StringRef(reinterpret_cast<const char *>(BuildID.data()), BuildID.size()), | ||
| ""); | ||
| } | ||
|
|
||
| // the code handles a malformed section header that points at data outside the file. | ||
cabbaken marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| TEST(BuildIDTest, InvalidSectionHeader) { | ||
| SmallString<0> Storage; | ||
| Expected<ELFObjectFile<ELF64LE>> ElfOrErr = toBinary<ELF64LE>(Storage, R"( | ||
| --- !ELF | ||
| FileHeader: | ||
| Class: ELFCLASS64 | ||
| Data: ELFDATA2LSB | ||
| Type: ET_EXEC | ||
| Machine: EM_X86_64 | ||
| ProgramHeaders: | ||
| - Type: PT_NOTE | ||
| FirstSec: .note.gnu.build-id | ||
| LastSec: .note.gnu.build-id | ||
| Sections: | ||
| - Name: .note.gnu.build-id | ||
| Type: SHT_NOTE | ||
| AddressAlign: 0x04 | ||
| ShOffset: 0xffffffffffffff88 | ||
| Notes: | ||
| - Name: "GNU" | ||
| Desc: "abb50d82b6bdc861" | ||
| Type: 3 | ||
| )"); | ||
| ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded()); | ||
| BuildIDRef BuildID = getBuildID(&ElfOrErr.get()); | ||
| EXPECT_EQ( | ||
| StringRef(reinterpret_cast<const char *>(BuildID.data()), BuildID.size()), | ||
| "\xAB\xB5\x0D\x82\xB6\xBD\xC8\x61"); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these are independent of your wider change, they should be their own PR, with appropriate unit testing, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This serves as an overflow check, and the unit test would fail without it. Do you think I should create a separate PR to merge this check first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and I see you've put a PR up for it.