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( ...@@ -625,26 +625,33 @@ bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) { void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
scoped_ptr<CdmPromise> promise = TakePromise(promise_id); scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
if (promise) { if (!promise ||
promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) {
NOTREACHED();
return;
}
SimpleCdmPromise* simple_promise( SimpleCdmPromise* simple_promise(
static_cast<SimpleCdmPromise*>(promise.get())); static_cast<SimpleCdmPromise*>(promise.get()));
simple_promise->resolve(); simple_promise->resolve();
}
} }
void ContentDecryptorDelegate::OnPromiseResolvedWithSession( void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
uint32 promise_id, uint32 promise_id,
PP_Var web_session_id) { PP_Var web_session_id) {
scoped_ptr<CdmPromise> promise = TakePromise(promise_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); StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
DCHECK(web_session_id_string); DCHECK(web_session_id_string);
if (promise) {
NewSessionCdmPromise* session_promise( NewSessionCdmPromise* session_promise(
static_cast<NewSessionCdmPromise*>(promise.get())); static_cast<NewSessionCdmPromise*>(promise.get()));
session_promise->resolve(web_session_id_string->value()); session_promise->resolve(web_session_id_string->value());
}
} }
void ContentDecryptorDelegate::OnPromiseRejected( void ContentDecryptorDelegate::OnPromiseRejected(
......
...@@ -63,34 +63,28 @@ void CdmPromise::reject(MediaKeys::Exception exception_code, ...@@ -63,34 +63,28 @@ void CdmPromise::reject(MediaKeys::Exception exception_code,
reject_cb_.Run(exception_code, system_code, error_message); reject_cb_.Run(exception_code, system_code, error_message);
} }
template <typename T> CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
CdmPromiseTemplate<T>::CdmPromiseTemplate(
base::Callback<void(const T&)> resolve_cb,
PromiseRejectedCB reject_cb) PromiseRejectedCB reject_cb)
: CdmPromise(reject_cb), resolve_cb_(resolve_cb) { : CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null()); DCHECK(!resolve_cb_.is_null());
} }
template <typename T> CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
CdmPromiseTemplate<T>::CdmPromiseTemplate(
base::Callback<void(const T&)> resolve_cb,
PromiseRejectedCB reject_cb, PromiseRejectedCB reject_cb,
const std::string& uma_name) const std::string& uma_name)
: CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) { : CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null()); DCHECK(!resolve_cb_.is_null());
DCHECK(!uma_name_.empty());
} }
template <typename T> CdmPromiseTemplate<void>::CdmPromiseTemplate() {
CdmPromiseTemplate<T>::CdmPromiseTemplate() {
} }
template <typename T> CdmPromiseTemplate<void>::~CdmPromiseTemplate() {
CdmPromiseTemplate<T>::~CdmPromiseTemplate() {
DCHECK(!is_pending_); DCHECK(!is_pending_);
} }
template <typename T> void CdmPromiseTemplate<void>::resolve() {
void CdmPromiseTemplate<T>::resolve(const T& result) {
DCHECK(is_pending_); DCHECK(is_pending_);
is_pending_ = false; is_pending_ = false;
if (!uma_name_.empty()) { if (!uma_name_.empty()) {
...@@ -98,31 +92,37 @@ void CdmPromiseTemplate<T>::resolve(const T& result) { ...@@ -98,31 +92,37 @@ void CdmPromiseTemplate<T>::resolve(const T& result) {
uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1, uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS); 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) PromiseRejectedCB reject_cb)
: CdmPromise(reject_cb), resolve_cb_(resolve_cb) { : CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null()); 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, PromiseRejectedCB reject_cb,
const std::string& uma_name) const std::string& uma_name)
: CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) { : CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
DCHECK(!resolve_cb_.is_null()); 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_); DCHECK(!is_pending_);
} }
void CdmPromiseTemplate<void>::resolve() { void CdmPromiseTemplate<std::string>::resolve(const std::string& result) {
DCHECK(is_pending_); DCHECK(is_pending_);
is_pending_ = false; is_pending_ = false;
if (!uma_name_.empty()) { if (!uma_name_.empty()) {
...@@ -130,11 +130,47 @@ void CdmPromiseTemplate<void>::resolve() { ...@@ -130,11 +130,47 @@ void CdmPromiseTemplate<void>::resolve() {
uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1, uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS); base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS);
} }
resolve_cb_.Run(); resolve_cb_.Run(result);
} }
// Explicit template instantiation for the Promises needed. CdmPromise::ResolveParameterType
template class MEDIA_EXPORT CdmPromiseTemplate<std::string>; CdmPromiseTemplate<std::string>::GetResolveParameterType() const {
template class MEDIA_EXPORT CdmPromiseTemplate<KeyIdsVector>; 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 } // namespace media
...@@ -35,6 +35,12 @@ class MEDIA_EXPORT CdmPromise { ...@@ -35,6 +35,12 @@ class MEDIA_EXPORT CdmPromise {
NUM_RESULT_CODES NUM_RESULT_CODES
}; };
enum ResolveParameterType {
VOID_TYPE,
STRING_TYPE,
KEY_IDS_VECTOR_TYPE
};
typedef base::Callback<void(MediaKeys::Exception exception_code, typedef base::Callback<void(MediaKeys::Exception exception_code,
uint32 system_code, uint32 system_code,
const std::string& error_message)> const std::string& error_message)>
...@@ -50,6 +56,8 @@ class MEDIA_EXPORT CdmPromise { ...@@ -50,6 +56,8 @@ class MEDIA_EXPORT CdmPromise {
uint32 system_code, uint32 system_code,
const std::string& error_message); const std::string& error_message);
virtual ResolveParameterType GetResolveParameterType() const = 0;
protected: protected:
CdmPromise(); CdmPromise();
CdmPromise(PromiseRejectedCB reject_cb); CdmPromise(PromiseRejectedCB reject_cb);
...@@ -70,47 +78,67 @@ class MEDIA_EXPORT CdmPromise { ...@@ -70,47 +78,67 @@ class MEDIA_EXPORT CdmPromise {
DISALLOW_COPY_AND_ASSIGN(CdmPromise); DISALLOW_COPY_AND_ASSIGN(CdmPromise);
}; };
template <typename T> // Specialization for no parameter to resolve().
class MEDIA_EXPORT CdmPromiseTemplate : public CdmPromise { template <>
class MEDIA_EXPORT CdmPromiseTemplate<void> : public CdmPromise {
public: public:
CdmPromiseTemplate(base::Callback<void(const T&)> resolve_cb, CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
PromiseRejectedCB rejected_cb); PromiseRejectedCB rejected_cb);
CdmPromiseTemplate(base::Callback<void(const T&)> resolve_cb, CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
PromiseRejectedCB rejected_cb, PromiseRejectedCB rejected_cb,
const std::string& uma_name); const std::string& uma_name);
virtual ~CdmPromiseTemplate(); virtual ~CdmPromiseTemplate();
virtual void resolve(const T& result); virtual void resolve();
virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
protected: protected:
// Allow subclasses to completely override the implementation. // Allow subclasses to completely override the implementation.
// TODO(jrummell): Remove when derived class SessionLoadedPromise
// (in ppapi_decryptor.cc) is no longer needed.
CdmPromiseTemplate(); CdmPromiseTemplate();
private: private:
base::Callback<void(const T&)> resolve_cb_; base::Callback<void(void)> resolve_cb_;
DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate); DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
}; };
// Specialization for no parameter to resolve().
template <> template <>
class MEDIA_EXPORT CdmPromiseTemplate<void> : public CdmPromise { class MEDIA_EXPORT CdmPromiseTemplate<std::string> : public CdmPromise {
public: public:
CdmPromiseTemplate(base::Callback<void(void)> resolve_cb, CdmPromiseTemplate(base::Callback<void(const std::string&)> resolve_cb,
PromiseRejectedCB rejected_cb); PromiseRejectedCB rejected_cb);
CdmPromiseTemplate(base::Callback<void(void)> resolve_cb, CdmPromiseTemplate(base::Callback<void(const std::string&)> resolve_cb,
PromiseRejectedCB rejected_cb, PromiseRejectedCB rejected_cb,
const std::string& uma_name); const std::string& uma_name);
virtual ~CdmPromiseTemplate(); virtual ~CdmPromiseTemplate();
virtual void resolve(); virtual void resolve(const std::string& result);
virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
protected: protected:
// Allow subclasses to completely override the implementation. // Allow subclasses to completely override the implementation.
// TODO(jrummell): Remove when derived class SessionLoadedPromise
// (in ppapi_decryptor.cc) is no longer needed.
CdmPromiseTemplate(); CdmPromiseTemplate();
private: 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); 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