CVE-2026-12466
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifmodules/desktop_capture/win/dxgi_output_duplicator.cc |
modified |
Files Changed
modules/desktop_capture/desktop_frame_rotation.ccmodules/desktop_capture/win/dxgi_output_duplicator.cc
Patch
From 15644107234aa9bc7a4bf7e9f9a2157a8a9415b4 Mon Sep 17 00:00:00 2001 From: Alexander Cooper <[email protected]> Date: Mon, 08 Jun 2026 10:13:41 -0700 Subject: [PATCH] Fix OOB write in RotateDesktopFrame and DXGI size mismatch Upgrade RTC_DCHECK to RTC_CHECK in RotateDesktopFrame to enforce bounds checks in release builds. Validate captured frame size against expected unrotated size in DxgiOutputDuplicator::Duplicate to fail gracefully on resolution changes. Fixed: chromium:520199394 Change-Id: Iad22c89cf3ef900b0ac58a72ec3a9f8d2e96123b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/479000 Auto-Submit: Alexander Cooper <[email protected]> Commit-Queue: Alexander Cooper <[email protected]> Reviewed-by: Mark Foltz <[email protected]> Cr-Commit-Position: refs/heads/main@{#47937} --- diff --git a/modules/desktop_capture/desktop_frame_rotation.cc b/modules/desktop_capture/desktop_frame_rotation.cc index a6b4d16..a7ea388 100644 --- a/modules/desktop_capture/desktop_frame_rotation.cc +++ b/modules/desktop_capture/desktop_frame_rotation.cc @@ -99,13 +99,13 @@ const DesktopVector& target_offset, DesktopFrame* target) { RTC_DCHECK(target); - RTC_DCHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect)); + RTC_CHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect)); // TODO(bugs.webrtc.org/436974448): Support other pixel formats. RTC_CHECK_EQ(FOURCC_ARGB, source.pixel_format()); // The rectangle in `target`. const DesktopRect target_rect = RotateAndOffsetRect(source_rect, source.size(), rotation, target_offset); - RTC_DCHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect)); + RTC_CHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect)); if (target_rect.is_empty()) { return; diff --git a/modules/desktop_capture/win/dxgi_output_duplicator.cc b/modules/desktop_capture/win/dxgi_output_duplicator.cc index f07a55a..946401a 100644 --- a/modules/desktop_capture/win/dxgi_output_duplicator.cc +++ b/modules/desktop_capture/win/dxgi_output_duplicator.cc @@ -229,6 +229,19 @@ // triggers screen flickering? const DesktopFrame& source = texture_->AsDesktopFrame(); + // During a resolution transition, DXGI might deliver a frame with the new + // size before the controller detects the change and reinitializes. + // `unrotated_size_` is cached at initialization and only updated when + // this object is recreated. We abort capture on mismatch to force + // reinitialization by the |DxgiDuplicatorController|. + if (!source.size().equals(unrotated_size_)) { + RTC_LOG(LS_WARNING) << "Captured frame size " << source.size().width() + << "x" << source.size().height() + << " does not match expected size " + << unrotated_size_.width() << "x" + << unrotated_size_.height(); + return false; + } if (rotation_ != Rotation::CLOCK_WISE_0) { for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); it.Advance()) {
Original Bug Report
Potential Heap Out-Of-Bounds Write in Browser via WebRTC DXGI Desktop Capture Rotation Path
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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential release-build bounds-enforcement gap in RotateDesktopFrame can allow a heap out-of-bounds write or underflow in the browser process on Windows. When a display-mode or resolution change occurs concurrent with rotated screen capture via the DXGI path, a size divergence between cached and live textures can cause coordinate calculations to bypass debug-only checks. This results in writing screen-pixel bytes to out-of-bounds heap memory via libyuv::ARGBRotate.
Affected files:
third_party/webrtc/modules/desktop_capture/desktop_frame_rotation.ccthird_party/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.ccthird_party/webrtc/modules/desktop_capture/win/dxgi_texture.cc
Estimated timestamp from git blame: 2016-11-30
Description
There is a potential heap out-of-bounds write (or heap underflow write) in the Windows browser process during WebRTC screen capture. The vulnerability stems from an asymmetry in how bounds are enforced in the capture pipeline. While the standard non-rotated copy path at third_party/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc:247 utilizes DesktopFrame::CopyPixelsFrom(), which performs release-active bounds validation using RTC_CHECK (fatal in release), the rotated copy path relies on RotateDesktopFrame() which uses debug-only RTC_DCHECK statements.
In release builds (NDEBUG), these RTC_DCHECK statements are compiled out. If a mismatch occurs between the cached capture dimensions and the live frame texture dimensions, coordinate calculations can produce out-of-bounds offsets which are then passed directly to libyuv::ARGBRotate() as raw pointers with no runtime safety boundaries.
Root Cause Analysis
-
Debug-Only Bounds Check: At
third_party/webrtc/modules/desktop_capture/desktop_frame_rotation.cc:102,108:RTC_DCHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect)); ... RTC_DCHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect));In production builds, these checks are omitted.
-
Stale vs. Live Size Divergence:
DxgiOutputDuplicatorcaches the unrotated display size (unrotated_size_) at initialization time based onDXGI_OUTPUT_DESC.DesktopCoordinates(atdxgi_output_duplicator.cc:79,147). However,DxgiTexture::CopyFrom()dynamically reads the live texture dimensions per-frame:D3D11_TEXTURE2D_DESC desc = {0}; texture->GetDesc(&desc); desktop_size_.set(desc.Width, desc.Height);(at
third_party/webrtc/modules/desktop_capture/win/dxgi_texture.cc:61-63). -
Integer Underflow and Pointer Arithmetic: During a resolution transition, if a smaller frame is captured before the duplication object is invalidated,
DxgiOutputDuplicator::Duplicate()computessource_rectbased on the old, larger cached size but executesRotateDesktopFrame()with the smaller live size. Under CLOCK_WISE_90 rotation,RotateAndOffsetRectcomputestarget_rect.left = size.height() - rect.bottom() + offset.x(). When the live heightsize.height()is smaller thanrect.bottom(), this subtraction underflows to a negative value. Pointer arithmetic inGetFrameDataAtPos()then calculates a pointer pointing prior to the heap-allocated destination buffer (atdesktop_frame.cc:140), resulting in a heap underflow write vialibyuv::ARGBRotate.
Potential Steps to Trigger
Note: These steps are theoretical/potential as our analysis toolchain does not have the capability to execute code.
- Web content requests screen capture via
getDisplayMedia(), and the user permits capture of a monitor rotated by 90 degrees. - Screen capture runs in the browser process via
ScreenCapturerWinDirectx. - Concurrently, a display-mode or resolution change is triggered on the system.
- If
IDXGIOutputDuplication::AcquireNextFrame()returnsS_OKwith a resized frame texture before signalingDXGI_ERROR_ACCESS_LOST,DxgiOutputDuplicatorprocesses the frame with divergent live vs. cached dimensions. - The rotation path calculates a negative target offset, leading
libyuv::ARGBRotateto perform a heap out-of-bounds write.
Suggested Fix
-
Harden Bounds Check: Upgrade the
RTC_DCHECKstatements insideRotateDesktopFrame()inthird_party/webrtc/modules/desktop_capture/desktop_frame_rotation.ccto release-activeRTC_CHECKassertions, matching the validation behavior inCopyPixelsFrom():RTC_CHECK(DesktopRect::MakeSize(source.size()).ContainsRect(source_rect)); RTC_CHECK(DesktopRect::MakeSize(target->size()).ContainsRect(target_rect)); -
Validate Input Dimensions: Inside
DxgiOutputDuplicator::Duplicate(), explicitly verify that the live source frame size matchesunrotated_size_prior to entering the rotation loop. If a mismatch is detected, abort capture or re-initialize the pipeline.
Evaluated with Chrome root at commit: d8b226a3be7c9c1ac9240c09e14698866c82e4ac
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.