[libunwind] eb21049 - [libunwind] Avoid reading OOB for non-existent .eh_frame_hdr (#68815)

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 11 11:46:14 PDT 2023


Author: Alexander Richardson
Date: 2023-10-11T19:46:09+01:00
New Revision: eb21049b4b904b072679ece60e73c6b0dc0d1ebf

URL: https://github.com/llvm/llvm-project/commit/eb21049b4b904b072679ece60e73c6b0dc0d1ebf
DIFF: https://github.com/llvm/llvm-project/commit/eb21049b4b904b072679ece60e73c6b0dc0d1ebf.diff

LOG: [libunwind] Avoid reading OOB for non-existent .eh_frame_hdr (#68815)

I was running the tests with baremetal picolibc which has a linker
script that __eh_frame_start==__eh_frame_end (not equal to zero) in
case there is no .eh_frame_hdr.
I noticed that libunwind was trying to read nonsense data because it
was printing messages such as
`libunwind: unsupported .eh_frame_hdr version: 20 at
https://github.com/llvm/llvm-project/commit/8000d308146ebf49cb364cb600e28a0a42e22c83`

This change adds a ehHdr size check to avoid reading this out-of-bounds
data and potentially crashing.

Added: 
    

Modified: 
    libunwind/src/EHHeaderParser.hpp

Removed: 
    


################################################################################
diff  --git a/libunwind/src/EHHeaderParser.hpp b/libunwind/src/EHHeaderParser.hpp
index ed4317c89055c9e..0662a1321e2c75e 100644
--- a/libunwind/src/EHHeaderParser.hpp
+++ b/libunwind/src/EHHeaderParser.hpp
@@ -55,6 +55,19 @@ template <typename A>
 bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
                                     pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
   pint_t p = ehHdrStart;
+
+  // Ensure that we don't read data beyond the end of .eh_frame_hdr
+  if (ehHdrEnd - ehHdrStart < 4) {
+    // Don't print a message for an empty .eh_frame_hdr (this can happen if
+    // the linker script defines symbols for it even in the empty case).
+    if (ehHdrEnd == ehHdrStart)
+      return false;
+    _LIBUNWIND_LOG("unsupported .eh_frame_hdr at %" PRIx64
+                   ": need at least 4 bytes of data but only got %zd",
+                   static_cast<uint64_t>(ehHdrStart),
+                   static_cast<size_t>(ehHdrEnd - ehHdrStart));
+    return false;
+  }
   uint8_t version = addressSpace.get8(p++);
   if (version != 1) {
     _LIBUNWIND_LOG("unsupported .eh_frame_hdr version: %" PRIu8 " at %" PRIx64,


        


More information about the cfe-commits mailing list