CVE-2026-85052
Overview
Background
- Crashpad
- Chromium’s crash-reporting library, bundled under
third_party/crashpad; this fix rolls it to revision60dd943f48d77dc8d05dabc04badbd8561d0b8c4. - `ProcessSnapshotSanitized` / `ScanStackForPointers`
- the sanitization pass over a captured process snapshot that walks the stack memory looking for pointer-shaped values (e.g. to redact them), templated on
Pointer. - `stack_pointer_` / `stack_->Address()`
- the captured stack-pointer register value and the base address of the captured stack memory region; the scan computes
sp_offsetas their difference. - `AssignIfInRange`
- a helper that stores an integer into a target only if it fits the target type’s range, returning
falseotherwise.
Root Cause Analysis
ScanStackForPointers computed sp_offset as stack_pointer_ - stack_->Address() and passed it straight to AssignIfInRange(&sp_offset, ...). As the added comment states, stack_pointer_ “might point below the stack region if ProcessReaderLinux interpreted it as pointing to a guard page,” so the subtraction of two unsigned addresses can underflow to a huge value. The old code’s only guard was AssignIfInRange, which merely checks that the (already-wrapped) difference fits size_t and returns false on failure — it does not detect that stack_pointer_ < stack_->Address(), so a below-region stack pointer produced a bogus enormous sp_offset that was then used (after alignment to aligned_sp_offset) to index into the stack buffer, yielding an out-of-bounds read while scanning.
The fix adds an explicit ordering check: if stack_pointer_ < stack_->Address() it sets sp_offset = 0 (treating the scan as starting at the region base), and only otherwise falls back to the AssignIfInRange path. This keeps the scan’s starting offset within the captured region and prevents the underflow-driven OOB read.
stack_pointer_ below stack_->Address() (a guard-page interpretation) underflowed into a huge sp_offset; the fix clamps that case to sp_offset = 0 before any range or indexing use.Attack Path
- Produce a crash with an out-of-range stack pointer
A process crashes such that its captured
stack_pointer_is interpreted byProcessReaderLinuxas pointing to a guard page below the captured stack region’s basestack_->Address(). - Underflowing offset
ScanStackForPointerscomputesstack_pointer_ - stack_->Address(); becausestack_pointer_ < stack_->Address(), the unsigned subtraction wraps to a very large value thatAssignIfInRangedoes not reject as a below-region condition. - Out-of-bounds stack scan
The bogus
sp_offset(after alignment) is used to walk the captured stack buffer, causing an out-of-bounds read during pointer scanning, consistent with the advisory’s “Out of bounds read in CrashReporting.” - Downstream effect
Any leakage or crash from reading past the buffer is not shown in the diff beyond the OOB read itself and is
(inferred).
Impact Assessment
stack_pointer_ is treated as a guard-page address below stack_->Address(). The advisory reports an out-of-bounds read and does not state exploitation in the wild; escalation beyond the read (information disclosure, crash) is (inferred).Files Changed
third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.ccthird_party/crashpad/crashpad/util/numeric/int128_test.ccthird_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.ccthird_party/crashpad/crashpad/util/misc/reinterpret_bytes.ccthird_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.ccthird_party/crashpad/README.chromiumthird_party/crashpad/crashpad/util/linux/pac_helper.ccthird_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.ccthird_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.ccthird_party/crashpad/crashpad/util/misc/capture_context_test_util_win.ccthird_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.ccthird_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc
Audit Directions
- Unsigned address subtractionAudit any
ptr_a - ptr_bon addresses/offsets whereptr_acan legitimately be belowptr_b; unsigned underflow produces huge values that later index or size buffers. - Range checks that miss the low endWhere a value is validated only with a fits-in-type or upper-bound helper (like
AssignIfInRange), confirm the below-region/negative case is separately rejected before use. - Attacker-influenced register/state in crash captureReview crash-snapshot and stack-scanning code that consumes register values (stack/frame pointers) which a crashing (potentially compromised) process can control, treating them as untrusted bounds.
Patch
From da2e30bc2075402c4bd68fe1af7674bfbe3f5a4a Mon Sep 17 00:00:00 2001 From: Joshua Peraza <[email protected]> Date: Wed, 26 Aug 2026 10:30:05 -0700 Subject: [PATCH] Update Crashpad to 60dd943f48d77dc8d05dabc04badbd8561d0b8c4 48b459d7aed3 Add missing build/build_config.h includes 60dd943f48d7 Round up OOB stack pointers in ScanStackForPointers Bug: 502304489 Change-Id: I8d2c6a0e72a03ecb8b25d4cb5292ef743a3c0d23 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8279916 Commit-Queue: Mark Mentovai <[email protected]> Auto-Submit: Joshua Peraza <[email protected]> Reviewed-by: Mark Mentovai <[email protected]> Cr-Commit-Position: refs/heads/main@{#1686535} --- diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index 8d2e2fda..a20b700 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium @@ -2,7 +2,7 @@ Short Name: crashpad URL: https://chromium.googlesource.com/crashpad/crashpad Version: N/A -Revision: ad1827ddbc03f1c214030b31b380243ded660b95 +Revision: 60dd943f48d77dc8d05dabc04badbd8561d0b8c4 Update Mechanism: Manual License: Apache-2.0 License File: crashpad/LICENSE diff --git a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc index afa1c9f..5d44229 100644 --- a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc +++ b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc @@ -52,7 +52,11 @@ template <typename Pointer> bool ScanStackForPointers(void* data, size_t size) { size_t sp_offset; - if (!AssignIfInRange(&sp_offset, stack_pointer_ - stack_->Address())) { + // stack_pointer_ might point below the stack region if ProcessReaderLinux + // interpreted it as pointing to a guard page. + if (stack_pointer_ < stack_->Address()) { + sp_offset = 0; + } else if (!AssignIfInRange(&sp_offset, stack_pointer_ - stack_->Address())) { return false; } const size_t aligned_sp_offset = diff --git a/third_party/crashpad/crashpad/util/linux/pac_helper.cc b/third_party/crashpad/crashpad/util/linux/pac_helper.cc index a9d5f04..49eccce2 100644 --- a/third_party/crashpad/crashpad/util/linux/pac_helper.cc +++ b/third_party/crashpad/crashpad/util/linux/pac_helper.cc @@ -24,6 +24,7 @@ #include <ptrauth.h> #endif +#include "build/build_config.h" #include "util/misc/address_types.h" namespace crashpad { diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc index 55820b9..9b357ada 100644 --- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc +++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc @@ -14,6 +14,7 @@ #include "util/misc/capture_context_test_util.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/from_pointer_cast.h" diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc index 8a75b03..841aec4 100644 --- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc +++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc @@ -14,6 +14,7 @@ #include "util/misc/capture_context_test_util.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/implicit_cast.h" diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc index e21d865..70a6a7d 100644 --- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc +++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc @@ -16,6 +16,7 @@ #include <iterator> +#include "build/build_config.h" #include "gtest/gtest.h" #include "util/win/context_wrappers.h" diff --git a/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc b/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc index 5909b728..e7e5809b 100644 --- a/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc +++ b/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc @@ -19,6 +19,7 @@ #include <algorithm> #include "base/logging.h" +#include "build/build_config.h" namespace crashpad { namespace internal { diff --git a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc index af245d3..dbdcb8b 100644 --- a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -22,6 +22,7 @@ #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" #include "test/multiprocess_exec.h" diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc index 1862488..a17b4c4 100644 --- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc @@ -25,6 +25,7 @@ #include "base/bit_cast.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/cpu_architecture.h" #include "snapshot/linux/process_reader_linux.h" diff --git a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc index caacc19..06589d99 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc @@ -16,6 +16,7 @@ #include <mach/mach.h> +#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad { diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc index aa78e55..efb3bf8 100644 --- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc +++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc @@ -20,6 +20,7 @@ #include "base/files/file_path.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/win/exception_snapshot_win.h" #include "snapshot/win/process_snapshot_win.h" diff --git a/third_party/crashpad/crashpad/util/numeric/int128_test.cc b/third_party/crashpad/crashpad/util/numeric/int128_test.cc index 5bc9e41..43eaf08 100644 --- a/third_party/crashpad/crashpad/util/numeric/int128_test.cc +++ b/third_party/crashpad/crashpad/util/numeric/int128_test.cc @@ -15,6 +15,7 @@ #include "util/numeric/int128.h" #include "base/bit_cast.h" +#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad {
Regression Test / PoC
diff --git a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
index af245d3..dbdcb8b 100644
--- a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
@@ -22,6 +22,7 @@
#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h"
#include "test/multiprocess_exec.h"
diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
index 1862488..a17b4c4 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
@@ -25,6 +25,7 @@
#include "base/bit_cast.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/cpu_architecture.h"
#include "snapshot/linux/process_reader_linux.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
index caacc19..06589d99 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
@@ -16,6 +16,7 @@
#include <mach/mach.h>
+#include "build/build_config.h"
#include "gtest/gtest.h"
namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
index aa78e55..efb3bf8 100644
--- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
@@ -20,6 +20,7 @@
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/win/exception_snapshot_win.h"
#include "snapshot/win/process_snapshot_win.h"
diff --git a/third_party/crashpad/crashpad/util/numeric/int128_test.cc b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
index 5bc9e41..43eaf08 100644
--- a/third_party/crashpad/crashpad/util/numeric/int128_test.cc
+++ b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
@@ -15,6 +15,7 @@
#include "util/numeric/int128.h"
#include "base/bit_cast.h"
+#include "build/build_config.h"
#include "gtest/gtest.h"
namespace crashpad {
Original Bug Report
Potential Heap OOB Read in crashpad_handler due to Integer Underflow in ScanStackForPointers
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team.
Overview: An integer underflow vulnerability exists in Crashpad’s ScanStackForPointers when calculating the offset between an attacker-supplied stack pointer and the resolved stack base address. By supplying a crafted ucontext_t and memory layout, a compromised sandboxed process can trick the privileged crashpad_handler into performing an out-of-bounds heap read. This can be leveraged as a timing oracle to leak heap contents and bypass ASLR in the handler process.
Affected files:
third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc
Estimated timestamp from git blame: 2023-04-10
Root Cause
A potential integer underflow exists in third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc within the ScanStackForPointers template function:
template <typename Pointer>
bool ScanStackForPointers(void* data, size_t size) {
size_t sp_offset;
if (!AssignIfInRange(&sp_offset, stack_pointer_ - stack_->Address())) {
return false;
}
const size_t aligned_sp_offset =
(sp_offset + sizeof(Pointer) - 1) & ~(sizeof(Pointer) - 1);
auto words = reinterpret_cast<Pointer*>(static_cast<char*>(data) +
aligned_sp_offset);
size_t word_count = (size - aligned_sp_offset) / sizeof(Pointer);
for (size_t index = 0; index < word_count; ++index) {
auto word = StripPACBits(words[index]);
if (word >= low_ && word < high_) {
return true;
}
}
return false;
}
If a client provides a stack_pointer_ that is strictly less than stack_->Address(), the subtraction stack_pointer_ - stack_->Address() underflows. Since VMAddress is uint64_t and size_t is a 64-bit unsigned integer on 64-bit systems, the underflowed value remains perfectly within the range of size_t. Consequently, AssignIfInRange returns true, assigning a massive positive value (e.g., 0xFFFFFFFFFFFFE000) to sp_offset.
When aligned_sp_offset is added to data, standard 64-bit pointer arithmetic wraps around, causing the words pointer to point to memory before the heap-allocated data buffer. Simultaneously, size - aligned_sp_offset also underflows. Because of integer modular arithmetic, this calculates the exact number of words required to scan from the out-of-bounds pointer up to the end of the legitimate data buffer.
Potential Exploitation Steps
(Note: These are theoretical/suggested steps, as our AI tooling does not currently have the ability to run a live proof of concept.)
- Setup: An attacker gains arbitrary code execution in a sandboxed client process.
- Memory Grooming (Client): The attacker maps a valid stack region (e.g., at
0x40000000) and an unreadable guard page immediately below it (e.g., at0x3FFFF000). - Fake Module: The attacker creates a fake ELF module in their memory space by manipulating the dynamic linker’s
link_map. They usePT_LOADsegments to arbitrarily define the[low_, high_)bounds they wish to scan for in the handler’s heap. - Fake Context: The attacker constructs a fake
ucontext_tstruct, setting the stack pointer (rsp/sp) to0x3FFFF000(inside the guard page) and the instruction pointer to a value outside the fake module. - Trigger: The attacker triggers a crash dump request via IPC to
crashpad_handler, passing pointers to the fakeucontext_tand aSanitizationInformationstruct pointing to their fake module. - Handler Processing:
crashpad_handlerreads the attacker’s context. When finding the stack mapping for0x3FFFF000,ProcessReaderLinuxdetects the guard page and safely bumpsstack_->Address()to the start of the valid mapping at0x40000000. - Underflow: In
ScanStackForPointers,stack_pointer_(0x3FFFF000) minusstack_->Address()(0x40000000) underflows to-0x1000(represented as a huge unsigned integer). - OOB Read:
wordspoints todata - 0x1000. The loop reads out-of-bounds heap memory before the allocated stack buffer. - Timing Oracle: If a value in the OOB memory falls within the attacker’s
[low_, high_)range, the function returnstrue, leading to full, slow minidump generation (involving heavy I/O). If no match is found, sanitization fails and the handler exits almost instantly. The attacker observes this massive timing difference to perform a binary search and leak heap contents, bypassing ASLR for the privilegedcrashpad_handlerprocess.
Suggested Fix
Add bounds checking before the pointer arithmetic in ScanStackForPointers:
if (stack_pointer_ < stack_->Address()) {
return false;
}
size_t sp_offset;
// ... existing AssignIfInRange check ...
const size_t aligned_sp_offset =
(sp_offset + sizeof(Pointer) - 1) & ~(sizeof(Pointer) - 1);
if (aligned_sp_offset > size) {
return false;
}
This ensures that the stack pointer resides within the bounds of the resolved stack region, completely eliminating the underflow and subsequent OOB read.
Evaluated with Chrome root at commit: 096fc8fdbfacf2546485756d03f160a3d04fcc9b
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.