Talos Vulnerability Report

TALOS-2023-1693

Google Chrome WebRTC RTCStatsCollector out of bounds memory access vulnerability

May 4, 2023
CVE Number

CVE-2023-0698

SUMMARY

An out-of-bounds memory access vulnerability exists in stats reporting functionality of the WebRTC implementation in Google Chrome 109.0.5414.74 and 108.0.5359.124. A specially crafted malicious web page can trigger an out-of-bounds access which can lead to type confusion and further memory corruption. A victim would need to navigate to a malicious webpage to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

Google Chrome 108.0.5359.124
Google Chrome 109.0.5414.74

PRODUCT URLS

Chrome - https://www.google.com/chrome/

CVSSv3 SCORE

8.3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L

CWE

CWE-129 - Improper Validation of Array Index

DETAILS

Google Chrome is a cross-platform web browser developed by Google and is currently the most popular web browser. One of the features it supports is WebRTC, which is primarily used for implementing web applications for real-time communication.

PeerConnection object has a method called getStats, which returns statistics about the overall connection. When generating a stats report, the request is handled by the signaling thread.

The class responsible for generating the report is RTCStatsCollector. Collector uses caching to avoid doing expensive operations on each request. Therefore, if the request was received inside the caching window, and there is a previously generated cached report, that report is delivered instead. If not, code generates a new status report by generating partial results from network and signal thread and merging them.

RTCStatsCollector::ProducePartialResultsOnNetworkThread(...) is responsible for generating partial results on the network thread.

void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
    int64_t timestamp_us,
    absl::optional<std::string> sctp_transport_name) {
  // ...

  std::set<std::string> transport_names;
  if (sctp_transport_name) {
    transport_names.emplace(std::move(*sctp_transport_name));
  }

  for (const auto& info : transceiver_stats_infos_) {
    if (info.transport_name)
      transport_names.insert(*info.transport_name);
  }

  std::map<std::string, cricket::TransportStats> transport_stats_by_name =
      pc_->GetTransportStatsByNames(transport_names);
  std::map<std::string, CertificateStatsPair> transport_cert_stats =
      PrepareTransportCertificateStats_n(transport_stats_by_name);

  ProducePartialResultsOnNetworkThreadImpl(
      timestamp_us, transport_stats_by_name, transport_cert_stats,
      network_report_.get());

  // ...
}

A function gathers all the transport names from sctp_transport_name, which was passed on to the task by calling PeerConnection::sctp_transport_name() and |transceiver_stats_infos_| member fields. These names are used to generate maps of cricket::TransportStats and CertificateStatsPair.

If we look at the implemenation of RTCStatsCollector::PrepareTransportCertificateStats_n(...), we can see the following:

// creates a new map
std::map<std::string, CertificateStatsPair> transport_cert_stats;
  {
    MutexLock lock(&cached_certificates_mutex_);
    // Copy the certificate info from the cache, avoiding expensive
    // rtc::SSLCertChain::GetStats() calls.
    for (const auto& pair : cached_certificates_by_transport_) {
      transport_cert_stats.insert(
          std::make_pair(pair.first, pair.second.Copy()));
    }
  }
  if (transport_cert_stats.empty()) {
    // in cases when the cache was empty, it generates new stats

It first declares |transport_cert_stats| map and inserts values from the |cached_certificates_by_transport_|. If there is nothing in the cache, it continues to fill the map with newly generated stats.

At the end of the function, it inserts newly generated stats or cached stats back into the cache again.

for (const auto& pair : transport_cert_stats) {
      cached_certificates_by_transport_.insert(
          std::make_pair(pair.first, pair.second.Copy()));
    }

After |transport_cert_stats| is created, RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(...) is called with generated maps as arguments.

void RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(
    int64_t timestamp_us,
    const std::map<std::string, cricket::TransportStats>&
        transport_stats_by_name,
    const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
    RTCStatsReport* partial_report) {
  RTC_DCHECK_RUN_ON(network_thread_);
  // ...
  ProduceTransportStats_n(timestamp_us, transport_stats_by_name,
                          transport_cert_stats, partial_report);
  // ...

It eventually calls RTCStatsCollector::ProduceTransportStats_n(...) to produce the stats. It iterates through the |transport_stats_by_name| and tries to find the associated CertificateStatsPair structure from |transport_cert_stats| and assumes it will always succeed (there’s only a DCHECK).

void RTCStatsCollector::ProduceTransportStats_n(
    int64_t timestamp_us,
    const std::map<std::string, cricket::TransportStats>&
        transport_stats_by_name,
    const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
    RTCStatsReport* report) const {
        // ...
    
    for (const auto& entry : transport_stats_by_name) {
    const std::string& transport_name = entry.first;
    // Get reference to local and remote certificates of this transport, if they
    // exist.
    const auto& certificate_stats_it =
        transport_cert_stats.find(transport_name);
    RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend()); // Debug check
    std::string local_certificate_id;
    if (certificate_stats_it->second.local) {
      local_certificate_id = RTCCertificateIDFromFingerprint(
          certificate_stats_it->second.local->fingerprint);
    }
    // ...

This can cause an issue when, on the first getStats() call, the RTCStatsCollector instance caches the generated |transport_cert_stats| and, before the cache is cleared (e.g. setLocalDescription eventually clears the cache), issues an another getStats() with an additional transport name in the PeerConnection instance. This will cause a reuse of |transport_cert_stats|, which doesn’t have certificate stats for the additional transport name that was added to the |transport_stats_by_name|.

const auto& certificate_stats_it =
        transport_cert_stats.find(transport_name);
    RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());

This situation will make transport_cert_stats.find(transport_name); fail, and |certificate_stats_it| will be equal to transport_cert_stats.cend(). Subsequent use of the iterator will result in out-of-bounds memory access.

In the proof-of-concept, first getStats call will cached certificate stats of transport name 2 (which comes from |transceiver_stats_infos_|) but not for sctp transport name (which is 3) because it is not set by the signaling thread at the time of cache generation. On the second getStats call, transport name 3 is available, so it gets included in the |transport_stats_by_name|. At this point cache has not yet been cleared.

Crash Information

=================================================================
==2308409==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x559193e4165d bp 0x7f2d1c0c5890 sp 0x7f2d1c0c5840 T39)
==2308409==The signal is caused by a READ memory access.
==2308409==Hint: this fault was caused by a dereference of a high value address (see register values below).  Disassemble the provided pc to learn which register was used.
    #0 0x559193e4165d in __is_long buildtools/third_party/libc++/trunk/include/string:1674:33
    #1 0x559193e4165d in size buildtools/third_party/libc++/trunk/include/string:1069:17
    #2 0x559193e4165d in std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>> std::Cr::operator+<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>(char const*, std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>> const&) buildtools/third_party/libc++/trunk/include/string:4255:27
    #3 0x559185cd4a44 in RTCCertificateIDFromFingerprint third_party/webrtc/pc/rtc_stats_collector.cc:72:15
    #4 0x559185cd4a44 in webrtc::RTCStatsCollector::ProduceTransportStats_n(long, std::Cr::map<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>, cricket::TransportStats, std::Cr::less<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>>, std::Cr::allocator<std::Cr::pair<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>> const, cricket::TransportStats>>> const&, std::Cr::map<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>, webrtc::RTCStatsCollector::CertificateStatsPair, std::Cr::less<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>>, std::Cr::allocator<std::Cr::pair<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>> const, webrtc::RTCStatsCollector::CertificateStatsPair>>> const&, webrtc::RTCStatsReport*) const third_party/webrtc/pc/rtc_stats_collector.cc:2190:30
    #5 0x559185cd25f2 in webrtc::RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(long, std::Cr::map<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>, cricket::TransportStats, std::Cr::less<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>>, std::Cr::allocator<std::Cr::pair<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>> const, cricket::TransportStats>>> const&, std::Cr::map<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>, webrtc::RTCStatsCollector::CertificateStatsPair, std::Cr::less<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>>, std::Cr::allocator<std::Cr::pair<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>> const, webrtc::RTCStatsCollector::CertificateStatsPair>>> const&, webrtc::RTCStatsReport*) third_party/webrtc/pc/rtc_stats_collector.cc:1531:3
    #6 0x559185cd0d88 in webrtc::RTCStatsCollector::ProducePartialResultsOnNetworkThread(long, absl::optional<std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>>) third_party/webrtc/pc/rtc_stats_collector.cc:1507:3
    #7 0x559185cec881 in operator() third_party/webrtc/pc/rtc_stats_collector.cc:1428:22
    #8 0x559185cec881 in __invoke<(lambda at ../../third_party/webrtc/pc/rtc_stats_collector.cc:1426:9)> buildtools/third_party/libc++/trunk/include/__functional/invoke.h:394:23
    #9 0x559185cec881 in invoke<(lambda at ../../third_party/webrtc/pc/rtc_stats_collector.cc:1426:9)> buildtools/third_party/libc++/trunk/include/__functional/invoke.h:531:12
    #10 0x559185cec881 in InvokeR<void, (lambda at ../../third_party/webrtc/pc/rtc_stats_collector.cc:1426:9), void> third_party/abseil-cpp/absl/functional/internal/any_invocable.h:130:3
    #11 0x559185cec881 in void absl::internal_any_invocable::RemoteInvoker<false, void, webrtc::RTCStatsCollector::GetStatsReportInternal(webrtc::RTCStatsCollector::RequestInfo)::$_1&&>(absl::internal_any_invocable::TypeErasedState*) third_party/abseil-cpp/absl/functional/internal/any_invocable.h:358:10
    #12 0x5591922a3bca in operator() third_party/abseil-cpp/absl/functional/internal/any_invocable.h:862:1
    #13 0x5591922a3bca in webrtc::ThreadWrapper::RunTaskQueueTask(absl::AnyInvocable<void () &&>) components/webrtc/thread_wrapper.cc:279:3
    #14 0x5591922a5a90 in Invoke<void (webrtc::ThreadWrapper::*)(absl::AnyInvocable<void () &&>), base::WeakPtr<webrtc::ThreadWrapper>, absl::AnyInvocable<void () &&> > base/functional/bind_internal.h:646:12
    #15 0x5591922a5a90 in MakeItSo<void (webrtc::ThreadWrapper::*)(absl::AnyInvocable<void () &&>), std::Cr::tuple<base::WeakPtr<webrtc::ThreadWrapper>, absl::AnyInvocable<void () &&> > > base/functional/bind_internal.h:847:5
    #16 0x5591922a5a90 in void base::internal::Invoker<base::internal::BindState<void (webrtc::ThreadWrapper::*)(absl::AnyInvocable<void () &&>), base::WeakPtr<webrtc::ThreadWrapper>, absl::AnyInvocable<void () &&>>, void ()>::RunImpl<void (webrtc::ThreadWrapper::*)(absl::AnyInvocable<void () &&>), std::Cr::tuple<base::WeakPtr<webrtc::ThreadWrapper>, absl::AnyInvocable<void () &&>>, 0ul, 1ul>(void (webrtc::ThreadWrapper::*&&)(absl::AnyInvocable<void () &&>), std::Cr::tuple<base::WeakPtr<webrtc::ThreadWrapper>, absl::AnyInvocable<void () &&>>&&, std::Cr::integer_sequence<unsigned long, 0ul, 1ul>) base/functional/bind_internal.h:919:12
    #17 0x559194fd1df9 in Run base/functional/callback.h:174:12
    #18 0x559194fd1df9 in base::TaskAnnotator::RunTaskImpl(base::PendingTask&) base/task/common/task_annotator.cc:154:32
    #19 0x559195018c19 in RunTask<(lambda at ../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:451:11)> base/task/common/task_annotator.h:84:5
    #20 0x559195018c19 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:449:23
    #21 0x55919501798a in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:300:30
    #22 0x55919501a054 in non-virtual thunk to base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
    #23 0x559194ed1903 in base::MessagePumpDefault::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_default.cc:40:55
    #24 0x55919501aa8d in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:609:12
    #25 0x559194f5e8ce in base::RunLoop::Run(base::Location const&) base/run_loop.cc:141:14
    #26 0x559195079dd2 in base::Thread::Run(base::RunLoop*) base/threading/thread.cc:338:13
    #27 0x55919507a1ed in base::Thread::ThreadMain() base/threading/thread.cc:408:3
    #28 0x5591950fd845 in base::(anonymous namespace)::ThreadFunc(void*) base/threading/platform_thread_posix.cc:103:13
    #29 0x7f2df2b38608 in start_thread /build/glibc-sMfBJT/glibc-2.31/nptl/pthread_create.c:477:8

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV buildtools/third_party/libc++/trunk/include/string:1674:33 in __is_long
Thread T39 (WebRTC_Network) created by T27 (Chrome_InProcRe) here:
    #0 0x559184aa63da in pthread_create /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors.cpp:208:3
    #1 0x5591950fcbba in base::(anonymous namespace)::CreateThread(unsigned long, bool, base::PlatformThread::Delegate*, base::PlatformThreadHandle*, base::ThreadType, base::MessagePumpType) base/threading/platform_thread_posix.cc:149:13
    #2 0x559195079192 in base::Thread::StartWithOptions(base::Thread::Options) base/threading/thread.cc:211:26
    #3 0x5591a7b2e356 in EnsureChromeThreadsStarted third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc:180:31
    #4 0x5591a7b2e356 in blink::PeerConnectionDependencyFactory::CreatePeerConnectionFactory() third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc:514:16
    #5 0x5591a7b2de9d in blink::PeerConnectionDependencyFactory::GetPcFactory() third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc:501:5
    #6 0x5591a7b374ad in blink::PeerConnectionDependencyFactory::CreatePeerConnection(webrtc::PeerConnectionInterface::RTCConfiguration const&, blink::WebLocalFrame*, webrtc::PeerConnectionObserver*, blink::ExceptionState&) third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc:736:8
    #7 0x5591a7b555cd in blink::RTCPeerConnectionHandler::Initialize(blink::ExecutionContext*, webrtc::PeerConnectionInterface::RTCConfiguration const&, blink::GoogMediaConstraints*, blink::WebLocalFrame*, blink::ExceptionState&) third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc:1095:50
    #8 0x5591aa3a24b6 in blink::RTCPeerConnection::RTCPeerConnection(blink::ExecutionContext*, webrtc::PeerConnectionInterface::RTCConfiguration, bool, blink::GoogMediaConstraints*, blink::ExceptionState&) third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc:612:23
    #9 0x5591aa39d49c in Call<blink::ExecutionContext *&, webrtc::PeerConnectionInterface::RTCConfiguration, bool, blink::GoogMediaConstraints *&, blink::ExceptionState &> v8/include/cppgc/allocation.h:242:32
    #10 0x5591aa39d49c in MakeGarbageCollected<blink::RTCPeerConnection, blink::ExecutionContext *&, webrtc::PeerConnectionInterface::RTCConfiguration, bool, blink::GoogMediaConstraints *&, blink::ExceptionState &> v8/include/cppgc/allocation.h:280:7
    #11 0x5591aa39d49c in MakeGarbageCollected<blink::RTCPeerConnection, blink::ExecutionContext *&, webrtc::PeerConnectionInterface::RTCConfiguration, bool, blink::GoogMediaConstraints *&, blink::ExceptionState &> third_party/blink/renderer/platform/heap/garbage_collected.h:34:10
    #12 0x5591aa39d49c in blink::RTCPeerConnection::Create(blink::ExecutionContext*, blink::RTCConfiguration const*, blink::GoogMediaConstraints*, blink::ExceptionState&) third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc:540:40
    #13 0x5591aa4baf22 in blink::(anonymous namespace)::v8_rtc_peer_connection::ConstructorCallback(v8::FunctionCallbackInfo<v8::Value> const&) gen/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection.cc:612:18
    #14 0x559189b2f1bc in v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) v8/src/api/api-arguments-inl.h:146:3
    #15 0x559189b2bf93 in v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<true>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, unsigned long*, int) v8/src/builtins/builtins-api.cc:112:36
    #16 0x559189b2acde in v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) v8/src/builtins/builtins-api.cc:139:5
    #17 0x55918c8dd437 in Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit setup-isolate-deserialize.cc
    #18 0x55918c8503d1 in Builtins_JSBuiltinsConstructStub setup-isolate-deserialize.cc
    #19 0x55918c98c5d3 in Builtins_ConstructHandler setup-isolate-deserialize.cc
    #20 0x55918c85282b in Builtins_InterpreterEntryTrampoline setup-isolate-deserialize.cc
    #21 0x55918c85282b in Builtins_InterpreterEntryTrampoline setup-isolate-deserialize.cc
    #22 0x55918c850e5b in Builtins_JSEntryTrampoline setup-isolate-deserialize.cc
    #23 0x55918c850b86 in Builtins_JSEntry setup-isolate-deserialize.cc
    #24 0x559189f3fb24 in Call v8/src/execution/simulator.h:155:12
    #25 0x559189f3fb24 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) v8/src/execution/execution.cc:427:33
    #26 0x559189f41375 in v8::internal::Execution::CallScript(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>) v8/src/execution/execution.cc:538:10
    #27 0x5591899cfbf4 in v8::Script::Run(v8::Local<v8::Context>, v8::Local<v8::Data>) v8/src/api/api.cc:2154:7
    #28 0x5591a085fd54 in blink::V8ScriptRunner::RunCompiledScript(v8::Isolate*, v8::Local<v8::Script>, v8::Local<v8::Data>, blink::ExecutionContext*) third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc:409:22
    #29 0x5591a0861444 in blink::V8ScriptRunner::CompileAndRunScript(blink::ScriptState*, blink::ClassicScript*, blink::ExecuteScriptPolicy, blink::V8ScriptRunner::RethrowErrorsOption) third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc:516:22
    #30 0x5591a27a3b5b in blink::ClassicScript::RunScriptOnScriptStateAndReturnValue(blink::ScriptState*, blink::ExecuteScriptPolicy, blink::V8ScriptRunner::RethrowErrorsOption) third_party/blink/renderer/core/script/classic_script.cc:217:10
    #31 0x5591a27ebc51 in blink::Script::RunScriptOnScriptState(blink::ScriptState*, blink::ExecuteScriptPolicy, blink::V8ScriptRunner::RethrowErrorsOption) third_party/blink/renderer/core/script/script.cc:31:17
    #32 0x5591a27ec0d7 in blink::Script::RunScript(blink::LocalDOMWindow*, blink::ExecuteScriptPolicy, blink::V8ScriptRunner::RethrowErrorsOption) third_party/blink/renderer/core/script/script.cc:38:3
    #33 0x5591a28038f3 in blink::PendingScript::ExecuteScriptBlockInternal(blink::Script*, blink::ScriptElementBase*, bool, bool, bool, base::TimeTicks, bool) third_party/blink/renderer/core/script/pending_script.cc:291:13
    #34 0x5591a2802e9c in blink::PendingScript::ExecuteScriptBlock() third_party/blink/renderer/core/script/pending_script.cc:188:3
    #35 0x5591a27f0b4b in blink::ScriptLoader::PrepareScript(blink::ScriptLoader::ParserBlockingInlineOption, WTF::TextPosition const&) third_party/blink/renderer/core/script/script_loader.cc:1259:60
    #36 0x5591a3a2e619 in blink::HTMLParserScriptRunner::ProcessScriptElementInternal(blink::Element*, WTF::TextPosition const&) third_party/blink/renderer/core/script/html_parser_script_runner.cc:535:52
    #37 0x5591a3a2dd8f in blink::HTMLParserScriptRunner::ProcessScriptElement(blink::Element*, WTF::TextPosition const&) third_party/blink/renderer/core/script/html_parser_script_runner.cc:298:3
    #38 0x5591a3a1465a in blink::HTMLDocumentParser::RunScriptsForPausedTreeBuilder() third_party/blink/renderer/core/html/parser/html_document_parser.cc:806:21
    #39 0x5591a3a14aa8 in blink::HTMLDocumentParser::CanTakeNextToken(base::TimeDelta&) third_party/blink/renderer/core/html/parser/html_document_parser.cc:820:5
    #40 0x5591a3a1107c in blink::HTMLDocumentParser::PumpTokenizer() third_party/blink/renderer/core/html/parser/html_document_parser.cc:889:36
    #41 0x5591a3a0ee39 in blink::HTMLDocumentParser::PumpTokenizerIfPossible() third_party/blink/renderer/core/html/parser/html_document_parser.cc:771:15
    #42 0x5591a3a0fa60 in blink::HTMLDocumentParser::DeferredPumpTokenizerIfPossible(bool, base::TimeTicks) third_party/blink/renderer/core/html/parser/html_document_parser.cc:756:7
    #43 0x5591a3a2a58e in Invoke<void (blink::HTMLDocumentParser::*)(bool, base::TimeTicks), cppgc::internal::BasicPersistent<blink::HTMLDocumentParser, cppgc::internal::StrongPersistentPolicy, cppgc::internal::IgnoreLocationPolicy, cppgc::internal::DisabledCheckingPolicy>, bool, base::TimeTicks> base/functional/bind_internal.h:646:12
    #44 0x5591a3a2a58e in MakeItSo<void (blink::HTMLDocumentParser::*)(bool, base::TimeTicks), std::Cr::tuple<cppgc::internal::BasicPersistent<blink::HTMLDocumentParser, cppgc::internal::StrongPersistentPolicy, cppgc::internal::IgnoreLocationPolicy, cppgc::internal::DisabledCheckingPolicy>, bool, base::TimeTicks> > base/functional/bind_internal.h:825:12
    #45 0x5591a3a2a58e in RunImpl<void (blink::HTMLDocumentParser::*)(bool, base::TimeTicks), std::Cr::tuple<cppgc::internal::BasicPersistent<blink::HTMLDocumentParser, cppgc::internal::StrongPersistentPolicy, cppgc::internal::IgnoreLocationPolicy, cppgc::internal::DisabledCheckingPolicy>, bool, base::TimeTicks>, 0UL, 1UL, 2UL> base/functional/bind_internal.h:919:12
    #46 0x5591a3a2a58e in base::internal::Invoker<base::internal::BindState<void (blink::HTMLDocumentParser::*)(bool, base::TimeTicks), cppgc::internal::BasicPersistent<blink::HTMLDocumentParser, cppgc::internal::StrongPersistentPolicy, cppgc::internal::IgnoreLocationPolicy, cppgc::internal::DisabledCheckingPolicy>, bool, base::TimeTicks>, void ()>::RunOnce(base::internal::BindStateBase*) base/functional/bind_internal.h:870:12
    #47 0x559194fd1df9 in Run base/functional/callback.h:174:12
    #48 0x559194fd1df9 in base::TaskAnnotator::RunTaskImpl(base::PendingTask&) base/task/common/task_annotator.cc:154:32
    #49 0x559195012cf3 in RunTask<(lambda at ../../base/task/sequence_manager/thread_controller_impl.cc:213:11)> base/task/common/task_annotator.h:84:5
    #50 0x559195012cf3 in base::sequence_manager::internal::ThreadControllerImpl::DoWork(base::sequence_manager::internal::ThreadControllerImpl::WorkType) base/task/sequence_manager/thread_controller_impl.cc:211:23
    #51 0x559195015869 in Invoke<void (base::sequence_manager::internal::ThreadControllerImpl::*)(base::sequence_manager::internal::ThreadControllerImpl::WorkType), const base::WeakPtr<base::sequence_manager::internal::ThreadControllerImpl> &, const base::sequence_manager::internal::ThreadControllerImpl::WorkType &> base/functional/bind_internal.h:646:12
    #52 0x559195015869 in MakeItSo<void (base::sequence_manager::internal::ThreadControllerImpl::*const &)(base::sequence_manager::internal::ThreadControllerImpl::WorkType), const std::Cr::tuple<base::WeakPtr<base::sequence_manager::internal::ThreadControllerImpl>, base::sequence_manager::internal::ThreadControllerImpl::WorkType> &> base/functional/bind_internal.h:847:5
    #53 0x559195015869 in RunImpl<void (base::sequence_manager::internal::ThreadControllerImpl::*const &)(base::sequence_manager::internal::ThreadControllerImpl::WorkType), const std::Cr::tuple<base::WeakPtr<base::sequence_manager::internal::ThreadControllerImpl>, base::sequence_manager::internal::ThreadControllerImpl::WorkType> &, 0UL, 1UL> base/functional/bind_internal.h:919:12
    #54 0x559195015869 in base::internal::Invoker<base::internal::BindState<void (base::sequence_manager::internal::ThreadControllerImpl::*)(base::sequence_manager::internal::ThreadControllerImpl::WorkType), base::WeakPtr<base::sequence_manager::internal::ThreadControllerImpl>, base::sequence_manager::internal::ThreadControllerImpl::WorkType>, void ()>::Run(base::internal::BindStateBase*) base/functional/bind_internal.h:883:12
    #55 0x559185152df8 in Run base/functional/callback.h:309:12
    #56 0x559185152df8 in void base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()>>::ForwardRepeating<>() base/cancelable_callback.h:121:15
    #57 0x559185153083 in Invoke<void (base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()> >::*)(), const base::WeakPtr<base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()> > > &> base/functional/bind_internal.h:646:12
    #58 0x559185153083 in MakeItSo<void (base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()> >::*const &)(), const std::Cr::tuple<base::WeakPtr<base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()> > > > &> base/functional/bind_internal.h:847:5
    #59 0x559185153083 in RunImpl<void (base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()> >::*const &)(), const std::Cr::tuple<base::WeakPtr<base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()> > > > &, 0UL> base/functional/bind_internal.h:919:12
    #60 0x559185153083 in base::internal::Invoker<base::internal::BindState<void (base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()>>::*)(), base::WeakPtr<base::internal::CancelableCallbackImpl<base::RepeatingCallback<void ()>>>>, void ()>::Run(base::internal::BindStateBase*) base/functional/bind_internal.h:883:12
    #61 0x559194fd1df9 in Run base/functional/callback.h:174:12
    #62 0x559194fd1df9 in base::TaskAnnotator::RunTaskImpl(base::PendingTask&) base/task/common/task_annotator.cc:154:32
    #63 0x559195018c19 in RunTask<(lambda at ../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:451:11)> base/task/common/task_annotator.h:84:5
    #64 0x559195018c19 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:449:23
    #65 0x55919501798a in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:300:30
    #66 0x55919501a054 in non-virtual thunk to base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
    #67 0x559194ed1903 in base::MessagePumpDefault::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_default.cc:40:55
    #68 0x55919501aa8d in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:609:12
    #69 0x559194f5e8ce in base::RunLoop::Run(base::Location const&) base/run_loop.cc:141:14
    #70 0x559195079dd2 in base::Thread::Run(base::RunLoop*) base/threading/thread.cc:338:13
    #71 0x55919507a1ed in base::Thread::ThreadMain() base/threading/thread.cc:408:3
    #72 0x5591950fd845 in base::(anonymous namespace)::ThreadFunc(void*) base/threading/platform_thread_posix.cc:103:13
    #73 0x7f2df2b38608 in start_thread /build/glibc-sMfBJT/glibc-2.31/nptl/pthread_create.c:477:8

Thread T27 (Chrome_InProcRe) created by T0 (chrome) here:
    #0 0x559184aa63da in pthread_create /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors.cpp:208:3
    #1 0x5591950fcbba in base::(anonymous namespace)::CreateThread(unsigned long, bool, base::PlatformThread::Delegate*, base::PlatformThreadHandle*, base::ThreadType, base::MessagePumpType) base/threading/platform_thread_posix.cc:149:13
    #2 0x559195079192 in base::Thread::StartWithOptions(base::Thread::Options) base/threading/thread.cc:211:26
    #3 0x55918e285306 in content::RenderProcessHostImpl::Init() content/browser/renderer_host/render_process_host_impl.cc:1752:27
    #4 0x55918de2690f in content::AgentSchedulingGroupHost::Init() content/browser/renderer_host/agent_scheduling_group_host.cc:265:20
    #5 0x55918e250b7a in InitRenderView content/browser/renderer_host/render_frame_host_manager.cc:3226:52
    #6 0x55918e250b7a in content::RenderFrameHostManager::ReinitializeMainRenderFrame(content::RenderFrameHostImpl*) content/browser/renderer_host/render_frame_host_manager.cc:3449:8
    #7 0x55918e24dd18 in content::RenderFrameHostManager::GetFrameHostForNavigation(content::NavigationRequest*, std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>*) content/browser/renderer_host/render_frame_host_manager.cc:1326:10
    #8 0x55918e24c981 in content::RenderFrameHostManager::DidCreateNavigationRequest(content::NavigationRequest*) content/browser/renderer_host/render_frame_host_manager.cc:1065:37
    #9 0x55918dec6aea in content::FrameTreeNode::CreatedNavigationRequest(std::Cr::unique_ptr<content::NavigationRequest, std::Cr::default_delete<content::NavigationRequest>>) content/browser/renderer_host/frame_tree_node.cc:613:21
    #10 0x55918e135114 in content::Navigator::Navigate(std::Cr::unique_ptr<content::NavigationRequest, std::Cr::default_delete<content::NavigationRequest>>, content::ReloadType) content/browser/renderer_host/navigator.cc:733:20
    #11 0x55918e080f68 in content::NavigationControllerImpl::NavigateWithoutEntry(content::NavigationController::LoadURLParams const&) content/browser/renderer_host/navigation_controller_impl.cc:3638:21
    #12 0x55918e08022e in content::NavigationControllerImpl::LoadURLWithParams(content::NavigationController::LoadURLParams const&) content/browser/renderer_host/navigation_controller_impl.cc:1289:10
    #13 0x5591a547ebd6 in (anonymous namespace)::LoadURLInContents(content::WebContents*, GURL const&, NavigateParams*) chrome/browser/ui/browser_navigator.cc:486:43
    #14 0x5591a547be45 in Navigate(NavigateParams*) chrome/browser/ui/browser_navigator.cc:781:27
    #15 0x5591a5556082 in StartupBrowserCreatorImpl::OpenTabsInBrowser(Browser*, chrome::startup::IsProcessStartup, std::Cr::vector<StartupTab, std::Cr::allocator<StartupTab>> const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:319:5
    #16 0x5591a5558de7 in StartupBrowserCreatorImpl::RestoreOrCreateBrowser(std::Cr::vector<StartupTab, std::Cr::allocator<StartupTab>> const&, StartupBrowserCreatorImpl::BrowserOpenBehavior, unsigned int, chrome::startup::IsProcessStartup, bool) chrome/browser/ui/startup/startup_browser_creator_impl.cc:658:13
    #17 0x5591a555504d in StartupBrowserCreatorImpl::DetermineURLsAndLaunch(chrome::startup::IsProcessStartup) chrome/browser/ui/startup/startup_browser_creator_impl.cc:454:22
    #18 0x5591a5554114 in StartupBrowserCreatorImpl::Launch(Profile*, chrome::startup::IsProcessStartup, std::Cr::unique_ptr<OldLaunchModeRecorder, std::Cr::default_delete<OldLaunchModeRecorder>>) chrome/browser/ui/startup/startup_browser_creator_impl.cc:184:32
    #19 0x5591a554b16c in StartupBrowserCreator::LaunchBrowser(base::CommandLine const&, Profile*, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, std::Cr::unique_ptr<OldLaunchModeRecorder, std::Cr::default_delete<OldLaunchModeRecorder>>) chrome/browser/ui/startup/startup_browser_creator.cc:683:9
    #20 0x5591a554cab7 in StartupBrowserCreator::ProcessLastOpenedProfiles(base::CommandLine const&, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, Profile*, std::Cr::vector<Profile*, std::Cr::allocator<Profile*>> const&) chrome/browser/ui/startup/startup_browser_creator.cc:1310:5
    #21 0x5591a554c232 in StartupBrowserCreator::LaunchBrowserForLastProfiles(base::CommandLine const&, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, StartupProfileInfo, std::Cr::vector<Profile*, std::Cr::allocator<Profile*>> const&) chrome/browser/ui/startup/startup_browser_creator.cc:754:3
    #22 0x5591a554a839 in StartupBrowserCreator::ProcessCmdLineImpl(base::CommandLine const&, base::FilePath const&, chrome::startup::IsProcessStartup, StartupProfileInfo, std::Cr::vector<Profile*, std::Cr::allocator<Profile*>> const&) chrome/browser/ui/startup/startup_browser_creator.cc:1261:3
    #23 0x5591a5548c7f in StartupBrowserCreator::Start(base::CommandLine const&, base::FilePath const&, StartupProfileInfo, std::Cr::vector<Profile*, std::Cr::allocator<Profile*>> const&) chrome/browser/ui/startup/startup_browser_creator.cc:638:10
    #24 0x559193ef94f4 in ChromeBrowserMainParts::PreMainMessageLoopRunImpl() chrome/browser/chrome_browser_main.cc:1715:25
    #25 0x559193ef7a05 in ChromeBrowserMainParts::PreMainMessageLoopRun() chrome/browser/chrome_browser_main.cc:1120:18
    #26 0x55918d1fd35d in content::BrowserMainLoop::PreMainMessageLoopRun() content/browser/browser_main_loop.cc:952:28
    #27 0x55918d20284f in Invoke<int (content::BrowserMainLoop::*)(), content::BrowserMainLoop *> base/functional/bind_internal.h:646:12
    #28 0x55918d20284f in MakeItSo<int (content::BrowserMainLoop::*)(), std::Cr::tuple<base::internal::UnretainedWrapper<content::BrowserMainLoop, base::RawPtrBanDanglingIfSupported> > > base/functional/bind_internal.h:825:12
    #29 0x55918d20284f in RunImpl<int (content::BrowserMainLoop::*)(), std::Cr::tuple<base::internal::UnretainedWrapper<content::BrowserMainLoop, base::RawPtrBanDanglingIfSupported> >, 0UL> base/functional/bind_internal.h:919:12
    #30 0x55918d20284f in base::internal::Invoker<base::internal::BindState<int (content::BrowserMainLoop::*)(), base::internal::UnretainedWrapper<content::BrowserMainLoop, base::RawPtrBanDanglingIfSupported>>, int ()>::RunOnce(base::internal::BindStateBase*) base/functional/bind_internal.h:870:12
    #31 0x55918e666de8 in Run base/functional/callback.h:174:12
    #32 0x55918e666de8 in content::StartupTaskRunner::RunAllTasksNow() content/browser/startup_task_runner.cc:43:29
    #33 0x55918d1fc8c2 in content::BrowserMainLoop::CreateStartupTasks() content/browser/browser_main_loop.cc:863:25
    #34 0x55918d204ad3 in content::BrowserMainRunnerImpl::Initialize(content::MainFunctionParams) content/browser/browser_main_runner_impl.cc:141:15
    #35 0x55918d1f8b22 in content::BrowserMain(content::MainFunctionParams) content/browser/browser_main.cc:26:32
    #36 0x559193d41374 in content::RunBrowserProcessMain(content::MainFunctionParams, content::ContentMainDelegate*) content/app/content_main_runner_impl.cc:691:10
    #37 0x559193d444c6 in content::ContentMainRunnerImpl::RunBrowser(content::MainFunctionParams, bool) content/app/content_main_runner_impl.cc:1228:10
    #38 0x559193d43dd1 in content::ContentMainRunnerImpl::Run() content/app/content_main_runner_impl.cc:1083:12
    #39 0x559193d3c66d in content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*) content/app/content_main.cc:342:36
    #40 0x559193d3cc79 in content::ContentMain(content::ContentMainParams) content/app/content_main.cc:370:10
    #41 0x559184af0ead in ChromeMain chrome/app/chrome_main.cc:174:12
    #42 0x7f2df12cc0b2 in __libc_start_main /build/glibc-sMfBJT/glibc-2.31/csu/../csu/libc-start.c:308:16

==2308409==ABORTING
VENDOR RESPONSE

This vulnerability was independently discovered by Talos and reported to Google. Another researcher, Cassidy Kim, had also submitted their report to Google prior to the Talos disclosure. We believe our analysis provides extra value to the community and are thus also publishing our report.

TIMELINE

2023-01-18 - Disclosure to Google by Cisco Talos
2023-01-19 - Google is able to replicate the results based on the Talos report
2023-01-20 - Patch created based on the Talos report
2023-01-20 - Marked as duplicate of the previous report
2023-02-07 - Patch released in stable channel
2023-05-04 - Public disclosure of report

Credit

Discovered by Jaewon Min of Cisco Talos.