Protect Session ID List With a Lock

(This is a merge of
https://widevine-internal-review.googlesource.com/#/c/11405
from the Widevine CDM Repo.)

AUPT is revealing a crash when destructing WVDrmPlugin due to
multi-threaded contention over the session map. As a fix, we are now
protecting access to the map via a mutex.

Bug: 17761616
Change-Id: Iddeca657effd3c7f3ff35ce334d7979291667cef
This commit is contained in:
John "Juce" Bruce
2014-10-13 13:40:44 -07:00
parent 95658e73b2
commit 3da4f9d7d5
2 changed files with 29 additions and 5 deletions

View File

@@ -16,6 +16,7 @@
#include "utils/Errors.h" #include "utils/Errors.h"
#include "utils/KeyedVector.h" #include "utils/KeyedVector.h"
#include "utils/List.h" #include "utils/List.h"
#include "utils/Mutex.h"
#include "utils/String8.h" #include "utils/String8.h"
#include "utils/Vector.h" #include "utils/Vector.h"
#include "wv_cdm_event_listener.h" #include "wv_cdm_event_listener.h"
@@ -26,6 +27,7 @@ namespace wvdrm {
using android::KeyedVector; using android::KeyedVector;
using android::List; using android::List;
using android::Mutex;
using android::status_t; using android::status_t;
using android::String8; using android::String8;
using android::Vector; using android::Vector;
@@ -229,6 +231,7 @@ class WVDrmPlugin : public android::DrmPlugin,
WvContentDecryptionModule* mCDM; WvContentDecryptionModule* mCDM;
WVGenericCryptoInterface* mCrypto; WVGenericCryptoInterface* mCrypto;
Mutex mCryptoSessionsMutex;
map<CdmSessionId, CryptoSession> mCryptoSessions; map<CdmSessionId, CryptoSession> mCryptoSessions;
status_t mapAndNotifyOfCdmResponseType(const Vector<uint8_t>& sessionId, status_t mapAndNotifyOfCdmResponseType(const Vector<uint8_t>& sessionId,

View File

@@ -35,10 +35,11 @@ using namespace wvcdm;
WVDrmPlugin::WVDrmPlugin(WvContentDecryptionModule* cdm, WVDrmPlugin::WVDrmPlugin(WvContentDecryptionModule* cdm,
WVGenericCryptoInterface* crypto) WVGenericCryptoInterface* crypto)
: mCDM(cdm), mCrypto(crypto) {} : mCDM(cdm), mCrypto(crypto), mCryptoSessionsMutex(), mCryptoSessions() {}
WVDrmPlugin::~WVDrmPlugin() { WVDrmPlugin::~WVDrmPlugin() {
typedef map<CdmSessionId, CryptoSession>::iterator mapIterator; typedef map<CdmSessionId, CryptoSession>::iterator mapIterator;
Mutex::Autolock lock(mCryptoSessionsMutex);
for (mapIterator iter = mCryptoSessions.begin(); for (mapIterator iter = mCryptoSessions.begin();
iter != mCryptoSessions.end(); iter != mCryptoSessions.end();
++iter) { ++iter) {
@@ -82,7 +83,10 @@ status_t WVDrmPlugin::openSession(Vector<uint8_t>& sessionId) {
OEMCrypto_SESSION oecSessionId; OEMCrypto_SESSION oecSessionId;
istringstream(info[QUERY_KEY_OEMCRYPTO_SESSION_ID]) >> oecSessionId; istringstream(info[QUERY_KEY_OEMCRYPTO_SESSION_ID]) >> oecSessionId;
{
Mutex::Autolock lock(mCryptoSessionsMutex);
mCryptoSessions[cdmSessionId] = CryptoSession(oecSessionId); mCryptoSessions[cdmSessionId] = CryptoSession(oecSessionId);
}
success = true; success = true;
} else { } else {
@@ -123,6 +127,7 @@ status_t WVDrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
CdmResponseType res = mCDM->CloseSession(cdmSessionId); CdmResponseType res = mCDM->CloseSession(cdmSessionId);
if (isCdmResponseTypeSuccess(res)) { if (isCdmResponseTypeSuccess(res)) {
Mutex::Autolock lock(mCryptoSessionsMutex);
mCryptoSessions.erase(cdmSessionId); mCryptoSessions.erase(cdmSessionId);
} }
@@ -559,7 +564,12 @@ status_t WVDrmPlugin::getPropertyByteArray(const String8& name,
status_t WVDrmPlugin::setPropertyString(const String8& name, status_t WVDrmPlugin::setPropertyString(const String8& name,
const String8& value) { const String8& value) {
if (name == "securityLevel") { if (name == "securityLevel") {
if (mCryptoSessions.size() == 0) { size_t sessionCount = 0;
{
Mutex::Autolock lock(mCryptoSessionsMutex);
sessionCount = mCryptoSessions.size();
}
if (sessionCount == 0) {
if (value == QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) { if (value == QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) {
mPropertySet.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3); mPropertySet.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
} else if (value == QUERY_VALUE_SECURITY_LEVEL_L1.c_str()) { } else if (value == QUERY_VALUE_SECURITY_LEVEL_L1.c_str()) {
@@ -600,7 +610,12 @@ status_t WVDrmPlugin::setPropertyString(const String8& name,
return android::BAD_VALUE; return android::BAD_VALUE;
} }
} else if (name == "sessionSharing") { } else if (name == "sessionSharing") {
if (mCryptoSessions.size() == 0) { size_t sessionCount = 0;
{
Mutex::Autolock lock(mCryptoSessionsMutex);
sessionCount = mCryptoSessions.size();
}
if (sessionCount == 0) {
if (value == kEnable) { if (value == kEnable) {
mPropertySet.set_is_session_sharing_enabled(true); mPropertySet.set_is_session_sharing_enabled(true);
} else if (value == kDisable) { } else if (value == kDisable) {
@@ -637,6 +652,7 @@ status_t WVDrmPlugin::setPropertyByteArray(const String8& name,
status_t WVDrmPlugin::setCipherAlgorithm(const Vector<uint8_t>& sessionId, status_t WVDrmPlugin::setCipherAlgorithm(const Vector<uint8_t>& sessionId,
const String8& algorithm) { const String8& algorithm) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
Mutex::Autolock lock(mCryptoSessionsMutex);
if (!mCryptoSessions.count(cdmSessionId)) { if (!mCryptoSessions.count(cdmSessionId)) {
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
@@ -656,6 +672,7 @@ status_t WVDrmPlugin::setCipherAlgorithm(const Vector<uint8_t>& sessionId,
status_t WVDrmPlugin::setMacAlgorithm(const Vector<uint8_t>& sessionId, status_t WVDrmPlugin::setMacAlgorithm(const Vector<uint8_t>& sessionId,
const String8& algorithm) { const String8& algorithm) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
Mutex::Autolock lock(mCryptoSessionsMutex);
if (!mCryptoSessions.count(cdmSessionId)) { if (!mCryptoSessions.count(cdmSessionId)) {
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
@@ -678,6 +695,7 @@ status_t WVDrmPlugin::encrypt(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& iv, const Vector<uint8_t>& iv,
Vector<uint8_t>& output) { Vector<uint8_t>& output) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
Mutex::Autolock lock(mCryptoSessionsMutex);
if (!mCryptoSessions.count(cdmSessionId)) { if (!mCryptoSessions.count(cdmSessionId)) {
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
@@ -717,6 +735,7 @@ status_t WVDrmPlugin::decrypt(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& iv, const Vector<uint8_t>& iv,
Vector<uint8_t>& output) { Vector<uint8_t>& output) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
Mutex::Autolock lock(mCryptoSessionsMutex);
if (!mCryptoSessions.count(cdmSessionId)) { if (!mCryptoSessions.count(cdmSessionId)) {
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
@@ -755,6 +774,7 @@ status_t WVDrmPlugin::sign(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& message, const Vector<uint8_t>& message,
Vector<uint8_t>& signature) { Vector<uint8_t>& signature) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
Mutex::Autolock lock(mCryptoSessionsMutex);
if (!mCryptoSessions.count(cdmSessionId)) { if (!mCryptoSessions.count(cdmSessionId)) {
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
@@ -810,6 +830,7 @@ status_t WVDrmPlugin::verify(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& signature, const Vector<uint8_t>& signature,
bool& match) { bool& match) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
Mutex::Autolock lock(mCryptoSessionsMutex);
if (!mCryptoSessions.count(cdmSessionId)) { if (!mCryptoSessions.count(cdmSessionId)) {
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;