The X86 stack walker was doing an illegal down cast from base-class (StackFrame) to derived-class (StackFrameX86).

Inline frames are always of the base-class type (StackFrame). Treating them as derived-class and accessing members was causing heap buffer overflows.

Change-Id: Id4122ab6a31f016933038a1cb63d45d5c38481f5
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3425445
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Ivan Penkov 2022-01-31 19:07:58 +00:00
parent 08bd844599
commit 8205b6edb8

View file

@ -141,6 +141,9 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
bool stack_scan_allowed) { bool stack_scan_allowed) {
StackFrame::FrameTrust trust = StackFrame::FRAME_TRUST_NONE; StackFrame::FrameTrust trust = StackFrame::FRAME_TRUST_NONE;
// The last frame can never be inline. A sequence of inline frames always
// finishes with a conventional frame.
assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE);
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
// Save the stack walking info we found, in case we need it later to // Save the stack walking info we found, in case we need it later to
@ -187,9 +190,15 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
uint32_t last_frame_callee_parameter_size = 0; uint32_t last_frame_callee_parameter_size = 0;
int frames_already_walked = frames.size(); int frames_already_walked = frames.size();
if (frames_already_walked >= 2) { for (int last_frame_callee_id = frames_already_walked - 2;
last_frame_callee_id >= 0; last_frame_callee_id--) {
// Searching for a real callee frame. Skipping inline frames since they
// cannot be downcasted to StackFrameX86.
if (frames[last_frame_callee_id]->trust == StackFrame::FRAME_TRUST_INLINE) {
continue;
}
const StackFrameX86* last_frame_callee const StackFrameX86* last_frame_callee
= static_cast<StackFrameX86*>(frames[frames_already_walked - 2]); = static_cast<StackFrameX86*>(frames[last_frame_callee_id]);
WindowsFrameInfo* last_frame_callee_info WindowsFrameInfo* last_frame_callee_info
= last_frame_callee->windows_frame_info; = last_frame_callee->windows_frame_info;
if (last_frame_callee_info && if (last_frame_callee_info &&
@ -516,6 +525,9 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo(
const vector<StackFrame*>& frames, const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info) { CFIFrameInfo* cfi_frame_info) {
// The last frame can never be inline. A sequence of inline frames always
// finishes with a conventional frame.
assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE);
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
last_frame->cfi_frame_info = cfi_frame_info; last_frame->cfi_frame_info = cfi_frame_info;
@ -542,6 +554,9 @@ StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase(
const vector<StackFrame*>& frames, const vector<StackFrame*>& frames,
bool stack_scan_allowed) { bool stack_scan_allowed) {
StackFrame::FrameTrust trust; StackFrame::FrameTrust trust;
// The last frame can never be inline. A sequence of inline frames always
// finishes with a conventional frame.
assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE);
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
uint32_t last_esp = last_frame->context.esp; uint32_t last_esp = last_frame->context.esp;
uint32_t last_ebp = last_frame->context.ebp; uint32_t last_ebp = last_frame->context.ebp;
@ -634,6 +649,9 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack,
const vector<StackFrame*>& frames = *stack->frames(); const vector<StackFrame*>& frames = *stack->frames();
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
// The last frame can never be inline. A sequence of inline frames always
// finishes with a conventional frame.
assert(last_frame->trust != StackFrame::FRAME_TRUST_INLINE);
scoped_ptr<StackFrameX86> new_frame; scoped_ptr<StackFrameX86> new_frame;
// If the resolver has Windows stack walking information, use that. // If the resolver has Windows stack walking information, use that.