1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[llvm-readobj] - Fix crashes and misbehaviors when reading strings from broken string tables.

There are cases when we either might print garbage or crash when
reading strings for dumping dynamic tags.

For example when a string table is not null-terminated or goes past the EOF.
This patch fixes issues mentioned.

Differential revision: https://reviews.llvm.org/D77216
This commit is contained in:
Georgii Rymar 2020-04-01 16:40:25 +03:00
parent 0a20e5334a
commit f462f0718a
4 changed files with 183 additions and 36 deletions

View File

@ -3,9 +3,9 @@
# RUN: yaml2obj %s --docnum=1 -o %t.bad-size
# RUN: llvm-readobj --all %t.bad-size 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning --check-prefix WARN
# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning: --check-prefix WARN
# RUN: llvm-readelf --all %t.bad-size 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning --check-prefix WARN-GNU
# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning: --check-prefix WARN-GNU
# WARN: warning: '[[FILE]]': invalid PT_DYNAMIC size (0x4){{$}}
# WARN: warning: '[[FILE]]': section with index 1 has invalid size (0x4){{$}}
@ -95,47 +95,47 @@ ProgramHeaders:
# RUN: llvm-readelf --dynamic-table %t.bad-string 2>&1 | \
# RUN: FileCheck %s --implicit-check-not=warning: --check-prefix BAD-STRING-GNU -DFILE=%t.bad-string
# BAD-STRING-LLVM: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM: LoadName: <?>
# BAD-STRING-LLVM: DynamicSection [ (10 entries)
# BAD-STRING-LLVM-NEXT: Tag Type Name/Value
# BAD-STRING-LLVM-NEXT: 0x0000000000000005 STRTAB 0x1000
# BAD-STRING-LLVM-NEXT: 0x000000000000000A STRSZ 1 (bytes)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: 0x0000000000000001 NEEDED Shared library: [<?>]
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: 0x000000007FFFFFFF FILTER Filter library: [<?>]
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: 0x000000007FFFFFFD AUXILIARY Auxiliary library: [<?>]
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: 0x000000007FFFFFFE USED Not needed object: [<?>]
## Note: there is no "string table at offset 0xb0..." warning here, because it was printed earlier.
# BAD-STRING-LLVM-NEXT: 0x000000000000000E SONAME Library soname: [<?>]
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: 0x000000000000000F RPATH Library rpath: [<?>]
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8, it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8: it goes past the end of the table (0xb1)
# BAD-STRING-LLVM-NEXT: 0x000000000000001D RUNPATH Library runpath: [<?>]
# BAD-STRING-LLVM-NEXT: 0x0000000000000000 NULL 0x0
# BAD-STRING-LLVM-NEXT: ]
# BAD-STRING-GNU: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6, it goes past the end of the table (0xb1)
# BAD-STRING-GNU: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: Dynamic section at offset 0xb1 contains 10 entries:
# BAD-STRING-GNU-NEXT: Tag Type Name/Value
# BAD-STRING-GNU-NEXT: 0x0000000000000005 (STRTAB) 0x1000
# BAD-STRING-GNU-NEXT: 0x000000000000000a (STRSZ) 1 (bytes)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2, it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: 0x0000000000000001 (NEEDED) Shared library: [<?>]
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3, it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: 0x000000007fffffff (FILTER) Filter library: [<?>]
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4, it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: 0x000000007ffffffd (AUXILIARY) Auxiliary library: [<?>]
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5, it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: 0x000000007ffffffe (USED) Not needed object: [<?>]
## Note: there is no "string table at offset 0xb6..." warning here, because it was printed earlier.
# BAD-STRING-GNU-NEXT: 0x000000000000000e (SONAME) Library soname: [<?>]
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7, it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: 0x000000000000000f (RPATH) Library rpath: [<?>]
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8, it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8: it goes past the end of the table (0xb1)
# BAD-STRING-GNU-NEXT: 0x000000000000001d (RUNPATH) Library runpath: [<?>]
# BAD-STRING-GNU-NEXT: 0x0000000000000000 (NULL) 0x0
@ -279,3 +279,133 @@ ProgramHeaders:
VAddr: 0x1000
Sections:
- Section: .dynamic
## Check how we handle cases when the dynamic string table is not null-terminated.
## Case A: the value of the DT_STRSZ tag is equal to the size of
## the not null-terminated dynamic string table.
# RUN: yaml2obj %s -DSTRSZ=7 --docnum=6 -o %t6
# RUN: llvm-readobj --dynamic-table %t6 2>&1 | \
# RUN: FileCheck %s -DFILE=%t6 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ
# RUN: llvm-readelf --dynamic-table %t6 2>&1 | \
# RUN: FileCheck %s -DFILE=%t6 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ
## Case B: the value of the DT_STRSZ tag is less than the size of
## the not null-terminated dynamic string table.
# RUN: yaml2obj %s -DSTRSZ=6 --docnum=6 -o %t7
# RUN: llvm-readobj --dynamic-table %t7 2>&1 | \
# RUN: FileCheck %s -DFILE=%t7 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-LESS
# RUN: llvm-readelf --dynamic-table %t7 2>&1 | \
# RUN: FileCheck %s -DFILE=%t7 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-LESS
## Case C: the value of the DT_STRSZ tag is one byte larger than the size of
## the not null-terminated dynamic string table.
# RUN: yaml2obj %s -DSTRSZ=8 --docnum=6 -o %t8
# RUN: llvm-readobj --dynamic-table %t8 2>&1 | \
# RUN: FileCheck %s -DFILE=%t8 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ
# RUN: llvm-readelf --dynamic-table %t8 2>&1 | \
# RUN: FileCheck %s -DFILE=%t8 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ
# NOT-TERMINATED: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4: the string table is not null-terminated
# NOT-TERMINATED: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb0: the string table is not null-terminated
# NOT-TERMINATED-NEXT: {{[(]?}}NEEDED{{[)]?}} Shared library: [<?>]
# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb1: the string table is not null-terminated
# NOT-TERMINATED-NEXT: {{[(]?}}FILTER{{[)]?}} Filter library: [<?>]
# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2: the string table is not null-terminated
# NOT-TERMINATED-NEXT: {{[(]?}}AUXILIARY{{[)]?}} Auxiliary library: [<?>]
# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3: the string table is not null-terminated
# NOT-TERMINATED-NEXT: {{[(]?}}USED{{[)]?}} Not needed object: [<?>]
# NOT-TERMINATED-NEXT: {{[(]?}}SONAME{{[)]?}} Library soname: [<?>]
# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5: the string table is not null-terminated
# NOT-TERMINATED-NEXT: {{[(]?}}RPATH{{[)]?}} Library rpath: [<?>]
# NOT-TERMINATED-GREQ-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: the string table is not null-terminated
# NOT-TERMINATED-LESS-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: it goes past the end of the table (0xb6)
# NOT-TERMINATED-NEXT: {{[(]?}}RUNPATH{{[)]?}} Library runpath: [<?>]
# NOT-TERMINATED-NEXT: {{[(]?}}NULL{{[)]?}} 0x0
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .dynstr
Type: SHT_STRTAB
Address: 0x1000
Content: '746573742e736f' ## "test.so", not null terminated.
- Type: Fill
Pattern: "61626300" ## 'a', 'b', 'c', '\0'.
Size: "4"
- Name: .dynamic
Type: SHT_DYNAMIC
Address: 0x1100
Entries:
- Tag: DT_STRTAB
Value: 0x1000
- Tag: DT_STRSZ
Value: [[STRSZ]]
- Tag: DT_NEEDED
Value: 0
- Tag: DT_FILTER
Value: 1
- Tag: DT_AUXILIARY
Value: 2
- Tag: DT_USED
Value: 3
- Tag: DT_SONAME
Value: 4
- Tag: DT_RPATH
Value: 5
- Tag: DT_RUNPATH
Value: 6
- Tag: DT_NULL
Value: 0
ProgramHeaders:
- Type: PT_LOAD
VAddr: 0x1000
Sections:
- Section: .dynstr
- Section: .dynamic
- Type: PT_DYNAMIC
VAddr: 0x1100
Sections:
- Section: .dynamic
## Check that we emit an appropriate warning when the dynamic string table ends past the end of the file.
## Case A: the value of DT_STRSZ tag is set so that the string table ends
## right before the EOF. No warning should be emitted.
# RUN: yaml2obj %s -DSTRSZ=0x210 --docnum=6 -o %t9.1
# RUN: llvm-readobj --dynamic-table %t9.1 | \
# RUN: FileCheck %s --implicit-check-not=warning: --check-prefix=BEFORE-THE-EOF
# RUN: llvm-readelf --dynamic-table %t9.1 | \
# RUN: FileCheck %s --implicit-check-not=warning: --check-prefix=BEFORE-THE-EOF
## Note: The code reads the data in [DT_STRTAB, DT_STRTAB + DT_STRSZ] as the string table
## as normal. Since the file ends with a zero byte, strings are dumped, but if it didn't,
## we'd get <?> printed instead. The important bit is that we don't get the past the end warning.
# BEFORE-THE-EOF: {{[(]?}}NEEDED{{[)]?}} Shared library: [test.soabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}FILTER{{[)]?}} Filter library: [est.soabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}AUXILIARY{{[)]?}} Auxiliary library: [st.soabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}USED{{[)]?}} Not needed object: [t.soabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}SONAME{{[)]?}} Library soname: [.soabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}RPATH{{[)]?}} Library rpath: [soabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}RUNPATH{{[)]?}} Library runpath: [oabc]
# BEFORE-THE-EOF-NEXT: {{[(]?}}NULL{{[)]?}} 0x0
## Case B: the value of DT_STRSZ tag is set so that the string table goes 1 byte past the EOF.
# RUN: yaml2obj %s -DSTRSZ=0x211 --docnum=6 -o %t9.2
# RUN: llvm-readobj --dynamic-table %t9.2 2>&1 | FileCheck %s -DFILE=%t9.2 --check-prefix=PAST-THE-EOF
# RUN: llvm-readelf --dynamic-table %t9.2 2>&1 | FileCheck %s -DFILE=%t9.2 --check-prefix=PAST-THE-EOF
# PAST-THE-EOF: warning: '[[FILE]]': string table at offset 0xb0 with size 0x211 goes past the end of the file (0x2c0)
# PAST-THE-EOF: {{[(]?}}NEEDED{{[)]?}} Shared library: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}FILTER{{[)]?}} Filter library: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}AUXILIARY{{[)]?}} Auxiliary library: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}USED{{[)]?}} Not needed object: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}SONAME{{[)]?}} Library soname: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}RPATH{{[)]?}} Library rpath: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}RUNPATH{{[)]?}} Library runpath: [<?>]
# PAST-THE-EOF-NEXT: {{[(]?}}NULL{{[)]?}} 0x0

View File

@ -14,7 +14,7 @@
# GNU: Dynamic section at offset 0x80 contains 4 entries:
# GNU-NEXT: Tag Type Name/Value
# GNU-NEXT: 0x0000000000000005 (STRTAB) 0x0
# GNU-NEXT: 0x000000000000000a (STRSZ) 7 (bytes)
# GNU-NEXT: 0x000000000000000a (STRSZ) 8 (bytes)
# GNU-NEXT: 0x000000000000000e (SONAME) Library soname: [test.so]
# GNU-NEXT: 0x0000000000000000 (NULL) 0x0
@ -37,7 +37,7 @@ Sections:
- Tag: DT_STRTAB
Value: [[DTSTRTABVAL]]
- Tag: DT_STRSZ
Value: 0x0000000000000007
Value: 0x0000000000000008
- Tag: DT_SONAME
Value: 0x0000000000000000
- Tag: DT_NULL

View File

@ -10,8 +10,8 @@
## Document that we also sort error entries.
# NEEDED-LIBS:{{^}}NeededLibraries [{{$}}
# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x9999a11, it goes past the end of the table (0x85){{$}}
# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x1111189, it goes past the end of the table (0x85){{$}}
# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x9999a11: it goes past the end of the table (0x85){{$}}
# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x1111189: it goes past the end of the table (0x85){{$}}
# NEEDED-LIBS-NEXT:{{^}} <?>{{$}}
# NEEDED-LIBS-NEXT:{{^}} <?>{{$}}
# NEEDED-LIBS-NEXT:{{^}} aaa{{$}}
@ -63,11 +63,11 @@ ProgramHeaders:
# RUN: llvm-readelf --needed-libs %t2 2>&1 | \
# RUN: FileCheck %s -DFILE=%t2 --implicit-check-not=warning: --check-prefix=EMPTY-DYNSTR
# EMPTY-DYNSTR: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x78, it goes past the end of the table (0x78)
# EMPTY-DYNSTR: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x78: it goes past the end of the table (0x78)
# EMPTY-DYNSTR-LLVM: LoadName: <?>
# EMPTY-DYNSTR: NeededLibraries [
# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x79, it goes past the end of the table (0x78)
# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x7a, it goes past the end of the table (0x78)
# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x79: it goes past the end of the table (0x78)
# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x7a: it goes past the end of the table (0x78)
# EMPTY-DYNSTR-NEXT: <?>
# EMPTY-DYNSTR-NEXT: <?>
# EMPTY-DYNSTR-NEXT: ]

View File

@ -2558,24 +2558,41 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type,
template <class ELFT>
StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
auto WarnAndReturn = [this](const Twine &Msg) {
reportUniqueWarning(createError(Msg));
if (DynamicStringTable.empty() && !DynamicStringTable.data()) {
reportUniqueWarning(createError("string table was not found"));
return "<?>";
}
auto WarnAndReturn = [this](const Twine &Msg, uint64_t Offset) {
reportUniqueWarning(createError("string table at offset 0x" +
Twine::utohexstr(Offset) + Msg));
return "<?>";
};
if (DynamicStringTable.empty() && !DynamicStringTable.data())
return WarnAndReturn("string table was not found");
if (Value < DynamicStringTable.size())
return DynamicStringTable.data() + Value;
const uint64_t FileSize = ObjF->getELFFile()->getBufSize();
const uint64_t Offset =
(const uint8_t *)DynamicStringTable.data() - ObjF->getELFFile()->base();
return WarnAndReturn(
"string table at offset 0x" + Twine::utohexstr(Offset) +
": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) +
", it goes past the end of the table (0x" +
Twine::utohexstr(Offset + DynamicStringTable.size()) + ")");
if (DynamicStringTable.size() > FileSize - Offset)
return WarnAndReturn(" with size 0x" +
Twine::utohexstr(DynamicStringTable.size()) +
" goes past the end of the file (0x" +
Twine::utohexstr(FileSize) + ")",
Offset);
if (Value >= DynamicStringTable.size())
return WarnAndReturn(
": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) +
": it goes past the end of the table (0x" +
Twine::utohexstr(Offset + DynamicStringTable.size()) + ")",
Offset);
if (DynamicStringTable.back() != '\0')
return WarnAndReturn(": unable to read the string at 0x" +
Twine::utohexstr(Offset + Value) +
": the string table is not null-terminated",
Offset);
return DynamicStringTable.data() + Value;
}
template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() {