From f49c2f1a2023da0cb055874fba050563dfea57db Mon Sep 17 00:00:00 2001 From: Ivan Penkov Date: Wed, 6 Sep 2023 11:21:48 -0700 Subject: [PATCH] The ARM64 stack walker was doing an illegal down cast from base-class (StackFrame) to derived-class (StackFrameARM64). Inline frames are always of the base-class type (StackFrame). Treating them as derived-class and accessing members is causing buffer overflows. Change-Id: Ib41b74256e6162e7d2b14ca3905dfaf5591b9c86 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/4847317 Reviewed-by: Joshua Peraza --- src/processor/stackwalker_arm64.cc | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc index 9c09835f..0fa02e04 100644 --- a/src/processor/stackwalker_arm64.cc +++ b/src/processor/stackwalker_arm64.cc @@ -267,15 +267,25 @@ void StackwalkerARM64::CorrectRegLRByFramePointer( last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]) return; - StackFrameARM64* last_last_frame = - static_cast(*(frames.end() - 2)); - uint64_t last_last_fp = - last_last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP]; + // Searching for a real callee frame. Skipping inline frames since they + // don't contain context (and cannot be downcasted to StackFrameARM64). + size_t last_frame_callee_id = frames.size() - 2; + while (last_frame_callee_id >= 0 && frames[last_frame_callee_id]->trust == + StackFrame::FRAME_TRUST_INLINE) { + last_frame_callee_id--; + } + if (last_frame_callee_id < 0) return; + StackFrameARM64* last_frame_callee = + static_cast(frames[last_frame_callee_id]); + + uint64_t last_frame_callee_fp = + last_frame_callee->context.iregs[MD_CONTEXT_ARM64_REG_FP]; uint64_t last_fp = 0; - if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp, &last_fp)) { - BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x" - << std::hex << last_last_fp; + if (last_frame_callee_fp && + !memory_->GetMemoryAtAddress(last_frame_callee_fp, &last_fp)) { + BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x" << std::hex + << last_frame_callee_fp; return; } // Give up if STACK CFI doesn't agree with frame pointer. @@ -283,9 +293,10 @@ void StackwalkerARM64::CorrectRegLRByFramePointer( return; uint64_t last_lr = 0; - if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp + 8, &last_lr)) { + if (last_frame_callee_fp && + !memory_->GetMemoryAtAddress(last_frame_callee_fp + 8, &last_lr)) { BPLOG(ERROR) << "Unable to read last_lr from (last_last_fp + 8): 0x" - << std::hex << (last_last_fp + 8); + << std::hex << (last_frame_callee_fp + 8); return; } last_lr = PtrauthStrip(last_lr);