Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in PrivateAI
DescriptionUse after free in PrivateAI
ComponentPrivateAI
Bug ClassUAF
Tracker485397279
Fix commit84d05b258ef8 (chromium/src) +524/-70
CISA KEVNot listed
CreditedKrace
Disclosed2026-04-07

Changed Functions

FunctionChangeNotes
source_set
components/private_ai/BUILD.gn
modified
IntegrationConnectionFactory
components/private_ai/client_impl_integration_test.cc
modified
logger_
components/private_ai/client_impl_integration_test.cc
modified
ClientImplIntegrationTest
components/private_ai/client_impl_integration_test.cc
modified
TEST_F
components/private_ai/client_impl_integration_test.cc
modified

Files Changed

  • components/private_ai/BUILD.gn
  • components/private_ai/client_impl_integration_test.cc
From 84d05b258ef82a9d3f0a2317167868861f7cea66 Mon Sep 17 00:00:00 2001
From: Christian Dullweber <[email protected]>
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 <[email protected]>
> Reviewed-by: Oleh Lamzin <[email protected]>
> Auto-Submit: Christian Dullweber <[email protected]>
> Commit-Queue: Oleh Lamzin <[email protected]>
> 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 <[email protected]>
Reviewed-by: Oleh Lamzin <[email protected]>
Commit-Queue: Christian Dullweber <[email protected]>
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();
Loading diff…

Regression Test / PoC

shipped with the fix
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)
Loading diff…

Original Bug Report

reported by [email protected]

Security: Heap-use-after-free in SecureChannelImpl::OnDecryptedResponse

Steps to reproduce the problem

  1. apply the change.txt to the newest Chromium and compile chrome with ASAN
  2. Run chrome with : ./chrome --user-data-dir=/tmp/noexist --enable-features=ZeroStateSuggestionsUseLegion,Legion
  3. 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: ClientImplConnectionBasicSecureChannelImpl.

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 \

View on issue tracker