Medium watch CVSS 3.1 chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
3.1
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncomplete cleanup in GetUserMedia
DescriptionIncomplete cleanup in GetUserMedia
ComponentGetUserMedia
Bug ClassLogic Error
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker543640868
Fix commit581a1e54096a (chromium/src) +129/-0
CWECWE-459
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedKeita Sode and Daisuke Hatakeyama (SYZD Research)
Reported2026-08-07 (per vendor advisory)
Fix landed2026-08-19 (public git)
Disclosed2026-09-15
Patch gapNot computed: several commits cite this bug and it is not yet established which one is the fix.

Background

`VideoCaptureDevice::InvalidateBuffers`
a newly added (non-pure) virtual method on the base capture-device interface whose job is to signal that the device’s currently allocated frame buffers must be dropped rather than kept alive for reuse.
`VideoCaptureDevice::Client`
the per-device bridge object (declared in video_capture_device_client.h) that owns the connection to the shared-memory VideoCaptureBufferPool; each device forwards InvalidateBuffers() to client_->InvalidateBuffers(), which reaches the pool implementation landed in the sibling CL 1/6.
Buffer pool invalidation
marking pooled shared-memory buffers as invalid so they are not silently reused for a new capture while a consumer may still hold or map the old handle, i.e. the cleanup step that prevents stale-buffer reuse.
GetUserMedia
the Web API path that grants a renderer camera access and streams captured frames to it through these pooled buffers, so any device that fails to invalidate leaves the renderer’s buffer view uncleaned.

Root Cause Analysis

The InvalidateBuffers capability was introduced across a six-CL series: CL 1/6 implemented the actual invalidation in the shared-memory buffer pool, and media::VideoCaptureDevice exposed a virtual InvalidateBuffers() entry point. The defect is that most concrete VideoCaptureDevice subclasses did not override the method, so on the code path that is supposed to reclaim buffers the call resolved to the base (no-op) implementation and never reached the pool for those device types — an incomplete-cleanup logic error rather than a missing bounds check.

As a result, buffers that were meant to be invalidated stayed live in the pool and could be recycled or remain mapped while a consumer still referenced the old content, violating the invariant that an invalidation request must propagate all the way from device to pool. This CL (3/6) fixes it by implementing InvalidateBuffers() in every device (Android, Apple, ChromeOS, Fuchsia, Linux/V4L2, WebRTC, DeckLink, file, fake, mock) so each one forwards to client_->InvalidateBuffers() and, through it, to the pool. Because the method is not yet pure virtual, the partial landing still tolerated gaps, but the follow-up CL noted in the message will mark it pure to guarantee no implementation is missed.

Key insight
The single mistake is that a newly added cleanup signal (InvalidateBuffers) was wired into the pool and the base interface but not into the concrete device implementations, so the invalidation silently became a no-op for real capture devices; the fix restores the end-to-end path by having every device forward the call to its Client and thus to the buffer pool.

Attack Path

  1. Start a capture stream A renderer obtains camera access via GetUserMedia, causing a concrete VideoCaptureDevice (e.g. VideoCaptureDeviceLinux, VideoCaptureDeviceApple, VideoCaptureDeviceAndroid) to allocate shared-memory frame buffers from the pool and share them with the consumer.
  2. Trigger the invalidation event An event that is supposed to reclaim buffers occurs (per the CL series, buffer invalidation on the pool side); the framework invokes VideoCaptureDevice::InvalidateBuffers() expecting the buffers to be dropped. (inferred — the specific trigger lives in sibling CL 1/6, not in this diff.)
  3. Invalidation is dropped Before the fix the device had no override, so the call hit the base no-op and never reached client_->InvalidateBuffers() or the pool; the buffers were not invalidated (incomplete cleanup).
  4. Stale buffer persists / is reused The un-invalidated shared-memory buffer remains valid and can be recycled for new content or stay mapped by the consumer, allowing access to buffer contents that should have been cleaned up. (inferred — the diff shows only the missing forwarding, not a concrete disclosure or corruption sink.)

Impact Assessment

This is a logic error (incomplete cleanup) in the video-capture path reachable from GetUserMedia; the missing invalidation runs in the browser/capture (utility) process that services the renderer’s camera stream, with the precondition that the user has granted camera access and that the invalidation event fires for an affected device type. What an attacker plausibly gains is access to stale or reused capture buffer contents that should have been invalidated (inferred), rather than a demonstrated memory-corruption primitive. The advisory classifies it as incomplete cleanup in GetUserMedia and reports no exploited-in-the-wild status; any escalation to information disclosure or memory corruption beyond the missing cleanup is (inferred).

Changed Functions

FunctionChangeNotes
if
media/capture/video/android/video_capture_device_android.cc
modified
if
media/capture/video/apple/video_capture_device_apple.mm
modified
if
media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
modified
if
media/capture/video/fake_video_capture_device.cc
modified
if
media/capture/video/fuchsia/video_capture_device_fuchsia.cc
modified

Files Changed

  • media/capture/video/mock_device_factory.cc
  • media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc
  • media/capture/video/fake_video_capture_device.cc
  • media/capture/video/linux/video_capture_device_webrtc.h
  • media/capture/video/linux/v4l2_capture_delegate_unittest.cc
  • media/capture/video/linux/v4l2_capture_delegate.cc
  • media/capture/video/linux/video_capture_device_linux.cc
  • media/capture/video/apple/video_capture_device_apple.mm
  • media/capture/video/fake_video_capture_device_factory.cc
  • media/capture/video/chromeos/camera_device_context.h
  • media/capture/video/mock_device.cc
  • media/capture/video/mac/video_capture_device_decklink_mac.h
  • media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
  • media/capture/video/file_video_capture_device.h
  • media/capture/video/video_capture_device_client.h
  • media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
  • media/capture/video/fuchsia/video_capture_device_fuchsia.h
  • media/capture/video/win/video_capture_device_mf_win.h
  • media/capture/video/chromeos/camera_device_context.cc
  • media/capture/video/chromeos/mock_video_capture_client.h
  • media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
  • media/capture/video/android/video_capture_device_android.cc
  • media/capture/video/fuchsia/video_capture_device_fuchsia.cc
  • media/capture/video/video_capture_device.h
  • media/capture/video/mock_device.h
  • media/capture/video/fake_video_capture_device.h
  • media/capture/video/linux/video_capture_device_linux.h
  • media/capture/video/win/video_capture_device_win.h
  • media/capture/video/linux/v4l2_capture_delegate.h
  • media/capture/video/win/video_capture_device_mf_win.cc
  • media/capture/video/mac/video_capture_device_decklink_mac.mm
  • media/capture/video/linux/video_capture_device_webrtc.cc
  • media/capture/video/android/video_capture_device_android.h
  • media/capture/video/win/video_capture_device_win.cc
  • media/capture/video/win/video_capture_device_mf_win_unittest.cc
  • media/capture/video/video_capture_device_client.cc
  • media/capture/video/mock_video_capture_device_client.h
  • media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc
  • media/capture/video/apple/video_capture_device_apple.h
  • media/capture/video/file_video_capture_device.cc
  • media/capture/video/chromeos/video_capture_device_chromeos_delegate.h

Audit Directions

  • Non-pure virtual interface points
    Audit any newly added virtual method that is intentionally left non-pure “to allow partial landing”; every concrete subclass that silently inherits a no-op is a candidate for the same incomplete-cleanup gap until the method is made pure virtual.
  • Cleanup/teardown fan-out
    Review lifecycle operations (stop, reconfigure, context-loss, invalidate) that must reach a shared resource (buffer pools, GPU handles, shared memory) through a chain of device/delegate/context objects, and confirm every hop in the chain forwards the call rather than dropping it.
  • Shared-memory buffer reuse
    Look for VideoCaptureBufferPool and cross-process buffer handoffs where a buffer can be recycled while a consumer still holds it, and verify an invalidation or reference-drop step actually executes before reuse for all device backends.
From 581a1e54096ae8f868a6eb78fd5d228f912711af Mon Sep 17 00:00:00 2001
From: Ilya Nikolaevskiy <[email protected]>
Date: Wed, 19 Aug 2026 04:42:16 -0700
Subject: [PATCH] Implement InvalidateBuffers for video capture (cl 3/6)

This CL implements InvalidateBuffers for all video capture devices in media/capture and exposes it in virtual method of media::VideoCaptureDevice, but it isn't pure virtual yet to allow partial landing.

All devices delegate the call to VideoCaptureDevice::Client, which forwards it to the pool, which already has the feature implemented in cl 1/6.

Future CL will mark it pure virtual to ensure that no interface implementation was missed.

Bug: 543640868
Change-Id: I58e4dd5c72acb8ed461f7aaeadb671cd32ed2160
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8257270
Reviewed-by: Guido Urdaneta <[email protected]>
Commit-Queue: Ilya Nikolaevskiy <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1682195}
---
diff --git a/media/capture/video/android/video_capture_device_android.cc b/media/capture/video/android/video_capture_device_android.cc
index 9b2c8823f7..95e8570 100644
--- a/media/capture/video/android/video_capture_device_android.cc
+++ b/media/capture/video/android/video_capture_device_android.cc
@@ -1091,3 +1091,10 @@
 }  // namespace media
 
 DEFINE_JNI(VideoCapture)
+
+void VideoCaptureDeviceAndroid::InvalidateBuffers() {
+  base::AutoLock lock(lock_);
+  if (client_) {
+    client_->InvalidateBuffers();
+  }
+}
diff --git a/media/capture/video/android/video_capture_device_android.h b/media/capture/video/android/video_capture_device_android.h
index e67415f..fee2452 100644
--- a/media/capture/video/android/video_capture_device_android.h
+++ b/media/capture/video/android/video_capture_device_android.h
@@ -117,6 +117,7 @@
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
+  void InvalidateBuffers() override;
 
   // VideoCaptureGpuContextLostObserver implementation.
   void OnContextLost() override;
diff --git a/media/capture/video/apple/video_capture_device_apple.h b/media/capture/video/apple/video_capture_device_apple.h
index aeec941..6b89e02 100644
--- a/media/capture/video/apple/video_capture_device_apple.h
+++ b/media/capture/video/apple/video_capture_device_apple.h
@@ -63,6 +63,7 @@
       std::unique_ptr<VideoCaptureDevice::Client> client) override;
   void StopAndDeAllocate() override;
   void TakePhoto(TakePhotoCallback callback) override;
+  void InvalidateBuffers() override;
   void GetPhotoState(GetPhotoStateCallback callback) override;
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
diff --git a/media/capture/video/apple/video_capture_device_apple.mm b/media/capture/video/apple/video_capture_device_apple.mm
index 806b1480..062dcb0 100644
--- a/media/capture/video/apple/video_capture_device_apple.mm
+++ b/media/capture/video/apple/video_capture_device_apple.mm
@@ -402,4 +402,11 @@
   return metadata;
 }
 
+void VideoCaptureDeviceApple::InvalidateBuffers() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  if (client_) {
+    client_->InvalidateBuffers();
+  }
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/camera_device_context.cc b/media/capture/video/chromeos/camera_device_context.cc
index b68c6bd..dd36ee4f 100644
--- a/media/capture/video/chromeos/camera_device_context.cc
+++ b/media/capture/video/chromeos/camera_device_context.cc
@@ -199,4 +199,11 @@
   }
 }
 
+void CameraDeviceContext::InvalidateBuffers(ClientType client_type) {
+  base::AutoLock lock(client_lock_);
+  if (clients_.count(client_type)) {
+    clients_[client_type]->InvalidateBuffers();
+  }
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/camera_device_context.h b/media/capture/video/chromeos/camera_device_context.h
index 5cc9f65..d1629697 100644
--- a/media/capture/video/chromeos/camera_device_context.h
+++ b/media/capture/video/chromeos/camera_device_context.h
@@ -113,6 +113,7 @@
   bool AddClient(ClientType client_type,
                  std::unique_ptr<VideoCaptureDevice::Client> client);
   void RemoveClient(ClientType client_type);
+  void InvalidateBuffers(ClientType client_type);
   void SetState(State state);
 
   State GetState();
diff --git a/media/capture/video/chromeos/mock_video_capture_client.h b/media/capture/video/chromeos/mock_video_capture_client.h
index 61e6cff6..ea3863e 100644
--- a/media/capture/video/chromeos/mock_video_capture_client.h
+++ b/media/capture/video/chromeos/mock_video_capture_client.h
@@ -28,6 +28,7 @@
   MOCK_METHOD1(OnFrameDropped, void(media::VideoCaptureFrameDropReason reason));
   MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
   MOCK_METHOD0(OnStarted, void(void));
+  MOCK_METHOD0(InvalidateBuffers, void());
 
   explicit MockVideoCaptureClient();
 
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
index d21e20e..c17f2955 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
@@ -343,4 +343,12 @@
   }
 }
 
+void VideoCaptureDeviceChromeOSDelegate::InvalidateBuffers(
+    ClientType client_type) {
+  DCHECK(capture_task_runner_->BelongsToCurrentThread());
+  if (device_context_) {
+    device_context_->InvalidateBuffers(client_type);
+  }
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h
index 3834033..7723165 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h
@@ -49,6 +49,7 @@
                         std::unique_ptr<VideoCaptureDevice::Client> client,
                         ClientType client_type);
   void StopAndDeAllocate(ClientType client_type);
+  void InvalidateBuffers(ClientType client_type);
   void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback);
   void GetPhotoState(VideoCaptureDevice::GetPhotoStateCallback callback);
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
index 3ebafb4..0111d20 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
@@ -52,4 +52,8 @@
   vcd_delegate_->SetPhotoOptions(std::move(settings), std::move(callback));
 }
 
+void VideoCaptureDeviceChromeOSHalv3::InvalidateBuffers() {
+  vcd_delegate_->InvalidateBuffers(client_type_);
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
index cca2b4f3..ede2ee6 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
@@ -37,6 +37,7 @@
   void AllocateAndStart(const VideoCaptureParams& params,
                         std::unique_ptr<Client> client) final;
   void StopAndDeAllocate() final;
+  void InvalidateBuffers() final;
   void TakePhoto(TakePhotoCallback callback) final;
   void GetPhotoState(GetPhotoStateCallback callback) final;
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
diff --git a/media/capture/video/fake_video_capture_device.cc b/media/capture/video/fake_video_capture_device.cc
index fd0975a..8258d516 100644
--- a/media/capture/video/fake_video_capture_device.cc
+++ b/media/capture/video/fake_video_capture_device.cc
@@ -216,6 +216,11 @@
   }
   virtual void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) = 0;
 
+  void InvalidateBuffers() {
+    CHECK(client_);
+    client_->InvalidateBuffers();
+  }
+
  protected:
   base::TimeDelta CalculateTimeSinceFirstInvocation(base::TimeTicks now) {
     if (first_ref_time_.is_null())
@@ -987,6 +992,12 @@
       /*capture_begin_timestamp=*/std::nullopt, /*metadata=*/std::nullopt);
 }
 
+void FakeVideoCaptureDevice::InvalidateBuffers() {
+  if (frame_deliverer_) {
+    frame_deliverer_->InvalidateBuffers();
+  }
+}
+
 void FakeVideoCaptureDevice::BeepAndScheduleNextCapture(
     base::TimeTicks expected_execution_time) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/media/capture/video/fake_video_capture_device.h b/media/capture/video/fake_video_capture_device.h
index b729fd1..85b052f 100644
--- a/media/capture/video/fake_video_capture_device.h
+++ b/media/capture/video/fake_video_capture_device.h
@@ -83,6 +83,7 @@
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
+  void InvalidateBuffers() override;
 
  private:
   void BeepAndScheduleNextCapture(base::TimeTicks expected_execution_time);
diff --git a/media/capture/video/fake_video_capture_device_factory.cc b/media/capture/video/fake_video_capture_device_factory.cc
index 86fe926..920c9d3 100644
--- a/media/capture/video/fake_video_capture_device_factory.cc
+++ b/media/capture/video/fake_video_capture_device_factory.cc
@@ -97,6 +97,7 @@
   void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override {}
   void TakePhoto(TakePhotoCallback callback) override {}
+  void InvalidateBuffers() override {}
 };
 
 }  // anonymous namespace
diff --git a/media/capture/video/file_video_capture_device.cc b/media/capture/video/file_video_capture_device.cc
index e5867be..10ad1ce 100644
--- a/media/capture/video/file_video_capture_device.cc
+++ b/media/capture/video/file_video_capture_device.cc
@@ -764,4 +764,8 @@
       next_frame_time_ - current_time);
 }
 
+void FileVideoCaptureDevice::InvalidateBuffers() {
+  client_->InvalidateBuffers();
+}
+
 }  // namespace media
diff --git a/media/capture/video/file_video_capture_device.h b/media/capture/video/file_video_capture_device.h
index ec822f5b..8e8a9f6 100644
--- a/media/capture/video/file_video_capture_device.h
+++ b/media/capture/video/file_video_capture_device.h
@@ -54,6 +54,7 @@
       const VideoCaptureParams& params,
       std::unique_ptr<VideoCaptureDevice::Client> client) override;
   void StopAndDeAllocate() override;
+  void InvalidateBuffers() override;
   void GetPhotoState(GetPhotoStateCallback callback) override;
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
diff --git a/media/capture/video/fuchsia/video_capture_device_fuchsia.cc b/media/capture/video/fuchsia/video_capture_device_fuchsia.cc
index 8d0e039..0750df3 100644
--- a/media/capture/video/fuchsia/video_capture_device_fuchsia.cc
+++ b/media/capture/video/fuchsia/video_capture_device_fuchsia.cc
@@ -471,4 +471,10 @@
   // Frame buffer is returned to the device by dropping the |frame_info|.
 }
 
+void VideoCaptureDeviceFuchsia::InvalidateBuffers() {
+  if (client_) {
+    client_->InvalidateBuffers();
+  }
+}
+
 }  // namespace media
diff --git a/media/capture/video/fuchsia/video_capture_device_fuchsia.h b/media/capture/video/fuchsia/video_capture_device_fuchsia.h
index d0a2d09..9693777 100644
--- a/media/capture/video/fuchsia/video_capture_device_fuchsia.h
+++ b/media/capture/video/fuchsia/video_capture_device_fuchsia.h
@@ -43,6 +43,7 @@
   void AllocateAndStart(const VideoCaptureParams& params,
                         std::unique_ptr<Client> client) override;
   void StopAndDeAllocate() override;
+  void InvalidateBuffers() override;
 
  private:
   // Disconnects the |stream_| and resets related state.
diff --git a/media/capture/video/linux/v4l2_capture_delegate.cc b/media/capture/video/linux/v4l2_capture_delegate.cc
index 3cb4c5d00..103b9ad1 100644
--- a/media/capture/video/linux/v4l2_capture_delegate.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate.cc
@@ -1446,4 +1446,8 @@
   return true;
 }
 
+void V4L2CaptureDelegate::InvalidateBuffers() {
+  client_->InvalidateBuffers();
+}
+
 }  // namespace media
diff --git a/media/capture/video/linux/v4l2_capture_delegate.h b/media/capture/video/linux/v4l2_capture_delegate.h
index 828cfc1..c4f5a01 100644
--- a/media/capture/video/linux/v4l2_capture_delegate.h
+++ b/media/capture/video/linux/v4l2_capture_delegate.h
@@ -71,6 +71,7 @@
                         float frame_rate,
                         std::unique_ptr<VideoCaptureDevice::Client> client);
   void StopAndDeAllocate();
+  void InvalidateBuffers();
 
   void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback);
 
diff --git a/media/capture/video/linux/video_capture_device_linux.cc b/media/capture/video/linux/video_capture_device_linux.cc
index e3c13fe..ec49c07 100644
--- a/media/capture/video/linux/video_capture_device_linux.cc
+++ b/media/capture/video/linux/video_capture_device_linux.cc
@@ -154,4 +154,12 @@
   waiter->Signal();
 }
 
+void VideoCaptureDeviceLinux::InvalidateBuffers() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(capture_impl_);
+  task_runner_->PostTask(FROM_HERE,
+                         base::BindOnce(&V4L2CaptureDelegate::InvalidateBuffers,
+                                        capture_impl_->GetWeakPtr()));
+}
+
 }  // namespace media
diff --git a/media/capture/video/linux/video_capture_device_linux.h b/media/capture/video/linux/video_capture_device_linux.h
index 9a352d1..5916184 100644
--- a/media/capture/video/linux/video_capture_device_linux.h
+++ b/media/capture/video/linux/video_capture_device_linux.h
@@ -49,6 +49,7 @@
   void AllocateAndStart(const VideoCaptureParams& params,
                         std::unique_ptr<Client> client) override;
   void StopAndDeAllocate() override;
+  void InvalidateBuffers() override;
   void TakePhoto(TakePhotoCallback callback) override;
   void GetPhotoState(GetPhotoStateCallback callback) override;
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
diff --git a/media/capture/video/linux/video_capture_device_webrtc.cc b/media/capture/video/linux/video_capture_device_webrtc.cc
index 7f1af53..006e1b0 100644
--- a/media/capture/video/linux/video_capture_device_webrtc.cc
+++ b/media/capture/video/linux/video_capture_device_webrtc.cc
@@ -162,3 +162,9 @@
 }
 
 }  // namespace media
+
+namespace media {
+void VideoCaptureDeviceWebRtc::InvalidateBuffers() {
+  client_->InvalidateBuffers();
+}
+}  // namespace media
diff --git a/media/capture/video/linux/video_capture_device_webrtc.h b/media/capture/video/linux/video_capture_device_webrtc.h
index 035b2e3..4aabe48 100644
--- a/media/capture/video/linux/video_capture_device_webrtc.h
+++ b/media/capture/video/linux/video_capture_device_webrtc.h
@@ -46,6 +46,7 @@
   void GetPhotoState(GetPhotoStateCallback callback) override;
   void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
+  void InvalidateBuffers() override;
 
   int32_t OnRawFrame(uint8_t* video_frame,
                      size_t video_frame_length,
diff --git a/media/capture/video/mac/video_capture_device_decklink_mac.h b/media/capture/video/mac/video_capture_device_decklink_mac.h
index 8f7b14f0..449debe 100644
--- a/media/capture/video/mac/video_capture_device_decklink_mac.h
+++ b/media/capture/video/mac/video_capture_device_decklink_mac.h
@@ -78,6 +78,7 @@
       const VideoCaptureParams& params,
       std::unique_ptr<VideoCaptureDevice::Client> client) override;
   void StopAndDeAllocate() override;
+  void InvalidateBuffers() override;
 
   // Protects concurrent setting and using of |client_|.
   base::Lock lock_;
diff --git a/media/capture/video/mac/video_capture_device_decklink_mac.mm b/media/capture/video/mac/video_capture_device_decklink_mac.mm
index 2c0764d..35487648 100644
--- a/media/capture/video/mac/video_capture_device_decklink_mac.mm
+++ b/media/capture/video/mac/video_capture_device_decklink_mac.mm
@@ -510,4 +510,9 @@
     decklink_capture_delegate_->StopAndDeAllocate();
 }
 
+void VideoCaptureDeviceDeckLinkMac::InvalidateBuffers() {
+  base::AutoLock lock(lock_);
+  client_->InvalidateBuffers();
+}
+
 }  // namespace media
diff --git a/media/capture/video/mock_device.cc b/media/capture/video/mock_device.cc
index b1e36d1..d9c6f3b 100644
--- a/media/capture/video/mock_device.cc
+++ b/media/capture/video/mock_device.cc
@@ -61,3 +61,10 @@
 }
 
 }  // namespace media
+
+namespace media {
+void MockDevice::InvalidateBuffers() {
+  client_->InvalidateBuffers();
+}
+
+}  // namespace media
diff --git a/media/capture/video/mock_device.h b/media/capture/video/mock_device.h
index c813964..c43fabd 100644
--- a/media/capture/video/mock_device.h
+++ b/media/capture/video/mock_device.h
@@ -43,6 +43,7 @@
   void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
... (file diff truncated)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc b/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc
index a48f6f6..7299af6e29 100644
--- a/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc
+++ b/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc
@@ -107,6 +107,7 @@
  private:
   // VideoCaptureDevice::Client implementation.
   void OnCaptureConfigurationChanged() override {}
+  void InvalidateBuffers() final {}
 
   void OnStarted() final {
     EXPECT_FALSE(started_);
diff --git a/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc
index 422fb78..3125fa6c 100644
--- a/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc
@@ -96,6 +96,7 @@
                     const std::string&));
 
   MOCK_METHOD1(OnFrameDropped, void(VideoCaptureFrameDropReason));
+  MOCK_METHOD0(InvalidateBuffers, void());
 
   double GetBufferPoolUtilization() const override { return 0.0; }
diff --git a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
index 9f33db8e..1aa6cff 100644
--- a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
@@ -309,6 +309,7 @@
                     const std::string&));
 
   MOCK_METHOD1(OnFrameDropped, void(VideoCaptureFrameDropReason));
+  MOCK_METHOD0(InvalidateBuffers, void());
 
   double GetBufferPoolUtilization() const override { return 0.0; }
diff --git a/media/capture/video/win/video_capture_device_mf_win_unittest.cc b/media/capture/video/win/video_capture_device_mf_win_unittest.cc
index a7e5e0e..f73251b 100644
--- a/media/capture/video/win/video_capture_device_mf_win_unittest.cc
+++ b/media/capture/video/win/video_capture_device_mf_win_unittest.cc
@@ -136,6 +136,7 @@
   double GetBufferPoolUtilization() const override { return 0.0; }
 
   MOCK_METHOD0(OnStarted, void());
+  MOCK_METHOD0(InvalidateBuffers, void());
 };
 
 class MockImageCaptureClient
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.