[RESTRICT AUTOMERGE] Fix CryptoPlugin 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: I4c83c44873eef960b654f387a3574fcad49c41a9
This commit is contained in:
Edwin Wong 2021-03-08 18:46:42 -08:00
parent e289b4aa83
commit a4e76aab23
3 changed files with 23 additions and 11 deletions

View file

@ -9,6 +9,7 @@ cc_library_static {
"-Werror", "-Werror",
"-Wextra", "-Wextra",
"-Wall", "-Wall",
"-Wthread-safety",
], ],
shared_libs: [ shared_libs: [
"liblog", "liblog",
@ -19,5 +20,5 @@ cc_library_static {
export_header_lib_headers: [ export_header_lib_headers: [
"libutils_headers", "libutils_headers",
], ],
export_include_dirs : ["include"] export_include_dirs: ["include"],
} }

View file

@ -53,6 +53,8 @@ namespace implementation {
uint32_t bufferId) { uint32_t bufferId) {
sp<IMemory> hidlMemory = mapMemory(base); sp<IMemory> hidlMemory = mapMemory(base);
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();
@ -65,7 +67,7 @@ namespace implementation {
const SharedBuffer& source, uint64_t offset, const SharedBuffer& source, uint64_t offset,
const DestinationBuffer& destination, const DestinationBuffer& destination,
decrypt_cb _hidl_cb) { decrypt_cb _hidl_cb) {
std::unique_lock<std::mutex> shared_buffer_lock(mSharedBufferLock);
if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) { if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set"); _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set");
return Void(); return Void();
@ -79,7 +81,7 @@ namespace implementation {
} }
} }
android::CryptoPlugin::Mode legacyMode; android::CryptoPlugin::Mode legacyMode = android::CryptoPlugin::kMode_Unencrypted;
switch(mode) { switch(mode) {
case Mode::UNENCRYPTED: case Mode::UNENCRYPTED:
legacyMode = android::CryptoPlugin::kMode_Unencrypted; legacyMode = android::CryptoPlugin::kMode_Unencrypted;
@ -170,6 +172,10 @@ namespace implementation {
_hidl_cb(Status::BAD_VALUE, 0, "invalid destination type"); _hidl_cb(Status::BAD_VALUE, 0, "invalid destination type");
return Void(); return Void();
} }
// release mSharedBufferLock
shared_buffer_lock.unlock();
ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(), ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
legacyMode, legacyPattern, srcPtr, legacySubSamples.get(), legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
subSamples.size(), destPtr, &detailMessage); subSamples.size(), destPtr, &detailMessage);

View file

@ -17,11 +17,14 @@
#ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H #ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
#define ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H #define ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
#include <android/hidl/memory/1.0/IMemory.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 <hidl/Status.h> #include <hidl/Status.h>
#include <media/hardware/CryptoAPI.h> #include <media/hardware/CryptoAPI.h>
#include <mutex>
namespace android { namespace android {
namespace hardware { namespace hardware {
namespace drm { namespace drm {
@ -60,19 +63,21 @@ struct CryptoPlugin : public ICryptoPlugin {
Return<void> setSharedBufferBase(const ::android::hardware::hidl_memory& base, Return<void> setSharedBufferBase(const ::android::hardware::hidl_memory& base,
uint32_t bufferId) override; uint32_t bufferId) override;
Return<void> decrypt(bool secure, const hidl_array<uint8_t, 16>& keyId, Return<void> decrypt(
const hidl_array<uint8_t, 16>& iv, Mode mode, const Pattern& pattern, bool secure, const hidl_array<uint8_t, 16>& keyId, const hidl_array<uint8_t, 16>& iv,
const hidl_vec<SubSample>& subSamples, const SharedBuffer& source, Mode mode, const Pattern& pattern, const hidl_vec<SubSample>& subSamples,
uint64_t offset, const DestinationBuffer& destination, const SharedBuffer& source, uint64_t offset, const DestinationBuffer& destination,
decrypt_cb _hidl_cb) override; decrypt_cb _hidl_cb) override NO_THREAD_SAFETY_ANALYSIS; // use unique_lock
private: private:
android::CryptoPlugin *mLegacyPlugin; android::CryptoPlugin *mLegacyPlugin;
std::map<uint32_t, sp<IMemory> > mSharedBufferMap; std::map<uint32_t, sp<IMemory>> mSharedBufferMap GUARDED_BY(mSharedBufferLock);
CryptoPlugin() = delete; CryptoPlugin() = delete;
CryptoPlugin(const CryptoPlugin &) = delete; CryptoPlugin(const CryptoPlugin &) = delete;
void operator=(const CryptoPlugin &) = delete; void operator=(const CryptoPlugin &) = delete;
std::mutex mSharedBufferLock;
}; };
} // namespace implementation } // namespace implementation