CVE-2026-11041
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TESTmedia/mojo/common/media_type_converters_unittest.cc |
modified | |
ifmedia/mojo/common/mojo_decoder_buffer_converter.cc |
modified | |
TESTmedia/mojo/common/mojo_decoder_buffer_converter_unittest.cc |
modified | |
ifmedia/mojo/services/mojo_demuxer_stream_adapter.cc |
modified |
Files Changed
media/mojo/common/media_type_converters.ccmedia/mojo/common/media_type_converters_unittest.ccmedia/mojo/common/mojo_decoder_buffer_converter.ccmedia/mojo/common/mojo_decoder_buffer_converter_unittest.ccmedia/mojo/services/mojo_demuxer_stream_adapter.cc
Patch
From 8fa45a02c280f88fc8f82d400c67e3d924c2bc7e Mon Sep 17 00:00:00 2001
From: Sangbaek Park <sangbaekpark@google.com>
Date: Wed, 22 Apr 2026 09:55:17 -0700
Subject: [PATCH] media: Validate DecoderBuffer subsample metadata from untrusted sources
This change hardens the Media Foundation-based decryption path on
Windows by adding validation checks for `DecoderBuffer` subsample
metadata. A compromised renderer could previously send a malformed
`DecoderBuffer` over a Mojo pipe, where the sum of clear and encrypted
bytes in its `DecryptConfig` subsamples exceeded the buffer's actual
data size. This unvalidated metadata could lead to out-of-bounds memory
access in the higher-privilege Media Foundation CDM utility process,
potentially resulting in a sandbox escape.
To mitigate this, validation is now performed at multiple layers:
1. Mojo Type Conversion (`media_type_converters.cc`): Added a check
using `media::DecoderBuffer::DoSubsamplesMatch()` during
`DecoderBuffer` deserialization to ensure the integrity of
`DecryptConfig` subsamples against the buffer's actual data size. If
validation fails, the deserialization returns `nullptr`.
2. Mojo Decoder Buffer Handling
(`mojo_decoder_buffer_converter.cc`): Modified
`MojoDecoderBufferReader::ReadDecoderBuffer` to gracefully handle
`nullptr` returns from the `TypeConverter` (due to validation failures)
by immediately invoking the callback with `nullptr` instead of a
`DCHECK`.
3. Demuxer Stream Adapter (`mojo_demuxer_stream_adapter.cc`): Added an
explicit check using `media::DecoderBuffer::DoSubsamplesMatch()` in
`MojoDemuxerStreamAdapter::OnBufferRead` to verify subsample integrity
immediately upon receiving a decrypted buffer from the renderer. If the
check fails, the read operation is stopped with a `kError`.
Tests: { MediaTypeConvertersTest.RejectOOBSubsample,
MojoDemuxerStreamAdapterTest.ReadAbortedOnOOBSubsample,
MojoDecoderBufferConverterTest.ReadMalformedDecoderBuffer }
Bug: 498700369
Change-Id: Idc643560381bd24844d0590e5778bbe91d03bc74
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7782949
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Sangbaek Park <sangbaekpark@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1618940}
---
diff --git a/media/mojo/common/media_type_converters.cc b/media/mojo/common/media_type_converters.cc
index 22631c2a..0630476 100644
--- a/media/mojo/common/media_type_converters.cc
+++ b/media/mojo/common/media_type_converters.cc
@@ -190,6 +190,11 @@
return nullptr;
}
buffer->set_decrypt_config(std::move(decrypt_config));
+
+ if (!media::DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+ DVLOG(1) << __func__ << ": Subsamples do not match buffer size";
+ return nullptr;
+ }
}
// TODO(dalecurtis): We intentionally do not deserialize the data section of
diff --git a/media/mojo/common/media_type_converters_unittest.cc b/media/mojo/common/media_type_converters_unittest.cc
index 298fe2db..31d3568 100644
--- a/media/mojo/common/media_type_converters_unittest.cc
+++ b/media/mojo/common/media_type_converters_unittest.cc
@@ -172,10 +172,7 @@
const char kKeyId[] = "00112233445566778899aabbccddeeff";
const char kIv[] = "0123456789abcdef";
- std::vector<SubsampleEntry> subsamples;
- subsamples.push_back(SubsampleEntry(10, 20));
- subsamples.push_back(SubsampleEntry(30, 40));
- subsamples.push_back(SubsampleEntry(50, 60));
+ std::vector<SubsampleEntry> subsamples = {SubsampleEntry(5, 8)};
// Original.
scoped_refptr<DecoderBuffer> buffer(DecoderBuffer::CopyFrom(kData));
@@ -207,10 +204,7 @@
const char kKeyId[] = "00112233445566778899aabbccddeeff";
const char kIv[] = "0123456789abcdef";
- std::vector<SubsampleEntry> subsamples;
- subsamples.push_back(SubsampleEntry(10, 20));
- subsamples.push_back(SubsampleEntry(30, 40));
- subsamples.push_back(SubsampleEntry(50, 60));
+ std::vector<SubsampleEntry> subsamples = {SubsampleEntry(5, 8)};
auto pattern = EncryptionPattern::Create(1, 2);
@@ -301,4 +295,28 @@
CompareAudioBuffers(kSampleFormatPlanarF32, *buffer, *result);
}
+// This test ensures that a `mojom::DecoderBuffer` with maliciously oversized
+// subsamples is correctly rejected during conversion to a C++ `DecoderBuffer`,
+// resulting in a `nullptr` return.
+TEST(MediaTypeConvertersTest, RejectOOBSubsample) {
+ const size_t kDataSize = 100;
+ auto buffer = base::MakeRefCounted<DecoderBuffer>(kDataSize);
+
+ std::vector<SubsampleEntry> subsamples;
+ // Set a malicious DecryptConfig with subsamples larger than data size
+ subsamples.push_back(SubsampleEntry(50, 500));
+
+ buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
+ "key_id", "0123456789abcdef", subsamples));
+
+ // Convert to Mojom
+ mojom::DecoderBufferPtr mojo_buffer = mojom::DecoderBuffer::From(*buffer);
+
+ // Convert back to DecoderBuffer
+ scoped_refptr<DecoderBuffer> converted_buffer =
+ mojo_buffer.To<scoped_refptr<DecoderBuffer>>();
+
+ EXPECT_FALSE(converted_buffer);
+}
+
} // namespace media
diff --git a/media/mojo/common/mojo_decoder_buffer_converter.cc b/media/mojo/common/mojo_decoder_buffer_converter.cc
index a38389f..915d7a1 100644
--- a/media/mojo/common/mojo_decoder_buffer_converter.cc
+++ b/media/mojo/common/mojo_decoder_buffer_converter.cc
@@ -132,7 +132,11 @@
scoped_refptr<DecoderBuffer> media_buffer(
mojo_buffer.To<scoped_refptr<DecoderBuffer>>());
- DCHECK(media_buffer);
+ if (!media_buffer) {
+ std::move(read_cb).Run(nullptr);
+ OnPipeError(MOJO_RESULT_INVALID_ARGUMENT);
+ return;
+ }
if (MediaTraceIsEnabled() && !media_buffer->end_of_stream()) {
TRACE_EVENT_BEGIN(
diff --git a/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc b/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc
index d0312d5..6690ace 100644
--- a/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc
+++ b/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc
@@ -14,6 +14,8 @@
#include "base/test/task_environment.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
+#include "media/base/subsample_entry.h"
+#include "media/mojo/common/media_type_converters.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -114,10 +116,7 @@
const char kKeyId[] = "00112233445566778899aabbccddeeff";
const char kIv[] = "0123456789abcdef";
- std::vector<SubsampleEntry> subsamples;
- subsamples.push_back(SubsampleEntry(10, 20));
- subsamples.push_back(SubsampleEntry(30, 40));
- subsamples.push_back(SubsampleEntry(50, 60));
+ std::vector<SubsampleEntry> subsamples = {SubsampleEntry(5, 8)};
scoped_refptr<DecoderBuffer> buffer(DecoderBuffer::CopyFrom(kData));
buffer->set_decrypt_config(
@@ -418,4 +417,31 @@
run_loop.Run();
}
+// This test confirms that `MojoDecoderBufferReader` correctly handles a
+// `nullptr` `DecoderBuffer` returned by the `TypeConverter` (due to subsample
+// validation failure) by invoking its read callback with `nullptr`, preventing
+// a `DCHECK` crash.
+TEST(MojoDecoderBufferConverterTest, ReadMalformedDecoderBuffer) {
+ base::test::SingleThreadTaskEnvironment task_environment;
+ base::RunLoop run_loop;
+ MojoDecoderBufferConverter converter;
+
+ // Create a buffer and attach a malformed DecryptConfig (subsamples larger
+ // than data size).
+ const uint8_t kData[] = "Hello, world";
+ auto media_buffer = DecoderBuffer::CopyFrom(kData);
+ std::vector<SubsampleEntry> subsamples;
+ subsamples.emplace_back(SubsampleEntry(50, 500));
+ media_buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
+ "key_id", "0123456789abcdef", subsamples));
+
+ auto mojo_buffer = mojom::DecoderBuffer::From(*media_buffer);
+ base::MockCallback<MojoDecoderBufferReader::ReadCB> mock_cb;
+ EXPECT_CALL(mock_cb, Run(testing::IsNull()))
+ .WillOnce(testing::InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+
+ converter.reader->ReadDecoderBuffer(std::move(mojo_buffer), mock_cb.Get());
+ run_loop.Run();
+}
+
} // namespace media
diff --git a/media/mojo/services/mojo_demuxer_stream_adapter.cc b/media/mojo/services/mojo_demuxer_stream_adapter.cc
index 4c3364b3..bb9ef291 100644
--- a/media/mojo/services/mojo_demuxer_stream_adapter.cc
+++ b/media/mojo/services/mojo_demuxer_stream_adapter.cc
@@ -129,9 +129,17 @@
if (!buffer) {
DVLOG(1) << __func__ << ": null buffer";
Regression Test / PoC
diff --git a/media/mojo/common/media_type_converters_unittest.cc b/media/mojo/common/media_type_converters_unittest.cc
index 298fe2db..31d3568 100644
--- a/media/mojo/common/media_type_converters_unittest.cc
+++ b/media/mojo/common/media_type_converters_unittest.cc
@@ -172,10 +172,7 @@
const char kKeyId[] = "00112233445566778899aabbccddeeff";
const char kIv[] = "0123456789abcdef";
- std::vector<SubsampleEntry> subsamples;
- subsamples.push_back(SubsampleEntry(10, 20));
- subsamples.push_back(SubsampleEntry(30, 40));
- subsamples.push_back(SubsampleEntry(50, 60));
+ std::vector<SubsampleEntry> subsamples = {SubsampleEntry(5, 8)};
// Original.
scoped_refptr<DecoderBuffer> buffer(DecoderBuffer::CopyFrom(kData));
@@ -207,10 +204,7 @@
const char kKeyId[] = "00112233445566778899aabbccddeeff";
const char kIv[] = "0123456789abcdef";
- std::vector<SubsampleEntry> subsamples;
- subsamples.push_back(SubsampleEntry(10, 20));
- subsamples.push_back(SubsampleEntry(30, 40));
- subsamples.push_back(SubsampleEntry(50, 60));
+ std::vector<SubsampleEntry> subsamples = {SubsampleEntry(5, 8)};
auto pattern = EncryptionPattern::Create(1, 2);
@@ -301,4 +295,28 @@
CompareAudioBuffers(kSampleFormatPlanarF32, *buffer, *result);
}
+// This test ensures that a `mojom::DecoderBuffer` with maliciously oversized
+// subsamples is correctly rejected during conversion to a C++ `DecoderBuffer`,
+// resulting in a `nullptr` return.
+TEST(MediaTypeConvertersTest, RejectOOBSubsample) {
+ const size_t kDataSize = 100;
+ auto buffer = base::MakeRefCounted<DecoderBuffer>(kDataSize);
+
+ std::vector<SubsampleEntry> subsamples;
+ // Set a malicious DecryptConfig with subsamples larger than data size
+ subsamples.push_back(SubsampleEntry(50, 500));
+
+ buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
+ "key_id", "0123456789abcdef", subsamples));
+
+ // Convert to Mojom
+ mojom::DecoderBufferPtr mojo_buffer = mojom::DecoderBuffer::From(*buffer);
+
+ // Convert back to DecoderBuffer
+ scoped_refptr<DecoderBuffer> converted_buffer =
+ mojo_buffer.To<scoped_refptr<DecoderBuffer>>();
+
+ EXPECT_FALSE(converted_buffer);
+}
+
} // namespace media
diff --git a/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc b/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc
index d0312d5..6690ace 100644
--- a/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc
+++ b/media/mojo/common/mojo_decoder_buffer_converter_unittest.cc
@@ -14,6 +14,8 @@
#include "base/test/task_environment.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
+#include "media/base/subsample_entry.h"
+#include "media/mojo/common/media_type_converters.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -114,10 +116,7 @@
const char kKeyId[] = "00112233445566778899aabbccddeeff";
const char kIv[] = "0123456789abcdef";
- std::vector<SubsampleEntry> subsamples;
- subsamples.push_back(SubsampleEntry(10, 20));
- subsamples.push_back(SubsampleEntry(30, 40));
- subsamples.push_back(SubsampleEntry(50, 60));
+ std::vector<SubsampleEntry> subsamples = {SubsampleEntry(5, 8)};
scoped_refptr<DecoderBuffer> buffer(DecoderBuffer::CopyFrom(kData));
buffer->set_decrypt_config(
@@ -418,4 +417,31 @@
run_loop.Run();
}
+// This test confirms that `MojoDecoderBufferReader` correctly handles a
+// `nullptr` `DecoderBuffer` returned by the `TypeConverter` (due to subsample
+// validation failure) by invoking its read callback with `nullptr`, preventing
+// a `DCHECK` crash.
+TEST(MojoDecoderBufferConverterTest, ReadMalformedDecoderBuffer) {
+ base::test::SingleThreadTaskEnvironment task_environment;
+ base::RunLoop run_loop;
+ MojoDecoderBufferConverter converter;
+
+ // Create a buffer and attach a malformed DecryptConfig (subsamples larger
+ // than data size).
+ const uint8_t kData[] = "Hello, world";
+ auto media_buffer = DecoderBuffer::CopyFrom(kData);
+ std::vector<SubsampleEntry> subsamples;
+ subsamples.emplace_back(SubsampleEntry(50, 500));
+ media_buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
+ "key_id", "0123456789abcdef", subsamples));
+
+ auto mojo_buffer = mojom::DecoderBuffer::From(*media_buffer);
+ base::MockCallback<MojoDecoderBufferReader::ReadCB> mock_cb;
+ EXPECT_CALL(mock_cb, Run(testing::IsNull()))
+ .WillOnce(testing::InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+
+ converter.reader->ReadDecoderBuffer(std::move(mojo_buffer), mock_cb.Get());
+ run_loop.Run();
+}
+
} // namespace media
diff --git a/media/mojo/services/mojo_demuxer_stream_adapter_unittest.cc b/media/mojo/services/mojo_demuxer_stream_adapter_unittest.cc
index 1ef1faf4..c7a94d1 100644
--- a/media/mojo/services/mojo_demuxer_stream_adapter_unittest.cc
+++ b/media/mojo/services/mojo_demuxer_stream_adapter_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "media/mojo/services/mojo_demuxer_stream_adapter.h"
+
#include <memory>
#include "base/run_loop.h"
@@ -10,11 +12,12 @@
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/decrypt_config.h"
#include "media/base/demuxer_stream.h"
#include "media/base/mock_filters.h"
+#include "media/base/subsample_entry.h"
#include "media/base/test_helpers.h"
#include "media/mojo/clients/mojo_demuxer_stream_impl.h"
-#include "media/mojo/services/mojo_demuxer_stream_adapter.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::base::test::RunOnceCallback;
@@ -207,4 +210,37 @@
loop.RunUntilIdle();
}
+// This test verifies that the `MojoDemuxerStreamAdapter` properly identifies
+// and stops a read operation when presented with a `DecoderBuffer` containing
+// malformed subsample data.
+TEST_F(MojoDemuxerStreamAdapterTest, ReadAbortedOnOOBSubsample) {
+ Initialize(DemuxerStream::Type::AUDIO);
+
+ base::RunLoop abort_read_loop;
+ DemuxerStream::DecoderBufferVector buffers;
+
+ auto buffer = base::MakeRefCounted<DecoderBuffer>(100);
+ std::vector<SubsampleEntry> subsamples;
+ // Set a malicious DecryptConfig with subsamples describing more bytes than
+ // data size
+ subsamples.emplace_back(SubsampleEntry(50, 500));
+ buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
+ "key_id", "0123456789abcdef", subsamples));
+
+ buffers.push_back(buffer);
+
+ EXPECT_CALL(*stream_, OnRead(_))
+ .WillOnce(RunOnceCallback<0>(DemuxerStream::Status::kOk, buffers));
+
+ auto done_cb = base::BindLambdaForTesting(
+ [&](DemuxerStream::Status status,
+ DemuxerStream::DecoderBufferVector read_buffers) {
+ EXPECT_EQ(status, DemuxerStream::Status::kError);
+ EXPECT_TRUE(read_buffers.empty());
+ abort_read_loop.QuitWhenIdle();
+ });
+ ReadBuffer(1, done_cb);
+ abort_read_loop.Run();
+}
+
} // namespace media
Original Bug Report
Missing validation of subsample metadata in MediaFoundation decryption path allows sandbox escape
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A compromised renderer can provide malicious subsample metadata in a DecoderBuffer that exceeds the buffer’s data size. This unvalidated metadata is passed to the Media Foundation (MF) utility process and converted into an IMFSample, potentially triggering an out-of-bounds memory access in an MF decryptor. This can lead to a sandbox escape from the renderer into the higher-privilege MF CDM utility process on Windows.
Affected files:
media/base/win/mf_helpers.ccmedia/mojo/services/mojo_demuxer_stream_adapter.ccmedia/renderers/win/media_foundation_stream_wrapper.ccmedia/mojo/common/media_type_converters.cc
Estimated timestamp from git blame: 2024-01-30
Vulnerability Summary
A potential security vulnerability exists in the MediaFoundation-based decryption path on Windows where subsample geometry provided by a renderer process is not validated before being passed to the Media Foundation (MF) utility process. A compromised renderer can supply a DecoderBuffer over the mojom::DemuxerStream Mojo pipe with a DecryptConfig whose subsamples describe more bytes than are actually present in the buffer’s data. This unvalidated metadata is subsequently used to create an IMFSample attribute in the MF CDM utility process, leading to a potential out-of-bounds (OOB) read or write.
Technical Details
In the MediaFoundationRenderer implementation, media data flows from the MojoDemuxerStreamImpl in the renderer process to the MojoDemuxerStreamAdapter in the MF utility process. The vulnerability arises from a lack of validation during this data flow:
- Missing Validation on Reception: When a
DecoderBufferis received via Mojo in the MF utility process,MojoDemuxerStreamAdapter::OnBufferRead(media/mojo/services/mojo_demuxer_stream_adapter.cc:127) processes the buffer but fails to callmedia::DecoderBuffer::DoSubsamplesMatch(). This helper function is used in other decryption paths (likeDecryptingVideoDecoder) to ensure that the sum of clear and encrypted bytes in the subsamples matches the buffer’s data size. - Unvalidated Type Conversion: The
media::TypeConverterforDecoderBufferinmedia/mojo/common/media_type_converters.ccdeserializes the Mojo struct and populates theDecryptConfigand its subsamples without any integrity checks against the buffer’s overall size. - Insecure IMFSample Creation: The unvalidated buffer is passed to
GenerateSampleFromDecoderBufferinmedia/base/win/mf_helpers.cc:673(called bymedia/renderers/win/media_foundation_stream_wrapper.cc). This function translates theDecoderBufferinto a Windows Media FoundationIMFSample. It allocates an OS-levelIMFMediaBufferof sizeN(the actual data size) and copies the data into it. - Malicious Metadata Attachment: Because the buffer is encrypted,
AddEncryptAttributes(media/base/win/mf_helpers.cc:150) is called. This helper iterates through the unvalidateddecrypt_config.subsamples()and attaches them as anMFSampleExtension_Encryption_SubSample_Mappingblob to theIMFSamplewithout any bounds checking against theNbyte data length. - OOB Memory Access: The resulting
IMFSamplecontains a memory buffer of sizeN, but the subsample mapping attribute describes a sizeM(whereM > N). When this sample is processed by a decrypting Media Foundation Transform (MFT), such as the PlayReady MFT in the MF CDM utility process, the MFT may rely on the provided subsample mapping. If the MFT iterates through this mapping without re-validating it against the buffer’s actual length, it results in an OOB read. For in-place decryption (such as AES-CTR or AES-CBC), this also results in an OOB write.
Impact
An attacker who has compromised the renderer process can potentially achieve memory corruption (OOB read/write) in the Media Foundation CDM utility process. As defined in sandbox/policy/win/sandbox_win.cc:581, this process runs in a less restrictive sandbox with JobLevel::kInteractive to allow it to launch the protected media pipeline process (mfpmp.exe). Furthermore, it runs with the LPAC USER_UNPROTECTED token, granting more privileges than the renderer. Exploiting this OOB write allows the attacker to execute arbitrary code within this less-restricted context, achieving a sandbox escape and privilege escalation on Windows systems using hardware-secure EME playback.
Suggested Attack Steps
(Note: These are potential steps; our tooling agent does not have the ability to run code to provide a working PoC.)
- Compromise a renderer process and initiate encrypted media playback (e.g., via Encrypted Media Extensions) to establish a connection to the Media Foundation CDM utility process.
- Construct a malicious
media::mojom::DecoderBuffermessage to send to the utility process over themojom::DemuxerStreaminterface. - Set the
data_sizeof the MojoDecoderBufferto a valid valueN(e.g., 100 bytes). - Populate the
decrypt_configfield of the MojoDecoderBufferwith an array ofsubsampleswhere the sum ofclear_bytesandcipher_bytesequalsM, whereMis significantly larger thanN(e.g., 1000 bytes). - Send the metadata over the Mojo message pipe, and the
Nbytes of actual media data over the associated Mojo DataPipe. - The MF CDM utility process will deserialize the buffer, create an
IMFSamplewith anN-byte buffer and theM-byte subsample mapping, and pass it to a decrypting MFT, potentially triggering the OOB memory access.
Recommended Fix
The media::DecoderBuffer::DoSubsamplesMatch() check must be enforced when receiving DecoderBuffer objects from a Mojo stream in the Media Foundation renderer path. This validation should occur as soon as the data is received and reassembled from the untrusted renderer process.
Specifically, a check like if (buffer->is_encrypted() && !media::DecoderBuffer::DoSubsamplesMatch(*buffer)) should be added to MojoDemuxerStreamAdapter::OnBufferRead in media/mojo/services/mojo_demuxer_stream_adapter.cc:127. If the subsamples do not match the buffer size, the stream adapter should abort the read or fail gracefully.
Evaluated with Chrome root at commit: 4859e669de60239572397b559c17dfab074511e9
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.