CVE-2025-0437
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifbase/metrics/field_trial.cc |
modified | |
forbase/metrics/persistent_histogram_allocator.cc |
modified | |
ifbase/metrics/persistent_histogram_allocator.cc |
modified |
Files Changed
base/metrics/field_trial.ccbase/metrics/persistent_histogram_allocator.cc
Patch
From 23479ae0d3332f5525cfd9491137fc6c0ffcb46a Mon Sep 17 00:00:00 2001 From: Roger McFarlane <[email protected]> Date: Tue, 10 Dec 2024 20:31:23 +0000 Subject: [PATCH] Remove PersistentMemoryAllocator::GetAllocSize() This CL removes PersistentMemoryAllocator::GetAllocSize() in favor of allowing various other API entry points to return the alloc size. This mitigates potential TOCTOU errors where the size of an alloc is validated by one API then separately fetched in another call. The size could otherwise be manipulated in between initial validation and the subsequent fetch. Bug: 378623799 Change-Id: I8021cf4c07f1a96172deb2a252326e9ffa525798 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6025612 Reviewed-by: Alexei Svitkine <[email protected]> Commit-Queue: Roger McFarlane <[email protected]> Cr-Commit-Position: refs/heads/main@{#1394492} --- diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 829a5c4b..bf2ffe6 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc @@ -124,7 +124,7 @@ } // Returns the boundary value for comparing against the FieldTrial's added -// groups for a given |divisor| (total probability) and |entropy_value|. +// groups for a given `divisor` (total probability) and `entropy_value`. FieldTrial::Probability GetGroupBoundaryValue( FieldTrial::Probability divisor, double entropy_value) { @@ -138,7 +138,7 @@ const double kEpsilon = 1e-8; const FieldTrial::Probability result = static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon); - // Ensure that adding the epsilon still results in a value < |divisor|. + // Ensure that adding the epsilon still results in a value < `divisor`. return std::min(result, divisor - 1); } @@ -259,7 +259,7 @@ if (forced_) { DCHECK(!group_name_.empty()); if (name == group_name_) { - // Note that while |group_| may be equal to |kDefaultGroupNumber| on the + // Note that while `group_` may be equal to `kDefaultGroupNumber` on the // forced trial, it will not have the same value as the default group // number returned from the non-forced |FactoryGetFieldTrial()| call, // which takes care to ensure that this does not happen. @@ -326,7 +326,7 @@ void FieldTrial::EnableBenchmarking() { // We don't need to see field trials created via CreateFieldTrial() for // benchmarking, because such field trials have only a single group and are - // not affected by randomization that |enable_benchmarking_| would disable. + // not affected by randomization that `enable_benchmarking_` would disable. DCHECK_EQ(0u, FieldTrialList::GetRandomizedFieldTrialCount()); enable_benchmarking_ = true; } @@ -453,7 +453,7 @@ if (group_ != kNotFinalized) return; accumulated_group_probability_ = divisor_; - // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not + // Here it's OK to use `kDefaultGroupNumber` since we can't be forced and not // finalized. DCHECK(!forced_); SetGroupChoice(default_group_name_, kDefaultGroupNumber); @@ -807,7 +807,7 @@ field_trial = new FieldTrial(name, kTotalProbability, group_name, 0, is_low_anonymity, is_overridden); // The group choice will be finalized in this method. So - // |is_randomized_trial| should be false. + // `is_randomized_trial` should be false. FieldTrialList::Register(field_trial, /*is_randomized_trial=*/false); // Force the trial, which will also finalize the group choice. field_trial->SetForced(); @@ -910,12 +910,12 @@ if (!field_trial->ref_) return false; + size_t allocated_size = 0; const FieldTrial::FieldTrialEntry* entry = global_->field_trial_allocator_->GetAsObject<FieldTrial::FieldTrialEntry>( - field_trial->ref_); + field_trial->ref_, &allocated_size); + CHECK(entry); - size_t allocated_size = - global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); uint64_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size; if (allocated_size < actual_size) diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc index 825c117..dcc2b2a 100644 --- a/base/metrics/persistent_histogram_allocator.cc +++ b/base/metrics/persistent_histogram_allocator.cc @@ -89,13 +89,13 @@ } // Calculate the number of bytes required to store all of a histogram's -// "counts". This will return zero (0) if |bucket_count| is not valid. +// "counts". This will return zero (0) if `bucket_count` is not valid. size_t CalculateRequiredCountsBytes(size_t bucket_count) { // 2 because each "sample count" also requires a backup "logged count" // used for calculating the delta during snapshot operations. const size_t kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount); - // If the |bucket_count| is such that it would overflow the return type, + // If the `bucket_count` is such that it would overflow the return type, // perhaps as the result of a malicious actor, then return zero to // indicate the problem to the caller. if (bucket_count > std::numeric_limits<size_t>::max() / kBytesPerBucket) @@ -176,7 +176,7 @@ PersistentSparseHistogramDataManager::LoadRecords( PersistentSampleMapRecords* sample_map_records, std::optional<HistogramBase::Sample> until_value) { - // DataManager must be locked in order to access the |sample_records_| + // DataManager must be locked in order to access the `sample_records_` // vectors. base::AutoLock auto_lock(lock_); @@ -222,7 +222,7 @@ } // Return all references found that have not yet been seen by - // |sample_map_records|, up until |until_value| (if applicable). + // `sample_map_records`, up until `until_value` (if applicable). std::vector<PersistentMemoryAllocator::Reference> new_references; CHECK_GE(found_records.size(), sample_map_records->seen_); auto new_found_records = @@ -230,9 +230,9 @@ new_references.reserve(new_found_records.size()); for (const auto& new_record : new_found_records) { new_references.push_back(new_record.reference); - // Maybe references after |until_value| were found. Stop here immediately in + // Maybe references after `until_value` were found. Stop here immediately in // such a case, since the caller will not expect any more samples after - // |until_value|. + // `until_value`. if (until_value.has_value() && new_record.value == until_value.value()) { break; } @@ -321,9 +321,9 @@ // count data (while these must reference the persistent counts) and always // add it to the local list of known histograms (while these may be simple // references to histograms in other processes). + size_t length = 0; PersistentHistogramData* data = - memory_allocator_->GetAsObject<PersistentHistogramData>(ref); - const size_t length = memory_allocator_->GetAllocSize(ref); + memory_allocator_->GetAsObject<PersistentHistogramData>(ref, &length); // Check that metadata is reasonable: name is null-terminated and non-empty, // ID fields have been loaded with a hash of the name (0 is considered @@ -331,7 +331,7 @@ if (!data || data->name[0] == '\0' || reinterpret_cast<char*>(data)[length - 1] != '\0' || data->samples_metadata.id == 0 || data->logged_metadata.id == 0 || - // Note: Sparse histograms use |id + 1| in |logged_metadata|. + // Note: Sparse histograms use `id + 1` in `logged_metadata`. (data->logged_metadata.id != data->samples_metadata.id && data->logged_metadata.id != data->samples_metadata.id + 1) || // Most non-matching values happen due to truncated names. Ideally, we @@ -374,7 +374,7 @@ histogram_data->histogram_type = histogram_type; histogram_data->flags = flags | HistogramBase::kIsPersistent; - // |counts_ref| relies on being zero'd out initially. Even though this + // `counts_ref` relies on being zero'd out initially. Even though this // should always be the case, manually zero it out again here in case there // was memory corruption (e.g. if the memory was mapped from a corrupted // spare file). @@ -388,7 +388,7 @@ size_t bucket_count = bucket_ranges->bucket_count(); size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count); if (counts_bytes == 0) { - // |bucket_count| was out-of-range. + // `bucket_count` was out-of-range. return nullptr; } @@ -396,8 +396,8 @@ // objects for re-use, it would be dangerous for one to hold a reference // from a persistent allocator that is not the global one (which is // permanent once set). If this stops being the case, this check can - // become an "if" condition beside "!ranges_ref" below and before - // set_persistent_reference() farther down. + // become an `if` condition beside `!ranges_ref` below and before + // `set_persistent_reference()` farther down. DCHECK_EQ(this, GlobalHistogramAllocator::Get()); // Re-use an existing BucketRanges persistent allocation if one is known; @@ -434,7 +434,7 @@ if (ranges_ref && histogram_data) { histogram_data->minimum = minimum; histogram_data->maximum = maximum; - // |bucket_count| must fit within 32-bits or the allocation of the counts + // `bucket_count` must fit within 32-bits or the allocation of the counts
Regression Test / PoC
diff --git a/base/metrics/persistent_memory_allocator_unittest.cc b/base/metrics/persistent_memory_allocator_unittest.cc
index 01ac173..a0b96616 100644
--- a/base/metrics/persistent_memory_allocator_unittest.cc
+++ b/base/metrics/persistent_memory_allocator_unittest.cc
@@ -141,11 +141,12 @@
ASSERT_TRUE(obj1);
Reference block1 = allocator_->GetAsReference(obj1);
ASSERT_NE(0U, block1);
- EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject1>(block1));
EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block1));
- EXPECT_LE(sizeof(TestObject1), allocator_->GetAllocSize(block1));
- EXPECT_GT(sizeof(TestObject1) + kAllocAlignment,
- allocator_->GetAllocSize(block1));
+ size_t alloc_size_1 = 0;
+ EXPECT_NE(nullptr,
+ allocator_->GetAsObject<TestObject1>(block1, &alloc_size_1));
+ EXPECT_LE(sizeof(TestObject1), alloc_size_1);
+ EXPECT_GT(sizeof(TestObject1) + kAllocAlignment, alloc_size_1);
PersistentMemoryAllocator::MemoryInfo meminfo1;
allocator_->GetMemoryInfo(&meminfo1);
EXPECT_EQ(meminfo0.total, meminfo1.total);
@@ -181,11 +182,12 @@
ASSERT_TRUE(obj2);
Reference block2 = allocator_->GetAsReference(obj2);
ASSERT_NE(0U, block2);
- EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject2>(block2));
EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject1>(block2));
- EXPECT_LE(sizeof(TestObject2), allocator_->GetAllocSize(block2));
- EXPECT_GT(sizeof(TestObject2) + kAllocAlignment,
- allocator_->GetAllocSize(block2));
+ size_t alloc_size_2 = 0;
+ EXPECT_NE(nullptr,
+ allocator_->GetAsObject<TestObject2>(block2, &alloc_size_2));
+ EXPECT_LE(sizeof(TestObject2), alloc_size_2);
+ EXPECT_GT(sizeof(TestObject2) + kAllocAlignment, alloc_size_2);
PersistentMemoryAllocator::MemoryInfo meminfo2;
allocator_->GetMemoryInfo(&meminfo2);
EXPECT_EQ(meminfo1.total, meminfo2.total);
@@ -966,10 +968,10 @@
uint32_t type_id;
Reference ref;
while ((ref = iter.GetNext(&type_id)) != 0) {
+ size_t size = 0;
const char* data = allocator.GetAsArray<char>(
- ref, 0, PersistentMemoryAllocator::kSizeAny);
+ ref, 0, PersistentMemoryAllocator::kSizeAny, &size);
uint32_t type = allocator.GetType(ref);
- size_t size = allocator.GetAllocSize(ref);
// Ensure compiler can't optimize-out above variables.
(void)data;
(void)type;
Original Bug Report
TOCTOU in PersistentHistogramAllocator::GetHistogram
Steps to reproduce the problem
- Apply the patch_renderer.diff with
--ignore-whitespaceargument. - Build the release version of Chrome and start it.
- Open a new tab and visit any URL.
- Close the tab. If the issue does not trigger, repeat the process of opening a new tab, visiting a URL, and closing the tab.
- Since ASAN on Windows cannot detect this vulnerability, You can use WinDbg to attach to the broker process and then perform the above operations to capture the exception.
Problem Description
This vulnerability can be triggered through process such as render, GPU, and utility to cause a crash in the broker processes. The current demonstration shows that in the render process, it requires opening a new page to visit a website and then closing the page to have a chance of triggering it, as this is a TOCTOU bug.
base/metrics/persistent_histogram_allocator.cc
std::unique_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram(
Reference ref) {
PersistentHistogramData* data =
memory_allocator_->GetAsObject<PersistentHistogramData>(ref);[1]
const size_t length = memory_allocator_->GetAllocSize(ref);[2]
if (!data || data->name[0] == '\0' ||
reinterpret_cast<char*>(data)[length - 1] != '\0' ||
data->samples_metadata.id == 0 || data->logged_metadata.id == 0 ||
(data->logged_metadata.id != data->samples_metadata.id &&
data->logged_metadata.id != data->samples_metadata.id + 1) ||
[3]HashMetricName(data->name) != data->samples_metadata.id) {
return nullptr;
}
return CreateHistogram(data);
}
When the function reaches point [1], the subsequently called function checks whether block->size is greater than or equal to 0x68.If it is, it will return data, which is a pointer to shared memory. The value of data is shared_memory_base + [shared_memory_base + 0x3c] + 0x10. This shared memory is also mapped in other processes, and is categorized based on metrics and types, such as render, GPU, utility, etc.
However, at point [2], when actually obtaining length, it only checks whether block->size is greater than 0x10.
Since this operation involves shared memory, there exists a TOCTOU (Time-of-Check to Time-of-Use) bug here.
If a child process modifies the value of size between points [1] and [2], it can bypass the subsequent check reinterpret_cast<char*>(data)[length - 1] != '\0'. This check is used to ensure that data->name is a null-terminated string.
Before entering function [3], the code calls strlen to get the length of data->name. If data->name is very long and reaches the end of the shared memory, the strlen function will read out-of-bounds into the next heap block to check for a null terminator.
There are three possible scenarios:
- The beginning of the next memory region happens to be
0. In this case, the out-of-bounds access does not have much impact. - The next memory region is not yet allocated. An out-of-bounds access by
strlenwill cause an exception. - The beginning of the next memory region is not
0. In this case,strlenwill return a value larger than the actual length ofdata->name.
In the third scenario, at point [3], the code will call OPENSSL_memcpy(data + n, in, len), which will lead to an out-of-bounds read.
HashMetricName(std::string_view name) –> MD5Sum(as_byte_span(name), &digest) –> MD5(data.data(), data.size(), digest->a.data()) –> MD5_Update –> crypto_md32_update
For this vulnerability patch, I recommend checking if the length is larger 0x68 after obtaining it. The code is as follows:
--- a/base/metrics/persistent_histogram_allocator.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -328,7 +328,7 @@ std::unique_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram(
// Check that metadata is reasonable: name is null-terminated and non-empty,
// ID fields have been loaded with a hash of the name (0 is considered
// unset/invalid).
- if (!data || data->name[0] == '\0' ||
+ if (length < 0x58 || !data || data->name[0] == '\0' ||
reinterpret_cast<char*>(data)[length - 1] != '\0' ||
data->samples_metadata.id == 0 || data->logged_metadata.id == 0 ||
// Note: Sparse histograms use |id + 1| in |logged_metadata|.
Additional Comments
Chrome Version: Version 131.0.6778.20 (Developer Build) (64-bit) commit 5b1aa5623a75aec826e1c812228173345a5065c3 (HEAD -> beta, origin/branch-heads/6778) Operating System: windows10
Summary
TOCTOU in PersistentHistogramAllocator::GetHistogram
Custom Questions
Type of crash:
browser
Crash state:
0:010> p
chrome!std::__Cr::__constexpr_strlen [inlined in chrome!base::PersistentHistogramAllocator::GetHistogram+0xad]:
00007ffc`1e43fc3d e8aebb3b09 call chrome!strlen (00007ffc`277fb7f0)
0:010> db 000001B1AD9300C0
000001b1`ad9300c0 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad9300d0 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad9300e0 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad9300f0 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad930100 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad930110 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad930120 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000001b1`ad930130 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0:010> p
(3300.167c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
chrome!strlen+0x31:
00007ffc`277fb821 488b10 mov rdx,qword ptr [rax] ds:000001b1`adb30000=????????????????
0:010> db 000001B1ADB30000
000001b1`adb30000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30010 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30020 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30030 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30040 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30050 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30060 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
000001b1`adb30070 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
0:010> k
# Child-SP RetAddr Call Site
00 00000036`d25fd0b8 00007ffc`1e43fc42 chrome!strlen+0x31 [C:\chromium\src\out\release\minkernel\crts\ucrt\src\appcrt\string\amd64\strlen.asm @ 70]
01 (Inline Function) --------`-------- chrome!std::__Cr::__constexpr_strlen+0x5 [C:\chromium\src\third_party\libc++\src\include\__string\constexpr_c_functions.h @ 66]
02 (Inline Function) --------`-------- chrome!std::__Cr::char_traits<char>::length+0x5 [C:\chromium\src\third_party\libc++\src\include\__string\char_traits.h @ 130]
03 (Inline Function) --------`-------- chrome!std::__Cr::__char_traits_length_checked+0x5 [C:\chromium\src\third_party\libc++\src\include\string_view @ 269]
04 (Inline Function) --------`-------- chrome!std::__Cr::basic_string_view<char,std::__Cr::char_traits<char> >::basic_string_view+0xa [C:\chromium\src\third_party\libc++\src\include\string_view @ 347]
05 00000036`d25fd0c0 00007ffc`1e43fb3d chrome!base::PersistentHistogramAllocator::GetHistogram+0xb2 [C:\chromium\src\base\metrics\persistent_histogram_allocator.cc @ 340]
06 00000036`d25fd120 00007ffc`2052ed7b chrome!base::PersistentHistogramAllocator::Iterator::GetNextWithIgnore+0xed [C:\chromium\src\base\metrics\persistent_histogram_allocator.cc @ 314]
07 (Inline Function) --------`-------- chrome!base::PersistentHistogramAllocator::Iterator::GetNext+0xb [C:\chromium\src\base\metrics\persistent_histogram_allocator.h @ 198]
08 00000036`d25fd2c0 00007ffc`16da3e98 chrome!metrics::SubprocessMetricsProvider::MergeHistogramDeltasFromAllocator+0x7b [C:\chromium\src\components\metrics\content\subprocess_metrics_provider.cc @ 268]
09 00000036`d25fd4d0 00007ffc`1e3dfe32 chrome!base::OnceCallback<void ()>::Run+0x58 [C:\chromium\src\base\functional\callback.h @ 156]
0a 00000036`d25fd550 00007ffc`1e3e0006 chrome!base::internal::PostTaskAndReplyRelay::RunTaskAndPostReply+0x32 [C:\chromium\src\base\threading\post_task_and_reply_impl.h @ 49]
0b (Inline Function) --------`-------- chrome!base::internal::DecayedFunctorTraits<void (*)(base::internal::PostTaskAndReplyRelay),base::internal::PostTaskAndReplyRelay &&>::Invoke+0x21 [C:\chromium\src\base\functional\bind_internal.h @ 671]
0c (Inline Function) --------`-------- chrome!base::internal::InvokeHelper<0,base::internal::FunctorTraits<void (*&&)(base::internal::PostTaskAndReplyRelay),base::internal::PostTaskAndReplyRelay &&>,void,0>::MakeItSo+0x21 [C:\chromium\src\base\functional\bind_internal.h @ 930]
0d (Inline Function) --------`-------- chrome!base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(base::internal::PostTaskAndReplyRelay),base::internal::PostTaskAndReplyRelay &&>,base::internal::BindState<0,1,0,void (*)(base::internal::PostTaskAndReplyRelay),base::internal::PostTaskAndReplyRelay>,void ()>::RunImpl+0x21 [C:\chromium\src\base\functional\bind_internal.h @ 1067]
0e 00000036`d25fd5e0 00007ffc`16da3e98 chrome!base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(base::internal::PostTaskAndReplyRelay),base::internal::PostTaskAndReplyRelay &&>,base::internal::BindState<0,1,0,void (*)(base::internal::PostTaskAndReplyRelay),base::internal::PostTaskAndReplyRelay>,void ()>::RunOnce+0x36 [C:\chromium\src\base\functional\bind_internal.h @ 980]
0f 00000036`d25fd660 00007ffc`1e3f7194 chrome!base::OnceCallback<void ()>::Run+0x58 [C:\chromium\src\base\functional\callback.h @ 156]
10 00000036`d25fd6e0 00007ffc`224e2173 chrome!base::TaskAnnotator::RunTaskImpl+0x154 [C:\chromium\src\base\task\common\task_annotator.cc @ 203]
11 (Inline Function) --------`-------- chrome!base::TaskAnnotator::RunTask+0x54 [C:\chromium\src\base\task\common\task_annotator.h @ 98]
12 (Inline Function) --------`-------- chrome!base::internal::TaskTracker::RunTaskImpl+0x78 [C:\chromium\src\base\task\thread_pool\task_tracker.cc @ 677]
13 00000036`d25fd780 00007ffc`224e14b6 chrome!base::internal::TaskTracker::RunBlockShutdown+0xc3 [C:\chromium\src\base\task\thread_pool\task_tracker.cc @ 670]
14 (Inline Function) --------`-------- chrome!base::internal::TaskTracker::RunTaskWithShutdownBehavior+0x5b [C:\chromium\src\base\task\thread_pool\task_tracker.cc @ 695]
15 00000036`d25fd840 00007ffc`224e0c91 chrome!base::internal::TaskTracker::RunTask+0x426 [C:\chromium\src\base\task\thread_pool\task_tracker.cc @ 524]
16 00000036`d25ff1e0 00007ffc`243741cc chrome!base::internal::TaskTracker::RunAndPopNextTask+0x2d1 [C:\chromium\src\base\task\thread_pool\task_tracker.cc @ 417]
17 00000036`d25ff490 00007ffc`24373a28 chrome!base::internal::WorkerThread::RunWorker+0x49c [C:\chromium\src\base\task\thread_pool\worker_thread.cc @ 493]
18 00000036`d25ff730 00007ffc`1e3864a4 chrome!base::internal::WorkerThread::RunBackgroundPooledWorker+0x18 [C:\chromium\src\base\task\thread_pool\worker_thread.cc @ 385]
19 00000036`d25ff770 00007ffc`8a387374 chrome!base::`anonymous namespace'::ThreadFunc+0x164 [C:\chromium\src\base\threading\platform_thread_win.cc @ 124]
1a 00000036`d25ff940 00007ffc`8acbcc91 KERNEL32!BaseThreadInitThunk+0x14
1b 00000036`d25ff970 00000000`00000000 ntdll!RtlUserThreadStart+0x21
Reporter credit:
Xiantong Hou and Pisanbao of Wuheng Lab
Additional Data
Category: Security
Chrome Channel: Dev
Regression: N/A
- https://source.chromium.org/chromium/chromium/src/+/main:base/metrics/persistent_memory_allocator.cc;drc=a45502c46d75f210c783e07384138379ea1e46e4;l=939
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/boringssl/src/crypto/fipsmodule/digest/md32_common.h;drc=a45502c46d75f210c783e07384138379ea1e46e4;l=127