[RESTRICT AUTOMERGE] Fix WVCryptoPlugin use after free vulnerability.

The shared memory buffer used by srcPtr can be freed by another
thread because it is not protected by a mutex. Subsequently,
a use after free AIGABRT can occur in a race condition.

SafetyNet logging is not added to avoid log spamming. The
mutex lock is called to setup for decryption, which is
called frequently.

The crash was reproduced on the device before the fix.
Verified the test passes after the fix.

Test: sts
  sts-tradefed run sts-engbuild-no-spl-lock -m StsHostTestCases --test android.security.sts.Bug_176495665#testPocBug_176495665

Test: push to device with target_hwasan-userdebug build
  adb shell /data/local/tmp/Bug-176495665_sts64

Bug: 176495665
Bug: 176444161
Change-Id: Ib54b4a86230300e7a3e4771ac091218f0024c323
This commit is contained in:
Edwin Wong
2021-04-08 10:20:33 -07:00
parent 28016986f5
commit 51371f481f
3 changed files with 15 additions and 3 deletions

View File

@@ -69,6 +69,8 @@ LOCAL_SHARED_LIBRARIES := \
libhidlmemory \ libhidlmemory \
liblog liblog
LOCAL_CFLAGS := -Wthread-safety
LOCAL_MODULE := libwvdrmcryptoplugin_hidl LOCAL_MODULE := libwvdrmcryptoplugin_hidl
LOCAL_PROPRIETARY_MODULE := true LOCAL_PROPRIETARY_MODULE := true

View File

@@ -7,9 +7,12 @@
#ifndef WV_CRYPTO_PLUGIN_H_ #ifndef WV_CRYPTO_PLUGIN_H_
#define WV_CRYPTO_PLUGIN_H_ #define WV_CRYPTO_PLUGIN_H_
#include <android-base/thread_annotations.h>
#include <android/hardware/drm/1.0/ICryptoPlugin.h> #include <android/hardware/drm/1.0/ICryptoPlugin.h>
#include <android/hidl/memory/1.0/IMemory.h> #include <android/hidl/memory/1.0/IMemory.h>
#include <mutex>
#include "wv_content_decryption_module.h" #include "wv_content_decryption_module.h"
#include "WVTypes.h" #include "WVTypes.h"
@@ -60,13 +63,13 @@ struct WVCryptoPlugin : public ICryptoPlugin {
const SharedBuffer& source, const SharedBuffer& source,
uint64_t offset, uint64_t offset,
const DestinationBuffer& destination, const DestinationBuffer& destination,
decrypt_cb _hidl_cb) override; decrypt_cb _hidl_cb) override NO_THREAD_SAFETY_ANALYSIS; // use unique_lock
private: private:
WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WVCryptoPlugin); WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WVCryptoPlugin);
wvcdm::CdmSessionId mSessionId; wvcdm::CdmSessionId mSessionId;
std::map<uint32_t, sp<IMemory> > mSharedBufferMap; std::map<uint32_t, sp<IMemory> > mSharedBufferMap GUARDED_BY(mSharedBufferLock);
sp<wvcdm::WvContentDecryptionModule> const mCDM; sp<wvcdm::WvContentDecryptionModule> const mCDM;
@@ -76,6 +79,8 @@ struct WVCryptoPlugin : public ICryptoPlugin {
static wvcdm::CdmResponseType countEncryptedBlocksInPatternedRange( static wvcdm::CdmResponseType countEncryptedBlocksInPatternedRange(
size_t range, const Pattern& pattern, uint64_t* result); size_t range, const Pattern& pattern, uint64_t* result);
static void incrementIV(uint64_t increaseBy, std::vector<uint8_t>* ivPtr); static void incrementIV(uint64_t increaseBy, std::vector<uint8_t>* ivPtr);
std::mutex mSharedBufferLock;
}; };
} // namespace widevine } // namespace widevine

View File

@@ -100,6 +100,8 @@ Return<void> WVCryptoPlugin::setSharedBufferBase(
sp<IMemory> hidlMemory = mapMemory(base); sp<IMemory> hidlMemory = mapMemory(base);
ALOGE_IF(hidlMemory == nullptr, "mapMemory returns nullptr"); ALOGE_IF(hidlMemory == nullptr, "mapMemory returns nullptr");
std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
// allow mapMemory to return nullptr // allow mapMemory to return nullptr
mSharedBufferMap[bufferId] = hidlMemory; mSharedBufferMap[bufferId] = hidlMemory;
return Void(); return Void();
@@ -116,7 +118,7 @@ Return<void> WVCryptoPlugin::decrypt(
uint64_t offset, uint64_t offset,
const DestinationBuffer& destination, const DestinationBuffer& destination,
decrypt_cb _hidl_cb) { decrypt_cb _hidl_cb) {
std::unique_lock<std::mutex> lock(mSharedBufferLock);
if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) { if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
"source decrypt buffer base not set"); "source decrypt buffer base not set");
@@ -187,6 +189,9 @@ Return<void> WVCryptoPlugin::decrypt(
destPtr = static_cast<void *>(handle); destPtr = static_cast<void *>(handle);
} }
// release mSharedBufferLock
lock.unlock();
// Calculate the output buffer size and determine if any subsamples are // Calculate the output buffer size and determine if any subsamples are
// encrypted. // encrypted.
size_t destSize = 0; size_t destSize = 0;