Fixed race condition in closeSession

Merged from http://go/wvgerrit/165061
poc: http://go/ag/20978750

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-09 22:28:45 +00:00
committed by Rahul Frias
parent 29aa1f3732
commit 4222daa047
4 changed files with 170 additions and 97 deletions

View File

@@ -46,6 +46,8 @@ namespace drm {
namespace V1_4 {
namespace widevine {
using std::shared_ptr;
using android::hardware::drm::V1_2::widevine::toHidlVec;
using android::hardware::drm::V1_2::widevine::toVector;
using wvcdm::CdmAppParameterMap;
@@ -208,15 +210,18 @@ WVDrmPlugin::~WVDrmPlugin() {
}
void WVDrmPlugin::Close() {
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();
if (mCdmIdentifierBuilder.is_sealed()) {
CdmIdentifier identifier;
Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
@@ -259,7 +264,7 @@ Status WVDrmPlugin::openSessionCommon(std::vector<uint8_t>& sessionId) {
info.count(wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID)) {
OEMCrypto_SESSION oecSessionId =
std::stoul(info[wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID]);
mCryptoSessions[cdmSessionId] = CryptoSession(oecSessionId);
mCryptoSessions.insert(cdmSessionId, oecSessionId);
success = true;
} else {
ALOGE("Unable to query key control info.");
@@ -1333,7 +1338,7 @@ Return<Status> WVDrmPlugin::setPropertyString(const hidl_string& propertyName,
std::string _value(value.c_str());
if (name == "securityLevel") {
if (mCryptoSessions.size() == 0) {
if (mCryptoSessions.empty()) {
if (_value == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) {
mPropertySet.set_security_level(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3);
} else if (_value == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1.c_str()) {
@@ -1373,7 +1378,7 @@ Return<Status> WVDrmPlugin::setPropertyString(const hidl_string& propertyName,
return Status::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) {
@@ -1388,7 +1393,7 @@ Return<Status> WVDrmPlugin::setPropertyString(const hidl_string& propertyName,
return Status::ERROR_DRM_UNKNOWN;
}
} else if (name == "appId") {
if (mCryptoSessions.size() == 0) {
if (mCryptoSessions.empty()) {
mPropertySet.set_app_id(_value.c_str());
} else {
ALOGE("App tried to set the application id while sessions are opened.");
@@ -1396,7 +1401,7 @@ Return<Status> WVDrmPlugin::setPropertyString(const hidl_string& propertyName,
return Status::ERROR_DRM_UNKNOWN;
}
} else if (name == "origin") {
if (mCryptoSessions.size() != 0) {
if (!mCryptoSessions.empty()) {
ALOGE("App tried to set the origin while sessions are opened.");
ALOGW("Returns UNKNOWN error for legacy status kErrorSessionIsOpen");
return Status::ERROR_DRM_UNKNOWN;
@@ -1511,14 +1516,13 @@ Return<Status> WVDrmPlugin::setCipherAlgorithm(
std::vector<uint8_t> sId = toVector(sessionId);
CdmSessionId cdmSessionId(sId.begin(), sId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return Status::ERROR_DRM_SESSION_NOT_OPENED;
}
CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (algo == "AES/CBC/NoPadding") {
cryptoSession.setCipherAlgorithm(OEMCrypto_AES_CBC_128_NO_PADDING);
cryptoSession->setCipherAlgorithm(OEMCrypto_AES_CBC_128_NO_PADDING);
} else {
return Status::ERROR_DRM_CANNOT_HANDLE;
}
@@ -1535,14 +1539,13 @@ Return<Status> WVDrmPlugin::setMacAlgorithm(const hidl_vec<uint8_t>& sessionId,
std::vector<uint8_t> sId = toVector(sessionId);
CdmSessionId cdmSessionId(sId.begin(), sId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
return Status::ERROR_DRM_SESSION_NOT_OPENED;
}
CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (algo == "HmacSHA256") {
cryptoSession.setMacAlgorithm(OEMCrypto_HMAC_SHA256);
cryptoSession->setMacAlgorithm(OEMCrypto_HMAC_SHA256);
} else {
return Status::ERROR_DRM_CANNOT_HANDLE;
}
@@ -1559,21 +1562,20 @@ Return<void> WVDrmPlugin::encrypt(const hidl_vec<uint8_t>& sessionId,
std::vector<uint8_t> output;
CdmSessionId cdmSessionId(sId.begin(), sId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
_hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, toHidlVec(output));
return Void();
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->cipherAlgorithm() == kInvalidCryptoAlgorithm) {
ALOGW("Returns UNKNOWN error for legacy status NO_INIT");
_hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(output));
return Void();
}
const std::vector<uint8_t> _keyId = toVector(keyId);
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
_keyId.data(), _keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -1586,9 +1588,9 @@ Return<void> WVDrmPlugin::encrypt(const hidl_vec<uint8_t>& sessionId,
const std::vector<uint8_t> _iv = toVector(iv);
output.resize(_input.size());
res = mCrypto->encrypt(cryptoSession.oecSessionId(), _input.data(),
res = mCrypto->encrypt(cryptoSession->oecSessionId(), _input.data(),
_input.size(), _iv.data(),
cryptoSession.cipherAlgorithm(), output.data());
cryptoSession->cipherAlgorithm(), output.data());
if (res == OEMCrypto_SUCCESS) {
_hidl_cb(Status::OK, toHidlVec(output));
@@ -1608,21 +1610,20 @@ Return<void> WVDrmPlugin::decrypt(const hidl_vec<uint8_t>& sessionId,
std::vector<uint8_t> output;
CdmSessionId cdmSessionId(sId.begin(), sId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
_hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, toHidlVec(output));
return Void();
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->cipherAlgorithm() == kInvalidCryptoAlgorithm) {
ALOGW("Returns UNKNOWN error for legacy status NO_INIT");
_hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(output));
return Void();
}
const std::vector<uint8_t> _keyId = toVector(keyId);
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
_keyId.data(), _keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -1635,9 +1636,9 @@ Return<void> WVDrmPlugin::decrypt(const hidl_vec<uint8_t>& sessionId,
const std::vector<uint8_t> _iv = toVector(iv);
output.resize(_input.size());
res = mCrypto->decrypt(cryptoSession.oecSessionId(), _input.data(),
res = mCrypto->decrypt(cryptoSession->oecSessionId(), _input.data(),
_input.size(), _iv.data(),
cryptoSession.cipherAlgorithm(), output.data());
cryptoSession->cipherAlgorithm(), output.data());
if (res == OEMCrypto_SUCCESS) {
_hidl_cb(Status::OK, toHidlVec(output));
@@ -1656,21 +1657,20 @@ Return<void> WVDrmPlugin::sign(const hidl_vec<uint8_t>& sessionId,
std::vector<uint8_t> signature;
CdmSessionId cdmSessionId(sId.begin(), sId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
_hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, toHidlVec(signature));
return Void();
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->macAlgorithm() == kInvalidCryptoAlgorithm) {
ALOGW("Returns UNKNOWN error for legacy status NO_INIT");
_hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(signature));
return Void();
}
const std::vector<uint8_t> _keyId = toVector(keyId);
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
_keyId.data(), _keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -1682,8 +1682,8 @@ Return<void> WVDrmPlugin::sign(const hidl_vec<uint8_t>& sessionId,
size_t signatureSize = 0;
const std::vector<uint8_t> msg = toVector(message);
res = mCrypto->sign(cryptoSession.oecSessionId(), msg.data(), msg.size(),
cryptoSession.macAlgorithm(), NULL, &signatureSize);
res = mCrypto->sign(cryptoSession->oecSessionId(), msg.data(), msg.size(),
cryptoSession->macAlgorithm(), NULL, &signatureSize);
if (res != OEMCrypto_ERROR_SHORT_BUFFER) {
ALOGE(
@@ -1700,8 +1700,8 @@ Return<void> WVDrmPlugin::sign(const hidl_vec<uint8_t>& sessionId,
signature.resize(signatureSize);
res = mCrypto->sign(cryptoSession.oecSessionId(), msg.data(), msg.size(),
cryptoSession.macAlgorithm(), signature.data(),
res = mCrypto->sign(cryptoSession->oecSessionId(), msg.data(), msg.size(),
cryptoSession->macAlgorithm(), signature.data(),
&signatureSize);
if (res == OEMCrypto_SUCCESS) {
@@ -1722,21 +1722,20 @@ Return<void> WVDrmPlugin::verify(const hidl_vec<uint8_t>& sessionId,
const std::vector<uint8_t> sId = toVector(sessionId);
CdmSessionId cdmSessionId(sId.begin(), sId.end());
if (!mCryptoSessions.count(cdmSessionId)) {
const shared_ptr<CryptoSession> cryptoSession = mCryptoSessions.get(cdmSessionId);
if (cryptoSession == nullptr) {
_hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, match);
return Void();
}
const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId];
if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) {
if (cryptoSession->macAlgorithm() == kInvalidCryptoAlgorithm) {
ALOGW("Returns UNKNOWN error for legacy status NO_INIT");
_hidl_cb(Status::ERROR_DRM_UNKNOWN, match);
return Void();
}
const std::vector<uint8_t> _keyId = toVector(keyId);
OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(),
OEMCryptoResult res = mCrypto->selectKey(cryptoSession->oecSessionId(),
_keyId.data(), _keyId.size());
if (res != OEMCrypto_SUCCESS) {
@@ -1747,8 +1746,8 @@ Return<void> WVDrmPlugin::verify(const hidl_vec<uint8_t>& sessionId,
const std::vector<uint8_t> _message = toVector(message);
const std::vector<uint8_t> _signature = toVector(signature);
res = mCrypto->verify(cryptoSession.oecSessionId(), _message.data(),
_message.size(), cryptoSession.macAlgorithm(),
res = mCrypto->verify(cryptoSession->oecSessionId(), _message.data(),
_message.size(), cryptoSession->macAlgorithm(),
_signature.data(), _signature.size());
if (res == OEMCrypto_SUCCESS) {