From df29c42108bd241e3c4b8e328a12892e540dff2d Mon Sep 17 00:00:00 2001 From: "John W. Bruce" Date: Wed, 14 Aug 2024 00:37:50 +0000 Subject: [PATCH] Limit output buffer size during decrypt fallback This is based on a patch submitted by Amlogic. When we're doing decrypt fallback, either in the CDM or the OEMCrypto tests, we sometimes fall back to a point where we're synthesizing new samples and/or subsamples for the content being decrypted. When this happens and the output buffer is clear, we should limit the size of the output buffer to only the space needed to hold the output. Previously, we've been passing the entire output buffer to every call. This can create a problem if the reason for the fallback is a lack of enough memory to communicate the buffers to the TA, since the output buffer will remain the same size as the total output. Restricting the buffer passed to each call to only the space needed by that call will reduce the memory requirement. Cherry-picked from http://go/wvgerrit/205311 Bug: 354834629 Test: x86-64 Merged from https://widevine-internal-review.googlesource.com/204810 Change-Id: I412f43d8f88c72072ef1dd5293436bdb58e500b3 --- .../cdm/core/src/crypto_session.cpp | 20 ++++++++++++++++++- .../test/oec_decrypt_fallback_chain.cpp | 16 ++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index b784a504..7ecae6e1 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -160,7 +160,6 @@ void AdvanceDestBuffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { switch (dest_buffer->type) { case OEMCrypto_BufferType_Clear: dest_buffer->buffer.clear.clear_buffer += bytes; - dest_buffer->buffer.clear.clear_buffer_length -= bytes; return; case OEMCrypto_BufferType_Secure: @@ -3153,6 +3152,11 @@ OEMCryptoResult CryptoSession::DecryptSample( } fake_sample.buffers.input_data_length = length; + if (fake_sample.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + fake_sample.buffers.output_descriptor.buffer.clear + .clear_buffer_length = length; + } fake_sample.subsamples = &clear_subsample; fake_sample.subsamples_length = 1; @@ -3180,6 +3184,11 @@ OEMCryptoResult CryptoSession::DecryptSample( } fake_sample.buffers.input_data_length = length; + if (fake_sample.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + fake_sample.buffers.output_descriptor.buffer.clear + .clear_buffer_length = length; + } fake_sample.subsamples = &encrypted_subsample; fake_sample.subsamples_length = 1; @@ -3272,6 +3281,10 @@ OEMCryptoResult CryptoSession::LegacyCopyBufferInChunks( // Calculate the size of the next chunk. const size_t chunk_size = std::min(remaining_input_data, max_chunk_size); + if (output_descriptor.type == OEMCrypto_BufferType_Clear) { + output_descriptor.buffer.clear.clear_buffer_length = chunk_size; + } + // Re-add "last subsample" flag if this is the last subsample. if (chunk_size == remaining_input_data) { subsample_flags |= OEMCrypto_LastSubsample; @@ -3319,6 +3332,11 @@ OEMCryptoResult CryptoSession::LegacyDecryptInChunks( // Calculate the size of the next chunk. const size_t chunk_size = std::min(remaining_input_data, max_chunk_size); fake_sample.buffers.input_data_length = chunk_size; + if (fake_sample.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = + chunk_size; + } if (is_protected) { fake_subsample.num_bytes_encrypted = chunk_size; } else { diff --git a/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp index 6cb7aac0..fe303fc6 100644 --- a/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -17,7 +17,6 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { switch (dest_buffer->type) { case OEMCrypto_BufferType_Clear: dest_buffer->buffer.clear.clear_buffer += bytes; - dest_buffer->buffer.clear.clear_buffer_length -= bytes; break; case OEMCrypto_BufferType_Secure: @@ -99,6 +98,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( const size_t length = subsample.num_bytes_clear + subsample.num_bytes_encrypted; fake_sample.buffers.input_data_length = length; + if (fake_sample.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = + length; + } fake_sample.subsamples = &subsample; fake_sample.subsamples_length = 1; @@ -144,6 +148,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.num_bytes_clear > 0) { fake_sample.buffers.input_data_length = subsample.num_bytes_clear; + if (fake_sample.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = + subsample.num_bytes_clear; + } fake_subsample.num_bytes_clear = subsample.num_bytes_clear; fake_subsample.num_bytes_encrypted = 0; fake_subsample.block_offset = 0; @@ -167,6 +176,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.num_bytes_encrypted > 0) { fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted; + if (fake_sample.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = + subsample.num_bytes_encrypted; + } fake_subsample.num_bytes_clear = 0; fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted; fake_subsample.block_offset = subsample.block_offset;