Commit ddb0fcf8 authored by jrummell's avatar jrummell Committed by Commit bot

Verify promise type before casting.

If a CDM calls the wrong Resolved() method to resolve a promise, the
promise is cast to the wrong type and causes a crash. This fixes the
problem by verifying that the promise is the correct type before
casting it.

BUG=408319
TEST=existing EME tests pass

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

Cr-Commit-Position: refs/heads/master@{#292440}
parent 8d2128e8
......@@ -625,26 +625,33 @@ bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
if (promise) {
if (!promise ||
promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) {
NOTREACHED();
return;
}
SimpleCdmPromise* simple_promise(
static_cast<SimpleCdmPromise*>(promise.get()));
simple_promise->resolve();
}
}
void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
uint32 promise_id,
PP_Var web_session_id) {
scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
if (!promise ||
promise->GetResolveParameterType() != media::CdmPromise::STRING_TYPE) {
NOTREACHED();
return;
}
StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
DCHECK(web_session_id_string);
if (promise) {
NewSessionCdmPromise* session_promise(
static_cast<NewSessionCdmPromise*>(promise.get()));
session_promise->resolve(web_session_id_string->value());
}
}
void ContentDecryptorDelegate::OnPromiseRejected(
......
......@@ -63,34 +63,28 @@ void CdmPromise::reject(MediaKeys::Exception exception_code,
reject_cb_.Run(exception_code, system_code, error_message);
}
template <typename T>
CdmPromiseTemplate<T>::CdmPromiseTemplate(
base::Callback<void(const T&)> resolve_cb,
CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
PromiseRejectedCB reject_cb)
: CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null());
}
template <typename T>
CdmPromiseTemplate<T>::CdmPromiseTemplate(
base::Callback<void(const T&)> resolve_cb,
CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
PromiseRejectedCB reject_cb,
const std::string& uma_name)
: CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null());
DCHECK(!uma_name_.empty());
}
template <typename T>
CdmPromiseTemplate<T>::CdmPromiseTemplate() {
CdmPromiseTemplate<void>::CdmPromiseTemplate() {
}
template <typename T>
CdmPromiseTemplate<T>::~CdmPromiseTemplate() {
CdmPromiseTemplate<void>::~CdmPromiseTemplate() {
DCHECK(!is_pending_);
}
template <typename T>
void CdmPromiseTemplate<T>::resolve(const T& result) {
void CdmPromiseTemplate<void>::resolve() {
DCHECK(is_pending_);
is_pending_ = false;
if (!uma_name_.empty()) {
......@@ -98,31 +92,37 @@ void CdmPromiseTemplate<T>::resolve(const T& result) {
uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS);
}
resolve_cb_.Run(result);
resolve_cb_.Run();
}
CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
CdmPromise::ResolveParameterType
CdmPromiseTemplate<void>::GetResolveParameterType() const {
return VOID_TYPE;
}
CdmPromiseTemplate<std::string>::CdmPromiseTemplate(
base::Callback<void(const std::string&)> resolve_cb,
PromiseRejectedCB reject_cb)
: CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null());
}
CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
CdmPromiseTemplate<std::string>::CdmPromiseTemplate(
base::Callback<void(const std::string&)> resolve_cb,
PromiseRejectedCB reject_cb,
const std::string& uma_name)
: CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null());
DCHECK(!uma_name_.empty());
}
CdmPromiseTemplate<void>::CdmPromiseTemplate() {
CdmPromiseTemplate<std::string>::CdmPromiseTemplate() {
}
CdmPromiseTemplate<void>::~CdmPromiseTemplate() {
CdmPromiseTemplate<std::string>::~CdmPromiseTemplate() {
DCHECK(!is_pending_);
}
void CdmPromiseTemplate<void>::resolve() {
void CdmPromiseTemplate<std::string>::resolve(const std::string& result) {
DCHECK(is_pending_);
is_pending_ = false;
if (!uma_name_.empty()) {
......@@ -130,11 +130,47 @@ void CdmPromiseTemplate<void>::resolve() {
uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS);
}
resolve_cb_.Run();
resolve_cb_.Run(result);
}
// Explicit template instantiation for the Promises needed.
template class MEDIA_EXPORT CdmPromiseTemplate<std::string>;
template class MEDIA_EXPORT CdmPromiseTemplate<KeyIdsVector>;
CdmPromise::ResolveParameterType
CdmPromiseTemplate<std::string>::GetResolveParameterType() const {
return STRING_TYPE;
}
CdmPromiseTemplate<KeyIdsVector>::CdmPromiseTemplate(
base::Callback<void(const KeyIdsVector&)> resolve_cb,
PromiseRejectedCB reject_cb)
: CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null());
}
CdmPromiseTemplate<KeyIdsVector>::CdmPromiseTemplate(
base::Callback<void(const KeyIdsVector&)> resolve_cb,
PromiseRejectedCB reject_cb,
const std::string& uma_name)
: CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null());
}
CdmPromiseTemplate<KeyIdsVector>::~CdmPromiseTemplate() {
DCHECK(!is_pending_);
}
void CdmPromiseTemplate<KeyIdsVector>::resolve(const KeyIdsVector& result) {
DCHECK(is_pending_);
is_pending_ = false;
if (!uma_name_.empty()) {
base::LinearHistogram::FactoryGet(
uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS);
}
resolve_cb_.Run(result);
}
CdmPromise::ResolveParameterType
CdmPromiseTemplate<KeyIdsVector>::GetResolveParameterType() const {
return KEY_IDS_VECTOR_TYPE;
}
} // namespace media
......@@ -35,6 +35,12 @@ class MEDIA_EXPORT CdmPromise {
NUM_RESULT_CODES
};
enum ResolveParameterType {
VOID_TYPE,
STRING_TYPE,
KEY_IDS_VECTOR_TYPE
};
typedef base::Callback<void(MediaKeys::Exception exception_code,
uint32 system_code,
const std::string& error_message)>
......@@ -50,6 +56,8 @@ class MEDIA_EXPORT CdmPromise {
uint32 system_code,
const std::string& error_message);
virtual ResolveParameterType GetResolveParameterType() const = 0;
protected:
CdmPromise();
CdmPromise(PromiseRejectedCB reject_cb);
......@@ -70,47 +78,67 @@ class MEDIA_EXPORT CdmPromise {
DISALLOW_COPY_AND_ASSIGN(CdmPromise);
};
template <typename T>
class MEDIA_EXPORT CdmPromiseTemplate : public CdmPromise {
// Specialization for no parameter to resolve().
template <>
class MEDIA_EXPORT CdmPromiseTemplate<void> : public CdmPromise {
public:
CdmPromiseTemplate(base::Callback<void(const T&)> resolve_cb,
CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
PromiseRejectedCB rejected_cb);
CdmPromiseTemplate(base::Callback<void(const T&)> resolve_cb,
CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
PromiseRejectedCB rejected_cb,
const std::string& uma_name);
virtual ~CdmPromiseTemplate();
virtual void resolve(const T& result);
virtual void resolve();
virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
protected:
// Allow subclasses to completely override the implementation.
// TODO(jrummell): Remove when derived class SessionLoadedPromise
// (in ppapi_decryptor.cc) is no longer needed.
CdmPromiseTemplate();
private:
base::Callback<void(const T&)> resolve_cb_;
base::Callback<void(void)> resolve_cb_;
DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
};
// Specialization for no parameter to resolve().
template <>
class MEDIA_EXPORT CdmPromiseTemplate<void> : public CdmPromise {
class MEDIA_EXPORT CdmPromiseTemplate<std::string> : public CdmPromise {
public:
CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
CdmPromiseTemplate(base::Callback<void(const std::string&)> resolve_cb,
PromiseRejectedCB rejected_cb);
CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
CdmPromiseTemplate(base::Callback<void(const std::string&)> resolve_cb,
PromiseRejectedCB rejected_cb,
const std::string& uma_name);
virtual ~CdmPromiseTemplate();
virtual void resolve();
virtual void resolve(const std::string& result);
virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
protected:
// Allow subclasses to completely override the implementation.
// TODO(jrummell): Remove when derived class SessionLoadedPromise
// (in ppapi_decryptor.cc) is no longer needed.
CdmPromiseTemplate();
private:
base::Callback<void(void)> resolve_cb_;
base::Callback<void(const std::string&)> resolve_cb_;
DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
};
template <>
class MEDIA_EXPORT CdmPromiseTemplate<KeyIdsVector> : public CdmPromise {
public:
CdmPromiseTemplate(base::Callback<void(const KeyIdsVector&)> resolve_cb,
PromiseRejectedCB rejected_cb);
CdmPromiseTemplate(base::Callback<void(const KeyIdsVector&)> resolve_cb,
PromiseRejectedCB rejected_cb,
const std::string& uma_name);
virtual ~CdmPromiseTemplate();
virtual void resolve(const KeyIdsVector& result);
virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
private:
base::Callback<void(const KeyIdsVector&)> resolve_cb_;
DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment