CVE-2026-11046
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifmedia/mojo/clients/BUILD.gn |
modified | |
TEST_Fmedia/mojo/clients/mojo_decryptor_unittest.cc |
modified |
Files Changed
media/mojo/clients/BUILD.gnmedia/mojo/clients/mojo_decryptor_unittest.ccmedia/mojo/services/mojo_decryptor_service.cc
Patch
From 8624aad6fb1c4bd7222efc4560ec71d06169056c Mon Sep 17 00:00:00 2001
From: Feras Aldahlawi <frs@chromium.org>
Date: Fri, 24 Apr 2026 11:12:00 -0700
Subject: [PATCH] media: Fix missing validation in MojoDecryptorService
Add explicit validation to MojoDecryptorService::InitializeVideoDecoder
to reject invalid configurations and terminate the Mojo connection if
detected.
Also add a unit test to verify that invalid configs are rejected and bad
messages are reported.
Bug: b:498728857
Change-Id: Iff7f4aa675a455d2b01279e9e3e372376a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7792238
Reviewed-by: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
Auto-Submit: Feras Aldahlawi <frs@chromium.org>
Commit-Queue: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1620343}
---
diff --git a/media/mojo/clients/BUILD.gn b/media/mojo/clients/BUILD.gn
index 7c5c3a80..66e1242 100644
--- a/media/mojo/clients/BUILD.gn
+++ b/media/mojo/clients/BUILD.gn
@@ -161,6 +161,8 @@
"//testing/gtest",
]
+ public_deps = [ "//mojo/public/cpp/test_support:test_utils" ]
+
if (is_android) {
sources += [ "mojo_android_overlay_unittest.cc" ]
diff --git a/media/mojo/clients/mojo_decryptor_unittest.cc b/media/mojo/clients/mojo_decryptor_unittest.cc
index e118140..36b0fdb7 100644
--- a/media/mojo/clients/mojo_decryptor_unittest.cc
+++ b/media/mojo/clients/mojo_decryptor_unittest.cc
@@ -11,6 +11,7 @@
#include <utility>
#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/test_message_loop.h"
#include "media/base/decryptor.h"
@@ -21,6 +22,7 @@
#include "media/mojo/mojom/decryptor.mojom.h"
#include "media/mojo/services/mojo_decryptor_service.h"
#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -387,4 +389,28 @@
base::RunLoop().RunUntilIdle();
}
+TEST_F(MojoDecryptorTest, InitializeVideoDecoder_InvalidConfig) {
+ Initialize();
+
+ mojo::test::BadMessageObserver bad_message_observer;
+
+
+ EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _)).Times(0);
+
+ gfx::Size coded_size(65536, 65536);
+ gfx::Rect visible_rect(0, 0, 65536, 65536);
+ gfx::Size natural_size(65536, 65536);
+ VideoDecoderConfig config(VideoCodec::kVP9, VP9PROFILE_PROFILE3,
+ VideoDecoderConfig::AlphaMode::kIsOpaque,
+ VideoColorSpace(), kNoTransformation, coded_size,
+ visible_rect, natural_size, std::vector<uint8_t>(),
+ EncryptionScheme());
+
+ mojo_decryptor_->InitializeVideoDecoder(config, base::DoNothing());
+
+ std::string bad_message = bad_message_observer.WaitForBadMessage();
+ EXPECT_EQ(bad_message, "Invalid VideoDecoderConfig");
+ base::RunLoop().RunUntilIdle();
+}
+
} // namespace media
diff --git a/media/mojo/services/mojo_decryptor_service.cc b/media/mojo/services/mojo_decryptor_service.cc
index 0476042..27d1cd4 100644
--- a/media/mojo/services/mojo_decryptor_service.cc
+++ b/media/mojo/services/mojo_decryptor_service.cc
@@ -125,6 +125,13 @@
const VideoDecoderConfig& config,
InitializeVideoDecoderCallback callback) {
DVLOG(2) << __func__;
+
+ if (!config.IsValidConfig()) {
+ std::move(callback).Run(false);
+ mojo::ReportBadMessage("Invalid VideoDecoderConfig");
+ return;
+ }
+
decryptor_->InitializeVideoDecoder(
config, base::BindOnce(&MojoDecryptorService::OnVideoDecoderInitialized,
weak_this_, std::move(callback)));
Regression Test / PoC
diff --git a/media/mojo/clients/mojo_decryptor_unittest.cc b/media/mojo/clients/mojo_decryptor_unittest.cc
index e118140..36b0fdb7 100644
--- a/media/mojo/clients/mojo_decryptor_unittest.cc
+++ b/media/mojo/clients/mojo_decryptor_unittest.cc
@@ -11,6 +11,7 @@
#include <utility>
#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/test_message_loop.h"
#include "media/base/decryptor.h"
@@ -21,6 +22,7 @@
#include "media/mojo/mojom/decryptor.mojom.h"
#include "media/mojo/services/mojo_decryptor_service.h"
#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -387,4 +389,28 @@
base::RunLoop().RunUntilIdle();
}
+TEST_F(MojoDecryptorTest, InitializeVideoDecoder_InvalidConfig) {
+ Initialize();
+
+ mojo::test::BadMessageObserver bad_message_observer;
+
+
+ EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _)).Times(0);
+
+ gfx::Size coded_size(65536, 65536);
+ gfx::Rect visible_rect(0, 0, 65536, 65536);
+ gfx::Size natural_size(65536, 65536);
+ VideoDecoderConfig config(VideoCodec::kVP9, VP9PROFILE_PROFILE3,
+ VideoDecoderConfig::AlphaMode::kIsOpaque,
+ VideoColorSpace(), kNoTransformation, coded_size,
+ visible_rect, natural_size, std::vector<uint8_t>(),
+ EncryptionScheme());
+
+ mojo_decryptor_->InitializeVideoDecoder(config, base::DoNothing());
+
+ std::string bad_message = bad_message_observer.WaitForBadMessage();
+ EXPECT_EQ(bad_message, "Invalid VideoDecoderConfig");
+ base::RunLoop().RunUntilIdle();
+}
+
} // namespace media
Original Bug Report
Missing VideoDecoderConfig validation in MojoDecryptorService
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 security team.
Overview: A compromised renderer can send a VideoDecoderConfig with maliciously large video dimensions directly to the CDM process via MojoDecryptorService. Because size validation is missing in the receiving service, these unbounded dimensions are passed directly into the closed-source CDM library. This likely leads to integer overflows during frame buffer allocation, potentially resulting in a heap buffer overflow and code execution within the sandboxed CDM utility process.
Affected files:
media/mojo/services/mojo_decryptor_service.ccmedia/mojo/mojom/video_decoder_config_mojom_traits.ccmedia/cdm/cdm_adapter.cc
Estimated timestamp from git blame: 2025-12-09
Summary
There is a potential missing validation check in MojoDecryptorService::InitializeVideoDecoder that could allow a compromised renderer to trigger memory corruption within the sandboxed Content Decryption Module (CDM) utility process.
The Mojo deserialization traits for media::mojom::VideoDecoderConfig deliberately do not call IsValidConfig() to enforce dimension limits, delegating this responsibility to the receiving services. While MojoVideoDecoderService correctly enforces this check, MojoDecryptorService does not, allowing arbitrarily large video dimensions to be passed directly into third-party, closed-source CDM libraries (like Widevine).
Technical Details
- Deserialization bypasses limits: When a
VideoDecoderConfigis sent over IPC,StructTraits<...>::Readinmedia/mojo/mojom/video_decoder_config_mojom_traits.ccreconstructs the object. The traits forgfx::Sizeonly verify thatwidthandheightare non-negative. Crucially, the traits do not callconfig.IsValidConfig(), allowing the creation of a config with dimensions that far exceedmedia::limits::kMaxDimension(32767). - Missing Service Validation: In
media/mojo/services/mojo_decryptor_service.cc,InitializeVideoDecoderreceives this config and forwards it immediately to the underlyingdecryptor_(typically aCdmAdapter). It fails to validate the config or invokemojo::ReportBadMessage. - ABI Translation: In
CdmAdapter::InitializeVideoDecoder(media/cdm/cdm_adapter.cc), the unvalidatedVideoDecoderConfigis translated into acdm::VideoDecoderConfig_3struct. The maliciouscoded_sizevalues are blindly copied into the ABI struct. - Library Execution: The
CdmAdapterpasses the struct into the closed-source CDM library. Video decoders typically calculate frame buffer allocations by multiplying width and height (e.g.,width * height * 1.5for YUV). Passing maximum 32-bit integer values guarantees an integer overflow, leading to an undersized heap allocation and a subsequent heap buffer overflow when the library attempts to write video data.
Potential Attack Steps
Note: These are potential steps based on code analysis; our tooling agent does not yet have the ability to run code to provide a verified proof-of-concept.
- An attacker compromises a sandboxed Renderer process (e.g., via a V8 bug).
- The attacker uses
media::mojom::InterfaceFactory::CreateCdmto request a CDM, which launches the CDM utility process and returns aCdmContextcontaining a directpending_remote<media::mojom::Decryptor>pipe. - The attacker crafts a malicious
VideoDecoderConfigcontaining a valid codec but extremely largecoded_sizedimensions (e.g.,width = 65536, height = 65536orINT_MAX). - The attacker calls
InitializeVideoDecoderon theDecryptorremote, sending the malicious config. - The CDM utility process receives the unvalidated dimensions, triggering an integer overflow and heap buffer overflow inside the third-party CDM library, leading to arbitrary code execution within the CDM process.
Suggested Fix
Add explicit validation to MojoDecryptorService::InitializeVideoDecoder to reject invalid configurations and terminate the Mojo connection if one is detected.
void MojoDecryptorService::InitializeVideoDecoder(
const VideoDecoderConfig& config,
InitializeVideoDecoderCallback callback) {
DVLOG(2) << __func__;
if (!config.IsValidConfig()) {
mojo::ReportBadMessage("Invalid VideoDecoderConfig");
return;
}
decryptor_->InitializeVideoDecoder(
config, base::BindOnce(&MojoDecryptorService::OnVideoDecoderInitialized,
weak_this_, std::move(callback)));
}
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.