Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in XR
DescriptionInformation leak in XR
ComponentXR
Bug ClassLogic Error
Tracker533001362
Fix commit86ca49b1d368 (chromium/src) +27/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
if
content/browser/xr/service/vr_service_impl.cc
modified

Files Changed

  • content/browser/xr/service/vr_service_impl.cc
  • content/browser/xr/service/vr_service_impl.h
From 86ca49b1d3680f6c9c60ab20d59440b3810df1f8 Mon Sep 17 00:00:00 2001
From: Alexander Cooper <[email protected]>
Date: Mon, 13 Jul 2026 11:08:52 -0700
Subject: [PATCH] Gate VRService RuntimesChanged on frame visibility

VRServiceImpl previously forwarded XR runtime hot-plug events via
RuntimesChanged() without checking if the associated RenderFrameHost
was visible.

To align with other platform sensors (e.g., DevicePostureProviderImpl)
and ensure events are only delivered to visible frames, this change:
- Adds an IsRenderFrameHostVisible() helper method to VRServiceImpl.
- Checks frame visibility in RuntimesChanged() and sets a
  pending_device_changed_ flag if the frame is not currently visible.
- Overrides WebContentsObserver::OnVisibilityChanged() to flush any
  deferred device change notifications once the associated frame
  becomes visible again.

TAG=agy

Fixed: 533001362
Change-Id: I405b72ce431b100eed229996c48911cce192a617
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8077558
Reviewed-by: Brandon Jones <[email protected]>
Commit-Queue: Alexander Cooper <[email protected]>
Commit-Queue: Brandon Jones <[email protected]>
Auto-Submit: Alexander Cooper <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1661243}
---

diff --git a/content/browser/xr/service/vr_service_impl.cc b/content/browser/xr/service/vr_service_impl.cc
index 2fde838f..8f3cf7f 100644
--- a/content/browser/xr/service/vr_service_impl.cc
+++ b/content/browser/xr/service/vr_service_impl.cc
@@ -274,6 +274,10 @@
 
 void VRServiceImpl::RuntimesChanged() {
   DVLOG(2) << __func__;
+  if (!IsRenderFrameHostVisible()) {
+    pending_device_changed_ = true;
+    return;
+  }
   if (service_client_) {
     service_client_->OnDeviceChanged();
   }
@@ -303,6 +307,18 @@
   receiver_->Close();
 }
 
+void VRServiceImpl::OnVisibilityChanged(content::Visibility visibility) {
+  // Re-check frame visibility, as our associated RenderFrameHost may remain
+  // hidden even when the top-level page becomes visible.
+  if (!pending_device_changed_ || !IsRenderFrameHostVisible()) {
+    return;
+  }
+  pending_device_changed_ = false;
+  if (service_client_) {
+    service_client_->OnDeviceChanged();
+  }
+}
+
 void VRServiceImpl::OnWebContentsFocusChanged(content::RenderWidgetHost* host,
                                               bool focused) {
   if (!render_frame_host_ || !render_frame_host_->GetView() ||
@@ -550,8 +566,7 @@
     return;
   }
 
-  if (render_frame_host_->GetVisibilityState() !=
-      content::PageVisibilityState::kVisible) {
+  if (!IsRenderFrameHostVisible()) {
     // Page visibility is verified blink-side, so this should never fail unless
     // the requesting client is misbehaving or compromised. Treat non-visible
     // page as unknown failure:
@@ -997,6 +1012,11 @@
   return content::WebContents::FromRenderFrameHost(render_frame_host_);
 }
 
+bool VRServiceImpl::IsRenderFrameHostVisible() const {
+  return render_frame_host_ && render_frame_host_->GetVisibilityState() ==
+                                   content::PageVisibilityState::kVisible;
+}
+
 void VRServiceImpl::Teardown() {
   if (!render_frame_host_) {
     return;
diff --git a/content/browser/xr/service/vr_service_impl.h b/content/browser/xr/service/vr_service_impl.h
index 65bd2a02..f36d92b 100644
--- a/content/browser/xr/service/vr_service_impl.h
+++ b/content/browser/xr/service/vr_service_impl.h
@@ -14,6 +14,7 @@
 #include "content/browser/xr/metrics/session_metrics_helper.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/permission_result.h"
+#include "content/public/browser/visibility.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/xr_install_helper.h"
 #include "device/vr/public/mojom/isolated_xr_service.mojom-forward.h"
@@ -126,6 +127,7 @@
   void OnWebContentsFocused(content::RenderWidgetHost* host) override;
   void OnWebContentsLostFocus(content::RenderWidgetHost* host) override;
   void RenderFrameDeleted(content::RenderFrameHost* host) override;
+  void OnVisibilityChanged(content::Visibility visibility) override;
 
   void OnWebContentsFocusChanged(content::RenderWidgetHost* host, bool focused);
 
@@ -137,6 +139,8 @@
   // assumption that we are not already in VR.
   SessionMetricsHelper* GetSessionMetricsHelper();
 
+  bool IsRenderFrameHostVisible() const;
+
   bool InternalSupportsSession(device::mojom::XRSessionOptions* options);
 
   void DoRequestPermissions(
@@ -206,6 +210,7 @@
   bool in_focused_frame_ = false;
   bool frames_throttled_ = false;
   bool has_immersive_session_ = false;
+  bool pending_device_changed_ = false;
 
   std::vector<XrCompatibleCallback> xr_compatible_callbacks_;
 
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.