From 03f8d1b6f7d35ffd68f21cf4358c3e029d86c01d Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Fri, 19 Nov 2021 22:48:54 +0000 Subject: [PATCH] Guard against double initialize Merge from Widevine repo of http://go/wvgerrit/139498 If L1 OEMCrypto fails to initialize, we won't try again. Bug: 206670307 Change-Id: I89084476ae01d9c98291392c2ce703ebc6326322 --- .../core/src/oemcrypto_adapter_dynamic.cpp | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 51bdfcb6..d0d2b3c6 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -718,7 +718,7 @@ struct LevelSession { level1_.Name = (L1_##Name##_t)dlsym(level1_library_, QUOTE(Function)); \ if (!level1_.Name) { \ LOGW("Could not load L1 %s. Falling back to L3.", QUOTE(Function)); \ - if (level1_.Terminate) level1_.Terminate(); \ + if (level1_.Terminate) Level1Terminate(); \ return false; \ } \ } @@ -740,7 +740,11 @@ class Adapter { public: using map_iterator = std::map::iterator; - Adapter() : level1_valid_(false), level1_library_(nullptr) {} + Adapter() + : level1_valid_(false), + level1_initialized_(false), + level1_failed_(false), + level1_library_(nullptr) {} // The adapter is only destroyed on certain errors, or when the process // dies. It is NOT deleted after each OEMCrypto_Terminate. @@ -819,9 +823,23 @@ class Adapter { return result; } + OEMCryptoResult Level1Terminate() { + OEMCryptoResult result = OEMCrypto_SUCCESS; + if (level1_.Terminate && level1_initialized_) { + LOGE("L1 Terminate"); + result = level1_.Terminate(); + } else { + LOGE("L1 Terminate not needed"); + } + level1_initialized_ = false; + return result; + } + void FallBackToLevel3() { + Level1Terminate(); level1_ = FunctionPointers(); // revert to all null pointers. level1_valid_ = false; + level1_failed_ = true; // Note: if the function pointers are bad, we do not close the library and // try again later. Instead, we permanently fall back to L3. This is a // debatable choice: I decided the risk of a dlclose resource leak out @@ -833,6 +851,12 @@ class Adapter { if (metrics == nullptr) { return false; } + if (level1_failed_) { + // If we failed to initialize the level 1 library before, then we don't + // try again. + LOGE("Still falling back to L3."); + return false; + } level1_valid_ = true; const uint32_t kMinimumVersion = 8; const uint32_t kMaximumVersion = 16; @@ -864,6 +888,7 @@ class Adapter { OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INITIALIZE_L1); return false; } + level1_initialized_ = true; level1_.version = level1_.APIVersion(); level1_.security_level = wvcdm::kSecurityLevelUninitialized; metrics->SetL1ApiVersion(level1_.version); @@ -874,7 +899,7 @@ class Adapter { level1_.version, kMinimumVersion); metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode( wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_WRONG_L1_VERSION); - level1_.Terminate(); + Level1Terminate(); return false; } @@ -996,7 +1021,6 @@ class Adapter { level1_.security_level = wvcdm::kSecurityLevelUnknown; } } - return true; } @@ -1083,7 +1107,7 @@ class Adapter { session_map_.clear(); OEMCryptoResult result = Level3_Terminate(); if (level1_valid_) { - result = level1_.Terminate(); + result = Level1Terminate(); } return result; } @@ -1154,8 +1178,7 @@ class Adapter { if (!level1_.IsKeyboxOrOEMCertValid) { // TODO(b/189989043): add metrics. LOGE("L1 invalid function pointers. Falling back to L3"); - if (level1_.Terminate) level1_.Terminate(); - level1_valid_ = false; + FallBackToLevel3(); return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid() : OEMCrypto_ERROR_NOT_IMPLEMENTED; } @@ -1205,14 +1228,16 @@ class Adapter { wvcdm::metrics:: OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX); } - if (level1_.Terminate) level1_.Terminate(); - level1_valid_ = false; + FallBackToLevel3(); return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid() : OEMCrypto_ERROR_NOT_IMPLEMENTED; } private: bool level1_valid_; + bool level1_initialized_; + // If the level 1 fails to initialize once, we don't try again. + bool level1_failed_; void* level1_library_; struct FunctionPointers level1_; struct FunctionPointers level3_;