-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libunwind] Avoid reading OOB for non-existent .eh_frame_hdr #68815
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
Conversation
@llvm/pr-subscribers-libunwind Author: Alexander Richardson (arichardson) ChangesI was running the tests with baremetal picolibc which has a linker This change adds a ehHdrSize check to avoid reading this out-of-bounds Depends on #68813 which I've included as the first commit here (not sure how to sensibly do stacked PRs). Full diff: https://github.com/llvm/llvm-project/pull/68815.diff 1 Files Affected:
diff --git a/libunwind/src/EHHeaderParser.hpp b/libunwind/src/EHHeaderParser.hpp
index ed4317c89055c9e..8d37594e7b9be89 100644
--- a/libunwind/src/EHHeaderParser.hpp
+++ b/libunwind/src/EHHeaderParser.hpp
@@ -35,7 +35,7 @@ template <typename A> class EHHeaderParser {
uint8_t table_enc;
};
- static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
+ static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, size_t ehHdrSize,
EHHeaderInfo &ehHdrInfo);
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
uint32_t sectionLength,
@@ -53,8 +53,21 @@ template <typename A> class EHHeaderParser {
template <typename A>
bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
- pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
+ size_t ehHdrSize, EHHeaderInfo &ehHdrInfo) {
pint_t p = ehHdrStart;
+ pint_t ehHdrEnd = ehHdrStart + ehHdrSize;
+
+ // Ensure that we don't read data beyond the end of .eh_frame_hdr
+ if (ehHdrSize < 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 (ehHdrSize == 0)
+ 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), ehHdrSize);
+ return false;
+ }
uint8_t version = addressSpace.get8(p++);
if (version != 1) {
_LIBUNWIND_LOG("unsupported .eh_frame_hdr version: %" PRIu8 " at %" PRIx64,
@@ -106,7 +119,7 @@ bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
pint_t ehHdrEnd = ehHdrStart + sectionLength;
EHHeaderParser<A>::EHHeaderInfo hdrInfo;
- if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
+ if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, sectionLength,
hdrInfo))
return false;
|
cda672a
to
0190d73
Compare
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.
Thank you!
0190d73
to
6341524
Compare
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 8000d308` This change adds a ehHdrSize check to avoid reading this out-of-bounds data and potentially crashing.
6341524
to
5d4e2bc
Compare
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 ehHdrSize check to avoid reading this out-of-bounds
data and potentially crashing.
Depends on #68813 which I've included as the first commit here (not sure how to sensibly do stacked PRs).