Fixed race condition in closeSession

Merged from http://go/wvgerrit/165059
poc: http://go/ag/20978761

Fix race that corrupts mCryptoSessions std::map,
and race that occurs when CryptoSessions are used after free.

Test: poc
Test: atest MediaDrmParameterizedTests
Test: atest GtsMediaTestCases

Bug: 258189255
Change-Id: I298d3e0770ace9cd590dfaacaa4c52a0732c2fe3
Merged-In: I298d3e0770ace9cd590dfaacaa4c52a0732c2fe3
This commit is contained in:
Edwin Wong
2023-01-04 01:56:05 +00:00
committed by Rahul Frias
parent 74a17c47f7
commit 97bbc07174
4 changed files with 173 additions and 102 deletions

View File

@@ -31,6 +31,8 @@ namespace {
namespace wvdrm {
using std::shared_ptr;
using namespace android;
using namespace std;
using namespace wvcdm;
@@ -85,16 +87,17 @@ WVDrmPlugin::WVDrmPlugin(const sp<WvContentDecryptionModule>& cdm,
mCdmIdentifier(kDefaultCdmIdentifier) {}
WVDrmPlugin::~WVDrmPlugin() {
typedef map<CdmSessionId, CryptoSession>::iterator mapIterator;
for (mapIterator iter = mCryptoSessions.begin();
iter != mCryptoSessions.end();
++iter) {
typedef map<CdmSessionId, shared_ptr<CryptoSession>>::iterator mapIterator;
auto cryptoSessions = mCryptoSessions.clear();
for (mapIterator iter = cryptoSessions.begin();
iter != cryptoSessions.end(); ++iter) {
CdmResponseType res = mCDM->CloseSession(iter->first);
if (!isCdmResponseTypeSuccess(res)) {
ALOGE("Failed to close session while destroying WVDrmPlugin");
}
}
mCryptoSessions.clear();
// clear local copy of cryptoSessions map
cryptoSessions.clear();
}
status_t WVDrmPlugin::openSession(Vector<uint8_t>& sessionId) {
@@ -117,7 +120,7 @@ status_t WVDrmPlugin::openSession(Vector<uint8_t>& sessionId) {
info.count(QUERY_KEY_OEMCRYPTO_SESSION_ID)) {
OEMCrypto_SESSION oecSessionId =
std::stoul(info[QUERY_KEY_OEMCRYPTO_SESSION_ID]);
mCryptoSessions[cdmSessionId] = CryptoSession(oecSessionId);
mCryptoSessions.insert(cdmSessionId, oecSessionId);
success = true;
} else {
ALOGE("Unable to query key control info.");
@@ -599,7 +602,7 @@ status_t WVDrmPlugin::getPropertyByteArray(const String8& name,
status_t WVDrmPlugin::setPropertyString(const String8& name,
const String8& value) {
if (name == "securityLevel") {
if (mCryptoSessions.size() == 0) {
if (mCryptoSessions.empty()) {
if (value == QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) {
mPropertySet.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
} else if (value == QUERY_VALUE_SECURITY_LEVEL_L1.c_str()) {
@@ -636,7 +639,7 @@ status_t WVDrmPlugin::setPropertyString(const String8& name,
return android::BAD_VALUE;
}
} else if (name == "sessionSharing") {
if (mCryptoSessions.size() == 0) {
if (mCryptoSessions.empty()) {
if (value == kEnable) {
mPropertySet.set_is_session_sharing_enabled(true);
} else if (value == kDisable) {
@@ -650,14 +653,14 @@ status_t WVDrmPlugin::setPropertyString(const String8& name,
return kErrorSessionIsOpen;
}
} else if (name == "appId") {
if (mCryptoSessions.size() == 0) {
if (mCryptoSessions.empty()) {
mPropertySet.set_app_id(value.string());
} else {
ALOGE("App tried to set the application id while sessions are opened.");
return kErrorSessionIsOpen;
}
} else if (name == "origin") {
if (mCryptoSessions.size() != 0) {
if (!mCryptoSessions.empty()) {
ALOGE("App tried to set the origin while sessions are opened.");
return kErrorSessionIsOpen;
} else {
@@ -720,14 +723,13 @@ status_t WVDrmPlugin::setCipherAlgorithm(const Vector<uint8_t>& sessionId,
return android::BAD_VALUE;
}
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (algorithm == "AES/CBC/NoPadding") {
cryptoSession.setCipherAlgorithm(OEMCrypto_AES_CBC_128_NO_PADDING);
cryptoSession->setCipherAlgorithm(OEMCrypto_AES_CBC_128_NO_PADDING);
} else {
return android::ERROR_DRM_CANNOT_HANDLE;
}
@@ -741,14 +743,13 @@ status_t WVDrmPlugin::setMacAlgorithm(const Vector<uint8_t>& sessionId,
return android::BAD_VALUE;
}
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (algorithm == "HmacSHA256") {
cryptoSession.setMacAlgorithm(OEMCrypto_HMAC_SHA256);
cryptoSession->setMacAlgorithm(OEMCrypto_HMAC_SHA256);
} else {
return android::ERROR_DRM_CANNOT_HANDLE;
}
@@ -762,17 +763,16 @@ status_t WVDrmPlugin::encrypt(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& iv,
Vector<uint8_t>& output) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->cipherAlgorithm() == kInvalidCryptoAlgorithm) {
return android::NO_INIT;
}
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
keyId.array(), keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -782,9 +782,9 @@ status_t WVDrmPlugin::encrypt(const Vector<uint8_t>& sessionId,
output.resize(input.size());
res = mCrypto->encrypt(cryptoSession.oecSessionId(), input.array(),
res = mCrypto->encrypt(cryptoSession->oecSessionId(), input.array(),
input.size(), iv.array(),
cryptoSession.cipherAlgorithm(), output.editArray());
cryptoSession->cipherAlgorithm(), output.editArray());
if (res == OEMCrypto_SUCCESS) {
return android::OK;
@@ -800,17 +800,16 @@ status_t WVDrmPlugin::decrypt(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& iv,
Vector<uint8_t>& output) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->cipherAlgorithm() == kInvalidCryptoAlgorithm) {
return android::NO_INIT;
}
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
keyId.array(), keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -820,9 +819,9 @@ status_t WVDrmPlugin::decrypt(const Vector<uint8_t>& sessionId,
output.resize(input.size());
res = mCrypto->decrypt(cryptoSession.oecSessionId(), input.array(),
res = mCrypto->decrypt(cryptoSession->oecSessionId(), input.array(),
input.size(), iv.array(),
cryptoSession.cipherAlgorithm(), output.editArray());
cryptoSession->cipherAlgorithm(), output.editArray());
if (res == OEMCrypto_SUCCESS) {
return android::OK;
@@ -837,17 +836,16 @@ status_t WVDrmPlugin::sign(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& message,
Vector<uint8_t>& signature) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->macAlgorithm() == kInvalidCryptoAlgorithm) {
return android::NO_INIT;
}
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
keyId.array(), keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -857,8 +855,8 @@ status_t WVDrmPlugin::sign(const Vector<uint8_t>& sessionId,
size_t signatureSize = 0;
res = mCrypto->sign(cryptoSession.oecSessionId(), message.array(),
message.size(), cryptoSession.macAlgorithm(),
res = mCrypto->sign(cryptoSession->oecSessionId(), message.array(),
message.size(), cryptoSession->macAlgorithm(),
NULL, &signatureSize);
if (res != OEMCrypto_ERROR_SHORT_BUFFER) {
@@ -873,8 +871,8 @@ status_t WVDrmPlugin::sign(const Vector<uint8_t>& sessionId,
signature.resize(signatureSize);
res = mCrypto->sign(cryptoSession.oecSessionId(), message.array(),
message.size(), cryptoSession.macAlgorithm(),
res = mCrypto->sign(cryptoSession->oecSessionId(), message.array(),
message.size(), cryptoSession->macAlgorithm(),
signature.editArray(), &signatureSize);
if (res == OEMCrypto_SUCCESS) {
@@ -891,17 +889,16 @@ status_t WVDrmPlugin::verify(const Vector<uint8_t>& sessionId,
const Vector<uint8_t>& signature,
bool& match) {
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->macAlgorithm() == kInvalidCryptoAlgorithm) {
return android::NO_INIT;
}
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
keyId.array(), keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -909,8 +906,8 @@ status_t WVDrmPlugin::verify(const Vector<uint8_t>& sessionId,
return mapAndNotifyOfOEMCryptoResult(sessionId, res);
}
res = mCrypto->verify(cryptoSession.oecSessionId(), message.array(),
message.size(), cryptoSession.macAlgorithm(),
res = mCrypto->verify(cryptoSession->oecSessionId(), message.array(),
message.size(), cryptoSession->macAlgorithm(),
signature.array(), signature.size());
if (res == OEMCrypto_SUCCESS) {