Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactSide-channel information leakage in ComputePressure
DescriptionSide-channel information leakage in ComputePressure
ComponentComputePressure
Bug ClassLogic Error
Tracker513009005
Fix commit4d118b514ddf (chromium/src) +96/-259
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
switch
content/browser/compute_pressure/pressure_client_impl.cc
modified

Files Changed

  • content/browser/compute_pressure/pressure_client_impl.cc
  • content/browser/compute_pressure/pressure_service_base.h
  • content/browser/compute_pressure/pressure_service_browsertest.cc
  • content/browser/compute_pressure/pressure_service_for_dedicated_worker.cc
From 4d118b514ddf83168b58d69c89aabd4570394568 Mon Sep 17 00:00:00 2001
From: Wei Wang <wei4.wang@intel.com>
Date: Sat, 23 May 2026 04:13:39 -0700
Subject: [PATCH] [PATCH 4/4] Revert "compute pressure: Calculate ownContributionEstimate"

This reverts commit c18b6b45fa249d8f36e56d481d08c4cd90f510ce.

This feature is creating information leak. There is no active
development on this feature anymore, therefore it was decided to
revert the patches related to this feature.

Bug: 513009005
Change-Id: I84fcc6da05b8c80272120ed6e822eedc56bd61e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7863882
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Commit-Queue: Wang, Wei4 <wei4.wang@intel.com>
Reviewed-by: Mike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1635415}
---

diff --git a/content/browser/compute_pressure/pressure_client_impl.cc b/content/browser/compute_pressure/pressure_client_impl.cc
index 257295f4..1b8c314c8 100644
--- a/content/browser/compute_pressure/pressure_client_impl.cc
+++ b/content/browser/compute_pressure/pressure_client_impl.cc
@@ -25,22 +25,14 @@
     device::mojom::PressureState state;
     switch (update->source) {
       case device::mojom::PressureSource::kCpu:
-        // No update from the virtual pressure source.
-        if (update->data->own_contribution_estimate ==
-            device::mojom::kDefaultOwnContributionEstimate) {
-          update->data->own_contribution_estimate =
-              service_->CalculateOwnContributionEstimate(
-                  update->data->cpu_utilization);
-        }
         state = service_->CalculateState(update->data->cpu_utilization);
         break;
       default:
         NOTREACHED();
     }
     client_associated_remote_->OnPressureUpdated(
-        blink::mojom::WebPressureUpdate::New(
-            update->source, state, update->data->own_contribution_estimate,
-            update->timestamp));
+        blink::mojom::WebPressureUpdate::New(update->source, state,
+                                             update->timestamp));
   }
 }
 
diff --git a/content/browser/compute_pressure/pressure_service_base.h b/content/browser/compute_pressure/pressure_service_base.h
index 19d0237..c59d7af 100644
--- a/content/browser/compute_pressure/pressure_service_base.h
+++ b/content/browser/compute_pressure/pressure_service_base.h
@@ -61,9 +61,7 @@
 
   // Verifies if the data should be delivered according to focus status.
   virtual bool ShouldDeliverUpdate() const = 0;
-  virtual double CalculateOwnContributionEstimate(
-      double global_cpu_utilization) = 0;
-  device::mojom::PressureState CalculateState(double global_cpu_utilization);
+  device::mojom::PressureState CalculateState(double cpu_utilization);
 
   // Returns a token for use with automation calls when one is set.
   virtual std::optional<base::UnguessableToken> GetTokenFor(
diff --git a/content/browser/compute_pressure/pressure_service_browsertest.cc b/content/browser/compute_pressure/pressure_service_browsertest.cc
index 7b40a360..f96fde6 100644
--- a/content/browser/compute_pressure/pressure_service_browsertest.cc
+++ b/content/browser/compute_pressure/pressure_service_browsertest.cc
@@ -154,8 +154,7 @@
 
   // Deliver update.
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.30,
-                                device::mojom::kDefaultOwnContributionEstimate);
+  auto data = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_.UpdateClients(std::move(update));
 
@@ -187,8 +186,7 @@
 
   // Deliver update.
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.30,
-                                device::mojom::kDefaultOwnContributionEstimate);
+  auto data = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_.UpdateClients(std::move(update));
 
@@ -220,8 +218,7 @@
 
   // Deliver update.
   const base::TimeTicks time1 = base::TimeTicks::Now();
-  auto data1 = PressureData::New(
-      /*cpu_utilization=*/0.30, device::mojom::kDefaultOwnContributionEstimate);
+  auto data1 = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1);
   pressure_manager_overrider_.UpdateClients(std::move(update1));
 
@@ -230,8 +227,7 @@
 
   // Deliver update.
   const base::TimeTicks time2 = time1 + base::Seconds(2);
-  auto data2 = PressureData::New(
-      /*cpu_utilization=*/0.70, device::mojom::kDefaultOwnContributionEstimate);
+  auto data2 = PressureData::New(/*cpu_utilization=*/0.70);
   PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2);
   pressure_manager_overrider_.UpdateClients(std::move(update2));
 
@@ -271,8 +267,7 @@
 
   // Deliver update.
   const base::TimeTicks time1 = base::TimeTicks::Now();
-  auto data1 = PressureData::New(
-      /*cpu_utilization=*/0.30, device::mojom::kDefaultOwnContributionEstimate);
+  auto data1 = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1);
   pressure_manager_overrider_.UpdateClients(std::move(update1));
 
@@ -296,8 +291,7 @@
 
   // Deliver update.
   const base::TimeTicks time2 = time1 + base::Seconds(2);
-  auto data2 = PressureData::New(
-      /*cpu_utilization=*/0.85, device::mojom::kDefaultOwnContributionEstimate);
+  auto data2 = PressureData::New(/*cpu_utilization=*/0.85);
   PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2);
   pressure_manager_overrider_.UpdateClients(std::move(update2));
 
@@ -306,8 +300,7 @@
 
   // Deliver update.
   const base::TimeTicks time3 = time2 + base::Seconds(2);
-  auto data3 = PressureData::New(
-      /*cpu_utilization=*/0.85, device::mojom::kDefaultOwnContributionEstimate);
+  auto data3 = PressureData::New(/*cpu_utilization=*/0.85);
   PressureUpdate update3(PressureSource::kCpu, std::move(data3), time3);
   pressure_manager_overrider_.UpdateClients(std::move(update3));
 
@@ -343,8 +336,7 @@
 
   // Deliver update.
   const base::TimeTicks time1 = base::TimeTicks::Now();
-  auto data1 = PressureData::New(
-      /*cpu_utilization=*/0.30, device::mojom::kDefaultOwnContributionEstimate);
+  auto data1 = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1);
   pressure_manager_overrider_.UpdateClients(std::move(update1));
 
@@ -367,8 +359,7 @@
 
   // Deliver update.
   const base::TimeTicks time2 = time1 + base::Seconds(2);
-  auto data2 = PressureData::New(
-      /*cpu_utilization=*/0.70, device::mojom::kDefaultOwnContributionEstimate);
+  auto data2 = PressureData::New(/*cpu_utilization=*/0.70);
   PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2);
   pressure_manager_overrider_.UpdateClients(std::move(update2));
 
@@ -377,8 +368,7 @@
 
   // Deliver update.
   const base::TimeTicks time3 = time2 + base::Seconds(2);
-  auto data3 = PressureData::New(
-      /*cpu_utilization=*/0.85, device::mojom::kDefaultOwnContributionEstimate);
+  auto data3 = PressureData::New(/*cpu_utilization=*/0.85);
   PressureUpdate update3(PressureSource::kCpu, std::move(data3), time3);
   pressure_manager_overrider_.UpdateClients(std::move(update3));
 
diff --git a/content/browser/compute_pressure/pressure_service_for_dedicated_worker.cc b/content/browser/compute_pressure/pressure_service_for_dedicated_worker.cc
index addec96..67fec718 100644
--- a/content/browser/compute_pressure/pressure_service_for_dedicated_worker.cc
+++ b/content/browser/compute_pressure/pressure_service_for_dedicated_worker.cc
@@ -4,28 +4,16 @@
 
 #include "content/browser/compute_pressure/pressure_service_for_dedicated_worker.h"
 
-#include "base/system/sys_info.h"
 #include "content/browser/compute_pressure/web_contents_pressure_manager_proxy.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/worker_host/dedicated_worker_host.h"
-#include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace content {
 
 PressureServiceForDedicatedWorker::PressureServiceForDedicatedWorker(
     DedicatedWorkerHost* host)
-    : worker_host_(host),
-      metrics_(
-#if BUILDFLAG(IS_MAC)
-          base::ProcessMetrics::CreateProcessMetrics(
-              host->GetProcessHost()->GetProcess().Handle(),
-              BrowserChildProcessHost::GetPortProvider())
-#else
-          base::ProcessMetrics::CreateProcessMetrics(
-              host->GetProcessHost()->GetProcess().Handle())
-#endif  // BUILDFLAG(IS_MAC)
-      ) {
+    : worker_host_(host) {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/compute_pressure/pressure_service_browsertest.cc b/content/browser/compute_pressure/pressure_service_browsertest.cc
index 7b40a360..f96fde6 100644
--- a/content/browser/compute_pressure/pressure_service_browsertest.cc
+++ b/content/browser/compute_pressure/pressure_service_browsertest.cc
@@ -154,8 +154,7 @@
 
   // Deliver update.
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.30,
-                                device::mojom::kDefaultOwnContributionEstimate);
+  auto data = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_.UpdateClients(std::move(update));
 
@@ -187,8 +186,7 @@
 
   // Deliver update.
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.30,
-                                device::mojom::kDefaultOwnContributionEstimate);
+  auto data = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_.UpdateClients(std::move(update));
 
@@ -220,8 +218,7 @@
 
   // Deliver update.
   const base::TimeTicks time1 = base::TimeTicks::Now();
-  auto data1 = PressureData::New(
-      /*cpu_utilization=*/0.30, device::mojom::kDefaultOwnContributionEstimate);
+  auto data1 = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1);
   pressure_manager_overrider_.UpdateClients(std::move(update1));
 
@@ -230,8 +227,7 @@
 
   // Deliver update.
   const base::TimeTicks time2 = time1 + base::Seconds(2);
-  auto data2 = PressureData::New(
-      /*cpu_utilization=*/0.70, device::mojom::kDefaultOwnContributionEstimate);
+  auto data2 = PressureData::New(/*cpu_utilization=*/0.70);
   PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2);
   pressure_manager_overrider_.UpdateClients(std::move(update2));
 
@@ -271,8 +267,7 @@
 
   // Deliver update.
   const base::TimeTicks time1 = base::TimeTicks::Now();
-  auto data1 = PressureData::New(
-      /*cpu_utilization=*/0.30, device::mojom::kDefaultOwnContributionEstimate);
+  auto data1 = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1);
   pressure_manager_overrider_.UpdateClients(std::move(update1));
 
@@ -296,8 +291,7 @@
 
   // Deliver update.
   const base::TimeTicks time2 = time1 + base::Seconds(2);
-  auto data2 = PressureData::New(
-      /*cpu_utilization=*/0.85, device::mojom::kDefaultOwnContributionEstimate);
+  auto data2 = PressureData::New(/*cpu_utilization=*/0.85);
   PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2);
   pressure_manager_overrider_.UpdateClients(std::move(update2));
 
@@ -306,8 +300,7 @@
 
   // Deliver update.
   const base::TimeTicks time3 = time2 + base::Seconds(2);
-  auto data3 = PressureData::New(
-      /*cpu_utilization=*/0.85, device::mojom::kDefaultOwnContributionEstimate);
+  auto data3 = PressureData::New(/*cpu_utilization=*/0.85);
   PressureUpdate update3(PressureSource::kCpu, std::move(data3), time3);
   pressure_manager_overrider_.UpdateClients(std::move(update3));
 
@@ -343,8 +336,7 @@
 
   // Deliver update.
   const base::TimeTicks time1 = base::TimeTicks::Now();
-  auto data1 = PressureData::New(
-      /*cpu_utilization=*/0.30, device::mojom::kDefaultOwnContributionEstimate);
+  auto data1 = PressureData::New(/*cpu_utilization=*/0.30);
   PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1);
   pressure_manager_overrider_.UpdateClients(std::move(update1));
 
@@ -367,8 +359,7 @@
 
   // Deliver update.
   const base::TimeTicks time2 = time1 + base::Seconds(2);
-  auto data2 = PressureData::New(
-      /*cpu_utilization=*/0.70, device::mojom::kDefaultOwnContributionEstimate);
+  auto data2 = PressureData::New(/*cpu_utilization=*/0.70);
   PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2);
   pressure_manager_overrider_.UpdateClients(std::move(update2));
 
@@ -377,8 +368,7 @@
 
   // Deliver update.
   const base::TimeTicks time3 = time2 + base::Seconds(2);
-  auto data3 = PressureData::New(
-      /*cpu_utilization=*/0.85, device::mojom::kDefaultOwnContributionEstimate);
+  auto data3 = PressureData::New(/*cpu_utilization=*/0.85);
   PressureUpdate update3(PressureSource::kCpu, std::move(data3), time3);
   pressure_manager_overrider_.UpdateClients(std::move(update3));
diff --git a/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc b/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc
index 4c920da..0d469eb 100644
--- a/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc
+++ b/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc
@@ -182,8 +182,7 @@
             device::mojom::PressureManagerAddClientResult::kOk);
 
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.4,
-                                /*own_contribution_estimate=*/0.20);
+  auto data = PressureData::New(/*cpu_utilization=*/0.4);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_->UpdateClients(update);
   client.WaitForUpdate();
@@ -191,7 +190,6 @@
   ASSERT_EQ(client.updates().size(), 1u);
   EXPECT_EQ(client.updates()[0].source, update.source);
   EXPECT_EQ(client.updates()[0].state, device::mojom::PressureState::kNominal);
-  EXPECT_EQ(client.updates()[0].own_contribution_estimate, 0.20);
   EXPECT_EQ(client.updates()[0].timestamp, update.timestamp);
 }
diff --git a/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc b/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc
index d5b0fe4..1b9958b 100644
--- a/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc
+++ b/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc
@@ -188,15 +188,13 @@
   ASSERT_EQ(future.Get(), device::mojom::PressureManagerAddClientResult::kOk);
 
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.2,
-                                /*own_contribution_estimate=*/0.20);
+  auto data = PressureData::New(/*cpu_utilization=*/0.2);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_->UpdateClients(update);
   client.WaitForUpdate();
   ASSERT_EQ(client.updates().size(), 1u);
   EXPECT_EQ(client.updates()[0].source, update.source);
   EXPECT_EQ(client.updates()[0].state, device::mojom::PressureState::kNominal);
-  EXPECT_EQ(client.updates()[0].own_contribution_estimate, 0.20);
   EXPECT_EQ(client.updates()[0].timestamp, update.timestamp);
 }
 
@@ -338,15 +336,13 @@
   ASSERT_EQ(future.Get(), device::mojom::PressureManagerAddClientResult::kOk);
 
   const base::TimeTicks time = base::TimeTicks::Now();
-  auto data = PressureData::New(/*cpu_utilization=*/0.4,
-                                /*own_contribution_estimate=*/0.20);
+  auto data = PressureData::New(/*cpu_utilization=*/0.4);
   PressureUpdate update(PressureSource::kCpu, std::move(data), time);
   pressure_manager_overrider_->UpdateClients(update);
   client.WaitForUpdate();
   ASSERT_EQ(client.updates().size(), 1u);
   EXPECT_EQ(client.updates()[0].source, update.source);
   EXPECT_EQ(client.updates()[0].state, device::mojom::PressureState::kNominal);
-  EXPECT_EQ(client.updates()[0].own_contribution_estimate, 0.20);
   EXPECT_EQ(client.updates()[0].timestamp, update.timestamp);
 }
diff --git a/services/device/compute_pressure/pressure_manager_impl_unittest.cc b/services/device/compute_pressure/pressure_manager_impl_unittest.cc
index 22a00930..55e778a3 100644
--- a/services/device/compute_pressure/pressure_manager_impl_unittest.cc
+++ b/services/device/compute_pressure/pressure_manager_impl_unittest.cc
@@ -150,11 +150,10 @@
 
   bool UpdateVirtualPressureSource(const base::UnguessableToken& token,
                                    mojom::PressureSource source,
-                                   mojom::PressureState state,
-                                   double own_contribution_estimate) {
+                                   mojom::PressureState state) {
     base::test::TestFuture<void> future;
-    manager_->UpdateVirtualPressureSourceData(
-        token, source, state, own_contribution_estimate, future.GetCallback());
+    manager_->UpdateVirtualPressureSourceState(token, source, state,
+                                               future.GetCallback());
     return future.Wait();
   }
 
@@ -280,8 +279,7 @@
       mojom::PressureManagerAddClientResult::kOk);
 
   EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                          mojom::PressureState::kCritical,
-                                          /*own_pressure_estimate=*/0.5));
+                                          mojom::PressureState::kCritical));
 
   FakePressureClient::WaitForUpdates({&client, &virtual_client});
 
@@ -314,8 +312,7 @@
   client.SetNextUpdateCallback(base::BindOnce(
       []() { FAIL() << "The update callback should not have been called"; }));
   EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                          mojom::PressureState::kCritical,
-                                          /*own_pressure_estimate=*/0.5));
+                                          mojom::PressureState::kCritical));
   task_environment_.RunUntilIdle();
   EXPECT_TRUE(client.updates().empty());
 }
@@ -343,9 +340,8 @@
   for (size_t i = 0; i < static_cast<size_t>(mojom::PressureState::kMaxValue);
        ++i) {
     mojom::PressureState state = static_cast<mojom::PressureState>(i);
-    EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                            state,
-                                            /*own_pressure_estimate=*/0.5));
+    EXPECT_TRUE(
+        UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu, state));
 
     virtual_client.WaitForUpdate();
 
@@ -361,8 +357,7 @@
 
   // Pressure source was removed.
   EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                          mojom::PressureState::kCritical,
-                                          /*own_pressure_estimate=*/0.5));
+                                          mojom::PressureState::kCritical));
   task_environment_.RunUntilIdle();
   EXPECT_EQ(virtual_client.updates().size(), update_count);
 }
@@ -380,9 +375,8 @@
 
   const mojom::PressureState state = mojom::PressureState::kSerious;
 
-  EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                          state,
-                                          /*own_pressure_estimate=*/0.5));
+  EXPECT_TRUE(
+      UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu, state));
 
   virtual_client.WaitForUpdate();
   virtual_client.WaitForUpdate();
@@ -407,16 +401,14 @@
 
   const mojom::PressureState state = mojom::PressureState::kSerious;
 
-  EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                          state,
-                                          /*own_pressure_estimate=*/0.5));
+  EXPECT_TRUE(
+      UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu, state));
 
   virtual_client.WaitForUpdate();
   ASSERT_EQ(virtual_client.updates().size(), 1U);
 
-  EXPECT_TRUE(UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu,
-                                          state,
-                                          /*own_pressure_estimate=*/0.5));
+  EXPECT_TRUE(
+      UpdateVirtualPressureSource(token, mojom::PressureSource::kCpu, state));
 
   virtual_client.WaitForUpdate();
   ASSERT_EQ(virtual_client.updates().size(), 2U);
diff --git a/services/device/public/cpp/test/scoped_pressure_manager_overrider.h b/services/device/public/cpp/test/scoped_pressure_manager_overrider.h
index f56e170a..7df0c50 100644
--- a/services/device/public/cpp/test/scoped_pressure_manager_overrider.h
+++ b/services/device/public/cpp/test/scoped_pressure_manager_overrider.h
@@ -48,12 +48,11 @@
       const base::UnguessableToken& token,
       mojom::PressureSource source,
       RemoveVirtualPressureSourceCallback callback) override {}
-  void UpdateVirtualPressureSourceData(
+  void UpdateVirtualPressureSourceState(
       const base::UnguessableToken& token,
       mojom::PressureSource source,
       mojom::PressureState state,
-      double own_contribution_estimate,
-      UpdateVirtualPressureSourceDataCallback callback) override {}
+      UpdateVirtualPressureSourceStateCallback callback) override {}
 
   bool is_supported_ = true;
   mojo::ReceiverSet<mojom::PressureManager> manager_receivers_;
diff --git a/third_party/blink/public/test/mojom/compute_pressure/web_pressure_manager_automation.test-mojom b/third_party/blink/public/test/mojom/compute_pressure/web_pressure_manager_automation.test-mojom
index 25a6393..1863733 100644
--- a/third_party/blink/public/test/mojom/compute_pressure/web_pressure_manager_automation.test-mojom
+++ b/third_party/blink/public/test/mojom/compute_pressure/web_pressure_manager_automation.test-mojom
@@ -13,7 +13,8 @@
   kSourceTypeAlreadyOverridden,
 };
 
-enum UpdateVirtualPressureSourceDataResult {
+// Result of UpdateVirtualPressureSourceState
+enum UpdateVirtualPressureSourceStateResult {
   kSuccess,
   kSourceTypeNotOverridden,
 };
@@ -34,10 +35,8 @@
   // Removes a previously created virtual pressure source.
   RemoveVirtualPressureSource(device.mojom.PressureSource source) => ();
 
-  // Sends a state and estimate update for a given virtual pressure source.
-  UpdateVirtualPressureSourceData(
-      device.mojom.PressureSource source,
-      device.mojom.PressureState state,
-      double own_contribution_estimate) =>
-      (UpdateVirtualPressureSourceDataResult result);
+  // Sends a state update for a given virtual pressure source.
+  UpdateVirtualPressureSourceState(
... (truncated)
Loading diff…

Original Bug Report

reported by vm...@google.com

Information Leak in Compute Pressure toJSON() Bypasses Side-Channel Mitigations

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: The PressureRecord::toJSON() method unconditionally serializes the ownContributionEstimate field, bypassing the RuntimeEnabled gating applied to the attribute. This leaks high-resolution, un-quantized system-wide CPU utilization data, effectively circumventing side-channel attack mitigations.

Affected files:

  • third_party/blink/renderer/modules/compute_pressure/pressure_record.cc
  • third_party/blink/renderer/modules/compute_pressure/pressure_record.idl
  • content/browser/compute_pressure/pressure_service_for_frame.cc
  • content/browser/compute_pressure/pressure_client_impl.cc
  • services/device/public/cpp/compute_pressure/cpu_pressure_converter.cc
  • third_party/blink/renderer/modules/compute_pressure/pressure_observer.cc

Estimated timestamp from git blame: Unknown (Google3 checkout)

Summary

There is a potential information leak in the Compute Pressure API where the PressureRecord::toJSON() method fails to respect the ComputePressureOwnContributionEstimate feature flag. This results in the exposure of high-resolution CPU utilization data that was intended to be restricted and quantized to prevent side-channel attacks.

Root Cause Analysis

In third_party/blink/renderer/modules/compute_pressure/pressure_record.idl, the ownContributionEstimate attribute is correctly gated behind a feature flag:

[RuntimeEnabled=ComputePressureOwnContributionEstimate]readonly attribute double? ownContributionEstimate;

However, the custom toJSON() implementation in third_party/blink/renderer/modules/compute_pressure/pressure_record.cc does not perform a corresponding check for RuntimeEnabledFeatures::ComputePressureOwnContributionEstimateEnabled(). It unconditionally adds the value to the result if it is present in the underlying C++ object:

ScriptObject PressureRecord::toJSON(ScriptState* script_state) const {
  V8ObjectBuilder result(script_state);
  result.AddString("source", source().AsCStr());
  result.AddString("state", state().AsCStr());
  if (ownContributionEstimate().has_value()) {
    result.AddNumber("ownContributionEstimate", own_contribution_estimate_); 
  } else {
    result.AddNull("ownContributionEstimate");
  }
  result.AddNumber("time", time());
  return result.ToScriptObject();
}

Additionally, PressureObserver::ShouldDispatch in third_party/blink/renderer/modules/compute_pressure/pressure_observer.cc uses this raw estimate to decide whether to trigger the observer callback:

return last_record->state() != state ||
       last_record->ownContributionEstimate() != maybe_estimate;

Because the estimate is derived from un-quantized system CPU data in the browser process, it changes frequently (often every sample). This causes the observer callback to fire at the maximum sampling rate (typically 1Hz), bypassing intended rate-limiting mitigations that should only allow updates when the coarse, quantized state transitions.

Security Impact

The Compute Pressure API incorporates ‘break-calibration’ mitigations (quantization and threshold randomization) specifically to prevent malicious web content from monitoring system-wide CPU activity via side-channels. Since ownContributionEstimate carries the raw global_cpu_utilization in an invertible form, leaking this value allows a page to recover high-resolution global CPU data. This enables cross-origin side-channel attacks, such as monitoring activity in other tabs or native applications.

Potential Reproduction Steps

Note: These steps are based on code analysis as the current environment does not support executing proof-of-concept code.

  1. Navigate to a secure origin (HTTPS) page in Chrome where Compute Pressure is enabled.
  2. Execute the following script in the DevTools console:
    const observer = new PressureObserver(records => {
      const record = records[0];
      console.log('Direct attribute:', record.ownContributionEstimate); 
      console.log('toJSON() output:', record.toJSON().ownContributionEstimate);
    });
    observer.observe('cpu');
    
  3. Observe that record.ownContributionEstimate returns undefined (correctly gated), but record.toJSON().ownContributionEstimate contains a high-precision double (the leaked raw data).

Suggested Fix

  1. Modify PressureRecord::toJSON in third_party/blink/renderer/modules/compute_pressure/pressure_record.cc to check RuntimeEnabledFeatures::ComputePressureOwnContributionEstimateEnabled(ExecutionContext::From(script_state)) before adding the ownContributionEstimate field to the builder.
  2. Update PressureObserver::ShouldDispatch in third_party/blink/renderer/modules/compute_pressure/pressure_observer.cc to ignore changes in the ownContributionEstimate if the ComputePressureOwnContributionEstimate feature flag is disabled.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker