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

llvm-objdump: printDynamicSection() out-of-bounds read #86612

Open
emaste opened this issue Mar 26, 2024 · 5 comments
Open

llvm-objdump: printDynamicSection() out-of-bounds read #86612

emaste opened this issue Mar 26, 2024 · 5 comments

Comments

@emaste
Copy link
Member

emaste commented Mar 26, 2024

Reported against FreeBSD at https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=277885, with attached ELF reproducer.

# llvm-objdump --version
LLVM (http://llvm.org/):
  LLVM version 17.0.6
  Optimized build with assertions.
...
# llvm-objdump -x objdump10a.exe
...
Dynamic Section:
  NEEDED       PLEASE submit a bug report to https://bugs.freebsd.org/submit/ and include the crash backtrace.
Stack dump:
0.      Program arguments: llvm-objdump -x objdump10a.exe
 #0 0x0000000001230c41 PrintStackTrace /usr/src/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc:602:13
 #1 0x000000000122f0b5 RunSignalHandlers /usr/src/contrib/llvm-project/llvm/lib/Support/Signals.cpp:105:18
 #2 0x0000000001231365 SignalHandler /usr/src/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3
 #3 0x00000008267d55ff handle_signal /usr/src/lib/libthr/thread/thr_sig.c:0:3
 #4 0x00000008267d4bbb thr_sighandler /usr/src/lib/libthr/thread/thr_sig.c:244:1
 #5 0x0000000822def2d3 ([vdso]+0x2d3)
 #6 0x0000000828b3a7eb /usr/src/lib/libc/amd64/string/strlen.S:95:0
 #7 0x0000000000df28c9 __constexpr_strlen /usr/obj/usr/src/amd64.amd64/tmp/usr/include/c++/v1/__string/constexpr_c_functions.h:49:10
 #8 0x0000000000df28c9 length /usr/obj/usr/src/amd64.amd64/tmp/usr/include/c++/v1/__string/char_traits.h:222:14
 #9 0x0000000000df28c9 StringRef /usr/src/contrib/llvm-project/llvm/include/llvm/ADT/StringRef.h:90:33
#10 0x0000000000df28c9 operator<< /usr/src/contrib/llvm-project/llvm/include/llvm/Support/raw_ostream.h:244:29
#11 0x0000000000df28c9 printDynamicSection /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp:233:16
#12 0x0000000000df28c9 printPrivateHeaders /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp:431:3
#13 0x0000000000e6a13c dumpObject /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:2815:7
#14 0x0000000000e654b0 dumpInput /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:0:5
#15 0x0000000000e654b0 for_each<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > *>, void (*)(llvm::StringRef)> /usr/obj/usr/src/amd64.amd64/tmp/usr/include/c++/v1/__algorithm/for_each.h:26:5
#16 0x0000000000e654b0 for_each<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > &, void (*)(llvm::StringRef)> /usr/src/contrib/llvm-project/llvm/include/llvm/ADT/STLExtras.h:1731:10
#17 0x0000000000e654b0 main /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:3248:3
#18 0x0000000828a660aa __libc_start1 /usr/src/lib/libc/csu/libc_start1.c:157:2
Segmentation fault (core dumped)
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 26, 2024

@llvm/issue-subscribers-tools-llvm-objdump

Author: Ed Maste (emaste)

Reported against FreeBSD at https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=277885, with attached ELF reproducer.
# llvm-objdump --version
LLVM (http://llvm.org/):
  LLVM version 17.0.6
  Optimized build with assertions.
...
# llvm-objdump -x objdump10a.exe
...
Dynamic Section:
  NEEDED       PLEASE submit a bug report to https://bugs.freebsd.org/submit/ and include the crash backtrace.
Stack dump:
0.      Program arguments: llvm-objdump -x objdump10a.exe
 #<!-- -->0 0x0000000001230c41 PrintStackTrace /usr/src/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc:602:13
 #<!-- -->1 0x000000000122f0b5 RunSignalHandlers /usr/src/contrib/llvm-project/llvm/lib/Support/Signals.cpp:105:18
 #<!-- -->2 0x0000000001231365 SignalHandler /usr/src/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3
 #<!-- -->3 0x00000008267d55ff handle_signal /usr/src/lib/libthr/thread/thr_sig.c:0:3
 #<!-- -->4 0x00000008267d4bbb thr_sighandler /usr/src/lib/libthr/thread/thr_sig.c:244:1
 #<!-- -->5 0x0000000822def2d3 ([vdso]+0x2d3)
 #<!-- -->6 0x0000000828b3a7eb /usr/src/lib/libc/amd64/string/strlen.S:95:0
 #<!-- -->7 0x0000000000df28c9 __constexpr_strlen /usr/obj/usr/src/amd64.amd64/tmp/usr/include/c++/v1/__string/constexpr_c_functions.h:49:10
 #<!-- -->8 0x0000000000df28c9 length /usr/obj/usr/src/amd64.amd64/tmp/usr/include/c++/v1/__string/char_traits.h:222:14
 #<!-- -->9 0x0000000000df28c9 StringRef /usr/src/contrib/llvm-project/llvm/include/llvm/ADT/StringRef.h:90:33
#<!-- -->10 0x0000000000df28c9 operator&lt;&lt; /usr/src/contrib/llvm-project/llvm/include/llvm/Support/raw_ostream.h:244:29
#<!-- -->11 0x0000000000df28c9 printDynamicSection /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp:233:16
#<!-- -->12 0x0000000000df28c9 printPrivateHeaders /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp:431:3
#<!-- -->13 0x0000000000e6a13c dumpObject /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:2815:7
#<!-- -->14 0x0000000000e654b0 dumpInput /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:0:5
#<!-- -->15 0x0000000000e654b0 for_each&lt;std::__1::__wrap_iter&lt;std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;, std::__1::allocator&lt;char&gt; &gt; *&gt;, void (*)(llvm::StringRef)&gt; /usr/obj/usr/src/amd64.amd64/tmp/usr/include/c++/v1/__algorithm/for_each.h:26:5
#<!-- -->16 0x0000000000e654b0 for_each&lt;std::__1::vector&lt;std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;, std::__1::allocator&lt;char&gt; &gt;, std::__1::allocator&lt;std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;, std::__1::allocator&lt;char&gt; &gt; &gt; &gt; &amp;, void (*)(llvm::StringRef)&gt; /usr/src/contrib/llvm-project/llvm/include/llvm/ADT/STLExtras.h:1731:10
#<!-- -->17 0x0000000000e654b0 main /usr/src/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:3248:3
#<!-- -->18 0x0000000828a660aa __libc_start1 /usr/src/lib/libc/csu/libc_start1.c:157:2
Segmentation fault (core dumped)

@jh7370
Copy link
Collaborator

jh7370 commented Mar 26, 2024

Possible duplicate of #85568? Could you check against HEAD, please?

@antoniofrighetto
Copy link
Contributor

Think this should work:

--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -233,7 +233,13 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {
       Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);
       if (StrTabOrErr) {
         const char *Data = StrTabOrErr.get().data();
-        outs() << (Data + Dyn.d_un.d_val) << "\n";
+        const auto SecSize =
+            unwrapOrError(Elf.getSection(ELF::SHT_DYNAMIC), Obj.getFileName())
+                ->sh_size;
+        if (Dyn.d_un.d_val > SecSize)
+          reportWarning("string table offset out-of-bound", Obj.getFileName());
+        else
+          outs() << Data + Dyn.d_un.d_val << "\n";
         continue;
       }
       reportWarning(toString(StrTabOrErr.takeError()), Obj.getFileName());

@emaste
Copy link
Member Author

emaste commented Mar 26, 2024

Possible duplicate of #85568? Could you check against HEAD, please?

These were submitted as separate FreeBSD issues, and indeed it is still reproducible at bf4fc00

Dynamic Section:
  NEEDED       PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: bin/llvm-objdump -x attachment.cgi?id=249399
 #0 0x0000000001ab76e8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/emaste/src/llvm-project/llvm/lib/Support/Unix/Signals.inc:731:8
 #1 0x0000000001ab5b25 llvm::sys::RunSignalHandlers() /home/emaste/src/llvm-project/llvm/lib/Support/Signals.cpp:106:18
 #2 0x0000000001ab7e76 SignalHandler(int) /home/emaste/src/llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3
 #3 0x0000000822e686ef handle_signal /usr/home/emaste/src/freebsd/lib/libthr/thread/thr_sig.c:0:3
 #4 0x0000000822e67cab thr_sighandler /usr/home/emaste/src/freebsd/lib/libthr/thread/thr_sig.c:244:1
 #5 0x00000008229612d3 ([vdso]+0x2d3)
 #6 0x00000008270b672b /usr/home/emaste/src/freebsd/lib/libc/amd64/string/strlen.S:95:0
 #7 0x00000000015faf9f std::__1::__constexpr_strlen[abi:un170006](char const*) /usr/include/c++/v1/__string/constexpr_c_functions.h:49:10
 #8 0x00000000015faf9f std::__1::char_traits<char>::length[abi:un170006](char const*) /usr/include/c++/v1/__string/char_traits.h:222:14
 #9 0x00000000015faf9f llvm::StringRef::StringRef(char const*) /home/emaste/src/llvm-project/llvm/include/llvm/ADT/StringRef.h:90:33
#10 0x00000000015faf9f llvm::raw_ostream::operator<<(char const*) /home/emaste/src/llvm-project/llvm/include/llvm/Support/raw_ostream.h:260:29
#11 0x00000000015faf9f (anonymous namespace)::ELFDumper<llvm::object::ELFType<(llvm::endianness)1, true>>::printDynamicSection() /home/emaste/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp:236:16
#12 0x00000000015faf9f (anonymous namespace)::ELFDumper<llvm::object::ELFType<(llvm::endianness)1, true>>::printPrivateHeaders() /home/emaste/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp:434:3
#13 0x00000000015c7835 dumpObject(llvm::object::ObjectFile*, llvm::object::Archive const*, llvm::object::Archive::Child const*) /home/emaste/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:3236:7
#14 0x00000000015beca0 dumpInput(llvm::StringRef) /home/emaste/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:0:5
#15 0x00000000015beca0 void (*std::__1::for_each[abi:un170006]<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*>, void (*)(llvm::StringRef)>(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*>, void (*)(llvm::StringRef)))(llvm::StringRef) /usr/include/c++/v1/__algorithm/for_each.h:26:5
#16 0x00000000015beca0 void (*llvm::for_each<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>&, void (*)(llvm::StringRef)>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>&, void (*)(llvm::StringRef)))(llvm::StringRef) /home/emaste/src/llvm-project/llvm/include/llvm/ADT/STLExtras.h:1725:10
#17 0x00000000015beca0 llvm_objdump_main(int, char**, llvm::ToolContext const&) /home/emaste/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp:3685:3
#18 0x0000000001651b44 main /home/emaste/src/llvm-project/build/tools/llvm-objdump/llvm-objdump-driver.cpp:17:10
#19 0x0000000826fe17ca __libc_start1 /usr/home/emaste/src/freebsd/lib/libc/csu/libc_start1.c:157:2
Segmentation fault (core dumped)

and no crash with @antoniofrighetto's patch:

...
         filesz 0x0000000000000048 memsz 0x0000000000000048 flags r--

Dynamic Section:
  NEEDED       bin/llvm-objdump: warning: 'attachment.cgi?id=249399': string table offset out-of-bound
  FLAGS_1      0x0000000008000000
  DEBUG        0x0000000000000000
...

artagnon added a commit to artagnon/llvm-project that referenced this issue Apr 3, 2024
When reading the dynamic string table, llvm-objdump used to crash if
the ELF was malformed, due to an erroneous consumption of error status.
Instead, propogate the error status to the caller, fixing the crash, and
printing a warning.

Fixes llvm#86612.
@MaskRay
Copy link
Member

MaskRay commented Apr 3, 2024

llvm/tools/llvm-objdump/ELFDump.cpp:70 consumeError(MappedAddrOrError.takeError()); has a bug. If DT_STRTAB is a wrong address, *MappedAddrOrError may crash.

@artagnon We need a minimal reproduce file. obj2yaml gives a start, but you need to scrub unneeded parts from the YAML file. A test filename like pr86612 is not descriptive. Reusing dynamic-section.test may be a good idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants