Reset crypto session pointers on RemoveKeys.
[ Merge of http://go/wvgerrit/189590 ] [ Cherry-pick of http://ag/26541307 ] The CDM session shares its CryptoSession instance with a few additional member objects (CdmLicense and PolicyEngine). When the CDM session's crypto session is reset, it must also reset the CdmLicense and PolicyEngine otherwise, a potential stale pointer reference may occur. Test: request_license_test on Oriole Test: run_x86_64_tests Bug: 311239278 Change-Id: Ie175513ae652dcd96e12e5e1def574a8a56d5863
This commit is contained in:
@@ -81,9 +81,7 @@ CdmSession::CdmSession(wvutil::FileSystem* file_system,
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
requested_security_level_(kLevelDefault),
|
||||
is_initial_usage_update_(true),
|
||||
is_usage_update_needed_(false),
|
||||
mock_license_parser_in_use_(false),
|
||||
mock_policy_engine_in_use_(false) {
|
||||
is_usage_update_needed_(false) {
|
||||
assert(metrics_); // metrics_ must not be null.
|
||||
crypto_metrics_ = metrics_->GetCryptoMetrics();
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
@@ -866,18 +864,10 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_index) {
|
||||
// The usage entry cannot be deleted if it has a crypto session handling
|
||||
// it, so close and reopen session.
|
||||
UpdateUsageEntryInformation();
|
||||
CdmResponseType sts;
|
||||
crypto_session_->Close();
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
M_TIME(sts = crypto_session_->Open(requested_security_level_),
|
||||
crypto_metrics_, crypto_session_open_, sts, requested_security_level_);
|
||||
if (sts != NO_ERROR) return sts;
|
||||
|
||||
usage_table_ = nullptr;
|
||||
bool has_support = false;
|
||||
if (crypto_session_->HasUsageTableSupport(&has_support) && has_support) {
|
||||
usage_table_ = crypto_session_->GetUsageTable();
|
||||
}
|
||||
crypto_session_->Close();
|
||||
CdmResponseType sts = ResetCryptoSession();
|
||||
if (sts != NO_ERROR) return sts;
|
||||
|
||||
if (usage_table_ == nullptr) {
|
||||
LOGE("Usage table header unavailable");
|
||||
@@ -1012,14 +1002,8 @@ bool CdmSession::StoreLicense(CdmOfflineLicenseState state, int* error_detail) {
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::RemoveKeys() {
|
||||
CdmResponseType sts;
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
// Ignore errors
|
||||
M_TIME(sts = crypto_session_->Open(requested_security_level_),
|
||||
crypto_metrics_, crypto_session_open_, sts, requested_security_level_);
|
||||
policy_engine_.reset(
|
||||
new PolicyEngine(session_id_, nullptr, crypto_session_.get()));
|
||||
return CdmResponseType(NO_ERROR);
|
||||
crypto_session_->Close();
|
||||
return ResetCryptoSession();
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::RemoveLicense() {
|
||||
@@ -1313,6 +1297,77 @@ CdmResponseType CdmSession::GenerateRsaSignature(const std::string& message,
|
||||
return crypto_session_->GenerateRsaSignature(message, signature, scheme);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::ResetCryptoSession() {
|
||||
LOGD("Resetting crypto session: session_id = %s, ksid = %s",
|
||||
IdToString(session_id_), IdToString(key_set_id_));
|
||||
if (mock_crypto_session_in_use_) {
|
||||
// If the crypto session is not reset, then there is nothing to do.
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
CdmResponseType sts;
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
usage_table_ = nullptr;
|
||||
M_TIME(sts = crypto_session_->Open(requested_security_level_),
|
||||
crypto_metrics_, crypto_session_open_, sts, requested_security_level_);
|
||||
|
||||
CdmResponseType final_sts(NO_ERROR);
|
||||
if (sts != NO_ERROR) {
|
||||
// Challenging case, still need to reset other components.
|
||||
LOGE("Failed to open crypto session: sts = %s", sts.ToString().c_str());
|
||||
final_sts = sts;
|
||||
} else {
|
||||
// Reset all component dependent on the crypto session.
|
||||
security_level_ = crypto_session_->GetSecurityLevel();
|
||||
crypto_metrics_->crypto_session_security_level_.Record(security_level_);
|
||||
|
||||
if (!file_handle_->Init(security_level_)) {
|
||||
LOGE("Unable to initialize file handle");
|
||||
final_sts = CdmResponseType(SESSION_FILE_HANDLE_INIT_ERROR);
|
||||
}
|
||||
|
||||
if (!file_handle_->HasCertificate(atsc_mode_enabled_)) {
|
||||
LOGE("Missing certificate: atsc_mode_enabled = %s",
|
||||
BoolToString(atsc_mode_enabled_));
|
||||
final_sts = CdmResponseType(NEED_PROVISIONING);
|
||||
}
|
||||
|
||||
bool has_support = false;
|
||||
if (crypto_session_->HasUsageTableSupport(&has_support) && has_support) {
|
||||
usage_table_ = crypto_session_->GetUsageTable();
|
||||
}
|
||||
}
|
||||
|
||||
// Even if the session is not open, other members need new session pointer.
|
||||
if (mock_policy_engine_in_use_) {
|
||||
// Simply pass the new pointer.
|
||||
policy_engine_->set_crypto_session(crypto_session_.get());
|
||||
} else {
|
||||
// Attempt to maintain event listener.
|
||||
WvCdmEventListener* event_listener =
|
||||
policy_engine_ ? policy_engine_->event_listener() : nullptr;
|
||||
policy_engine_.reset(
|
||||
new PolicyEngine(session_id_, event_listener, crypto_session_.get()));
|
||||
}
|
||||
|
||||
if (mock_license_parser_in_use_) {
|
||||
license_parser_->set_crypto_session(crypto_session_.get());
|
||||
license_parser_->set_policy_engine(policy_engine_.get());
|
||||
} else {
|
||||
license_parser_.reset(new CdmLicense(session_id_));
|
||||
std::string service_certificate;
|
||||
if (!Properties::GetServiceCertificate(session_id_, &service_certificate))
|
||||
service_certificate.clear();
|
||||
if (!license_parser_->Init(Properties::UsePrivacyMode(session_id_),
|
||||
service_certificate, crypto_session_.get(),
|
||||
policy_engine_.get())) {
|
||||
LOGE("Failed to initialize license parser");
|
||||
final_sts = CdmResponseType(LICENSE_PARSER_INIT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return final_sts;
|
||||
}
|
||||
|
||||
// For testing only - takes ownership of pointers
|
||||
|
||||
void CdmSession::set_license_parser(CdmLicense* license_parser) {
|
||||
@@ -1322,6 +1377,7 @@ void CdmSession::set_license_parser(CdmLicense* license_parser) {
|
||||
|
||||
void CdmSession::set_crypto_session(CryptoSession* crypto_session) {
|
||||
crypto_session_.reset(crypto_session);
|
||||
mock_crypto_session_in_use_ = true;
|
||||
}
|
||||
|
||||
void CdmSession::set_policy_engine(PolicyEngine* policy_engine) {
|
||||
|
||||
@@ -195,9 +195,7 @@ std::vector<CryptoKey> ExtractContentKeys(
|
||||
} // namespace
|
||||
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
: crypto_session_(nullptr),
|
||||
policy_engine_(nullptr),
|
||||
session_id_(session_id),
|
||||
: session_id_(session_id),
|
||||
initialized_(false),
|
||||
protocol_version_(video_widevine::VERSION_2_2),
|
||||
renew_with_client_id_(false),
|
||||
@@ -207,16 +205,18 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
license_key_type_(kLicenseKeyTypeContent) {}
|
||||
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id, wvutil::Clock* clock)
|
||||
: crypto_session_(nullptr),
|
||||
policy_engine_(nullptr),
|
||||
session_id_(session_id),
|
||||
: session_id_(session_id),
|
||||
initialized_(false),
|
||||
protocol_version_(video_widevine::VERSION_2_2),
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
use_privacy_mode_(false),
|
||||
clock_(clock),
|
||||
license_key_type_(kLicenseKeyTypeContent) {
|
||||
clock_.reset(clock);
|
||||
if (!clock_) {
|
||||
LOGW("Input |clock| is null, using default");
|
||||
clock_.reset(new wvutil::Clock());
|
||||
}
|
||||
}
|
||||
|
||||
CdmLicense::~CdmLicense() {}
|
||||
|
||||
@@ -39,9 +39,12 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||
if (version >= kMinOemCryptoApiVersionSupportsRenewalDelayBase) {
|
||||
policy_timers_.reset(new PolicyTimersV18());
|
||||
}
|
||||
} else {
|
||||
LOGW("Failed to get API version: session_id = %s", IdToString(session_id));
|
||||
}
|
||||
|
||||
if (policy_timers_ == nullptr) {
|
||||
if (!policy_timers_) {
|
||||
// Use V16 policy timers if getting version failed.
|
||||
policy_timers_.reset(new PolicyTimersV16());
|
||||
}
|
||||
InitDevice(crypto_session);
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace wvcdm {
|
||||
namespace {
|
||||
const char kEmptyIdRep[] = "<empty>";
|
||||
const char kNullIdRep[] = "<null>";
|
||||
const char kFalseRep[] = "false";
|
||||
const char kTrueRep[] = "true";
|
||||
|
||||
// Thread local buffer used by UnknownEnumValueToString() to represent
|
||||
// unknown enum values.
|
||||
@@ -894,6 +896,8 @@ const char* IdPtrToString(const std::string* id) {
|
||||
return id->empty() ? kEmptyIdRep : id->c_str();
|
||||
}
|
||||
|
||||
const char* BoolToString(bool value) { return value ? kTrueRep : kFalseRep; }
|
||||
|
||||
const char* OemCryptoResultToString(OEMCryptoResult result) {
|
||||
switch (result) {
|
||||
/* OEMCrypto return values */
|
||||
|
||||
Reference in New Issue
Block a user