diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 1e3f85c6..0d0230a5 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -17,6 +17,7 @@ #include "key_session.h" #include "metrics_collections.h" #include "oemcrypto_adapter.h" +#include "rw_lock.h" #include "timer_metric.h" #include "wv_cdm_types.h" @@ -256,7 +257,7 @@ class CryptoSession { // OEMCrypto to use a test keybox. // Ownership of the object is transfered to CryptoSession. static void SetCryptoSessionFactory(CryptoSessionFactory* factory) { - std::unique_lock auto_lock(factory_lock_); + std::unique_lock auto_lock(factory_mutex_); factory_.reset(factory); } @@ -311,25 +312,59 @@ class CryptoSession { size_t max_chunk_size); static void IncrementIV(uint64_t increase_by, std::vector* iv_out); - // These methods should be used to take the various CryptoSession locks in - // preference to taking the locks directly. + // These methods should be used to take the various CryptoSession mutexes in + // preference to taking the mutexes directly. // - // The Static Field Lock should be taken before accessing any of - // CryptoSession's non-atomic static fields. The OEMCrypto Lock should be - // taken before calling into OEMCrypto. Note that accessing |key_session_| - // often accesses OEMCrypto, so this lock should be held before calling into - // |key_session_| as well. If a function needs to take both locks - // simultaneously, it must *always* take the Static Field Lock first. In - // general, locks should only be held for the minimum time necessary. - // (e.g. |oem_crypto_lock_| should only be held for the duration of a single - // call into OEMCrypto, unless there is a compelling argument otherwise such - // as making two calls into OEMCrypto immediately after each other.) + // A lock should be taken on the Static Field Mutex before accessing any of + // CryptoSession's non-atomic static fields. It can be taken as a reader or as + // a writer, depending on how you will be accessing the static fields. + // + // Before calling into OEMCrypto, code must take locks on the OEMCrypto Mutex + // and/or the OEMCrypto Session Mutex. Which of them should be taken and how + // depends on the OEMCrypto function being called; consult the OEMCrypto + // specification's threading guarantees before making any calls. The OEMCrypto + // specification defines several classes of functions for the purposes of + // parallelism. The methods below lock the OEMCrypto Mutex and OEMCrypto + // Session Mutex in the correct order and manner to fulfill the guarantees in + // the specification. + // + // For this function class... | ...use this locking method + // ------------------------------+--------------------------- + // Initialization & Termination | WithOecWriteLock() + // Property | WithOecReadLock() + // Session Initialization | WithOecWriteLock() + // Usage Table | WithOecWriteLock() + // Session | WithOecSessionLock() + // + // Note that accessing |key_session_| often accesses the OEMCrypto session, so + // WithOecSessionLock() should be used before accessing |key_session_| as + // well. + // + // If a function needs to take a lock on both the Static Field Mutex and some + // of the OEMCrypto mutexes simultaneously, it must *always* lock the Static + // Field Mutex before the OEMCrypto mutexes. + // + // In general, all locks should only be held for the minimum time necessary + // (e.g. a lock on the OEMCrypto mutexes should only be held for the duration + // of a single call into OEMCrypto) unless there is a compelling argument + // otherwise, such as making two calls into OEMCrypto immediately after each + // other. template - static auto WithStaticFieldLock(const char* tag, Func body) + static auto WithStaticFieldWriteLock(const char* tag, Func body) -> decltype(body()); template - static auto WithOecLock(const char* tag, Func body) -> decltype(body()); + static auto WithStaticFieldReadLock(const char* tag, Func body) + -> decltype(body()); + + template + static auto WithOecWriteLock(const char* tag, Func body) -> decltype(body()); + + template + static auto WithOecReadLock(const char* tag, Func body) -> decltype(body()); + + template + auto WithOecSessionLock(const char* tag, Func body) -> decltype(body()); static bool IsInitialized(); @@ -337,11 +372,12 @@ class CryptoSession { static const size_t kAes128BlockSize = 16; // Block size for AES_CBC_128 static const size_t kSignatureSize = 32; // size for HMAC-SHA256 signature - // The |WithStaticFieldLock| and |WithOecLock| methods should be used in - // preference to taking these locks directly. When taken, the rules of - // ordering documented with those functions must still be upheld. - static std::mutex static_field_lock_; - static std::mutex oem_crypto_lock_; + // The locking methods above should be used in preference to taking these + // mutexes directly. If code takes these manually and needs to take more + // than one, it must *always* take them in the order they are defined here. + static shared_mutex static_field_mutex_; + static shared_mutex oem_crypto_mutex_; + std::mutex oem_crypto_session_mutex_; static bool initialized_; static int session_count_; @@ -374,9 +410,9 @@ class CryptoSession { uint32_t api_version_; // In order to avoid creating a deadlock if instantiation needs to take any - // of the CryptoSession static locks, |factory_| is protected by its own lock - // that is only used in the two funtions that interact with it. - static std::mutex factory_lock_; + // of the CryptoSession static mutexes, |factory_| is protected by its own + // mutex that is only used in the two funtions that interact with it. + static std::mutex factory_mutex_; static std::unique_ptr factory_; CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession); diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 5e736b7b..f5eee281 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -75,8 +75,8 @@ void DeleteX509Stack(STACK_OF(X509)* stack) { } // namespace namespace wvcdm { -std::mutex CryptoSession::static_field_lock_; -std::mutex CryptoSession::oem_crypto_lock_; +shared_mutex CryptoSession::static_field_mutex_; +shared_mutex CryptoSession::oem_crypto_mutex_; bool CryptoSession::initialized_ = false; int CryptoSession::session_count_ = 0; UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL; @@ -214,7 +214,7 @@ CdmResponseType CryptoSession::GetProvisioningMethod( SecurityLevel requested_security_level, CdmClientTokenType* token_type) { OEMCrypto_ProvisioningMethod method; - WithOecLock("GetProvisioningMethod", [&] { + WithOecReadLock("GetProvisioningMethod", [&] { method = OEMCrypto_GetProvisioningMethod(requested_security_level); }); metrics_->oemcrypto_provisioning_method_.Record(method); @@ -241,12 +241,12 @@ CdmResponseType CryptoSession::GetProvisioningMethod( void CryptoSession::Init() { LOGV("CryptoSession::Init"); - WithStaticFieldLock("Init", [&] { + WithStaticFieldWriteLock("Init", [&] { session_count_ += 1; if (!initialized_) { std::string sandbox_id; OEMCryptoResult sts; - WithOecLock("Init", [&] { + WithOecWriteLock("Init", [&] { if (Properties::GetSandboxId(&sandbox_id) && !sandbox_id.empty()) { sts = OEMCrypto_SetSandbox( reinterpret_cast(sandbox_id.c_str()), @@ -268,7 +268,7 @@ void CryptoSession::Init() { void CryptoSession::Terminate() { LOGV("CryptoSession::Terminate"); - WithStaticFieldLock("Terminate", [&] { + WithStaticFieldWriteLock("Terminate", [&] { LOGV("initialized_=%d, session_count_=%d", initialized_, session_count_); if (session_count_ > 0) { session_count_ -= 1; @@ -277,7 +277,7 @@ void CryptoSession::Terminate() { } if (session_count_ > 0 || !initialized_) return; OEMCryptoResult sts; - WithOecLock("Terminate", [&] { + WithOecWriteLock("Terminate", [&] { sts = OEMCrypto_Terminate(); }); if (OEMCrypto_SUCCESS != sts) { @@ -307,7 +307,7 @@ CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) { uint8_t* buf = reinterpret_cast(&temp_buffer[0]); OEMCryptoResult status; - WithOecLock("GetTokenFromKeybox", [&] { + WithOecReadLock("GetTokenFromKeybox", [&] { M_TIME( status = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_), @@ -338,7 +338,7 @@ CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) { while (true) { size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); - WithOecLock("GetTokenFromOemCert", [&] { + WithOecSessionLock("GetTokenFromOemCert", [&] { status = OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size); }); @@ -402,7 +402,7 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel( } std::string security_level; - WithOecLock("GetSecurityLevel", [&] { + WithOecReadLock("GetSecurityLevel", [&] { security_level = OEMCrypto_SecurityLevel(requested_level); }); @@ -448,14 +448,14 @@ CdmResponseType CryptoSession::GetInternalDeviceUniqueId( id.resize(id_length); OEMCryptoResult sts; - WithOecLock("GetInternalDeviceUniqueId Attempt 1", [&] { + WithOecReadLock("GetInternalDeviceUniqueId Attempt 1", [&] { sts = OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_); }); // Increment the count of times this method was called. metrics_->oemcrypto_get_device_id_.Increment(sts); if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { id.resize(id_length); - WithOecLock("GetInternalDeviceUniqueId Attempt 2", [&] { + WithOecReadLock("GetInternalDeviceUniqueId Attempt 2", [&] { sts = OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_); }); @@ -494,7 +494,7 @@ CdmResponseType CryptoSession::GetExternalDeviceUniqueId( size_t id_length = 0; OEMCryptoResult sts; - WithOecLock("GetExternalDeviceUniqueId", [&] { + WithOecReadLock("GetExternalDeviceUniqueId", [&] { sts = OEMCrypto_GetDeviceID(NULL, &id_length, requested_security_level_); }); metrics_->oemcrypto_get_device_id_.Increment(sts); @@ -538,7 +538,7 @@ bool CryptoSession::GetApiVersion(SecurityLevel security_level, return false; } - WithOecLock("GetApiVersion", [&] { + WithOecReadLock("GetApiVersion", [&] { *version = OEMCrypto_APIVersion(security_level); }); // Record the version into the metrics. @@ -758,7 +758,7 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) { uint8_t CryptoSession::GetSecurityPatchLevel() { uint8_t patch; - WithOecLock("GetSecurityPatchLevel", [&] { + WithOecReadLock("GetSecurityPatchLevel", [&] { patch = OEMCrypto_Security_Patch_Level(requested_security_level_); }); metrics_->oemcrypto_security_patch_level_.Record(patch); @@ -781,15 +781,17 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { OEMCrypto_SESSION sid; requested_security_level_ = requested_security_level; OEMCryptoResult sts; - WithOecLock("Open() calling OEMCrypto_OpenSession", [&] { + WithOecWriteLock("Open() calling OEMCrypto_OpenSession", [&] { sts = OEMCrypto_OpenSession(&sid, requested_security_level); }); if (sts != OEMCrypto_SUCCESS) { - WithStaticFieldLock("Open() reporting OEMCrypto_OpenSession Failure", [&] { - LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", - sts, session_count_, (int)initialized_); - }); + WithStaticFieldReadLock( + "Open() reporting OEMCrypto_OpenSession Failure", + [&] { + LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", + sts, session_count_, (int)initialized_); + }); return MapOEMCryptoResult(sts, OPEN_CRYPTO_SESSION_ERROR, "Open"); } @@ -808,7 +810,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { uint64_t request_id_base; OEMCryptoResult random_sts; - WithOecLock("Open() calling OEMCrypto_GetRandom", [&] { + WithOecReadLock("Open() calling OEMCrypto_GetRandom", [&] { random_sts = OEMCrypto_GetRandom( reinterpret_cast(&request_id_base), sizeof(request_id_base)); }); @@ -834,10 +836,10 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { if (security_level == kSecurityLevelL1 || security_level == kSecurityLevelL3) { { - // This block cannot use |WithStaticFieldLock| because it needs to - // unlock the lock partway through. - LOGV("Static Field Lock - Open() Initializing Usage Table"); - std::unique_lock auto_lock(static_field_lock_); + // This block cannot use |WithStaticFieldWriteLock| because it needs + // to unlock the lock partway through. + LOGV("Static Field Write Lock - Open() Initializing Usage Table"); + std::unique_lock auto_lock(static_field_mutex_); UsageTableHeader** header = security_level == kSecurityLevelL1 ? &usage_table_header_l1_ @@ -866,7 +868,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { metrics_->oemcrypto_usage_table_support_.SetError(result); } - WithOecLock("Open() calling key_session_.reset()", [&] { + WithOecSessionLock("Open() calling key_session_.reset()", [&] { key_session_.reset(new ContentKeySession(oec_session_id_, metrics_)); }); @@ -880,7 +882,7 @@ void CryptoSession::Close() { OEMCryptoResult close_sts; bool update_usage_table = false; - WithOecLock("Close", [&] { + WithOecWriteLock("Close", [&] { close_sts = OEMCrypto_CloseSession(oec_session_id_); }); metrics_->oemcrypto_close_session_.Increment(close_sts); @@ -932,7 +934,7 @@ CdmResponseType CryptoSession::LoadKeys( CdmResponseType result = KEY_ADDED; OEMCryptoResult sts; - WithOecLock("LoadKeys", [&] { + WithOecSessionLock("LoadKeys", [&] { if (key_type == kLicenseKeyTypeEntitlement && key_session_->Type() != KeySession::kEntitlement) { key_session_.reset(new EntitlementKeySession(oec_session_id_, metrics_)); @@ -979,7 +981,7 @@ CdmResponseType CryptoSession::LoadKeys( CdmResponseType CryptoSession::LoadEntitledContentKeys( const std::vector& key_array) { OEMCryptoResult sts; - WithOecLock("LoadEntitledContentKeys", [&] { + WithOecSessionLock("LoadEntitledContentKeys", [&] { sts = key_session_->LoadEntitledContentKeys(key_array); }); @@ -1009,7 +1011,7 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey( size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); OEMCryptoResult sts; - WithOecLock( + WithOecSessionLock( "LoadCertificatePrivateKey() calling OEMCrypto_GetOEMPublicCertificate", [&] { sts = @@ -1018,7 +1020,7 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey( metrics_->oemcrypto_get_oem_public_certificate_.Increment(sts); LOGV("LoadDeviceRSAKey: id=%lu", oec_session_id_); - WithOecLock( + WithOecSessionLock( "LoadCertificatePrivateKey() calling OEMCrypto_LoadDeviceRSAKey()", [&] { M_TIME(sts = OEMCrypto_LoadDeviceRSAKey( @@ -1050,7 +1052,7 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message, } LOGV("RefreshKeys: id=%lu", oec_session_id_); OEMCryptoResult refresh_sts; - WithOecLock("RefreshKeys", [&] { + WithOecSessionLock("RefreshKeys", [&] { M_TIME(refresh_sts = OEMCrypto_RefreshKeys( oec_session_id_, msg, message.size(), reinterpret_cast(signature.data()), @@ -1067,7 +1069,7 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message, CdmResponseType CryptoSession::SelectKey(const std::string& key_id, CdmCipherMode cipher_mode) { OEMCryptoResult sts; - WithOecLock("SelectKey", [&] { + WithOecSessionLock("SelectKey", [&] { sts = key_session_->SelectKey(key_id, cipher_mode); }); @@ -1105,7 +1107,7 @@ CdmResponseType CryptoSession::SelectKey(const std::string& key_id, CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message) { OEMCryptoResult sts; - WithOecLock("GenerateDerivedKeys without session_key", [&] { + WithOecSessionLock("GenerateDerivedKeys without session_key", [&] { sts = key_session_->GenerateDerivedKeys(message); }); @@ -1116,7 +1118,7 @@ CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message) { CdmResponseType CryptoSession::GenerateDerivedKeys( const std::string& message, const std::string& session_key) { OEMCryptoResult sts; - WithOecLock("GenerateDerivedKeys with session_key", [&] { + WithOecSessionLock("GenerateDerivedKeys with session_key", [&] { sts = key_session_->GenerateDerivedKeys(message, session_key); }); @@ -1138,7 +1140,7 @@ CdmResponseType CryptoSession::GenerateSignature(const std::string& message, // At most two attempts. // The first attempt may fail due to buffer too short for (int i = 0; i < 2; ++i) { - WithOecLock("GenerateSignature", [&] { + WithOecSessionLock("GenerateSignature", [&] { M_TIME(sts = OEMCrypto_GenerateSignature( oec_session_id_, reinterpret_cast(message.data()), @@ -1181,7 +1183,7 @@ CdmResponseType CryptoSession::GenerateRsaSignature(const std::string& message, // At most two attempts. // The first attempt may fail due to buffer too short for (int i = 0; i < 2; ++i) { - WithOecLock("GenerateRsaSignature", [&] { + WithOecSessionLock("GenerateRsaSignature", [&] { M_TIME(sts = OEMCrypto_GenerateRSASignature( oec_session_id_, reinterpret_cast(message.data()), @@ -1247,7 +1249,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { if (!params.is_encrypted && params.subsample_flags == (OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)) { - WithOecLock("Decrypt() calling CopyBuffer", [&] { + WithOecSessionLock("Decrypt() calling CopyBuffer", [&] { M_TIME(sts = OEMCrypto_CopyBuffer(oec_session_id_, params.encrypt_buffer, params.encrypt_length, &buffer_descriptor, @@ -1279,7 +1281,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { if (result != NO_ERROR) return result; } - WithOecLock("Decrypt() calling key_session_->Decrypt()", [&] { + WithOecSessionLock("Decrypt() calling key_session_->Decrypt()", [&] { sts = key_session_->Decrypt(params, buffer_descriptor, pattern_descriptor); }); @@ -1348,7 +1350,7 @@ bool CryptoSession::UsageInformationSupport(SecurityLevel security_level, return false; } - WithOecLock("UsageInformationSupport", [&] { + WithOecReadLock("UsageInformationSupport", [&] { *has_support = OEMCrypto_SupportsUsageTable(security_level); }); return true; @@ -1365,7 +1367,7 @@ CdmResponseType CryptoSession::UpdateUsageInformation() { } OEMCryptoResult status; - WithOecLock("UpdateUsageInformation", [&] { + WithOecWriteLock("UpdateUsageInformation", [&] { status = OEMCrypto_UpdateUsageTable(); }); metrics_->oemcrypto_update_usage_table_.Increment(status); @@ -1385,7 +1387,7 @@ CdmResponseType CryptoSession::DeactivateUsageInformation( // TODO(fredgc or rfrias): make sure oec_session_id_ is valid. OEMCryptoResult status; - WithOecLock("DeactivateUsageInformation", [&] { + WithOecWriteLock("DeactivateUsageInformation", [&] { status = OEMCrypto_DeactivateUsageEntry( oec_session_id_, pst, provider_session_token.length()); }); @@ -1425,7 +1427,7 @@ CdmResponseType CryptoSession::GenerateUsageReport( size_t usage_length = 0; OEMCryptoResult status; - WithOecLock("GenerateUsageReport Attempt 1", [&] { + WithOecWriteLock("GenerateUsageReport Attempt 1", [&] { status = OEMCrypto_ReportUsage( oec_session_id_, pst, provider_session_token.length(), NULL, &usage_length); @@ -1439,7 +1441,7 @@ CdmResponseType CryptoSession::GenerateUsageReport( std::vector buffer(usage_length); - WithOecLock("GenerateUsageReport Attempt 2", [&] { + WithOecWriteLock("GenerateUsageReport Attempt 2", [&] { status = OEMCrypto_ReportUsage(oec_session_id_, pst, provider_session_token.length(), &buffer[0], &usage_length); @@ -1516,7 +1518,7 @@ CdmResponseType CryptoSession::ReleaseUsageInformation( const uint8_t* pst = msg + GetOffset(message, provider_session_token); OEMCryptoResult status; - WithOecLock("ReleaseUsageInformation", [&] { + WithOecWriteLock("ReleaseUsageInformation", [&] { status = OEMCrypto_DeleteUsageEntry( oec_session_id_, pst, provider_session_token.length(), msg, message.length(), sig, signature.length()); @@ -1538,7 +1540,7 @@ CdmResponseType CryptoSession::DeleteUsageInformation( CdmResponseType response = NO_ERROR; LOGV("CryptoSession::DeleteUsageInformation"); OEMCryptoResult status; - WithOecLock("DeleteUsageInformation", [&] { + WithOecWriteLock("DeleteUsageInformation", [&] { status = OEMCrypto_ForceDeleteUsageEntry( reinterpret_cast(provider_session_token.c_str()), provider_session_token.length()); @@ -1559,7 +1561,7 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation( const std::vector& provider_session_tokens) { LOGV("CryptoSession::DeleteMultipleUsageInformation"); CdmResponseType response = NO_ERROR; - WithOecLock("DeleteMultipleUsageInformation", [&] { + WithOecWriteLock("DeleteMultipleUsageInformation", [&] { for (size_t i = 0; i < provider_session_tokens.size(); ++i) { OEMCryptoResult status = OEMCrypto_ForceDeleteUsageEntry( reinterpret_cast(provider_session_tokens[i].c_str()), @@ -1581,7 +1583,7 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation( CdmResponseType CryptoSession::DeleteAllUsageReports() { LOGV("DeleteAllUsageReports"); OEMCryptoResult status; - WithOecLock("DeleteAllUsageReports", [&] { + WithOecWriteLock("DeleteAllUsageReports", [&] { status = OEMCrypto_DeleteOldUsageTable(); }); metrics_->oemcrypto_delete_usage_table_.Increment(status); @@ -1598,7 +1600,7 @@ CdmResponseType CryptoSession::DeleteAllUsageReports() { bool CryptoSession::IsAntiRollbackHwPresent() { bool is_present; - WithOecLock("IsAntiRollbackHwPresent", [&] { + WithOecReadLock("IsAntiRollbackHwPresent", [&] { is_present = OEMCrypto_IsAntiRollbackHwPresent(requested_security_level_); }); metrics_->oemcrypto_is_anti_rollback_hw_present_.Record(is_present); @@ -1612,7 +1614,7 @@ CdmResponseType CryptoSession::GenerateNonce(uint32_t* nonce) { } OEMCryptoResult result; - WithOecLock("GenerateNonce", [&] { + WithOecSessionLock("GenerateNonce", [&] { result = OEMCrypto_GenerateNonce(oec_session_id_, nonce); }); metrics_->oemcrypto_generate_nonce_.Increment(result); @@ -1690,7 +1692,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey( // and 0 as wrapped_rsa_key_length. size_t wrapped_rsa_key_length = 0; OEMCryptoResult status; - WithOecLock("RewrapDeviceRSAKey Attempt 1", [&] { + WithOecSessionLock("RewrapDeviceRSAKey Attempt 1", [&] { M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( oec_session_id_, signed_msg, message.size(), reinterpret_cast(signature.data()), @@ -1705,7 +1707,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey( } wrapped_rsa_key->resize(wrapped_rsa_key_length); - WithOecLock("RewrapDeviceRSAKey Attempt 2", [&] { + WithOecSessionLock("RewrapDeviceRSAKey Attempt 2", [&] { M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( oec_session_id_, signed_msg, message.size(), reinterpret_cast(signature.data()), @@ -1749,7 +1751,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey30( // and 0 as wrapped_rsa_key_length. size_t wrapped_private_key_length = 0; OEMCryptoResult status; - WithOecLock("RewrapDeviceRSAKey30 Attempt 1", [&] { + WithOecSessionLock("RewrapDeviceRSAKey30 Attempt 1", [&] { M_TIME( status = OEMCrypto_RewrapDeviceRSAKey30( oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(), @@ -1766,7 +1768,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey30( } wrapped_private_key->resize(wrapped_private_key_length); - WithOecLock("RewrapDeviceRSAKey30 Attempt 2", [&] { + WithOecSessionLock("RewrapDeviceRSAKey30 Attempt 2", [&] { M_TIME( status = OEMCrypto_RewrapDeviceRSAKey30( oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(), @@ -1809,7 +1811,7 @@ CdmResponseType CryptoSession::GetHdcpCapabilities(SecurityLevel security_level, return PARAMETER_NULL; } OEMCryptoResult status; - WithOecLock("GetHdcpCapabilities", [&] { + WithOecReadLock("GetHdcpCapabilities", [&] { status = OEMCrypto_GetHDCPCapability(security_level, current, max); }); @@ -1837,7 +1839,7 @@ bool CryptoSession::GetSupportedCertificateTypes( } uint32_t oec_support; - WithOecLock("GetSupportedCertificateTypes", [&] { + WithOecReadLock("GetSupportedCertificateTypes", [&] { oec_support = OEMCrypto_SupportedCertificates(requested_security_level_); }); support->rsa_2048_bit = oec_support & OEMCrypto_Supports_RSA_2048bit; @@ -1853,7 +1855,7 @@ CdmResponseType CryptoSession::GetRandom(size_t data_length, return PARAMETER_NULL; } OEMCryptoResult sts; - WithOecLock("GetRandom", [&] { + WithOecReadLock("GetRandom", [&] { sts = OEMCrypto_GetRandom(random_data, data_length); }); metrics_->oemcrypto_get_random_.Increment(sts); @@ -1876,7 +1878,7 @@ CdmResponseType CryptoSession::GetNumberOfOpenSessions( size_t sessions_count; OEMCryptoResult status; - WithOecLock("GetNumberOfOpenSessions", [&] { + WithOecReadLock("GetNumberOfOpenSessions", [&] { status = OEMCrypto_GetNumberOfOpenSessions(security_level, &sessions_count); }); @@ -1907,7 +1909,7 @@ CdmResponseType CryptoSession::GetMaxNumberOfSessions( size_t max_sessions = 0; OEMCryptoResult status; - WithOecLock("GetMaxNumberOfSessions", [&] { + WithOecReadLock("GetMaxNumberOfSessions", [&] { status = OEMCrypto_GetMaxNumberOfSessions(security_level, &max_sessions); }); @@ -1931,7 +1933,7 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) { } OEMCryptoResult status; - WithOecLock("GetSrmVersion", [&] { + WithOecReadLock("GetSrmVersion", [&] { status = OEMCrypto_GetCurrentSRMVersion(srm_version); }); @@ -1942,7 +1944,7 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) { bool CryptoSession::IsSrmUpdateSupported() { LOGV("IsSrmUpdateSupported"); if (!IsInitialized()) return false; - return WithOecLock("IsSrmUpdateSupported", [&] { + return WithOecReadLock("IsSrmUpdateSupported", [&] { return OEMCrypto_IsSRMUpdateSupported(); }); } @@ -1956,7 +1958,7 @@ CdmResponseType CryptoSession::LoadSrm(const std::string& srm) { } OEMCryptoResult status; - WithOecLock("LoadSrm", [&] { + WithOecWriteLock("LoadSrm", [&] { status = OEMCrypto_LoadSRM( reinterpret_cast(srm.data()), srm.size()); }); @@ -1984,7 +1986,7 @@ bool CryptoSession::GetResourceRatingTier(SecurityLevel security_level, LOGE("tier destination not provided"); return false; } - WithOecLock("GetResourceRatingTier", [&] { + WithOecReadLock("GetResourceRatingTier", [&] { *tier = OEMCrypto_ResourceRatingTier(security_level); }); if (*tier < RESOURCE_RATING_TIER_LOW || *tier > RESOURCE_RATING_TIER_HIGH) { @@ -2010,7 +2012,7 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level, return false; } const char* build_information; - WithOecLock("GetBuildInformation", [&] { + WithOecReadLock("GetBuildInformation", [&] { build_information = OEMCrypto_BuildInformation(security_level); }); if (build_information == nullptr) { @@ -2030,7 +2032,7 @@ uint32_t CryptoSession::IsDecryptHashSupported(SecurityLevel security_level) { } uint32_t secure_decrypt_support; - WithOecLock("IsDecryptHashSupported", [&] { + WithOecReadLock("IsDecryptHashSupported", [&] { secure_decrypt_support = OEMCrypto_SupportsDecryptHash(security_level); }); switch (secure_decrypt_support) { @@ -2052,7 +2054,7 @@ CdmResponseType CryptoSession::SetDecryptHash( const std::string& hash) { LOGV("SetDecryptHash"); OEMCryptoResult sts; - WithOecLock("SetDecryptHash", [&] { + WithOecSessionLock("SetDecryptHash", [&] { sts = OEMCrypto_SetDecryptHash( oec_session_id_, frame_number, reinterpret_cast(hash.data()), hash.size()); @@ -2071,7 +2073,7 @@ CdmResponseType CryptoSession::GetDecryptHashError(std::string* error_string) { uint32_t failed_frame_number; OEMCryptoResult sts; - WithOecLock("GetDecryptHashError", [&] { + WithOecSessionLock("GetDecryptHashError", [&] { sts = OEMCrypto_GetHashErrorCode(oec_session_id_, &failed_frame_number); }); error_string->assign(std::to_string(sts)); @@ -2127,7 +2129,7 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer, OEMCryptoResult sts; - WithOecLock("GenericEncrypt", [&] { + WithOecSessionLock("GenericEncrypt", [&] { M_TIME( sts = OEMCrypto_Generic_Encrypt( oec_session_id_, reinterpret_cast(in_buffer.data()), @@ -2190,7 +2192,7 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer, OEMCryptoResult sts; - WithOecLock("GenericDecrypt", [&] { + WithOecSessionLock("GenericDecrypt", [&] { M_TIME( sts = OEMCrypto_Generic_Decrypt( oec_session_id_, reinterpret_cast(in_buffer.data()), @@ -2251,7 +2253,7 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message, // At most two attempts. // The first attempt may fail due to buffer too short for (int i = 0; i < 2; ++i) { - WithOecLock("GenericSign", [&] { + WithOecSessionLock("GenericSign", [&] { M_TIME( sts = OEMCrypto_Generic_Sign( oec_session_id_, reinterpret_cast(message.data()), @@ -2312,7 +2314,7 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message, if (result != NO_ERROR) return result; OEMCryptoResult sts; - WithOecLock("GenericVerify", [&] { + WithOecSessionLock("GenericVerify", [&] { M_TIME( sts = OEMCrypto_Generic_Verify( oec_session_id_, reinterpret_cast(message.data()), @@ -2391,7 +2393,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader( size_t usage_table_header_size = usage_table_header->size(); OEMCryptoResult result; - WithOecLock("CreateUsageTableHeader Attempt 1", [&] { + WithOecWriteLock("CreateUsageTableHeader Attempt 1", [&] { result = OEMCrypto_CreateUsageTableHeader( requested_security_level_, reinterpret_cast( @@ -2401,7 +2403,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader( if (result == OEMCrypto_ERROR_SHORT_BUFFER) { usage_table_header->resize(usage_table_header_size); - WithOecLock("CreateUsageTableHeader Attempt 2", [&] { + WithOecWriteLock("CreateUsageTableHeader Attempt 2", [&] { result = OEMCrypto_CreateUsageTableHeader( requested_security_level_, reinterpret_cast( @@ -2423,7 +2425,7 @@ CdmResponseType CryptoSession::LoadUsageTableHeader( LOGV("LoadUsageTableHeader: id=%lu", oec_session_id_); OEMCryptoResult result; - WithOecLock("LoadUsageTableHeader", [&] { + WithOecWriteLock("LoadUsageTableHeader", [&] { result = OEMCrypto_LoadUsageTableHeader( requested_security_level_, reinterpret_cast(usage_table_header.data()), @@ -2468,7 +2470,7 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) { } OEMCryptoResult result; - WithOecLock("CreateUsageEntry", [&] { + WithOecWriteLock("CreateUsageEntry", [&] { result = OEMCrypto_CreateNewUsageEntry(oec_session_id_, entry_number); }); @@ -2495,7 +2497,7 @@ CdmResponseType CryptoSession::LoadUsageEntry( LOGV("LoadUsageEntry: id=%lu", oec_session_id_); OEMCryptoResult result; - WithOecLock("LoadUsageEntry", [&] { + WithOecWriteLock("LoadUsageEntry", [&] { result = OEMCrypto_LoadUsageEntry( oec_session_id_, entry_number, reinterpret_cast(usage_entry.data()), @@ -2546,7 +2548,7 @@ CdmResponseType CryptoSession::UpdateUsageEntry( size_t usage_table_header_len = 0; size_t usage_entry_len = 0; OEMCryptoResult result; - WithOecLock("UpdateUsageEntry Attempt 1", [&] { + WithOecWriteLock("UpdateUsageEntry Attempt 1", [&] { result = OEMCrypto_UpdateUsageEntry( oec_session_id_, NULL, &usage_table_header_len, NULL, &usage_entry_len); }); @@ -2556,7 +2558,7 @@ CdmResponseType CryptoSession::UpdateUsageEntry( usage_table_header->resize(usage_table_header_len); usage_entry->resize(usage_entry_len); - WithOecLock("UpdateUsageEntry Attempt 2", [&] { + WithOecWriteLock("UpdateUsageEntry Attempt 2", [&] { result = OEMCrypto_UpdateUsageEntry( oec_session_id_, reinterpret_cast( @@ -2588,7 +2590,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader( size_t usage_table_header_len = 0; OEMCryptoResult result; - WithOecLock("ShrinkUsageTableHeader Attempt 1", [&] { + WithOecWriteLock("ShrinkUsageTableHeader Attempt 1", [&] { result = OEMCrypto_ShrinkUsageTableHeader( requested_security_level_, new_entry_count, NULL, &usage_table_header_len); @@ -2597,7 +2599,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader( if (result == OEMCrypto_ERROR_SHORT_BUFFER) { usage_table_header->resize(usage_table_header_len); - WithOecLock("ShrinkUsageTableHeader Attempt 2", [&] { + WithOecWriteLock("ShrinkUsageTableHeader Attempt 2", [&] { result = OEMCrypto_ShrinkUsageTableHeader( requested_security_level_, new_entry_count, reinterpret_cast( @@ -2618,7 +2620,7 @@ CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) { LOGV("MoveUsageEntry: id=%lu", oec_session_id_); OEMCryptoResult result; - WithOecLock("MoveUsageEntry", [&] { + WithOecWriteLock("MoveUsageEntry", [&] { result = OEMCrypto_MoveEntry(oec_session_id_, new_entry_number); }); @@ -2660,7 +2662,7 @@ bool CryptoSession::CreateOldUsageEntry( } OEMCryptoResult result; - WithOecLock("CreateOldUsageEntry", [&] { + WithOecWriteLock("CreateOldUsageEntry", [&] { result = OEMCrypto_CreateOldUsageEntry( requested_security_level_, time_since_license_received, time_since_first_decrypt, time_since_last_decrypt, status, @@ -2683,7 +2685,7 @@ CdmResponseType CryptoSession::CopyOldUsageEntry( LOGV("CopyOldUsageEntry: id=%lu", oec_session_id_); OEMCryptoResult result; - WithOecLock("CopyOldUsageEntry", [&] { + WithOecWriteLock("CopyOldUsageEntry", [&] { result = OEMCrypto_CopyOldUsageEntry( oec_session_id_, reinterpret_cast(provider_session_token.data()), @@ -2699,7 +2701,7 @@ bool CryptoSession::GetAnalogOutputCapabilities(bool* can_support_output, bool* can_support_cgms_a) { LOGV("GetAnalogOutputCapabilities: id=%lu", oec_session_id_); uint32_t flags; - WithOecLock("GetAnalogOutputCapabilities", [&] { + WithOecReadLock("GetAnalogOutputCapabilities", [&] { flags = OEMCrypto_GetAnalogOutputFlags(requested_security_level_); }); @@ -2779,7 +2781,7 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks( } OEMCryptoResult sts; - WithOecLock("CopyBufferInChunks", [&] { + WithOecSessionLock("CopyBufferInChunks", [&] { M_TIME(sts = OEMCrypto_CopyBuffer( oec_session_id_, params.encrypt_buffer + additional_offset, chunk_size, &buffer_descriptor, subsample_flags), @@ -2853,7 +2855,7 @@ OEMCryptoResult CryptoSession::DecryptInChunks( // pattern length long, which is also guaranteed to be an exact number // of AES blocks long. OEMCryptoResult sts; - WithOecLock("DecryptInChunks", [&] { + WithOecSessionLock("DecryptInChunks", [&] { M_TIME( sts = OEMCrypto_DecryptCENC( oec_session_id_, params.encrypt_buffer + additional_offset, @@ -2927,27 +2929,52 @@ void CryptoSession::IncrementIV(uint64_t increase_by, } template -auto CryptoSession::WithStaticFieldLock(const char* tag, Func body) +auto CryptoSession::WithStaticFieldWriteLock(const char* tag, Func body) -> decltype(body()) { - LOGV("Static Field Lock - %s", tag); - std::unique_lock auto_lock(static_field_lock_); + LOGV("Static Field Write Lock - %s", tag); + std::unique_lock auto_lock(static_field_mutex_); return body(); } template -auto CryptoSession::WithOecLock(const char* tag, Func body) +auto CryptoSession::WithStaticFieldReadLock(const char* tag, Func body) -> decltype(body()) { - LOGV("OEMCrypto Lock - %s", tag); - std::unique_lock auto_lock(oem_crypto_lock_); + LOGV("Static Field Read Lock - %s", tag); + shared_lock auto_lock(static_field_mutex_); + return body(); +} + +template +auto CryptoSession::WithOecWriteLock(const char* tag, Func body) + -> decltype(body()) { + LOGV("OEMCrypto Write Lock - %s", tag); + std::unique_lock auto_lock(oem_crypto_mutex_); + return body(); +} + +template +auto CryptoSession::WithOecReadLock(const char* tag, Func body) + -> decltype(body()) { + LOGV("OEMCrypto Read Lock - %s", tag); + shared_lock auto_lock(oem_crypto_mutex_); + return body(); +} + +template +auto CryptoSession::WithOecSessionLock(const char* tag, Func body) + -> decltype(body()) { + LOGV("OEMCrypto Session Lock - %s", tag); + shared_lock oec_auto_lock(oem_crypto_mutex_); + std::unique_lock session_auto_lock(oem_crypto_session_mutex_); return body(); } bool CryptoSession::IsInitialized() { - return WithStaticFieldLock("IsInitialized", [] { return initialized_; }); + return WithStaticFieldReadLock("IsInitialized", [] { return initialized_; }); } // CryptoSesssionFactory support -std::mutex CryptoSession::factory_lock_; +std::mutex CryptoSession::factory_mutex_; // The factory will either be set by WvCdmTestBase, or a default factory is // created on the first call to MakeCryptoSession. std::unique_ptr CryptoSession::factory_ = @@ -2955,7 +2982,7 @@ std::unique_ptr CryptoSession::factory_ = CryptoSession* CryptoSession::MakeCryptoSession( metrics::CryptoMetrics* crypto_metrics) { - std::unique_lock auto_lock(factory_lock_); + std::unique_lock auto_lock(factory_mutex_); // If the factory_ has not been set, then use a default factory. if (factory_.get() == NULL) factory_.reset(new CryptoSessionFactory()); return factory_->MakeCryptoSession(crypto_metrics);