CVE-2026-5874
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
source_setcomponents/private_ai/BUILD.gn |
modified | |
IntegrationConnectionFactorycomponents/private_ai/client_impl_integration_test.cc |
modified | |
logger_components/private_ai/client_impl_integration_test.cc |
modified | |
ClientImplIntegrationTestcomponents/private_ai/client_impl_integration_test.cc |
modified | |
TEST_Fcomponents/private_ai/client_impl_integration_test.cc |
modified |
Files Changed
components/private_ai/BUILD.gncomponents/private_ai/client_impl_integration_test.cc
Patch
From 84d05b258ef82a9d3f0a2317167868861f7cea66 Mon Sep 17 00:00:00 2001
From: Christian Dullweber <dullweber@chromium.org>
Date: Thu, 26 Feb 2026 07:48:00 -0800
Subject: [PATCH] Reland "Legion: Clear disconnect handler on destroy"
This is a reland of commit a05183da7089f1b2cedf6eab0ac1e92499309761
Original change's description:
> Legion: Clear disconnect handler on destroy
>
> Ensure that we only call one disconnect handler per disconnect.
> Add integration tests for the whole ClientImpl+Connection stack.
>
> Bug: 485397279
> Change-Id: I58498cdf00eb68836bf272bf0b2a25f32ef760b7
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7602453
> Commit-Queue: Christian Dullweber <dullweber@chromium.org>
> Reviewed-by: Oleh Lamzin <lamzin@google.com>
> Auto-Submit: Christian Dullweber <dullweber@chromium.org>
> Commit-Queue: Oleh Lamzin <lamzin@google.com>
> Cr-Commit-Position: refs/heads/main@{#1590168}
Cq-Include-Trybots: luci.chromium.try:linux_chromium_msan_rel_ng
Bug: 485397279
Change-Id: Ia3acb8b62a318e62f991bdf15e5d31ee0337bf90
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7610708
Auto-Submit: Christian Dullweber <dullweber@chromium.org>
Reviewed-by: Oleh Lamzin <lamzin@google.com>
Commit-Queue: Christian Dullweber <dullweber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1590816}
---
diff --git a/components/private_ai/BUILD.gn b/components/private_ai/BUILD.gn
index c0f60d8f8..7d69b730 100644
--- a/components/private_ai/BUILD.gn
+++ b/components/private_ai/BUILD.gn
@@ -102,6 +102,8 @@
sources = [
"testing/fake_connection.cc",
"testing/fake_connection.h",
+ "testing/fake_secure_channel.cc",
+ "testing/fake_secure_channel.h",
"testing/fake_token_manager.cc",
"testing/fake_token_manager.h",
"testing/mock_private_ai_client.h",
@@ -118,6 +120,7 @@
source_set("unit_tests") {
testonly = true
sources = [
+ "client_impl_integration_test.cc",
"client_impl_unittest.cc",
"connection_basic_unittest.cc",
"connection_metrics_unittest.cc",
diff --git a/components/private_ai/client_impl_integration_test.cc b/components/private_ai/client_impl_integration_test.cc
new file mode 100644
index 0000000..d9ef0bc95
--- /dev/null
+++ b/components/private_ai/client_impl_integration_test.cc
@@ -0,0 +1,341 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/run_until.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/types/expected.h"
+#include "components/private_ai/client_impl.h"
+#include "components/private_ai/common/private_ai_logger.h"
+#include "components/private_ai/connection_basic.h"
+#include "components/private_ai/connection_metrics.h"
+#include "components/private_ai/connection_timeout.h"
+#include "components/private_ai/connection_token_attestation.h"
+#include "components/private_ai/error_code.h"
+#include "components/private_ai/private_ai_common.h"
+#include "components/private_ai/proto/private_ai.pb.h"
+#include "components/private_ai/secure_channel.h"
+#include "components/private_ai/testing/fake_secure_channel.h"
+#include "components/private_ai/testing/fake_token_manager.h"
+#include "services/network/test/test_network_context.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace private_ai {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Invoke;
+
+class IntegrationConnectionFactory : public ConnectionFactory {
+ public:
+ IntegrationConnectionFactory(
+ FakeSecureChannelFactory::OnCreatedCallback on_secure_channel_created,
+ FakeSecureChannelFactory::OnDestroyedCallback on_secure_channel_destroyed,
+ phosphor::TokenManager* token_manager,
+ PrivateAiLogger* logger)
+ : on_secure_channel_created_(std::move(on_secure_channel_created)),
+ on_secure_channel_destroyed_(std::move(on_secure_channel_destroyed)),
+ token_manager_(token_manager),
+ logger_(logger) {}
+
+ std::unique_ptr<Connection> Create(
+ base::OnceCallback<void(ErrorCode)> on_disconnect) override {
+ auto split_on_disconnect =
+ base::SplitOnceCallback(std::move(on_disconnect));
+
+ auto secure_channel_factory = std::make_unique<FakeSecureChannelFactory>(
+ on_secure_channel_created_, on_secure_channel_destroyed_);
+
+ std::unique_ptr<Connection> connection =
+ std::make_unique<ConnectionBasic>(std::move(secure_channel_factory),
+ std::move(split_on_disconnect.first));
+
+ connection = std::make_unique<ConnectionMetrics>(std::move(connection));
+
+ connection = std::make_unique<ConnectionTimeout>(std::move(connection));
+
+ connection = std::make_unique<ConnectionTokenAttestation>(
+ std::move(connection), token_manager_, logger_,
+ std::move(split_on_disconnect.second));
+
+ return connection;
+ }
+
+ private:
+ FakeSecureChannelFactory::OnCreatedCallback on_secure_channel_created_;
+ FakeSecureChannelFactory::OnDestroyedCallback on_secure_channel_destroyed_;
+ raw_ptr<phosphor::TokenManager> token_manager_;
+ raw_ptr<PrivateAiLogger> logger_;
+};
+
+} // namespace
+
+class ClientImplIntegrationTest : public testing::Test {
+ public:
+ void SetUp() override {
+ auto logger = std::make_unique<PrivateAiLogger>();
+ PrivateAiLogger* logger_ptr = logger.get();
+ auto factory = std::make_unique<IntegrationConnectionFactory>(
+ base::BindRepeating(
+ &ClientImplIntegrationTest::on_secure_channel_created,
+ base::Unretained(this)),
+ base::BindRepeating(
+ &ClientImplIntegrationTest::on_secure_channel_destroyed,
+ base::Unretained(this)),
+ &token_manager_, logger_ptr);
+
+ client_ =
+ std::make_unique<ClientImpl>(std::move(factory), std::move(logger));
+ }
+
+ void TearDown() override {
+ // Ensure that all SecureChannels are destroyed.
+ client_.reset();
+ ASSERT_TRUE(
+ base::test::RunUntil([&]() { return secure_channels_.empty(); }));
+ }
+
+ void on_secure_channel_created(FakeSecureChannel* secure_channel) {
+ secure_channels_.push_back(secure_channel);
+ }
+
+ void on_secure_channel_destroyed(FakeSecureChannel* secure_channel) {
+ std::erase(secure_channels_, secure_channel);
+ }
+
+ FakeSecureChannel* last_secure_channel() {
+ if (secure_channels_.empty()) {
+ return nullptr;
+ }
+ return secure_channels_.back();
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+ FakeTokenManager token_manager_;
+ std::vector<raw_ptr<FakeSecureChannel>> secure_channels_;
+ std::unique_ptr<ClientImpl> client_;
+};
+
+TEST_F(ClientImplIntegrationTest, FullStackSuccess) {
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future;
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "hello", future.GetCallback(), /*options=*/{});
+
+ // 1. Attestation starts. FakeTokenManager gets a request.
+ EXPECT_EQ(token_manager_.GetPendingCallbackCount(), 1u);
+ token_manager_.RunPendingCallbacks();
Regression Test / PoC
diff --git a/components/private_ai/client_impl_integration_test.cc b/components/private_ai/client_impl_integration_test.cc
new file mode 100644
index 0000000..d9ef0bc95
--- /dev/null
+++ b/components/private_ai/client_impl_integration_test.cc
@@ -0,0 +1,341 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/run_until.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/types/expected.h"
+#include "components/private_ai/client_impl.h"
+#include "components/private_ai/common/private_ai_logger.h"
+#include "components/private_ai/connection_basic.h"
+#include "components/private_ai/connection_metrics.h"
+#include "components/private_ai/connection_timeout.h"
+#include "components/private_ai/connection_token_attestation.h"
+#include "components/private_ai/error_code.h"
+#include "components/private_ai/private_ai_common.h"
+#include "components/private_ai/proto/private_ai.pb.h"
+#include "components/private_ai/secure_channel.h"
+#include "components/private_ai/testing/fake_secure_channel.h"
+#include "components/private_ai/testing/fake_token_manager.h"
+#include "services/network/test/test_network_context.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace private_ai {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Invoke;
+
+class IntegrationConnectionFactory : public ConnectionFactory {
+ public:
+ IntegrationConnectionFactory(
+ FakeSecureChannelFactory::OnCreatedCallback on_secure_channel_created,
+ FakeSecureChannelFactory::OnDestroyedCallback on_secure_channel_destroyed,
+ phosphor::TokenManager* token_manager,
+ PrivateAiLogger* logger)
+ : on_secure_channel_created_(std::move(on_secure_channel_created)),
+ on_secure_channel_destroyed_(std::move(on_secure_channel_destroyed)),
+ token_manager_(token_manager),
+ logger_(logger) {}
+
+ std::unique_ptr<Connection> Create(
+ base::OnceCallback<void(ErrorCode)> on_disconnect) override {
+ auto split_on_disconnect =
+ base::SplitOnceCallback(std::move(on_disconnect));
+
+ auto secure_channel_factory = std::make_unique<FakeSecureChannelFactory>(
+ on_secure_channel_created_, on_secure_channel_destroyed_);
+
+ std::unique_ptr<Connection> connection =
+ std::make_unique<ConnectionBasic>(std::move(secure_channel_factory),
+ std::move(split_on_disconnect.first));
+
+ connection = std::make_unique<ConnectionMetrics>(std::move(connection));
+
+ connection = std::make_unique<ConnectionTimeout>(std::move(connection));
+
+ connection = std::make_unique<ConnectionTokenAttestation>(
+ std::move(connection), token_manager_, logger_,
+ std::move(split_on_disconnect.second));
+
+ return connection;
+ }
+
+ private:
+ FakeSecureChannelFactory::OnCreatedCallback on_secure_channel_created_;
+ FakeSecureChannelFactory::OnDestroyedCallback on_secure_channel_destroyed_;
+ raw_ptr<phosphor::TokenManager> token_manager_;
+ raw_ptr<PrivateAiLogger> logger_;
+};
+
+} // namespace
+
+class ClientImplIntegrationTest : public testing::Test {
+ public:
+ void SetUp() override {
+ auto logger = std::make_unique<PrivateAiLogger>();
+ PrivateAiLogger* logger_ptr = logger.get();
+ auto factory = std::make_unique<IntegrationConnectionFactory>(
+ base::BindRepeating(
+ &ClientImplIntegrationTest::on_secure_channel_created,
+ base::Unretained(this)),
+ base::BindRepeating(
+ &ClientImplIntegrationTest::on_secure_channel_destroyed,
+ base::Unretained(this)),
+ &token_manager_, logger_ptr);
+
+ client_ =
+ std::make_unique<ClientImpl>(std::move(factory), std::move(logger));
+ }
+
+ void TearDown() override {
+ // Ensure that all SecureChannels are destroyed.
+ client_.reset();
+ ASSERT_TRUE(
+ base::test::RunUntil([&]() { return secure_channels_.empty(); }));
+ }
+
+ void on_secure_channel_created(FakeSecureChannel* secure_channel) {
+ secure_channels_.push_back(secure_channel);
+ }
+
+ void on_secure_channel_destroyed(FakeSecureChannel* secure_channel) {
+ std::erase(secure_channels_, secure_channel);
+ }
+
+ FakeSecureChannel* last_secure_channel() {
+ if (secure_channels_.empty()) {
+ return nullptr;
+ }
+ return secure_channels_.back();
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+ FakeTokenManager token_manager_;
+ std::vector<raw_ptr<FakeSecureChannel>> secure_channels_;
+ std::unique_ptr<ClientImpl> client_;
+};
+
+TEST_F(ClientImplIntegrationTest, FullStackSuccess) {
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future;
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "hello", future.GetCallback(), /*options=*/{});
+
+ // 1. Attestation starts. FakeTokenManager gets a request.
+ EXPECT_EQ(token_manager_.GetPendingCallbackCount(), 1u);
+ token_manager_.RunPendingCallbacks();
+
+ // 2. SecureChannel (Basic) is created and gets the attestation request.
+ auto* channel = last_secure_channel();
+ ASSERT_TRUE(channel);
+ EXPECT_TRUE(channel->last_written_request().has_anonymous_token_request());
+
+ // 3. Respond to attestation.
+ proto::PrivateAiResponse attestation_response;
+ attestation_response.set_request_id(
+ channel->last_written_request().request_id());
+ channel->send_back_response(attestation_response);
+
+ // 4. Now the original text request should be sent.
+ EXPECT_TRUE(channel->last_written_request().has_generate_content_request());
+
+ // 5. Respond to text request.
+ proto::PrivateAiResponse text_response;
+ text_response.set_request_id(channel->last_written_request().request_id());
+ text_response.mutable_generate_content_response()
+ ->add_candidates()
+ ->mutable_content()
+ ->add_parts()
+ ->set_text("world");
+ channel->send_back_response(text_response);
+
+ // 6. Verify final result.
+ auto result = future.Get();
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(result.value(), "world");
+}
+
+TEST_F(ClientImplIntegrationTest, AttestationFailure) {
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future;
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "hello", future.GetCallback(), /*options=*/{});
+
+ // 1. Attestation starts.
+ EXPECT_EQ(token_manager_.GetPendingCallbackCount(), 1u);
+ // Simulate token fetch failure.
+ token_manager_.RespondToGetAuthToken(std::nullopt);
+
+ // 2. Client should receive an error.
+ auto result = future.Get();
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error(), ErrorCode::kClientAttestationFailed);
+}
+
+TEST_F(ClientImplIntegrationTest, Timeout) {
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future;
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "hello", future.GetCallback(),
+ {.timeout = base::Seconds(5)});
+
+ // Complete attestation successfully.
+ token_manager_.RunPendingCallbacks();
+ auto* channel = last_secure_channel();
+ ASSERT_TRUE(channel);
+ proto::PrivateAiResponse attestation_response;
+ attestation_response.set_request_id(
+ channel->last_written_request().request_id());
+ channel->send_back_response(attestation_response);
+
+ // Text request is sent.
+ EXPECT_TRUE(channel->last_written_request().has_generate_content_request());
+
+ // Wait for timeout.
+ task_environment_.FastForwardBy(base::Seconds(6));
+
+ // Verify timeout error.
+ auto result = future.Get();
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error(), ErrorCode::kTimeout);
+}
+
+TEST_F(ClientImplIntegrationTest, ConcurrentRequestsDuringAttestation) {
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future1;
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future2;
+
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "request1", future1.GetCallback(), /*options=*/{});
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "request2", future2.GetCallback(), /*options=*/{});
+
+ // 1. Attestation starts (only one token fetch should be triggered).
+ EXPECT_EQ(token_manager_.GetPendingCallbackCount(), 1u);
+ token_manager_.RunPendingCallbacks();
+
+ auto* channel = last_secure_channel();
+ ASSERT_TRUE(channel);
+
+ // 2. Complete attestation.
+ proto::PrivateAiResponse attestation_response;
+ attestation_response.set_request_id(
+ channel->last_written_request().request_id());
+ channel->send_back_response(attestation_response);
+
+ // 3. Now both requests should be sent.
+ ASSERT_EQ(channel->written_requests().size(), 3u);
+
+ // Handle request 1
+ EXPECT_EQ(channel->written_requests()[1]
+ .generate_content_request()
+ .contents(0)
+ .parts(0)
+ .text(),
+ "request1");
+ int32_t id1 = channel->written_requests()[1].request_id();
+ proto::PrivateAiResponse resp1;
+ resp1.set_request_id(id1);
+ resp1.mutable_generate_content_response()
+ ->add_candidates()
+ ->mutable_content()
+ ->add_parts()
+ ->set_text("response1");
+ channel->send_back_response(resp1);
+
+ // Handle request 2
+ EXPECT_EQ(channel->written_requests()[2]
+ .generate_content_request()
+ .contents(0)
+ .parts(0)
+ .text(),
+ "request2");
+ int32_t id2 = channel->written_requests()[2].request_id();
+ proto::PrivateAiResponse resp2;
+ resp2.set_request_id(id2);
+ resp2.mutable_generate_content_response()
+ ->add_candidates()
+ ->mutable_content()
+ ->add_parts()
+ ->set_text("response2");
+ channel->send_back_response(resp2);
+
+ // 4. Verify both results.
+ EXPECT_EQ(future1.Get().value(), "response1");
+ EXPECT_EQ(future2.Get().value(), "response2");
+}
+
+TEST_F(ClientImplIntegrationTest, DisconnectDuringAttestation) {
+ base::test::TestFuture<base::expected<std::string, ErrorCode>> future;
+ client_->SendTextRequest(proto::FeatureName::FEATURE_NAME_UNSPECIFIED,
+ "hello", future.GetCallback(), /*options=*/{});
+
+ // 1. Attestation starts.
+ token_manager_.RunPendingCallbacks();
+ auto* channel = last_secure_channel();
+ ASSERT_TRUE(channel);
+
+ // 2. Simulate channel disconnect before responding to attestation.
+ channel->send_back_error(ErrorCode::kNetworkError);
+
+ // 3. The original request should fail with the disconnect error.
+ ASSERT_TRUE(future.IsReady());
... (truncated)
Original Bug Report
Security: Heap-use-after-free in SecureChannelImpl::OnDecryptedResponse
Steps to reproduce the problem
- apply the change.txt to the newest Chromium and compile chrome with ASAN
- Run chrome with :
./chrome --user-data-dir=/tmp/noexist --enable-features=ZeroStateSuggestionsUseLegion,Legion - Move mouse to the “Ask Gemini” button. (Don’t need to click)
Note that this UAF can be exploited to escape the sandbox without requiring a compromised renderer. The patch I provided only simulates a successful decryption operation to trigger the callback, and does not affect Chromium’s original logic
Bisect This UAF is introduced in this commit: https://chromium-review.googlesource.com/c/chromium/src/+/7139550 According to the commit, this UAF affects Chrome Stable 144.0.7559.59.
Problem Description
Vulnerability Analysis
In the SecureChannleImpl class, response_callback_ deletes the SecureChannleImpl instance itself [1]. Therefore, any reference to |this| after invoking the callback will result in a use-after-free vulnerability.
[1]
void SecureChannelImpl::OnDecryptedResponse(
const std::optional<Request>& decrypted_response) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!decrypted_response.has_value()) {
DLOG(ERROR) << "Failed to decrypt response.";
FailAllRequestsAndClose(ErrorCode::kDecryptionFailed);
return;
}
DVLOG(1) << "Response decrypted successfully.";
CHECK(response_callback_);
response_callback_.Run(base::ok(*decrypted_response)); //@audit: the response_callback_ will delete |this|
ProcessPendingEncryptionRequests();
}
void SecureChannelImpl::ProcessPendingEncryptionRequests() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(state_, State::kEstablished);
if (state_ != State::kEstablished) { //@audit: use after |this| hase been deleted
return;
}
SecureChannelImpl is owned by a std::unique_ptr created by ConnectionBasic [2], which itself is owned by a std::unique_ptr in ClientImpl [3][4]. This establishes an ownership chain: ClientImpl → ConnectionBasic → SecureChannelImpl.
ConnectionBasic is reset in ClientImpl::OnConnectionDisconnected() [5]. This function is registered as a callback in ConnectionBasic, which in turn passes ConnectionBasic::OnResponseReceived to SecureChannelImpl as a callback. When triggered, this callback ultimately deletes ClientImpl, thereby destroying ConnectionBasic and, consequently, SecureChannelImpl.
[2]
ConnectionBasic::ConnectionBasic(
std::unique_ptr<SecureChannel::Factory> secure_channel_factory,
base::OnceClosure on_disconnect)
: on_disconnect_(std::move(on_disconnect)) {
CHECK(secure_channel_factory);
CHECK(on_disconnect_);
secure_channel_ = secure_channel_factory->Create(base::BindRepeating(
&ConnectionBasic::OnResponseReceived, weak_factory_.GetWeakPtr()));
CHECK(secure_channel_);
}
[3]
std::unique_ptr<Connection> CreateBasicMetricsTimeoutConnection(
const GURL& url,
network::mojom::NetworkContext* network_context,
LegionLogger* logger,
base::OnceClosure on_disconnect) {
auto connection_basic = std::make_unique<ConnectionBasic>(
std::make_unique<SecureChannelImpl::FactoryImpl>(url, network_context,
logger),
std::move(on_disconnect));
auto connection_metrics =
std::make_unique<ConnectionMetrics>(std::move(connection_basic));
auto connection_timeout =
std::make_unique<ConnectionTimeout>(std::move(connection_metrics));
return connection_timeout;
}
[4]
Connection* ClientImpl::GetOrCreateConnection() {
if (!connection_) {
connection_ = connection_factory_->Create(base::BindRepeating(
&ClientImpl::OnConnectionDisconnected, base::Unretained(this)));
}
return connection_.get();
}
[5]
void ClientImpl::OnConnectionDisconnected() {
logger_->LogInfo(FROM_HERE,
"Connection disconnected. Destroying connection.");
connection_.reset();
}
[1] https://source.chromium.org/chromium/chromium/src/+/main:components/legion/secure_channel_impl.cc;l=357 [2] https://source.chromium.org/chromium/chromium/src/+/main:components/legion/connection_basic.cc;l=26 [3] https://source.chromium.org/chromium/chromium/src/+/main:components/legion/connection_factory_impl.cc;l=33 [4] https://source.chromium.org/chromium/chromium/src/+/main:components/legion/client_impl.cc;l=95 [5] https://source.chromium.org/chromium/chromium/src/+/main:components/legion/client_impl.cc;l=183
Summary
Security: Heap-use-after-free in SecureChannelImpl::OnDecryptedResponse
Custom Questions
Type of crash:
browser
Crash state:
================================================================= ==608920==ERROR: AddressSanitizer: heap-use-after-free on address 0x7c1f73a6fca0 at pc 0x5653945f5dc2 bp 0x7ffc213669d0 sp 0x7ffc213669c8 READ of size 4 at 0x7c1f73a6fca0 thread T0 (chrome) #0 0x5653945f5dc1 in legion::SecureChannelImpl::ProcessPendingEncryptionRequests() components/legion/secure_channel_impl.cc:421:7 #1 0x5653945f6ce2 in legion::SecureChannelImpl::OnDecryptedResponse(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) components/legion/secure_channel_impl.cc:367:3 #2 0x5653945f8980 in base::internal::Invoker<base::internal::FunctorTraits<void (legion::SecureChannelImpl::&&)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), base::WeakPtrlegion::SecureChannelImpl&&>, base::internal::BindState<true, true, false, void (legion::SecureChannelImpl::)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), base::WeakPtrlegion::SecureChannelImpl>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::RunOnce(base::internal::BindStateBase*, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/bind_internal.h:740:12 #3 0x565394607987 in base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>::Run(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/callback.h:155:12 #4 0x565394607bc5 in base::internal::Invoker<base::internal::FunctorTraits<void (base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>::* const&)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>, std::__Cr::default_delete<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>>> const&>, base::internal::BindState<true, true, false, void (base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>::)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>, std::__Cr::default_delete<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>>>>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::Run(base::internal::BindStateBase, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/bind_internal.h:740:12 #5 0x565394603ecb in base::internal::Invoker<base::internal::FunctorTraits<legion::SecureSessionAsyncImpl::Decrypt(oak::session::v1::EncryptedMessage const&, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>)::$_0&&, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>&&>, base::internal::BindState<false, false, false, legion::SecureSessionAsyncImpl::Decrypt(oak::session::v1::EncryptedMessage const&, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>)::$_0, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::RunOnce(base::internal::BindStateBase*, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/callback.h:155:12 #6 0x565394607212 in mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::Run(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/callback.h:155:12 #7 0x565394607435 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::&&)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>, std::__Cr::default_delete<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>>>&&>, base::internal::BindState<true, true, false, void (mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>, std::__Cr::default_delete<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>>>>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::RunOnce(base::internal::BindStateBase*, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/bind_internal.h:740:12 #8 0x56539461ff5d in legion::mojom::OakSession_Decrypt_ForwardToCallback::Accept(mojo::Message*) base/functional/callback.h:155:12 #9 0x7f4ff243391f in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:1079:41 #10 0x7f4ff244a65b in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19 #11 0x7f4ff2438b64 in mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:747:20 #12 0x7f4ff2459c1e in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:1204:42 #13 0x7f4ff245844d in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:790:7 #14 0x7f4ff244a65b in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19 #15 0x7f4ff241eeff in mojo::Connector::DispatchMessage(mojo::ScopedHandleBasemojo::MessageHandle) mojo/public/cpp/bindings/lib/connector.cc:568:49 #16 0x7f4ff242074e in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:629:14 #17 0x7f4ff24201e7 in mojo::Connector::OnWatcherHandleReady(char const*, unsigned int) mojo/public/cpp/bindings/lib/connector.cc:454:3 #18 0x7f4ff2422dd1 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::Connector::* const&)(char const*, unsigned int), mojo::Connector*, char const* const&>, base::internal::BindState<true, true, false, void (mojo::Connector::)(char const, unsigned int), base::internal::UnretainedWrapper<mojo::Connector, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>, base::internal::UnretainedWrapper<char const, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void (unsigned int)>::Run(base::internal::BindStateBase*, unsigned int) base/functional/bind_internal.h:740:12 #19 0x7f4ff242247e in base::RepeatingCallback<void (unsigned int)>::Run(unsigned int) const & base/functional/callback.h:343:12 #20 0x7f4ff2422234 in base::internal::Invoker<base::internal::FunctorTraits<void (* const&)(base::RepeatingCallback<void (unsigned int)> const&, unsigned int, mojo::HandleSignalsState const&), base::RepeatingCallback<void (unsigned int)> const&>, base::internal::BindState<false, true, false, void ()(base::RepeatingCallback<void (unsigned int)> const&, unsigned int, mojo::HandleSignalsState const&), base::RepeatingCallback<void (unsigned int)>>, void (unsigned int, mojo::HandleSignalsState const&)>::Run(base::internal::BindStateBase, unsigned int, mojo::HandleSignalsState const&) base/functional/bind_internal.h:673:12 #21 0x7f4ff0767430 in base::RepeatingCallback<void (unsigned int, mojo::HandleSignalsState const&)>::Run(unsigned int, mojo::HandleSignalsState const&) const & base/functional/callback.h:343:12 #22 0x7f4ff0766e0b in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:286:14 #23 0x7f4ff0767e74 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::SimpleWatcher::&&)(int, unsigned int, mojo::HandleSignalsState const&), base::WeakPtrmojo::SimpleWatcher&&, int&&, unsigned int&&, mojo::HandleSignalsState&&>, base::internal::BindState<true, true, false, void (mojo::SimpleWatcher::)(int, unsigned int, mojo::HandleSignalsState const&), base::WeakPtrmojo::SimpleWatcher, int, unsigned int, mojo::HandleSignalsState>, void ()>::RunOnce(base::internal::BindStateBase*) base/functional/bind_internal.h:740:12 #24 0x7f4ff1c8d8b2 in base::TaskAnnotator::RunTaskImpl(base::PendingTask&) base/functional/callback.h:155:12 #25 0x7f4ff1d0ee2e in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) base/task/common/task_annotator.h:112:5 #26 0x7f4ff1d0de06 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:346:40 #27 0x7f4ff1ee2737 in base::MessagePumpGlib::HandleDispatch() base/message_loop/message_pump_glib.cc:736:46 #28 0x7f4ff1ee5ee2 in base::(anonymous namespace)::WorkSourceDispatch(_GSource*, int ()(void), void*) base/message_loop/message_pump_glib.cc:355:43 #29 0x7f4f82e7617c in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x5217c) (BuildId: 2c1d2f9d4a08c71a36797aeb246ab7ae377934ea)
0x7c1f73a6fca0 is located 32 bytes inside of 144-byte region [0x7c1f73a6fc80,0x7c1f73a6fd10) freed by thread T0 (chrome) here: #0 0x56539178f4d2 in operator delete(void*, unsigned long) (/home/krace/fuzz/chromium/src/out/ui/chrome+0x67e64d2) (BuildId: 3cd4a8fa4a7bd132) #1 0x5653945e1635 in legion::ConnectionBasic::~ConnectionBasic() gen/third_party/libc++/src/include/__memory/unique_ptr.h:74:5 #2 0x5653945e7d07 in legion::ConnectionMetrics::~ConnectionMetrics() gen/third_party/libc++/src/include/__memory/unique_ptr.h:74:5 #3 0x5653945edc8c in legion::ConnectionTimeout::~ConnectionTimeout() gen/third_party/libc++/src/include/__memory/unique_ptr.h:74:5 #4 0x5653945f0334 in legion::ConnectionTokenAttestation::~ConnectionTokenAttestation() gen/third_party/libc++/src/include/__memory/unique_ptr.h:74:5 #5 0x5653945d9f0c in legion::ClientImpl::OnConnectionDisconnected() gen/third_party/libc++/src/include/__memory/unique_ptr.h:74:5 #6 0x5653945dd862 in base::internal::Invoker<base::internal::FunctorTraits<void (legion::ClientImpl::* const&)(), legion::ClientImpl*>, base::internal::BindState<true, true, false, void (legion::ClientImpl::)(), base::internal::UnretainedWrapper<legion::ClientImpl, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void ()>::Run(base::internal::BindStateBase) base/functional/bind_internal.h:740:12 #7 0x5653945e20de in legion::ConnectionBasic::HandleDisconnect(legion::ErrorCode) base/functional/callback.h:155:12 #8 0x5653945e0f2d in legion::ConnectionBasic::OnResponseReceived(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>) components/legion/connection_basic.cc:71:5 #9 0x5653945e297b in void base::internal::DecayedFunctorTraits<void (legion::ConnectionBasic::)(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>), base::WeakPtrlegion::ConnectionBasic const&>::Invoke<void (legion::ConnectionBasic::)(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>), base::WeakPtrlegion::ConnectionBasic const&, base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>>(void (legion::ConnectionBasic::)(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>), base::WeakPtrlegion::ConnectionBasic const&, base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>&&) base/functional/bind_internal.h:740:12 #10 0x5653945e26b2 in base::internal::Invoker<base::internal::FunctorTraits<void (legion::ConnectionBasic:: const&)(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>), base::WeakPtrlegion::ConnectionBasic const&>, base::internal::BindState<true, true, false, void (legion::ConnectionBasic::)(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>), base::WeakPtrlegion::ConnectionBasic>, void (base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>)>::Run(base::internal::BindStateBase, base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>&&) base/functional/bind_internal.h:956:5 #11 0x5653945f712f in base::RepeatingCallback<void (base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>)>::Run(base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>) const & base/functional/callback.h:343:12 #12 0x5653945f6ca5 in legion::SecureChannelImpl::OnDecryptedResponse(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) components/legion/secure_channel_impl.cc:365:22 #13 0x5653945f8980 in base::internal::Invoker<base::internal::FunctorTraits<void (legion::SecureChannelImpl::&&)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), base::WeakPtrlegion::SecureChannelImpl&&>, base::internal::BindState<true, true, false, void (legion::SecureChannelImpl::)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), base::WeakPtrlegion::SecureChannelImpl>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::RunOnce(base::internal::BindStateBase*, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/bind_internal.h:740:12 #14 0x565394607987 in base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>::Run(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/callback.h:155:12 #15 0x565394607bc5 in base::internal::Invoker<base::internal::FunctorTraits<void (base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>::* const&)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>, std::__Cr::default_delete<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>>> const&>, base::internal::BindState<true, true, false, void (base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>::)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>, std::__Cr::default_delete<base::internal::OnceCallbackHolder<std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&>>>>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::Run(base::internal::BindStateBase, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/bind_internal.h:740:12 #16 0x565394603ecb in base::internal::Invoker<base::internal::FunctorTraits<legion::SecureSessionAsyncImpl::Decrypt(oak::session::v1::EncryptedMessage const&, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>)::$_0&&, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>&&>, base::internal::BindState<false, false, false, legion::SecureSessionAsyncImpl::Decrypt(oak::session::v1::EncryptedMessage const&, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>)::$_0, base::OnceCallback<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::RunOnce(base::internal::BindStateBase*, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/callback.h:155:12 #17 0x565394607212 in mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::Run(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/callback.h:155:12 #18 0x565394607435 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::&&)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>, std::__Cr::default_delete<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>>>&&>, base::internal::BindState<true, true, false, void (mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::)(std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&), std::__Cr::unique_ptr<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>, std::__Cr::default_delete<mojo::internal::CallbackWithDeleteHelper<void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>>>>, void (std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&)>::RunOnce(base::internal::BindStateBase*, std::__Cr::optional<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>> const&) base/functional/bind_internal.h:740:12 #19 0x56539461ff5d in legion::mojom::OakSession_Decrypt_ForwardToCallback::Accept(mojo::Message*) base/functional/callback.h:155:12 #20 0x7f4ff243391f in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:1079:41 #21 0x7f4ff244a65b in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19 #22 0x7f4ff2438b64 in mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:747:20 #23 0x7f4ff2459c1e in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:1204:42 #24 0x7f4ff245844d in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:790:7 #25 0x7f4ff244a65b in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19 #26 0x7f4ff241eeff in mojo::Connector::DispatchMessage(mojo::ScopedHandleBasemojo::MessageHandle) mojo/public/cpp/bindings/lib/connector.cc:568:49 #27 0x7f4ff242074e in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:629:14 #28 0x7f4ff24201e7 in mojo::Connector::OnWatcherHandleReady(char const*, unsigned int) mojo/public/cpp/bindings/lib/connector.cc:454:3 #29 0x7f4ff2422dd1 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::Connector::* const&)(char const*, unsigned int), mojo::Connector*, char const* const&>, base::internal::BindState<true, true, false, void (mojo::Connector::)(char const, unsigned int), base::internal::UnretainedWrapper<mojo::Connector, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>, base::internal::UnretainedWrapper<char const, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void (unsigned int)>::Run(base::internal::BindStateBase*, unsigned int) base/functional/bind_internal.h:740:12
previously allocated by thread T0 (chrome) here: #0 0x56539178e8cd in operator new(unsigned long) (/home/krace/fuzz/chromium/src/out/ui/chrome+0x67e58cd) (BuildId: 3cd4a8fa4a7bd132) #1 0x5653945f3b60 in legion::SecureChannelImpl::FactoryImpl::Create(base::RepeatingCallback<void (base::expected<std::__Cr::vector<unsigned char, std::__Cr::allocator<unsigned char>>, legion::ErrorCode>)>) gen/third_party/libc++/src/include/__memory/unique_ptr.h:756:26 #2 0x5653945e0692 in legion::ConnectionBasic::ConnectionBasic(std::__Cr::unique_ptr<legion::SecureChannel::Factory, std::__Cr::default_deletelegion::SecureChannel::Factory>, base::OnceCallback<void ()>) components/legion/connection_basic.cc:26:45 #3 0x5653945e61f3 in legion::(anonymous namespace)::CreateTokenAttestationConnection(GURL const&, legion::phosphor::TokenManager*, base::RepeatingCallback<void ()>, network::mojom::NetworkContext*) gen/third_party/libc++/src/include/__memory/unique_ptr.h:756:30 #4 0x5653945e5f14 in legion::TokenConnectionFactoryImpl::Create(base::RepeatingCallback<void ()>) components/legion/connection_factory_impl.cc:101:10 #5 0x5653945d9c96 in legion::ClientImpl::GetOrCreateConnection() components/legion/client_impl.cc:90:40 #6 0x5653945d98dd in legion::ClientImpl::EstablishSession(base::OnceCallback<void (base::expected<void, legion::ErrorCode>)>) components/legion/client_impl.cc:84:3 #7 0x56539ec13bc6 in TabStripActionContainer::OnGlicButtonHovered() chrome/browser/ui/views/tabs/tab_strip_action_container.cc:99:17 #8 0x56539ec1b8c2 in base::internal::Invoker<base::internal::FunctorTraits<void (TabStripActionContainer::* const&)(), TabStripActionContainer*>, base::internal::BindState<true, true, false, void (TabStripActionContainer::)(), base::internal::UnretainedWrapper<TabStripActionContainer, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void ()>::Run(base::internal::BindStateBase) base/functional/bind_internal.h:740:12 #9 0x565391f2accf in base::RepeatingCallback<void ()>::Run() const & base/functional/callback.h:343:12 #10 0x565397089f4e in glic::TabStripGlicButton::StateChanged(views::Button::ButtonState) chrome/browser/ui/views/tabs/glic/tab_strip_glic_button.cc:475:25 #11 0x7f4fc1dfc1d9 in views::Button::SetState(views::Button::ButtonState) ui/views/controls/button/button.cc:263:3 #12 0x7f4feca86fd4 in ui::ScopedTargetHandler::OnEvent(ui::Event*) ui/events/scoped_target_handler.cc:30:24 #13 0x7f4feca6e308 in ui::EventDispatcher::DispatchEvent(ui::EventHandler*, ui::Event*) ui/events/event_dispatcher.cc:189:12 #14 0x7f4feca6ce6b in ui::EventDispatcher::ProcessEvent(ui::EventTarget*, ui::Event*) ui/events/event_dispatcher.cc:138:5 #15 0x7f4feca6c5c4 in ui::EventDispatcherDelegate::DispatchEventToTarget(ui::EventTarget*, ui::Event*) ui/events/event_dispatcher.cc:84:14 #16 0x7f4feca6c0fa in ui::EventDispatcherDelegate::DispatchEvent(ui::EventTarget*, ui::Event*) ui/events/event_dispatcher.cc:56:15 #17 0x7f4fc2100a96 in views::internal::RootView::HandleMouseEnteredOrMoved(ui::MouseEvent const&) ui/views/widget/root_view.cc:912:13 #18 0x7f4fc21320e0 in views::Widget::OnMouseEvent(ui::MouseEvent*) ui/views/widget/widget.cc #19 0x7f4fc2200b95 in views::DesktopNativeWidgetAura::OnMouseEvent(ui::MouseEvent*) ui/views/widget/desktop_aura/desktop_native_widget_aura.cc:1445:30 #20 0x7f4feca6e308 in ui::EventDispatcher::DispatchEvent(ui::EventHandler*, ui::Event*) ui/events/event_dispatcher.cc:189:12 #21 0x7f4feca6ce6b in ui::EventDispatcher::ProcessEvent(ui::EventTarget*, ui::Event*) ui/events/event_dispatcher.cc:138:5 #22 0x7f4feca6c5c4 in ui::EventDispatcherDelegate::DispatchEventToTarget(ui::EventTarget*, ui::Event*) ui/events/event_dispatcher.cc:84:14 #23 0x7f4feca6c0fa in ui::EventDispatcherDelegate::DispatchEvent(ui::EventTarget*, ui::Event*) ui/events/event_dispatcher.cc:56:15 #24 0x7f4feca74aaf in ui::EventProcessor::OnEventFromSource(ui::Event*) ui/events/event_processor.cc:72:19 #25 0x7f4feca78051 in ui::EventSource::DeliverEventToSink(ui::Event*) ui/events/event_source.cc:119:16 #26 0x7f4feca779f4 in ui::EventSource::SendEventToSinkFromRewriter(ui::Event const*, ui::EventRewriter const*) ui/events/event_source.cc:134:12 #27 0x7f4fd1706fbd in aura::WindowTreeHostPlatform::DispatchEvent(ui::Event*) ui/aura/window_tree_host_platform.cc:300:38 #28 0x7f4fc2208d38 in views::DesktopWindowTreeHostLinux::DispatchEvent(ui::Event*) ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc:250:29 #29 0x7f4ff2c31487 in base::internal::Invoker<base::internal::FunctorTraits<void (ui::PlatformWindowDelegate::&&)(ui::Event), ui::PlatformWindowDelegate*>, base::internal::BindState<true, true, false, void (ui::PlatformWindowDelegate::)(ui::Event), base::internal::UnretainedWrapper<ui::PlatformWindowDelegate, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void (ui::Event*)>::RunOnce(base::internal::BindStateBase*, ui::Event*) base/functional/bind_internal.h:740:12
SUMMARY: AddressSanitizer: heap-use-after-free components/legion/secure_channel_impl.cc:421:7 in legion::SecureChannelImpl::ProcessPendingEncryptionRequests() Shadow bytes around the buggy address: 0x7c1f73a6fa00: f7 fa fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x7c1f73a6fa80: fd fd fd fa fa fa fa fa fa fa f7 fa fd fd fd fd 0x7c1f73a6fb00: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa 0x7c1f73a6fb80: fa fa fa fa f7 fa fd fd fd fd fd fd fd fd fd fd 0x7c1f73a6fc00: fd fd fd fd fd fd fd fa fa fa fa fa fa fa f7 fa =>0x7c1f73a6fc80: fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd 0x7c1f73a6fd00: fd fd fa fa fa fa fa fa f7 fa fd fd fd fd fd fd 0x7c1f73a6fd80: fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa 0x7c1f73a6fe00: fa fa f7 fa fd fd fd fd fd fd fd fd fd fd fd fd 0x7c1f73a6fe80: fd fd fd fd fd fd fa fa fa fa fa fa f7 fa fd fd 0x7c1f73a6ff00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb
==608920==ADDITIONAL INFO
==608920==Note: Please include this section with the ASan report. Task trace: #0 0x7f4ff076782a in mojo::SimpleWatcher::Context::Notify(unsigned int, MojoHandleSignalsState, unsigned int) mojo/public/cpp/system/simple_watcher.cc:103:13
Command line: /home/krace/fuzz/chromium/src/out/ui/chrome --user-data-dir=/tmp/noexist --enable-features=ZeroStateSuggestionsUseLegion,Legion --flag-switches-begin --flag-switches-end --ozone-platform=x11
MiraclePtr Status: NOT PROTECTED No raw_ptr<T> access to this region was detected prior to this crash. This crash is still exploitable with MiraclePtr. Refer to https://chromium.googlesource.com/chromium/src/+/main/base/memory/raw_ptr.md for details.
==608920==END OF ADDITIONAL INFO
==608920==ABORTING
Reporter credit:
Please only credit: Krace
Additional Data
Category: Security
Chrome Channel: Stable
Regression: N/A \
- https://chromium-review.googlesource.com/c/chromium/src/+/7139550
- https://chromium.googlesource.com/chromium/src/+/main/base/memory/raw_ptr.md
- https://source.chromium.org/chromium/chromium/src/+/main:components/legion/client_impl.cc;l=183
- https://source.chromium.org/chromium/chromium/src/+/main:components/legion/client_impl.cc;l=95
- https://source.chromium.org/chromium/chromium/src/+/main:components/legion/connection_basic.cc;l=26
- https://source.chromium.org/chromium/chromium/src/+/main:components/legion/connection_factory_impl.cc;l=33
- https://source.chromium.org/chromium/chromium/src/+/main:components/legion/secure_channel_impl.cc;l=357