Bug 1867628 - Fire a load event when frame-ancestors blocks an iframe (similar to X-Frame-Options). r=nika,smaug

Differential Revision: https://phabricator.services.mozilla.com/D196036
This commit is contained in:
Tom Schuster 2023-12-19 10:05:12 +00:00
parent 8782212612
commit 061fc361e2
14 changed files with 49 additions and 44 deletions

View file

@ -10525,22 +10525,23 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
uriModified = false;
}
bool isXFOError = false;
bool isEmbeddingBlockedError = false;
if (mFailedChannel) {
nsresult status;
mFailedChannel->GetStatus(&status);
isXFOError = status == NS_ERROR_XFO_VIOLATION;
isEmbeddingBlockedError = status == NS_ERROR_XFO_VIOLATION ||
status == NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION;
}
nsLoadFlags loadFlags = aLoadState->CalculateChannelLoadFlags(
mBrowsingContext, Some(uriModified), Some(isXFOError));
mBrowsingContext, Some(uriModified), Some(isEmbeddingBlockedError));
nsCOMPtr<nsIChannel> channel;
if (DocumentChannel::CanUseDocumentChannel(aLoadState->URI()) &&
!isAboutBlankLoadOntoInitialAboutBlank) {
channel = DocumentChannel::CreateForDocument(aLoadState, loadInfo,
loadFlags, this, cacheKey,
uriModified, isXFOError);
channel = DocumentChannel::CreateForDocument(
aLoadState, loadInfo, loadFlags, this, cacheKey, uriModified,
isEmbeddingBlockedError);
MOZ_ASSERT(channel);
// Disable keyword fixup when using DocumentChannel, since

View file

@ -1092,7 +1092,7 @@ void nsDocShellLoadState::CalculateLoadURIFlags() {
nsLoadFlags nsDocShellLoadState::CalculateChannelLoadFlags(
BrowsingContext* aBrowsingContext, Maybe<bool> aUriModified,
Maybe<bool> aIsXFOError) {
Maybe<bool> aIsEmbeddingBlockedError) {
MOZ_ASSERT(aBrowsingContext);
nsLoadFlags loadFlags = aBrowsingContext->GetDefaultLoadFlags();
@ -1106,13 +1106,13 @@ nsLoadFlags nsDocShellLoadState::CalculateChannelLoadFlags(
// These values aren't available for loads initiated in the Parent process.
MOZ_ASSERT_IF(loadType == LOAD_HISTORY, aUriModified.isSome());
MOZ_ASSERT_IF(loadType == LOAD_ERROR_PAGE, aIsXFOError.isSome());
MOZ_ASSERT_IF(loadType == LOAD_ERROR_PAGE, aIsEmbeddingBlockedError.isSome());
if (loadType == LOAD_ERROR_PAGE) {
// Error pages are LOAD_BACKGROUND, unless it's an
// XFO error for which we want an error page to load
// XFO / frame-ancestors error for which we want an error page to load
// but additionally want the onload() event to fire.
if (!*aIsXFOError) {
if (!*aIsEmbeddingBlockedError) {
loadFlags |= nsIChannel::LOAD_BACKGROUND;
}
}

View file

@ -363,10 +363,12 @@ class nsDocShellLoadState final {
void CalculateLoadURIFlags();
// Compute the load flags to be used by creating channel. aUriModified and
// aIsXFOError are expected to be Nothing when called from Parent process.
// aIsEmbeddingBlockedError are expected to be Nothing when called from parent
// process.
nsLoadFlags CalculateChannelLoadFlags(
mozilla::dom::BrowsingContext* aBrowsingContext,
mozilla::Maybe<bool> aUriModified, mozilla::Maybe<bool> aIsXFOError);
mozilla::Maybe<bool> aUriModified,
mozilla::Maybe<bool> aIsEmbeddingBlockedError);
mozilla::dom::DocShellLoadStateInit Serialize(
mozilla::ipc::IProtocol* aActor);

View file

@ -67,14 +67,15 @@ NS_INTERFACE_MAP_END
DocumentChannel::DocumentChannel(nsDocShellLoadState* aLoadState,
net::LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, uint32_t aCacheKey,
bool aUriModified, bool aIsXFOError)
bool aUriModified,
bool aIsEmbeddingBlockedError)
: mLoadState(aLoadState),
mCacheKey(aCacheKey),
mLoadFlags(aLoadFlags),
mURI(aLoadState->URI()),
mLoadInfo(aLoadInfo),
mUriModified(aUriModified),
mIsXFOError(aIsXFOError) {
mIsEmbeddingBlockedError(aIsEmbeddingBlockedError) {
LOG(("DocumentChannel ctor [this=%p, uri=%s]", this,
aLoadState->URI()->GetSpecOrDefault().get()));
RefPtr<nsHttpHandler> handler = nsHttpHandler::GetInstance();
@ -171,15 +172,16 @@ bool DocumentChannel::CanUseDocumentChannel(nsIURI* aURI) {
already_AddRefed<DocumentChannel> DocumentChannel::CreateForDocument(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
uint32_t aCacheKey, bool aUriModified, bool aIsXFOError) {
uint32_t aCacheKey, bool aUriModified, bool aIsEmbeddingBlockedError) {
RefPtr<DocumentChannel> channel;
if (XRE_IsContentProcess()) {
channel = new DocumentChannelChild(aLoadState, aLoadInfo, aLoadFlags,
aCacheKey, aUriModified, aIsXFOError);
} else {
channel =
new ParentProcessDocumentChannel(aLoadState, aLoadInfo, aLoadFlags,
aCacheKey, aUriModified, aIsXFOError);
new DocumentChannelChild(aLoadState, aLoadInfo, aLoadFlags, aCacheKey,
aUriModified, aIsEmbeddingBlockedError);
} else {
channel = new ParentProcessDocumentChannel(
aLoadState, aLoadInfo, aLoadFlags, aCacheKey, aUriModified,
aIsEmbeddingBlockedError);
}
channel->SetNotificationCallbacks(aNotificationCallbacks);
return channel.forget();

View file

@ -67,7 +67,7 @@ class DocumentChannel : public nsIIdentChannel {
static already_AddRefed<DocumentChannel> CreateForDocument(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
uint32_t aCacheKey, bool aUriModified, bool aIsXFOError);
uint32_t aCacheKey, bool aUriModified, bool aIsEmbeddingBlockedError);
static already_AddRefed<DocumentChannel> CreateForObject(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks);
@ -77,7 +77,7 @@ class DocumentChannel : public nsIIdentChannel {
protected:
DocumentChannel(nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, uint32_t aCacheKey, bool aUriModified,
bool aIsXFOError);
bool aIsEmbeddingBlockedError);
void ShutdownListeners(nsresult aStatusCode);
virtual void DeleteIPDL() {}
@ -106,9 +106,10 @@ class DocumentChannel : public nsIIdentChannel {
// mUriModified is true if we're doing a history load and the URI of the
// session history had been modified by pushState/replaceState.
bool mUriModified = false;
// mIsXFOError is true if we're handling a load error and the status of the
// failed channel is NS_ERROR_XFO_VIOLATION.
bool mIsXFOError = false;
// mIsEmbeddingBlockedError is true if we're handling a load error and the
// status of the failed channel is NS_ERROR_XFO_VIOLATION or
// NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION.
bool mIsEmbeddingBlockedError = false;
};
NS_DEFINE_STATIC_IID_ACCESSOR(DocumentChannel, DOCUMENT_CHANNEL_IID)

View file

@ -48,9 +48,10 @@ DocumentChannelChild::DocumentChannelChild(nsDocShellLoadState* aLoadState,
net::LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags,
uint32_t aCacheKey,
bool aUriModified, bool aIsXFOError)
bool aUriModified,
bool aIsEmbeddingBlockedError)
: DocumentChannel(aLoadState, aLoadInfo, aLoadFlags, aCacheKey,
aUriModified, aIsXFOError) {
aUriModified, aIsEmbeddingBlockedError) {
mLoadingContext = nullptr;
LOG(("DocumentChannelChild ctor [this=%p, uri=%s]", this,
aLoadState->URI()->GetSpecOrDefault().get()));
@ -119,7 +120,7 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
case ExtContentPolicy::TYPE_SUBDOCUMENT: {
DocumentCreationArgs docArgs;
docArgs.uriModified() = mUriModified;
docArgs.isXFOError() = mIsXFOError;
docArgs.isEmbeddingBlockedError() = mIsEmbeddingBlockedError;
ipcElementCreationArgs = docArgs;
break;

View file

@ -27,7 +27,8 @@ class DocumentChannelChild final : public DocumentChannel,
public:
DocumentChannelChild(nsDocShellLoadState* aLoadState,
class LoadInfo* aLoadInfo, nsLoadFlags aLoadFlags,
uint32_t aCacheKey, bool aUriModified, bool aIsXFOError);
uint32_t aCacheKey, bool aUriModified,
bool aIsEmbeddingBlockedError);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK

View file

@ -69,7 +69,7 @@ bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext,
promise = mDocumentLoadListener->OpenDocument(
loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
aArgs.asyncOpenTime(), aArgs.timing(), std::move(clientInfo),
Some(docArgs.uriModified()), Some(docArgs.isXFOError()),
Some(docArgs.uriModified()), Some(docArgs.isEmbeddingBlockedError()),
contentParent, &rv);
} else {
const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs();

View file

@ -933,7 +933,7 @@ auto DocumentLoadListener::OpenDocument(
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
Maybe<bool> aUriModified, Maybe<bool> aIsXFOError,
Maybe<bool> aUriModified, Maybe<bool> aIsEmbeddingBlockedError,
dom::ContentParent* aContentParent, nsresult* aRv) -> RefPtr<OpenPromise> {
LOG(("DocumentLoadListener [%p] OpenDocument [uri=%s]", this,
aLoadState->URI()->GetSpecOrDefault().get()));
@ -950,7 +950,8 @@ auto DocumentLoadListener::OpenDocument(
CreateDocumentLoadInfo(browsingContext, aLoadState);
nsLoadFlags loadFlags = aLoadState->CalculateChannelLoadFlags(
browsingContext, std::move(aUriModified), std::move(aIsXFOError));
browsingContext, std::move(aUriModified),
std::move(aIsEmbeddingBlockedError));
// Keep track of navigation for the Bounce Tracking Protection.
if (browsingContext->IsTopContent()) {

View file

@ -163,7 +163,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
Maybe<bool> aUriModified, Maybe<bool> aIsXFOError,
Maybe<bool> aUriModified, Maybe<bool> aIsEmbeddingBlockedError,
dom::ContentParent* aContentParent, nsresult* aRv);
RefPtr<OpenPromise> OpenObject(

View file

@ -455,7 +455,7 @@ struct CookieStruct
struct DocumentCreationArgs {
bool uriModified;
bool isXFOError;
bool isEmbeddingBlockedError;
};
struct ObjectCreationArgs {

View file

@ -34,9 +34,9 @@ NS_IMPL_ISUPPORTS_INHERITED(ParentProcessDocumentChannel, DocumentChannel,
ParentProcessDocumentChannel::ParentProcessDocumentChannel(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, uint32_t aCacheKey, bool aUriModified,
bool aIsXFOError)
bool aIsEmbeddingBlockedError)
: DocumentChannel(aLoadState, aLoadInfo, aLoadFlags, aCacheKey,
aUriModified, aIsXFOError) {
aUriModified, aIsEmbeddingBlockedError) {
LOG(("ParentProcessDocumentChannel ctor [this=%p]", this));
}
@ -176,8 +176,8 @@ NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen(
if (isDocumentLoad) {
promise = mDocumentLoadListener->OpenDocument(
mLoadState, mCacheKey, Some(mChannelId), TimeStamp::Now(), mTiming,
std::move(initialClientInfo), Some(mUriModified), Some(mIsXFOError),
nullptr /* ContentParent */, &rv);
std::move(initialClientInfo), Some(mUriModified),
Some(mIsEmbeddingBlockedError), nullptr /* ContentParent */, &rv);
} else {
promise = mDocumentLoadListener->OpenObject(
mLoadState, mCacheKey, Some(mChannelId), TimeStamp::Now(), mTiming,

View file

@ -25,7 +25,8 @@ class ParentProcessDocumentChannel : public DocumentChannel,
ParentProcessDocumentChannel(nsDocShellLoadState* aLoadState,
class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, uint32_t aCacheKey,
bool aUriModified, bool aIsXFOError);
bool aUriModified,
bool aIsEmbeddingBlockedError);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK

View file

@ -1,5 +0,0 @@
[deny.html]
expected: TIMEOUT
[`DENY` blocks cross-origin framing with CSP frame-ancestors 'self']
expected: TIMEOUT