-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[llvm-objdump][ELF] Ensure offset to verdaux entry array does not go past size #115284
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
base: main
Are you sure you want to change the base?
[llvm-objdump][ELF] Ensure offset to verdaux entry array does not go past size #115284
Conversation
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-objectyaml Author: Antonio Frighetto (antoniofrighetto) ChangesValidate Fixes: #86611. Full diff: https://github.com/llvm/llvm-project/pull/115284.diff 5 Files Affected:
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 8f045d6383623b..5383037582124c 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -582,6 +582,7 @@ struct VerdefEntry {
std::optional<uint16_t> Flags;
std::optional<uint16_t> VersionNdx;
std::optional<uint32_t> Hash;
+ std::optional<uint16_t> AuxVOffset;
std::vector<StringRef> VerNames;
};
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index fc234581a45a70..a379a3e0d4a596 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1655,7 +1655,7 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
VerDef.vd_flags = E.Flags.value_or(0);
VerDef.vd_ndx = E.VersionNdx.value_or(0);
VerDef.vd_hash = E.Hash.value_or(0);
- VerDef.vd_aux = sizeof(Elf_Verdef);
+ VerDef.vd_aux = E.AuxVOffset.value_or(sizeof(Elf_Verdef));
VerDef.vd_cnt = E.VerNames.size();
if (I == Section.Entries->size() - 1)
VerDef.vd_next = 0;
@@ -1665,13 +1665,13 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
CBA.write((const char *)&VerDef, sizeof(Elf_Verdef));
for (size_t J = 0; J < E.VerNames.size(); ++J, ++AuxCnt) {
- Elf_Verdaux VernAux;
- VernAux.vda_name = DotDynstr.getOffset(E.VerNames[J]);
+ Elf_Verdaux VerdAux;
+ VerdAux.vda_name = DotDynstr.getOffset(E.VerNames[J]);
if (J == E.VerNames.size() - 1)
- VernAux.vda_next = 0;
+ VerdAux.vda_next = 0;
else
- VernAux.vda_next = sizeof(Elf_Verdaux);
- CBA.write((const char *)&VernAux, sizeof(Elf_Verdaux));
+ VerdAux.vda_next = sizeof(Elf_Verdaux);
+ CBA.write((const char *)&VerdAux, sizeof(Elf_Verdaux));
}
}
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index e97248cbcf5682..821f48723b35e5 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1921,6 +1921,7 @@ void MappingTraits<ELFYAML::VerdefEntry>::mapping(IO &IO,
IO.mapOptional("Flags", E.Flags);
IO.mapOptional("VersionNdx", E.VersionNdx);
IO.mapOptional("Hash", E.Hash);
+ IO.mapOptional("AuxVOffset", E.AuxVOffset);
IO.mapRequired("Names", E.VerNames);
}
diff --git a/llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test b/llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test
new file mode 100644
index 00000000000000..abf9a2829f248c
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test
@@ -0,0 +1,29 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objdump -p %t 2>&1 | FileCheck --check-prefix=BROKEN-VERDEF -DFILE=%t %s
+
+# BROKEN-VERDEF: Version definitions:
+# BROKEN-VERDEF-NEXT: warning: '[[FILE]]': out-of-bound while parsing verdaux entries, corrupted verdef section
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+ Entry: 0x0000000000001000
+Sections:
+ - Name: .gnu.version_d
+ Type: SHT_GNU_verdef
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0000000000000230
+ AddressAlign: 0x0000000000000004
+ Entries:
+ - Version: 1
+ Flags: 44
+ VersionNdx: 0
+ Hash: 12345
+ AuxVOffset: 0x45
+ Names:
+ - VERSION_1
+DynamicSymbols: []
+...
diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index 5ac13495662faf..3c5d11ef8ba751 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -39,6 +39,9 @@ template <typename ELFT> class ELFDumper : public Dumper {
void printProgramHeaders();
void printSymbolVersion();
void printSymbolVersionDependency(const typename ELFT::Shdr &Sec);
+ void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
+ ArrayRef<uint8_t> Contents,
+ StringRef StrTab);
};
} // namespace
@@ -380,9 +383,9 @@ void ELFDumper<ELFT>::printSymbolVersionDependency(
}
template <class ELFT>
-static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
- ArrayRef<uint8_t> Contents,
- StringRef StrTab) {
+void ELFDumper<ELFT>::printSymbolVersionDefinition(
+ const typename ELFT::Shdr &Shdr, ArrayRef<uint8_t> Contents,
+ StringRef StrTab) {
outs() << "\nVersion definitions:\n";
const uint8_t *Buf = Contents.data();
@@ -398,6 +401,12 @@ static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
<< format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash);
const uint8_t *BufAux = Buf + Verdef->vd_aux;
+ if (BufAux > Contents.end()) {
+ reportWarning("out-of-bound while parsing verdaux entries, corrupted "
+ "verdef section",
+ Obj.getFileName());
+ break;
+ }
uint16_t VerdauxIndex = 0;
while (BufAux) {
auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux);
@@ -430,7 +439,7 @@ template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() {
if (Shdr.sh_type == ELF::SHT_GNU_verneed)
printSymbolVersionDependency(Shdr);
else
- printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
+ printSymbolVersionDefinition(Shdr, Contents, StrTab);
}
}
|
Change in ObjectYAML can be pre-committed separately, if it looks good. |
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.
I think it would be worth splitting the yaml2obj part into a separate PR. It should include tests too for yaml2obj (and possibly obj2yaml, if it can be used to generate YAML for such a corrupt object).
llvm/lib/ObjectYAML/ELFEmitter.cpp
Outdated
Elf_Verdaux VerdAux; | ||
VerdAux.vda_name = DotDynstr.getOffset(E.VerNames[J]); | ||
if (J == E.VerNames.size() - 1) | ||
VernAux.vda_next = 0; | ||
VerdAux.vda_next = 0; | ||
else | ||
VernAux.vda_next = sizeof(Elf_Verdaux); | ||
CBA.write((const char *)&VernAux, sizeof(Elf_Verdaux)); | ||
VerdAux.vda_next = sizeof(Elf_Verdaux); | ||
CBA.write((const char *)&VerdAux, sizeof(Elf_Verdaux)); |
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.
As this is unrelated, could you put it in a separate commit, please?
llvm/lib/ObjectYAML/ELFYAML.cpp
Outdated
@@ -1921,6 +1921,7 @@ void MappingTraits<ELFYAML::VerdefEntry>::mapping(IO &IO, | |||
IO.mapOptional("Flags", E.Flags); | |||
IO.mapOptional("VersionNdx", E.VersionNdx); | |||
IO.mapOptional("Hash", E.Hash); | |||
IO.mapOptional("AuxVOffset", E.AuxVOffset); |
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.
If I understand it correctly, all this does is set the value - it doesn't actually cause the data to be written to do a different offset. Is that correct?
Assuming that's the case, I'd suggest naming it after the spec name of vd_aux
, e.g. VDAux
. This is to match the similar fields like SHName
and SHOffset
for sections, whose only impact is to modify the section header (in contrast with the Name
and Offset
fields etc).
Flags: 44 | ||
VersionNdx: 0 | ||
Hash: 12345 | ||
AuxVOffset: 0x45 |
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.
I'd put a comment somewhere around here, or possibly at the start of the YAML, highlighting how this field is invalid.
llvm/tools/llvm-objdump/ELFDump.cpp
Outdated
reportWarning("out-of-bound while parsing verdaux entries, corrupted " | ||
"verdef section", | ||
Obj.getFileName()); |
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.
Please rewrite this error to include as much context as possible. In particular, take a look at how llvm-readobj and llvm-objdump describe section names, and include the actual offset and expected offset.
I'd consider something like "vd_aux value xxx in section xxx points past the end of the section at offset xxx", where "xxx" should be replaced with appropriate strings/numbers.
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.
I went with 'vd_aux value %val in section verdef points past end of the section, corrupted section,' as I don't think it’s that relevant to provide the exact byte count by which the aux entry went out of bounds. I added 'corrupted section' consistently with the other warnings.
f94b791
to
48f9f14
Compare
@jh7370, I rebased this to the other PR, but commits have been split up. Should have reviewed everything, feel free to let me know if it makes sense. |
# RUN: yaml2obj %s -o %t | ||
# RUN: llvm-objdump -p %t 2>&1 | FileCheck --check-prefix=BROKEN-VERDEF -DFILE=%t %s | ||
|
||
# Ensure we emit a warning when vd_aux offset field is invalid. |
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.
##
llvm/tools/obj2yaml/elf2yaml.cpp
Outdated
return createStringError(errc::invalid_argument, | ||
"vd_aux value " + Twine(Verdef->vd_aux) + | ||
" in section verdef points past end of the " | ||
"section, corrupted section"); |
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.
, corrupted section
reads strange
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.
Rephrased for both.
ab4c234
to
5f36ef3
Compare
…past size Validate `vd_aux` while parsing `Elf_Verdef` structure. Fixes: llvm#86611.
5f36ef3
to
4aa80da
Compare
Rebased it to main. |
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.
Please don't force push to active reviews. It's against LLVM review policy, there's actual no need to, it makes it harder to review (because you can't view changes since the previous review) and leads to "commit not found" style errors when clicking on links.
reportWarning("corrupted section: vd_aux value " + Twine(Verdef->vd_aux) + | ||
" in section verdef points past end of the section", | ||
Obj.getFileName()); |
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.
I went with 'vd_aux value %val in section verdef points past end of the section, corrupted section,' as I don't think it’s that relevant to provide the exact byte count by which the aux entry went out of bounds. I added 'corrupted section' consistently with the other warnings.
I just searched for the string "corrupted section" and haven't found any relevant reference. What other warnings are you trying to be consistent with?
Please use the describe
method (in Object\ELF.h) in place of "in section verdef" to be consistent with other recent messages added/changed in llvm-readelf.
The idea of including the section size is that it could be the size that is malformed, not the vd_aux value (for whatever reason). ELFDumper.cpp in llvm-readelf has a number of examples of this sort of message pattern (search for "past the end"). There may be others too.
- Version: 1 | ||
Flags: 0 | ||
VersionNdx: 0 | ||
VDAux: 69 |
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 still could do with a comment saying how it's invalid (i.e. what it should be).
Obsoleted by #128434 . We should reuse |
Validate
vd_aux
while parsingElf_Verdef
structure.Fixes: #86611.