Skip to content

Commit

Permalink
Check CDM API version compatibility before registering component.
Browse files Browse the repository at this point in the history
Compatibility is not checked before installing a component. This should be prevented on the server side.

BUG=311374
TEST=video.canPlayType('video/webm; codecs="vp8"', 'com.widevine.alpha'); is affirmative when manifest contains supported "x-cdm-*-versions" values and "" when any value is unsupported.

Review URL: https://codereview.chromium.org/47513020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232424 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
ddorwin@chromium.org committed Nov 1, 2013
1 parent f2928a9 commit 9813665
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 12 deletions.
1 change: 1 addition & 0 deletions chrome/browser/component_updater/DEPS
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include_rules = [
"+media/cdm/ppapi/supported_cdm_versions.h",
"+ppapi/shared_impl/ppapi_permissions.h",
"+ppapi/thunk",
"+third_party/widevine"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
Expand All @@ -28,6 +30,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "media/cdm/ppapi/supported_cdm_versions.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"

#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
Expand Down Expand Up @@ -68,6 +71,23 @@ const char kWidevineCdmArch[] =
"???";
#endif

// The CDM manifest includes several custom values, all beginning with "x-cdm-".
// All values are strings.
// All values that are lists are delimited by commas. No trailing commas.
// For example, "1,2,4".
const char kCdmValueDelimiter = ',';
COMPILE_ASSERT(kCdmValueDelimiter == kCdmSupportedCodecsValueDelimiter,
cdm_delimiters_do_not_match);
// The following entries are required.
// Interface versions are lists of integers (e.g. "1" or "1,2,4").
// These are checked in this file before registering the CDM.
const char kCdmModuleVersionsName[] = "x-cdm-module-versions";
const char kCdmInstanceVersionsName[] = "x-cdm-instance-versions";
const char kCdmHostVersionsName[] = "x-cdm-host-versions";
// The codecs list is a list of simple codec names (e.g. "vp8,vorbis").
// The list is passed to other parts of Chrome.
const char kCdmCodecsListName[] = "x-cdm-codecs";

// Widevine CDM is packaged as a multi-CRX. Widevine CDM binaries are located in
// _platform_specific/<platform_arch> folder in the package. This function
// returns the platform-specific subdirectory that is part of that multi-CRX.
Expand Down Expand Up @@ -109,11 +129,67 @@ bool MakeWidevineCdmPluginInfo(
return true;
}

typedef bool (*VersionCheckFunc)(int version);

bool CheckForCompatibleVersion(const base::DictionaryValue& manifest,
const std::string version_name,
VersionCheckFunc version_check_func) {
std::string versions_string;
if (!manifest.GetString(version_name, &versions_string)) {
DLOG(WARNING)
<< "Widevine CDM component manifest is missing " << version_name;
// TODO(ddorwin): Remove this once all users have been updated.
// The original manifests did not include this string, so add its version.
if (version_name == kCdmModuleVersionsName)
versions_string = "4";
else if (version_name == kCdmInstanceVersionsName)
versions_string = "1";
else if (version_name == kCdmHostVersionsName)
versions_string = "1";
}
DLOG_IF(WARNING, versions_string.empty())
<< "Widevine CDM component manifest has empty " << version_name;

std::vector<std::string> versions;
base::SplitString(versions_string,
kCdmValueDelimiter,
&versions);

for (size_t i = 0; i < versions.size(); ++i) {
int version = 0;
if (base::StringToInt(versions[i], &version))
if (version_check_func(version))
return true;
}

DLOG(WARNING) << "Widevine CDM component manifest has no supported "
<< version_name << " in '" << versions_string << "'";
return false;
}

// Returns whether the CDM's API versions, as specified in the manifest, are
// compatible with this Chrome binary.
// Checks the module API, CDM instance API, and Host API.
// This should never fail except in rare cases where the component has not been
// updated recently or the user downgrades Chrome.
bool IsCompatibleWithChrome(const base::DictionaryValue& manifest) {
return
CheckForCompatibleVersion(manifest,
kCdmModuleVersionsName,
media::IsSupportedCdmModuleVersion) &&
CheckForCompatibleVersion(manifest,
kCdmInstanceVersionsName,
media::IsSupportedCdmInterfaceVersion) &&
CheckForCompatibleVersion(manifest,
kCdmHostVersionsName,
media::IsSupportedCdmHostVersion);
}

void GetAdditionalParams(const base::DictionaryValue& manifest,
std::vector<base::string16>* additional_param_names,
std::vector<base::string16>* additional_param_values) {
base::string16 codecs;
if (manifest.GetString("x-cdm-codecs", &codecs)) {
if (manifest.GetString(kCdmCodecsListName, &codecs)) {
DLOG_IF(WARNING, codecs.empty())
<< "Widevine CDM component manifest has empty codecs list";
additional_param_names->push_back(
Expand Down Expand Up @@ -199,7 +275,11 @@ void WidevineCdmComponentInstallerTraits::ComponentReady(
const base::Version& version,
const base::FilePath& path,
scoped_ptr<base::DictionaryValue> manifest) {
// TODO(ddorwin): Check API version compatibility. Return if fails.
if (!IsCompatibleWithChrome(*manifest)) {
DLOG(WARNING) << "Installed Widevine CDM component is incompatible.";
return;
}

base::FilePath adapter_install_path = GetPlatformDirectory(path)
.AppendASCII(kWidevineCdmAdapterFileName);
RegisterWidevineCdmWithChrome(version,
Expand Down
31 changes: 27 additions & 4 deletions media/cdm/ppapi/cdm_adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "media/cdm/ppapi/cdm_adapter.h"

#include "media/cdm/ppapi/cdm_helpers.h"
#include "media/cdm/ppapi/supported_cdm_versions.h"

#if defined(CHECK_DOCUMENT_URL)
#include "ppapi/cpp/dev/url_util_dev.h"
Expand Down Expand Up @@ -912,12 +913,34 @@ void* GetCdmHost(int host_interface_version, void* user_data) {
if (!host_interface_version || !user_data)
return NULL;

COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion ==
cdm::ContentDecryptionModule_2::Host::kVersion,
update_code_below);

// Ensure IsSupportedCdmHostVersion matches implementation of this function.
// Always update this DCHECK when updating this function.
// If this check fails, update this function and DCHECK or update
// IsSupportedCdmHostVersion.
PP_DCHECK(
// Future version is not supported.
!IsSupportedCdmHostVersion(
cdm::ContentDecryptionModule::Host::kVersion + 1) &&
// Current version is supported.
IsSupportedCdmHostVersion(cdm::ContentDecryptionModule::Host::kVersion) &&
// Include all previous supported versions here.
IsSupportedCdmHostVersion(cdm::Host_1::kVersion) &&
// One older than the oldest supported version is not supported.
!IsSupportedCdmHostVersion(cdm::Host_1::kVersion - 1));
PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));

CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
switch (host_interface_version) {
case cdm::ContentDecryptionModule_1::Host::kVersion:
return static_cast<cdm::ContentDecryptionModule_1::Host*>(cdm_adapter);
case cdm::ContentDecryptionModule_2::Host::kVersion:
return static_cast<cdm::ContentDecryptionModule_2::Host*>(cdm_adapter);
// The latest CDM host version.
case cdm::ContentDecryptionModule::Host::kVersion:
return static_cast<cdm::ContentDecryptionModule::Host*>(cdm_adapter);
// Older supported version(s) of the CDM host.
case cdm::Host_1::kVersion:
return static_cast<cdm::Host_1*>(cdm_adapter);
default:
PP_NOTREACHED();
return NULL;
Expand Down
31 changes: 25 additions & 6 deletions media/cdm/ppapi/cdm_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "media/cdm/ppapi/api/content_decryption_module.h"
#include "media/cdm/ppapi/cdm_helpers.h"
#include "media/cdm/ppapi/supported_cdm_versions.h"
#include "ppapi/cpp/logging.h"

namespace media {
Expand Down Expand Up @@ -215,22 +216,40 @@ CdmWrapper* CdmWrapper::Create(const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_2::kVersion,
update_code_below);

// Ensure IsSupportedCdmInterfaceVersion matches this implementation.
// Always update this DCHECK when updating this function.
// If this check fails, update this function and DCHECK or update
// IsSupportedCdmInterfaceVersion.
PP_DCHECK(
!IsSupportedCdmInterfaceVersion(
cdm::ContentDecryptionModule::kVersion + 1) &&
IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion) &&
IsSupportedCdmInterfaceVersion(
cdm::ContentDecryptionModule_1::kVersion) &&
!IsSupportedCdmInterfaceVersion(
cdm::ContentDecryptionModule_1::kVersion - 1));

// Try to create the CDM using the latest CDM interface version.
CdmWrapper* cdm_adapter =
CdmWrapper* cdm_wrapper =
CdmWrapperImpl<cdm::ContentDecryptionModule>::Create(
key_system, key_system_size, get_cdm_host_func, user_data);
if (cdm_adapter)
return cdm_adapter;
if (cdm_wrapper)
return cdm_wrapper;

// Try to see if the CDM supports older version(s) of CDM interface(s).
cdm_adapter = CdmWrapperImpl<cdm::ContentDecryptionModule_1>::Create(
// Try to see if the CDM supports older version(s) of the CDM interface.
cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_1>::Create(
key_system, key_system_size, get_cdm_host_func, user_data);
return cdm_adapter;
return cdm_wrapper;
}

// When updating the CdmAdapter, ensure you've updated the CdmWrapper to contain
// stub implementations for new or modified methods that the older CDM interface
// does not have.
// Also update supported_cdm_versions.h.
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_2::kVersion,
ensure_cdm_wrapper_templates_have_old_version_support);
Expand Down
56 changes: 56 additions & 0 deletions media/cdm/ppapi/supported_cdm_versions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_CDM_PPAPI_SUPPORTED_CDM_VERSIONS_H_
#define MEDIA_CDM_PPAPI_SUPPORTED_CDM_VERSIONS_H_

#include "media/cdm/ppapi/api/content_decryption_module.h"

namespace media {

// TODO(ddorwin): Move to content_decryption_module.h.
#define CDM_MODULE_VERSION 4

bool IsSupportedCdmModuleVersion(int version) {
switch(version) {
// Latest.
case CDM_MODULE_VERSION:
return true;
default:
return false;
}
}

bool IsSupportedCdmInterfaceVersion(int version) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_2::kVersion,
update_code_below);
switch(version) {
// Latest.
case cdm::ContentDecryptionModule::kVersion:
// Older supported versions.
case cdm::ContentDecryptionModule_1::kVersion:
return true;
default:
return false;
}
}

bool IsSupportedCdmHostVersion(int version) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion ==
cdm::ContentDecryptionModule_2::Host::kVersion,
update_code_below);
switch(version) {
// Supported versions in increasing order (there is no default).
case cdm::Host_1::kVersion:
case cdm::Host_2::kVersion:
return true;
default:
return false;
}
}

} // namespace media

#endif // MEDIA_CDM_PPAPI_SUPPORTED_CDM_VERSIONS_H_
1 change: 1 addition & 0 deletions media/media_cdm.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
'cdm/ppapi/cdm_helpers.h',
'cdm/ppapi/cdm_wrapper.h',
'cdm/ppapi/linked_ptr.h',
'cdm/ppapi/supported_cdm_versions.h',
],
'conditions': [
['os_posix == 1 and OS != "mac" and enable_pepper_cdms==1', {
Expand Down
1 change: 1 addition & 0 deletions third_party/widevine/cdm/widevine_cdm.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
'<(DEPTH)/media/cdm/ppapi/cdm_helpers.h',
'<(DEPTH)/media/cdm/ppapi/cdm_wrapper.h',
'<(DEPTH)/media/cdm/ppapi/linked_ptr.h',
'<(DEPTH)/media/cdm/ppapi/supported_cdm_versions.h',
],
'conditions': [
[ 'os_posix == 1 and OS != "mac"', {
Expand Down

0 comments on commit 9813665

Please sign in to comment.