[lld] 25863cc - [ELF] .note.gnu.property: error for invalid pr_datasize
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 08:06:00 PDT 2020
Author: Fangrui Song
Date: 2020-08-25T08:05:39-07:00
New Revision: 25863cc512a38ae9b1235ee62faa79ff2aa3c226
URL: https://github.com/llvm/llvm-project/commit/25863cc512a38ae9b1235ee62faa79ff2aa3c226
DIFF: https://github.com/llvm/llvm-project/commit/25863cc512a38ae9b1235ee62faa79ff2aa3c226.diff
LOG: [ELF] .note.gnu.property: error for invalid pr_datasize
A n_type==NT_GNU_PROPERTY_TYPE_0 note encodes a program property.
If pr_datasize is invalid, LLD may crash
(https://github.com/ClangBuiltLinux/linux/issues/1141)
This patch adds some error checking, supports big-endian, and add some tests
for invalid n_descsz.
Differential Revision: https://reviews.llvm.org/D86422
Added:
lld/test/ELF/gnu-property-err.s
Modified:
lld/ELF/InputFiles.cpp
Removed:
################################################################################
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index fbb9ac758a4f..bfc8e9c1e53b 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -780,20 +780,21 @@ static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) {
// of zero or more type-length-value fields. We want to find a field of a
// certain type. It seems a bit too much to just store a 32-bit value, perhaps
// the ABI is unnecessarily complicated.
-template <class ELFT>
-static uint32_t readAndFeatures(ObjFile<ELFT> *obj, ArrayRef<uint8_t> data) {
+template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
using Elf_Nhdr = typename ELFT::Nhdr;
using Elf_Note = typename ELFT::Note;
uint32_t featuresSet = 0;
+ ArrayRef<uint8_t> data = sec.data();
+ auto reportFatal = [&](const uint8_t *place, const char *msg) {
+ fatal(toString(sec.file) + ":(" + sec.name + "+0x" +
+ Twine::utohexstr(place - sec.data().data()) + "): " + msg);
+ };
while (!data.empty()) {
// Read one NOTE record.
- if (data.size() < sizeof(Elf_Nhdr))
- fatal(toString(obj) + ": .note.gnu.property: section too short");
-
auto *nhdr = reinterpret_cast<const Elf_Nhdr *>(data.data());
- if (data.size() < nhdr->getSize())
- fatal(toString(obj) + ": .note.gnu.property: section too short");
+ if (data.size() < sizeof(Elf_Nhdr) || data.size() < nhdr->getSize())
+ reportFatal(data.data(), "data is too short");
Elf_Note note(*nhdr);
if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName() != "GNU") {
@@ -808,25 +809,26 @@ static uint32_t readAndFeatures(ObjFile<ELFT> *obj, ArrayRef<uint8_t> data) {
// Read a body of a NOTE record, which consists of type-length-value fields.
ArrayRef<uint8_t> desc = note.getDesc();
while (!desc.empty()) {
+ const uint8_t *place = desc.data();
if (desc.size() < 8)
- fatal(toString(obj) + ": .note.gnu.property: section too short");
-
- uint32_t type = read32le(desc.data());
- uint32_t size = read32le(desc.data() + 4);
+ reportFatal(place, "program property is too short");
+ uint32_t type = read32<ELFT::TargetEndianness>(desc.data());
+ uint32_t size = read32<ELFT::TargetEndianness>(desc.data() + 4);
+ desc = desc.slice(8);
+ if (desc.size() < size)
+ reportFatal(place, "program property is too short");
if (type == featureAndType) {
// We found a FEATURE_1_AND field. There may be more than one of these
// in a .note.gnu.property section, for a relocatable object we
// accumulate the bits set.
- featuresSet |= read32le(desc.data() + 8);
+ if (size < 4)
+ reportFatal(place, "FEATURE_1_AND entry is too short");
+ featuresSet |= read32<ELFT::TargetEndianness>(desc.data());
}
- // On 64-bit, a payload may be followed by a 4-byte padding to make its
- // size a multiple of 8.
- if (ELFT::Is64Bits)
- size = alignTo(size, 8);
-
- desc = desc.slice(size + 8); // +8 for Type and Size
+ // Padding is present in the note descriptor, if necessary.
+ desc = desc.slice(alignTo<(ELFT::Is64Bits ? 8 : 4)>(size));
}
// Go to next NOTE record to look for more FEATURE_1_AND descriptions.
@@ -985,8 +987,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &sec) {
// .note.gnu.property containing a single AND'ed bitmap, we discard an input
// file's .note.gnu.property section.
if (name == ".note.gnu.property") {
- ArrayRef<uint8_t> contents = check(this->getObj().getSectionContents(&sec));
- this->andFeatures = readAndFeatures(this, contents);
+ this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name));
return &InputSection::discarded;
}
diff --git a/lld/test/ELF/gnu-property-err.s b/lld/test/ELF/gnu-property-err.s
new file mode 100644
index 000000000000..c400484e8816
--- /dev/null
+++ b/lld/test/ELF/gnu-property-err.s
@@ -0,0 +1,55 @@
+# REQUIRES: aarch64
+# RUN: split-file %s %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/1.s -o %t1.o
+# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR1
+
+# ERR1: error: {{.*}}.o:(.note.gnu.property+0x0): data is too short
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/2.s -o %t2.o
+# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2
+# RUN: llvm-mc -filetype=obj -triple=aarch64_be %t/2.s -o %t2be.o
+# RUN: not ld.lld %t2be.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2
+
+# ERR2: error: {{.*}}.o:(.note.gnu.property+0x10): program property is too short
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/3.s -o %t3.o
+# RUN: not ld.lld %t3.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR3
+# RUN: llvm-mc -filetype=obj -triple=aarch64_be %t/3.s -o %t3be.o
+# RUN: not ld.lld %t3be.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR3
+
+# ERR3: error: {{.*}}.o:(.note.gnu.property+0x10): FEATURE_1_AND entry is too short
+
+#--- 1.s
+.section ".note.gnu.property", "a"
+.long 4
+.long 17 // n_descsz too long
+.long 5 // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4 // pr_datasz
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+#--- 2.s
+.section ".note.gnu.property", "a"
+.long 4
+.long 16 // n_descsz
+.long 5 // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 9 // pr_datasz too long
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+#--- 3.s
+.section ".note.gnu.property", "a"
+.long 4
+.long 8 // n_descsz
+.long 5 // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 0 // pr_datasz too short
More information about the llvm-commits
mailing list