mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 1554847 - Improve cross-origin checks in canvas API - consider intermediate redirects, r=jya
Differential Revision: https://phabricator.services.mozilla.com/D32792 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
ee29b15f6b
commit
f4c9f068fa
@ -4238,6 +4238,11 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (NS_FAILED(imgRequest->GetHadCrossOriginRedirects(
|
||||
&res.mHadCrossOriginRedirects))) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement);
|
||||
if (!res.mSourceSurface) {
|
||||
return res;
|
||||
@ -4251,7 +4256,8 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
|
||||
res.mSize = res.mSourceSurface->GetSize();
|
||||
res.mPrincipal = principal.forget();
|
||||
res.mImageRequest = imgRequest.forget();
|
||||
res.mIsWriteOnly = CheckWriteOnlySecurity(res.mCORSUsed, res.mPrincipal);
|
||||
res.mIsWriteOnly = CheckWriteOnlySecurity(res.mCORSUsed, res.mPrincipal,
|
||||
res.mHadCrossOriginRedirects);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -174,8 +174,7 @@ bool IsImageExtractionAllowed(Document* aDocument, JSContext* aCx,
|
||||
if (XRE_IsContentProcess()) {
|
||||
BrowserChild* browserChild = BrowserChild::GetFrom(win);
|
||||
if (browserChild) {
|
||||
browserChild->SendShowCanvasPermissionPrompt(origin,
|
||||
isAutoBlockCanvas);
|
||||
browserChild->SendShowCanvasPermissionPrompt(origin, isAutoBlockCanvas);
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
@ -295,12 +294,17 @@ bool HasDrawWindowPrivilege(JSContext* aCx, JSObject* /* unused */) {
|
||||
nsGkAtoms::all_urlsPermission);
|
||||
}
|
||||
|
||||
bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal) {
|
||||
bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal,
|
||||
bool aHadCrossOriginRedirects) {
|
||||
if (!aPrincipal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aCORSUsed) {
|
||||
if (aHadCrossOriginRedirects) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIGlobalObject* incumbentSettingsObject = dom::GetIncumbentGlobal();
|
||||
if (NS_WARN_IF(!incumbentSettingsObject)) {
|
||||
return true;
|
||||
|
@ -176,7 +176,8 @@ void DashArrayToJSVal(nsTArray<T>& dashes, JSContext* cx,
|
||||
|
||||
// returns true if write-only mode must used for this principal based on
|
||||
// the incumbent global.
|
||||
bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal);
|
||||
bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal,
|
||||
bool aHadCrossOriginRedirects);
|
||||
|
||||
} // namespace CanvasUtils
|
||||
} // namespace mozilla
|
||||
|
@ -770,8 +770,10 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
|
||||
|
||||
// Check security.
|
||||
nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
|
||||
bool hadCrossOriginRedirects = aVideoEl.HadCrossOriginRedirects();
|
||||
bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
|
||||
bool writeOnly = CheckWriteOnlySecurity(CORSUsed, principal);
|
||||
bool writeOnly =
|
||||
CheckWriteOnlySecurity(CORSUsed, principal, hadCrossOriginRedirects);
|
||||
|
||||
// Create ImageBitmap.
|
||||
RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
|
||||
|
@ -5867,6 +5867,13 @@ already_AddRefed<nsIPrincipal> HTMLMediaElement::GetCurrentPrincipal() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HTMLMediaElement::HadCrossOriginRedirects() {
|
||||
if (mDecoder) {
|
||||
return mDecoder->HadCrossOriginRedirects();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPrincipal> HTMLMediaElement::GetCurrentVideoPrincipal() {
|
||||
if (mDecoder) {
|
||||
return mDecoder->GetCurrentPrincipal();
|
||||
|
@ -279,6 +279,10 @@ class HTMLMediaElement : public nsGenericHTMLElement,
|
||||
// principal. Returns null if nothing is playing.
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
||||
|
||||
// Return true if the loading of this resource required cross-origin
|
||||
// redirects.
|
||||
bool HadCrossOriginRedirects();
|
||||
|
||||
// Principal of the currently playing video resource. Anything accessing the
|
||||
// image container of this element must have a principal that subsumes this
|
||||
// principal. If there are no live video tracks but content has been rendered
|
||||
|
@ -72,6 +72,10 @@ class BaseMediaResource : public MediaResource,
|
||||
// Get the current principal for the channel
|
||||
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
||||
|
||||
// Return true if the loading of this resource required cross-origin
|
||||
// redirects.
|
||||
virtual bool HadCrossOriginRedirects() = 0;
|
||||
|
||||
/**
|
||||
* Open the stream. This creates a stream listener and returns it in
|
||||
* aStreamListener; this listener needs to be notified of incoming data.
|
||||
|
@ -501,6 +501,11 @@ already_AddRefed<nsIPrincipal> ChannelMediaDecoder::GetCurrentPrincipal() {
|
||||
return mResource ? mResource->GetCurrentPrincipal() : nullptr;
|
||||
}
|
||||
|
||||
bool ChannelMediaDecoder::HadCrossOriginRedirects() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mResource ? mResource->HadCrossOriginRedirects() : false;
|
||||
}
|
||||
|
||||
bool ChannelMediaDecoder::IsTransportSeekable() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mResource->IsTransportSeekable();
|
||||
|
@ -91,6 +91,7 @@ class ChannelMediaDecoder
|
||||
|
||||
void AddSizeOfResources(ResourceSizes* aSizes) override;
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||
bool HadCrossOriginRedirects() override;
|
||||
bool IsTransportSeekable() override;
|
||||
void SetLoadInBackground(bool aLoadInBackground) override;
|
||||
void Suspend() override;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsIClassOfService.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
#include "nsITimedChannel.h"
|
||||
#include "nsHttp.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
@ -604,6 +605,11 @@ already_AddRefed<nsIPrincipal> ChannelMediaResource::GetCurrentPrincipal() {
|
||||
return do_AddRef(mSharedInfo->mPrincipal);
|
||||
}
|
||||
|
||||
bool ChannelMediaResource::HadCrossOriginRedirects() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mSharedInfo->mHadCrossOriginRedirects;
|
||||
}
|
||||
|
||||
bool ChannelMediaResource::CanClone() {
|
||||
return !mClosed && mCacheStream.IsAvailableForSharing();
|
||||
}
|
||||
@ -816,6 +822,20 @@ void ChannelMediaResource::UpdatePrincipal() {
|
||||
r->CacheClientNotifyPrincipalChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// ChannelMediaResource can recreate the channel. When this happens, we don't
|
||||
// want to overwrite mHadCrossOriginRedirects because the new channel could
|
||||
// skip intermediate redirects.
|
||||
if (!mSharedInfo->mHadCrossOriginRedirects) {
|
||||
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
|
||||
if (timedChannel) {
|
||||
bool allRedirectsSameOrigin = false;
|
||||
mSharedInfo->mHadCrossOriginRedirects =
|
||||
NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin(
|
||||
&allRedirectsSameOrigin)) &&
|
||||
!allRedirectsSameOrigin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelMediaResource::CacheClientNotifySuspendedStatusChanged(
|
||||
|
@ -66,8 +66,12 @@ class ChannelMediaResource
|
||||
// Store information shared among resources. Main thread only.
|
||||
struct SharedInfo {
|
||||
NS_INLINE_DECL_REFCOUNTING(SharedInfo);
|
||||
|
||||
SharedInfo() : mHadCrossOriginRedirects(false) {}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsTArray<ChannelMediaResource*> mResources;
|
||||
bool mHadCrossOriginRedirects;
|
||||
|
||||
private:
|
||||
~SharedInfo() = default;
|
||||
@ -117,6 +121,7 @@ class ChannelMediaResource
|
||||
void Suspend(bool aCloseImmediately) override;
|
||||
void Resume() override;
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||
bool HadCrossOriginRedirects() override;
|
||||
bool CanClone() override;
|
||||
already_AddRefed<BaseMediaResource> CloneData(
|
||||
MediaResourceCallback* aDecoder) override;
|
||||
|
@ -164,6 +164,20 @@ CloneableWithRangeMediaResource::GetCurrentPrincipal() {
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
bool CloneableWithRangeMediaResource::HadCrossOriginRedirects() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
|
||||
if (!timedChannel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allRedirectsSameOrigin = false;
|
||||
return NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin(
|
||||
&allRedirectsSameOrigin)) &&
|
||||
!allRedirectsSameOrigin;
|
||||
}
|
||||
|
||||
nsresult CloneableWithRangeMediaResource::ReadFromCache(char* aBuffer,
|
||||
int64_t aOffset,
|
||||
uint32_t aCount) {
|
||||
|
@ -31,6 +31,7 @@ class CloneableWithRangeMediaResource : public BaseMediaResource {
|
||||
void Suspend(bool aCloseImmediately) override {}
|
||||
void Resume() override {}
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||
bool HadCrossOriginRedirects() override;
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
|
||||
uint32_t aCount) override;
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsITimedChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -117,6 +118,20 @@ already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() {
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
bool FileMediaResource::HadCrossOriginRedirects() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
|
||||
if (!timedChannel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allRedirectsSameOrigin = false;
|
||||
return NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin(
|
||||
&allRedirectsSameOrigin)) &&
|
||||
!allRedirectsSameOrigin;
|
||||
}
|
||||
|
||||
nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset,
|
||||
uint32_t aCount) {
|
||||
MutexAutoLock lock(mLock);
|
||||
|
@ -27,6 +27,7 @@ class FileMediaResource : public BaseMediaResource {
|
||||
void Suspend(bool aCloseImmediately) override {}
|
||||
void Resume() override {}
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||
bool HadCrossOriginRedirects() override;
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
|
||||
uint32_t aCount) override;
|
||||
|
||||
|
@ -126,6 +126,10 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
||||
// Return the principal of the current URI being played or downloaded.
|
||||
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
||||
|
||||
// Return true if the loading of this resource required cross-origin
|
||||
// redirects.
|
||||
virtual bool HadCrossOriginRedirects() = 0;
|
||||
|
||||
// Return the time position in the video stream being
|
||||
// played measured in seconds.
|
||||
virtual double GetCurrentTime();
|
||||
|
@ -182,6 +182,12 @@ already_AddRefed<nsIPrincipal> HLSDecoder::GetCurrentPrincipal() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HLSDecoder::HadCrossOriginRedirects() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Bug 1478843
|
||||
return false;
|
||||
}
|
||||
|
||||
void HLSDecoder::Play() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
HLS_DEBUG("HLSDecoder", "MediaElement called Play");
|
||||
|
@ -35,6 +35,7 @@ class HLSDecoder final : public MediaDecoder {
|
||||
|
||||
void AddSizeOfResources(ResourceSizes* aSizes) override;
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||
bool HadCrossOriginRedirects() override;
|
||||
bool IsTransportSeekable() override { return true; }
|
||||
void Suspend() override;
|
||||
void Resume() override;
|
||||
|
@ -335,6 +335,11 @@ already_AddRefed<nsIPrincipal> MediaSourceDecoder::GetCurrentPrincipal() {
|
||||
return do_AddRef(mPrincipal);
|
||||
}
|
||||
|
||||
bool MediaSourceDecoder::HadCrossOriginRedirects() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef MSE_DEBUG
|
||||
#undef MSE_DEBUGV
|
||||
|
||||
|
@ -50,6 +50,8 @@ class MediaSourceDecoder : public MediaDecoder,
|
||||
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||
|
||||
bool HadCrossOriginRedirects() override;
|
||||
|
||||
bool IsTransportSeekable() override { return true; }
|
||||
|
||||
// Returns a structure describing the state of the MediaSource internal
|
||||
|
@ -7514,10 +7514,14 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
|
||||
result.mCORSUsed = (corsmode != imgIRequest::CORS_NONE);
|
||||
}
|
||||
|
||||
bool hadCrossOriginRedirects = true;
|
||||
imgRequest->GetHadCrossOriginRedirects(&hadCrossOriginRedirects);
|
||||
|
||||
result.mPrincipal = principal.forget();
|
||||
result.mHadCrossOriginRedirects = hadCrossOriginRedirects;
|
||||
result.mImageRequest = imgRequest.forget();
|
||||
result.mIsWriteOnly =
|
||||
CanvasUtils::CheckWriteOnlySecurity(result.mCORSUsed, result.mPrincipal);
|
||||
result.mIsWriteOnly = CanvasUtils::CheckWriteOnlySecurity(
|
||||
result.mCORSUsed, result.mPrincipal, result.mHadCrossOriginRedirects);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -7565,6 +7569,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
|
||||
result.mHasSize = true;
|
||||
result.mSize = size;
|
||||
result.mPrincipal = aElement->NodePrincipal();
|
||||
result.mHadCrossOriginRedirects = false;
|
||||
result.mIsWriteOnly = aElement->IsWriteOnly();
|
||||
|
||||
return result;
|
||||
@ -7611,8 +7616,9 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
|
||||
result.mHasSize = true;
|
||||
result.mSize = result.mLayersImage->GetSize();
|
||||
result.mPrincipal = principal.forget();
|
||||
result.mIsWriteOnly =
|
||||
CanvasUtils::CheckWriteOnlySecurity(result.mCORSUsed, result.mPrincipal);
|
||||
result.mHadCrossOriginRedirects = aElement->HadCrossOriginRedirects();
|
||||
result.mIsWriteOnly = CanvasUtils::CheckWriteOnlySecurity(
|
||||
result.mCORSUsed, result.mPrincipal, result.mHadCrossOriginRedirects);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -8626,7 +8632,8 @@ bool nsLayoutUtils::IsAPZTestLoggingEnabled() {
|
||||
|
||||
nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
|
||||
// Use safe default values here
|
||||
: mIsWriteOnly(true),
|
||||
: mHadCrossOriginRedirects(false),
|
||||
mIsWriteOnly(true),
|
||||
mIsStillLoading(false),
|
||||
mHasSize(false),
|
||||
mCORSUsed(false),
|
||||
|
@ -2163,6 +2163,9 @@ class nsLayoutUtils {
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
/* The image request, if the element is an nsIImageLoadingContent */
|
||||
nsCOMPtr<imgIRequest> mImageRequest;
|
||||
/* True if cross-origins redirects have been done in order to load this
|
||||
* resource */
|
||||
bool mHadCrossOriginRedirects;
|
||||
/* Whether the element was "write only", that is, the bits should not be
|
||||
* exposed to content */
|
||||
bool mIsWriteOnly;
|
||||
|
Loading…
Reference in New Issue
Block a user