From 5060edc565a0e3df14153ec54f61c14ec0d40ea1 Mon Sep 17 00:00:00 2001 From: Santiago Seifert Date: Thu, 30 Sep 2021 13:15:21 +0000 Subject: [PATCH 01/14] Fix heap-buffer-overflow in MPEG4Extractor am: d13a4efc7a Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/av/+/15747591 Bug: 201632451 Bug: 188893559 Change-Id: Ie775311a46cb1ddddd30e8cfa882d549b9ddfd05 Merged-In: I31f2b9a4f1b561c4466c76ea2af8dd532622102a (cherry picked from commit 3c5de138ed3b697e0119e7526ae7f6ed09f357cc) --- media/extractors/mp4/MPEG4Extractor.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) mode change 100755 => 100644 media/extractors/mp4/MPEG4Extractor.cpp diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp old mode 100755 new mode 100644 index a976a2b12a..f157d359b2 --- a/media/extractors/mp4/MPEG4Extractor.cpp +++ b/media/extractors/mp4/MPEG4Extractor.cpp @@ -146,6 +146,7 @@ static const size_t kMaxPcmFrameSize = 8192; MediaBufferHelper *mBuffer; + size_t mSrcBufferSize; uint8_t *mSrcBuffer; bool mIsHeif; @@ -4882,6 +4883,7 @@ MPEG4Source::MPEG4Source( mNALLengthSize(0), mStarted(false), mBuffer(NULL), + mSrcBufferSize(0), mSrcBuffer(NULL), mIsHeif(itemTable != NULL), mItemTable(itemTable), @@ -5060,6 +5062,7 @@ media_status_t MPEG4Source::start() { // file probably specified a bad max size return AMEDIA_ERROR_MALFORMED; } + mSrcBufferSize = max_size; mStarted = true; @@ -5076,6 +5079,7 @@ media_status_t MPEG4Source::stop() { mBuffer = NULL; } + mSrcBufferSize = 0; delete[] mSrcBuffer; mSrcBuffer = NULL; @@ -6242,13 +6246,20 @@ media_status_t MPEG4Source::read( // Whole NAL units are returned but each fragment is prefixed by // the start code (0x00 00 00 01). ssize_t num_bytes_read = 0; - num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size); + bool mSrcBufferFitsDataToRead = size <= mSrcBufferSize; + if (mSrcBufferFitsDataToRead) { + num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size); + } else { + // We are trying to read a sample larger than the expected max sample size. + // Fall through and let the failure be handled by the following if. + android_errorWriteLog(0x534e4554, "188893559"); + } if (num_bytes_read < (ssize_t)size) { mBuffer->release(); mBuffer = NULL; - return AMEDIA_ERROR_IO; + return mSrcBufferFitsDataToRead ? AMEDIA_ERROR_IO : AMEDIA_ERROR_MALFORMED; } uint8_t *dstData = (uint8_t *)mBuffer->data(); From 4b8694e737a2820d2d7fa41ec9820ac2a1008f91 Mon Sep 17 00:00:00 2001 From: Manisha Jajoo Date: Fri, 23 Jul 2021 23:03:50 +0530 Subject: [PATCH 02/14] C2SoftMp3Dec: fix OOB write in output buffer outputFrameSize, calOutSize and outSize are calculated at 8bit level However, the library expects outputFrameSize in int16 samples. One of the initialization of outputFrameSize was in bytes. This is now corrected. Test: clusterfuzz generated poc in bug Test: atest android.mediav2.cts.CodecDecoderTest Test: atest VtsHalMediaC2V1_0TargetAudioDecTest Bug: 193363621 Change-Id: Iac62c4e9d77e7f95f2c692f5ea236e7a5c536dcb (cherry picked from commit dc32721e28e79df4dd2f5bb896bcf586ebeda5e9) --- media/codec2/components/mp3/C2SoftMp3Dec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp index 5ba7e3d78f..3984f62278 100644 --- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp +++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp @@ -405,7 +405,7 @@ void C2SoftMP3::process( mConfig->inputBufferCurrentLength = (inSize - inPos); mConfig->inputBufferMaxLength = 0; mConfig->inputBufferUsedLength = 0; - mConfig->outputFrameSize = (calOutSize - outSize); + mConfig->outputFrameSize = (calOutSize - outSize) / sizeof(int16_t); mConfig->pOutputBuffer = reinterpret_cast (wView.data() + outSize); ERROR_CODE decoderErr; From b8e36e76b55a74ede20a4de0235b55d26d62d01a Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Wed, 29 Sep 2021 08:24:26 -0700 Subject: [PATCH 03/14] SimpleDecodingSource:Prevent OOB write in heap mem doRead() doesn't handle situations when received byte do not fit into input buffer in case of vorbis audio compression. It results in OOB write in heap memory right after the allocated input buffer. Added code to copy kKeyValidSamples only if there was enough space. Otherwise, print a warning log. Bug: 194105348 Test: post-submit media cts tests Change-Id: I2b27580deff9ad937b68703a1e7c3ff2a6dccc60 (cherry picked from commit a625b40e1c210f1e8ed57962eee9f70cef06fb1b) (cherry picked from commit f3590a1b18d8cde4ac1cbc135c1022816096438d) Merged-In:I2b27580deff9ad937b68703a1e7c3ff2a6dccc60 --- media/libstagefright/SimpleDecodingSource.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp index 771dfeabf5..55aa86b8cb 100644 --- a/media/libstagefright/SimpleDecodingSource.cpp +++ b/media/libstagefright/SimpleDecodingSource.cpp @@ -318,18 +318,23 @@ status_t SimpleDecodingSource::doRead( } size_t cpLen = min(in_buf->range_length(), in_buffer->capacity()); memcpy(in_buffer->base(), (uint8_t *)in_buf->data() + in_buf->range_offset(), - cpLen ); + cpLen); if (mIsVorbis) { int32_t numPageSamples; if (!in_buf->meta_data().findInt32(kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } - memcpy(in_buffer->base() + cpLen, &numPageSamples, sizeof(numPageSamples)); + if (cpLen + sizeof(numPageSamples) <= in_buffer->capacity()) { + memcpy(in_buffer->base() + cpLen, &numPageSamples, sizeof(numPageSamples)); + cpLen += sizeof(numPageSamples); + } else { + ALOGW("Didn't have enough space to copy kKeyValidSamples"); + } } res = mCodec->queueInputBuffer( - in_ix, 0 /* offset */, in_buf->range_length() + (mIsVorbis ? 4 : 0), + in_ix, 0 /* offset */, cpLen, timestampUs, 0 /* flags */); if (res != OK) { ALOGI("[%s] failed to queue input buffer #%zu", mComponentName.c_str(), in_ix); From 069384de9b4392babb233cf0c3c46e0059ad39de Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Tue, 9 Nov 2021 16:14:41 -0800 Subject: [PATCH 04/14] Better buffer-overrun prevention fixes end-of-buffer detection. Adds buffer-was-empty detection. Bug: 204445255 Test: ran poc from bug Change-Id: I42117ce1455d1cac2bd43f16d67d77ec436b0fe2 (cherry picked from commit b51ed962d5186b68f883540e557894e881a8272d) (cherry picked from commit 190e90959f3c34781c5276d50a5ee561c438db09) Merged-In:I42117ce1455d1cac2bd43f16d67d77ec436b0fe2 --- media/libmediametrics/include/media/MediaMetricsItem.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h index 303343f91c..e36f0a0f39 100644 --- a/media/libmediametrics/include/media/MediaMetricsItem.h +++ b/media/libmediametrics/include/media/MediaMetricsItem.h @@ -466,16 +466,15 @@ class BaseItem { template <> // static status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) { const char *ptr = *bufferpptr; - while (*ptr != 0) { + do { if (ptr >= bufferptrmax) { ALOGE("%s: buffer exceeded", __func__); return BAD_VALUE; } - ++ptr; - } - const size_t size = (ptr - *bufferpptr) + 1; + } while (*ptr++ != 0); + // ptr is terminator+1, == bufferptrmax if we finished entire buffer *val = *bufferpptr; - *bufferpptr += size; + *bufferpptr = ptr; return NO_ERROR; } template <> // static From d26a91ab2437b196dda9065f165982d7a400ef2c Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Mon, 6 Dec 2021 10:22:33 -0800 Subject: [PATCH 05/14] Safetynet logging for b/204445255 Bug: 204445255 Test: poc from original bug Change-Id: I569477d0771e1c03318df9ef271cf3201d472c99 (cherry picked from commit 94e58d6b2497d2e0f7e86e2c979e7f6958c84590) Merged-In:I569477d0771e1c03318df9ef271cf3201d472c99 --- media/libmediametrics/include/media/MediaMetricsItem.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h index e36f0a0f39..7ce75ed4f7 100644 --- a/media/libmediametrics/include/media/MediaMetricsItem.h +++ b/media/libmediametrics/include/media/MediaMetricsItem.h @@ -27,6 +27,7 @@ #include #include +#include #include #include // nsecs_t @@ -469,6 +470,7 @@ class BaseItem { do { if (ptr >= bufferptrmax) { ALOGE("%s: buffer exceeded", __func__); + android_errorWriteLog(0x534e4554, "204445255"); return BAD_VALUE; } } while (*ptr++ != 0); From ad67d78cefabacea4939d6bcbb3e4f631820b178 Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Tue, 11 Jan 2022 23:44:20 -0800 Subject: [PATCH 06/14] C2AllocatorIon:protect mMappings using mutex Use mutex to prevent multiple threads accessing same member of mMappings list at the same time. Bug: 193790350 Test: adb shell UBSAN_OPTIONS=print_stacktrace=1 /data/local/tmp/C2FuzzerMp3Dec -rss_limit_mb=2560 -timeout=90 -runs=100 /data/local/tmp/clusterfuzz-testcase-minimized-C2FuzzerMp3Dec-5713156165206016 Change-Id: I24e53629d5a6dfad22b84dd2278eb1a288c9ab35 Merged-In: I24e53629d5a6dfad22b84dd2278eb1a288c9ab35 (cherry picked from commit 9d2295f3a008f60bcfa3d2da3b43c078efec1878) (cherry picked from commit 416da6e8da6b6a16c5c00bddd9fbc7a5f060cd58) Merged-In:I24e53629d5a6dfad22b84dd2278eb1a288c9ab35 --- media/codec2/vndk/C2AllocatorIon.cpp | 37 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp index 6d27a0212d..9410ce93fc 100644 --- a/media/codec2/vndk/C2AllocatorIon.cpp +++ b/media/codec2/vndk/C2AllocatorIon.cpp @@ -202,6 +202,7 @@ class C2AllocationIon::Impl { c2_status_t err = mapInternal(mapSize, mapOffset, alignmentBytes, prot, flags, &(map.addr), addr); if (map.addr) { + std::lock_guard guard(mMutexMappings); mMappings.push_back(map); } return err; @@ -212,22 +213,26 @@ class C2AllocationIon::Impl { ALOGD("tried to unmap unmapped buffer"); return C2_NOT_FOUND; } - for (auto it = mMappings.begin(); it != mMappings.end(); ++it) { - if (addr != (uint8_t *)it->addr + it->alignmentBytes || - size + it->alignmentBytes != it->size) { - continue; + { // Scope for the lock_guard of mMutexMappings. + std::lock_guard guard(mMutexMappings); + for (auto it = mMappings.begin(); it != mMappings.end(); ++it) { + if (addr != (uint8_t *)it->addr + it->alignmentBytes || + size + it->alignmentBytes != it->size) { + continue; + } + int err = munmap(it->addr, it->size); + if (err != 0) { + ALOGD("munmap failed"); + return c2_map_errno(errno); + } + if (fence) { + *fence = C2Fence(); // not using fences + } + (void)mMappings.erase(it); + ALOGV("successfully unmapped: addr=%p size=%zu fd=%d", addr, size, + mHandle.bufferFd()); + return C2_OK; } - int err = munmap(it->addr, it->size); - if (err != 0) { - ALOGD("munmap failed"); - return c2_map_errno(errno); - } - if (fence) { - *fence = C2Fence(); // not using fences - } - (void)mMappings.erase(it); - ALOGV("successfully unmapped: addr=%p size=%zu fd=%d", addr, size, mHandle.bufferFd()); - return C2_OK; } ALOGD("unmap failed to find specified map"); return C2_BAD_VALUE; @@ -236,6 +241,7 @@ class C2AllocationIon::Impl { virtual ~Impl() { if (!mMappings.empty()) { ALOGD("Dangling mappings!"); + std::lock_guard guard(mMutexMappings); for (const Mapping &map : mMappings) { (void)munmap(map.addr, map.size); } @@ -315,6 +321,7 @@ class C2AllocationIon::Impl { size_t size; }; std::list mMappings; + std::mutex mMutexMappings; }; class C2AllocationIon::ImplV2 : public C2AllocationIon::Impl { From 6b779962588ef76c44b0da8a5085772329cdf10a Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Wed, 2 Feb 2022 13:33:50 -0800 Subject: [PATCH 07/14] Safe parsing of HEIF framecount information Bug: 215002587 Test: POC described in bug Change-Id: I92f8fdfe860cb360fb0ae099db3c92776ba7390f (cherry picked from commit e89e632f9aa04e15291ee096b3152b40474a993d) (cherry picked from commit 616bd340ecded759720199bcf5b8562e0fdf3f59) Merged-In:I92f8fdfe860cb360fb0ae099db3c92776ba7390f --- media/libheif/HeifDecoderImpl.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp index 273d91ccde..4a96e7b093 100644 --- a/media/libheif/HeifDecoderImpl.cpp +++ b/media/libheif/HeifDecoderImpl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -421,7 +422,13 @@ bool HeifDecoderImpl::reinit(HeifFrameInfo* frameInfo) { initFrameInfo(&mSequenceInfo, videoFrame); - mSequenceLength = atoi(mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT)); + const char* frameCount = mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT); + if (frameCount == nullptr) { + android_errorWriteWithInfoLog(0x534e4554, "215002587", -1, NULL, 0); + ALOGD("No valid sequence information in metadata"); + return false; + } + mSequenceLength = atoi(frameCount); if (defaultInfo == nullptr) { defaultInfo = &mSequenceInfo; From 600adbf0e303336b9d27909ec0580b6166650f1e Mon Sep 17 00:00:00 2001 From: Santiago Seifert Date: Thu, 19 May 2022 15:29:26 +0000 Subject: [PATCH 08/14] Avoid read out of bounds Bug: 230493653 Change-Id: Ieca5a5390d3cf73fff6aa552d065363d84e1ccc2 Merged-In: Ieca5a5390d3cf73fff6aa552d065363d84e1ccc2 Test: See bug for PoC. (cherry picked from commit 306aad773337f228bffcf5bf07a3e6663226f42c) (cherry picked from commit 9d33304ec75b366ed9750e7bde6f96f8c704e1c8) Merged-In: Ieca5a5390d3cf73fff6aa552d065363d84e1ccc2 --- media/extractors/mp4/MPEG4Extractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp index f157d359b2..78e3f00b44 100644 --- a/media/extractors/mp4/MPEG4Extractor.cpp +++ b/media/extractors/mp4/MPEG4Extractor.cpp @@ -4573,7 +4573,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( if (len2 == 0) { return ERROR_MALFORMED; } - if (offset >= csd_size || csd[offset] != 0x01) { + if (offset + len1 > csd_size || csd[offset] != 0x01) { return ERROR_MALFORMED; } // formerly kKeyVorbisInfo From 2e0c25bb1d43eb0e7d95cb14f07773583d2f2520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Budnik?= Date: Mon, 20 Jun 2022 10:36:28 +0000 Subject: [PATCH 09/14] Fix Out of Bounds read in TextDescriptions.cpp Fixing vulnerability in extract3GGPGlobalDescriptions() in TextDescriptions.cpp Bug: 233735886 Test: Run related PoC. See bug. Change-Id: I87955b911d0a40390755321d332a11ecc9b20354 (cherry picked from commit b63d4e785ba4d896bbbd50d4f09bda13294926af) Merged-In: I87955b911d0a40390755321d332a11ecc9b20354 --- media/libstagefright/timedtext/TextDescriptions.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp index 2c2d11d45b..3fec9edf65 100644 --- a/media/libstagefright/timedtext/TextDescriptions.cpp +++ b/media/libstagefright/timedtext/TextDescriptions.cpp @@ -466,6 +466,10 @@ status_t TextDescriptions::extract3GPPGlobalDescriptions( if (subChunkType == FOURCC('f', 't', 'a', 'b')) { + if(subChunkSize < 8) { + return OK; + } + tmpData += 8; size_t subChunkRemaining = subChunkSize - 8; From 901dabe431a86fdd5760e3a75c87cd8b11ce4fc3 Mon Sep 17 00:00:00 2001 From: jiabin Date: Wed, 15 Jun 2022 19:26:01 +0000 Subject: [PATCH 10/14] Cache MMAP client silenced state. When starting MMAP input stream, APM will check if the client is allowed to capture at that moment or not and call setRecordSilenced if the client is not allowed. However, the client is not active when starting the MMAP input stream. In that case, the client silenced state will be lost and the client will be able to capture even though it is not allowed. In this CL, when setRecordSilenced is called, it will cache the client silenced state so that it can apply when the client is active. Test: atest AAudioTests Test: repo steps from the bug Bug: 235850634 Change-Id: I49b5a0f08d1747053f868db6e88c0f677256fc3c Merged-In: I49b5a0f08d1747053f868db6e88c0f677256fc3c (cherry picked from commit 0960903b2fee5d1d449ffcd598e0b5d3a945d99a) (cherry picked from commit a2f00f95e0e74efe439a591b236afb598dbf8972) Merged-In: I49b5a0f08d1747053f868db6e88c0f677256fc3c --- services/audioflinger/Threads.cpp | 12 ++++++++++++ services/audioflinger/Threads.h | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 4431486a0a..96ab1f59e2 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -8925,6 +8925,12 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client, if (isOutput()) { ret = AudioSystem::startOutput(portId); } else { + { + // Add the track record before starting input so that the silent status for the + // client can be cached. + Mutex::Autolock _l(mLock); + setClientSilencedState_l(portId, false /*silenced*/); + } ret = AudioSystem::startInput(portId); } @@ -8943,6 +8949,7 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client, } else { mHalStream->stop(); } + eraseClientSilencedState_l(portId); return PERMISSION_DENIED; } @@ -8951,6 +8958,9 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client, mChannelMask, mSessionId, isOutput(), client.clientUid, client.clientPid, IPCThreadState::self()->getCallingPid(), portId); + if (!isOutput()) { + track->setSilenced_l(isClientSilenced_l(portId)); + } if (isOutput()) { // force volume update when a new track is added @@ -9007,6 +9017,7 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) } mActiveTracks.remove(track); + eraseClientSilencedState_l(track->portId()); mLock.unlock(); if (isOutput()) { @@ -9786,6 +9797,7 @@ void AudioFlinger::MmapCaptureThread::setRecordSilenced(audio_port_handle_t port broadcast_l(); } } + setClientSilencedIfExists_l(portId, silenced); } void AudioFlinger::MmapCaptureThread::toAudioPortConfig(struct audio_port_config *config) diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index b8356d3a23..21ab59353d 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1847,6 +1847,26 @@ class MmapThread : public ThreadBase virtual void setRecordSilenced(audio_port_handle_t portId __unused, bool silenced __unused) {} + void setClientSilencedState_l(audio_port_handle_t portId, bool silenced) { + mClientSilencedStates[portId] = silenced; + } + + size_t eraseClientSilencedState_l(audio_port_handle_t portId) { + return mClientSilencedStates.erase(portId); + } + + bool isClientSilenced_l(audio_port_handle_t portId) const { + const auto it = mClientSilencedStates.find(portId); + return it != mClientSilencedStates.end() ? it->second : false; + } + + void setClientSilencedIfExists_l(audio_port_handle_t portId, bool silenced) { + const auto it = mClientSilencedStates.find(portId); + if (it != mClientSilencedStates.end()) { + it->second = silenced; + } + } + protected: void dumpInternals_l(int fd, const Vector& args) override; void dumpTracks_l(int fd, const Vector& args) override; @@ -1866,6 +1886,7 @@ class MmapThread : public ThreadBase AudioHwDevice* const mAudioHwDev; ActiveTracks mActiveTracks; float mHalVolFloat; + std::map mClientSilencedStates; int32_t mNoCallbackWarningCount; static constexpr int32_t kMaxNoCallbackWarnings = 5; From 40f752b508a8a43543556d1fff446e572f267894 Mon Sep 17 00:00:00 2001 From: Edwin Wong Date: Tue, 21 Jun 2022 01:36:43 +0000 Subject: [PATCH 11/14] RESTRICT AUTOMERGE - [Fix vulnerability] setSecurityLevel in clearkey Potential race condition in clearkey setSecurityLevel. POC test in http://go/ag/19083795 Test: sts-tradefed run sts-dynamic-develop -m StsHostTestCases -t android.security.sts.CVE_2022_2209#testPocCVE_2022_2209 Bug: 235601882 Change-Id: I6447fb539ef0cb395772c61e6f3e1504ccde331b Merged-In: I2e2084e85fe45d7d7f958c59b0063a477c7d24bf (cherry picked from commit d37b69272aa68a92357baa95d0eb87012666a90b) Merged-In: I6447fb539ef0cb395772c61e6f3e1504ccde331b --- drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp | 2 ++ drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp index 6f69110d50..0e5169c9e0 100644 --- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp +++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp @@ -623,6 +623,7 @@ Return DrmPlugin::getSecurityLevel(const hidl_vec& sessionId, return Void(); } + Mutex::Autolock lock(mSecurityLevelLock); std::map, SecurityLevel>::iterator itr = mSecurityLevel.find(sid); if (itr == mSecurityLevel.end()) { @@ -653,6 +654,7 @@ Return DrmPlugin::setSecurityLevel(const hidl_vec& sessionId, return Status::ERROR_DRM_SESSION_NOT_OPENED; } + Mutex::Autolock lock(mSecurityLevelLock); std::map, SecurityLevel>::iterator itr = mSecurityLevel.find(sid); if (itr != mSecurityLevel.end()) { diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h index 894985bd1b..e957cee194 100644 --- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h +++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h @@ -398,7 +398,8 @@ struct DrmPlugin : public IDrmPlugin { std::map mStringProperties; std::map > mByteArrayProperties; std::map > mReleaseKeysMap; - std::map, SecurityLevel> mSecurityLevel; + std::map, SecurityLevel> mSecurityLevel + GUARDED_BY(mSecurityLevelLock); sp mListener; sp mListenerV1_2; SessionLibrary *mSessionLibrary; @@ -419,6 +420,7 @@ struct DrmPlugin : public IDrmPlugin { DeviceFiles mFileHandle GUARDED_BY(mFileHandleLock); Mutex mFileHandleLock; Mutex mSecureStopLock; + Mutex mSecurityLevelLock; CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin); }; From a50d8aef7a0a978f5a165176c60bce35cf72c90b Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Thu, 1 Dec 2022 15:33:25 -0600 Subject: [PATCH 12/14] move MediaCodec metrics processing to looper thread consolidate to avoid concurrency/mutex problems. Bug: 256087846 Bug: 245860753 Test: atest CtsMediaV2TestCases Test: atest CtsMediaCodecTestCases Merged-In: Ie77f0028cab8091edd97d3a60ad4c80da3092cfe Merged-In: I56eceb6b12ce14348d3f9f2944968e70c6086aa8 Merged-In: I94b0a2ac029dc0b90a93e9ed844768e9da5259b9 Change-Id: I739248436a4801a4b9a96395f481640f2956cedf (cherry picked from commit 49e842e70836bbd58970beefac9c7b6bfe6a124b) Merged-In: I739248436a4801a4b9a96395f481640f2956cedf --- media/libstagefright/MediaCodec.cpp | 119 ++++++++++++++---- .../include/media/stagefright/MediaCodec.h | 4 + 2 files changed, 101 insertions(+), 22 deletions(-) diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 553f59a41f..8283187c80 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -720,6 +720,8 @@ MediaCodec::MediaCodec( }; } + // we want an empty metrics record for any early getMetrics() call + // this should be the *only* initMediametrics() call that's not on the Looper thread initMediametrics(); } @@ -728,8 +730,17 @@ MediaCodec::~MediaCodec() { mResourceManagerProxy->removeClient(); flushMediametrics(); + + // clean any saved metrics info we stored as part of configure() + if (mConfigureMsg != nullptr) { + mediametrics_handle_t metricsHandle; + if (mConfigureMsg->findInt64("metrics", &metricsHandle)) { + mediametrics_delete(metricsHandle); + } + } } +// except for in constructor, called from the looper thread (and therefore mutexed) void MediaCodec::initMediametrics() { if (mMetricsHandle == 0) { mMetricsHandle = mediametrics_create(kCodecKeyName); @@ -759,11 +770,12 @@ void MediaCodec::initMediametrics() { } void MediaCodec::updateMediametrics() { - ALOGV("MediaCodec::updateMediametrics"); if (mMetricsHandle == 0) { return; } + Mutex::Autolock _lock(mMetricsLock); + if (mLatencyHist.getCount() != 0 ) { mediametrics_setInt64(mMetricsHandle, kCodecLatencyMax, mLatencyHist.getMax()); mediametrics_setInt64(mMetricsHandle, kCodecLatencyMin, mLatencyHist.getMin()); @@ -798,6 +810,8 @@ void MediaCodec::updateMediametrics() { #endif } +// called to update info being passed back via getMetrics(), which is a +// unique copy for that call, no concurrent access worries. void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) { ALOGD("MediaCodec::updateEphemeralMediametrics()"); @@ -837,7 +851,13 @@ void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) { } void MediaCodec::flushMediametrics() { + ALOGD("flushMediametrics"); + + // update does its own mutex locking updateMediametrics(); + + // ensure mutex while we do our own work + Mutex::Autolock _lock(mMetricsLock); if (mMetricsHandle != 0) { if (mediametrics_count(mMetricsHandle) > 0) { mediametrics_selfRecord(mMetricsHandle); @@ -1220,6 +1240,8 @@ status_t MediaCodec::init(const AString &name) { } msg->setString("name", name); + // initial naming setup covers the period before the first call to ::configure(). + // after that, we manage this through ::configure() and the setup message. if (mMetricsHandle != 0) { mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str()); mediametrics_setCString(mMetricsHandle, kCodecMode, @@ -1279,18 +1301,24 @@ status_t MediaCodec::configure( const sp &descrambler, uint32_t flags) { sp msg = new AMessage(kWhatConfigure, this); + mediametrics_handle_t nextMetricsHandle = mediametrics_create(kCodecKeyName); - if (mMetricsHandle != 0) { + if (nextMetricsHandle != 0) { int32_t profile = 0; if (format->findInt32("profile", &profile)) { - mediametrics_setInt32(mMetricsHandle, kCodecProfile, profile); + mediametrics_setInt32(nextMetricsHandle, kCodecProfile, profile); } int32_t level = 0; if (format->findInt32("level", &level)) { - mediametrics_setInt32(mMetricsHandle, kCodecLevel, level); + mediametrics_setInt32(nextMetricsHandle, kCodecLevel, level); } - mediametrics_setInt32(mMetricsHandle, kCodecEncoder, + mediametrics_setInt32(nextMetricsHandle, kCodecEncoder, (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0); + + // moved here from ::init() + mediametrics_setCString(nextMetricsHandle, kCodecCodec, mInitName.c_str()); + mediametrics_setCString(nextMetricsHandle, kCodecMode, + mIsVideo ? kCodecModeVideo : kCodecModeAudio); } if (mIsVideo) { @@ -1300,17 +1328,17 @@ status_t MediaCodec::configure( mRotationDegrees = 0; } - if (mMetricsHandle != 0) { - mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth); - mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight); - mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees); + if (nextMetricsHandle != 0) { + mediametrics_setInt32(nextMetricsHandle, kCodecWidth, mVideoWidth); + mediametrics_setInt32(nextMetricsHandle, kCodecHeight, mVideoHeight); + mediametrics_setInt32(nextMetricsHandle, kCodecRotation, mRotationDegrees); int32_t maxWidth = 0; if (format->findInt32("max-width", &maxWidth)) { - mediametrics_setInt32(mMetricsHandle, kCodecMaxWidth, maxWidth); + mediametrics_setInt32(nextMetricsHandle, kCodecMaxWidth, maxWidth); } int32_t maxHeight = 0; if (format->findInt32("max-height", &maxHeight)) { - mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight); + mediametrics_setInt32(nextMetricsHandle, kCodecMaxHeight, maxHeight); } } @@ -1334,13 +1362,23 @@ status_t MediaCodec::configure( } else { msg->setPointer("descrambler", descrambler.get()); } - if (mMetricsHandle != 0) { - mediametrics_setInt32(mMetricsHandle, kCodecCrypto, 1); + if (nextMetricsHandle != 0) { + mediametrics_setInt32(nextMetricsHandle, kCodecCrypto, 1); } } else if (mFlags & kFlagIsSecure) { ALOGW("Crypto or descrambler should be given for secure codec"); } + if (mConfigureMsg != nullptr) { + // if re-configuring, we have one of these from before. + // Recover the space before we discard the old mConfigureMsg + mediametrics_handle_t metricsHandle; + if (mConfigureMsg->findInt64("metrics", &metricsHandle)) { + mediametrics_delete(metricsHandle); + } + } + msg->setInt64("metrics", nextMetricsHandle); + // save msg for reset mConfigureMsg = msg; @@ -1851,24 +1889,42 @@ status_t MediaCodec::getCodecInfo(sp *codecInfo) const { return OK; } +// this is the user-callable entry point status_t MediaCodec::getMetrics(mediametrics_handle_t &reply) { reply = 0; - // shouldn't happen, but be safe - if (mMetricsHandle == 0) { - return UNKNOWN_ERROR; + sp msg = new AMessage(kWhatGetMetrics, this); + sp response; + status_t err; + if ((err = PostAndAwaitResponse(msg, &response)) != OK) { + return err; } - // update any in-flight data that's not carried within the record - updateMediametrics(); + CHECK(response->findInt64("metrics", &reply)); - // send it back to the caller. - reply = mediametrics_dup(mMetricsHandle); + return OK; +} - updateEphemeralMediametrics(reply); +// runs on the looper thread (for mutex purposes) +void MediaCodec::onGetMetrics(const sp& msg) { - return OK; + mediametrics_handle_t results = 0; + + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + if (mMetricsHandle != 0) { + updateMediametrics(); + results = mediametrics_dup(mMetricsHandle); + updateEphemeralMediametrics(results); + } else { + results = mediametrics_dup(mMetricsHandle); + } + + sp response = new AMessage; + response->setInt64("metrics", results); + response->postReply(replyID); } status_t MediaCodec::getInputBuffers(Vector > *buffers) const { @@ -2813,6 +2869,13 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } + case kWhatGetMetrics: + { + onGetMetrics(msg); + break; + } + + case kWhatConfigure: { if (mState != INITIALIZED) { @@ -2833,6 +2896,18 @@ void MediaCodec::onMessageReceived(const sp &msg) { sp format; CHECK(msg->findMessage("format", &format)); + // start with a copy of the passed metrics info for use in this run + mediametrics_handle_t handle; + CHECK(msg->findInt64("metrics", &handle)); + if (handle != 0) { + if (mMetricsHandle != 0) { + flushMediametrics(); + } + mMetricsHandle = mediametrics_dup(handle); + // and set some additional metrics values + initMediametrics(); + } + int32_t push; if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) { mFlags |= kFlagPushBlankBuffersOnShutdown; diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h index 7614ba5e6b..24f148e717 100644 --- a/media/libstagefright/include/media/stagefright/MediaCodec.h +++ b/media/libstagefright/include/media/stagefright/MediaCodec.h @@ -328,6 +328,7 @@ struct MediaCodec : public AHandler { kWhatSetNotification = 'setN', kWhatDrmReleaseCrypto = 'rDrm', kWhatCheckBatteryStats = 'chkB', + kWhatGetMetrics = 'getM', }; enum { @@ -373,6 +374,7 @@ struct MediaCodec : public AHandler { sp mSurface; SoftwareRenderer *mSoftRenderer; + Mutex mMetricsLock; mediametrics_handle_t mMetricsHandle = 0; nsecs_t mLifetimeStartNs = 0; void initMediametrics(); @@ -380,6 +382,8 @@ struct MediaCodec : public AHandler { void flushMediametrics(); void updateEphemeralMediametrics(mediametrics_handle_t item); void updateLowLatency(const sp &msg); + void onGetMetrics(const sp& msg); + sp mOutputFormat; sp mInputFormat; From 9b5fa96c52c3d2bd107035f9b8395dff8deb5301 Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Mon, 27 Mar 2023 18:16:46 -0500 Subject: [PATCH 13/14] Fix NuMediaExtractor::readSampleData buffer Handling readSampleData() did not initialize buffer before filling it, leading to OOB memory references. Correct and clarify the book keeping around output buffer management. Bug: 275418191 Test: CtsMediaExtractorTestCases w/debug messages (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:943fc12219b21d2a98f0ddc070b9b316a6f5d412) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:84c69bca81175feb2fd97ebb22e432ee41572786) Merged-In: Ie744f118526f100d82a312c64f7c6fcf20773b6d Change-Id: Ie744f118526f100d82a312c64f7c6fcf20773b6d --- media/libstagefright/NuMediaExtractor.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index c6385079dd..7c4855ba35 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -627,9 +627,11 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples( numPageSamples = -1; } + // insert, including accounting for the space used. memcpy((uint8_t *)buffer->data() + mbuf->range_length(), &numPageSamples, sizeof(numPageSamples)); + buffer->setRange(buffer->offset(), buffer->size() + sizeof(numPageSamples)); uint32_t type; const void *data; @@ -678,6 +680,8 @@ status_t NuMediaExtractor::readSampleData(const sp &buffer) { ssize_t minIndex = fetchAllTrackSamples(); + buffer->setRange(0, 0); // start with an empty buffer + if (minIndex < 0) { return ERROR_END_OF_STREAM; } @@ -693,25 +697,25 @@ status_t NuMediaExtractor::readSampleData(const sp &buffer) { sampleSize += sizeof(int32_t); } + // capacity() is ok since we cleared out the buffer if (buffer->capacity() < sampleSize) { return -ENOMEM; } + const size_t srclen = it->mBuffer->range_length(); const uint8_t *src = (const uint8_t *)it->mBuffer->data() + it->mBuffer->range_offset(); - memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length()); + memcpy((uint8_t *)buffer->data(), src, srclen); + buffer->setRange(0, srclen); status_t err = OK; if (info->mTrackFlags & kIsVorbis) { + // adjusts range when it inserts the extra bits err = appendVorbisNumPageSamples(it->mBuffer, buffer); } - if (err == OK) { - buffer->setRange(0, sampleSize); - } - return err; } From 137b6bed5b56112e5cf3935ac15cb2807e6d6af8 Mon Sep 17 00:00:00 2001 From: Shruti Bihani Date: Thu, 6 Jul 2023 08:41:56 +0000 Subject: [PATCH 14/14] Fix Segv on unknown address error flagged by fuzzer test. The error is thrown when the destructor tries to free pointer memory. This is happening for cases where the pointer was not initialized. Initializing it to a default value fixes the error. Bug: 245135112 Test: Build mtp_host_property_fuzzer and run on the target device (cherry picked from commit 3afa6e80e8568fe63f893fa354bc79ef91d3dcc0) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d44311374e41a26b28db56794c9a7890a13a6972) Merged-In: I255cd68b7641e96ac47ab81479b9b46b78c15580 Change-Id: I255cd68b7641e96ac47ab81479b9b46b78c15580 --- media/mtp/MtpProperty.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h index bfd5f7f59a..1eb8874af1 100644 --- a/media/mtp/MtpProperty.h +++ b/media/mtp/MtpProperty.h @@ -26,6 +26,9 @@ namespace android { class MtpDataPacket; struct MtpPropertyValue { + // pointer str initialized to NULL so that free operation + // is not called for pre-assigned value + MtpPropertyValue() : str (NULL) {} union { int8_t i8; uint8_t u8;