Bug 1583076 - Make nsCSPService::ConsultCSPForRedirect return both the AsyncOnChannelRedirect result, as well as an optional result to cancel the old channel with. r=ckerschb

Differential Revision: https://phabricator.services.mozilla.com/D46740

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Matt Woodrow 2019-09-25 08:25:22 +00:00
parent 507bc7d9ba
commit edbd9409af
5 changed files with 36 additions and 32 deletions

View File

@ -296,12 +296,13 @@ CSPService::AsyncOnChannelRedirect(nsIChannel* oldChannel,
return rv;
}
int16_t decision = nsIContentPolicy::ACCEPT;
rv = ConsultCSPForRedirect(originalUri, newUri, loadInfo, &decision);
if (NS_CP_REJECTED(decision)) {
Maybe<nsresult> cancelCode;
rv = ConsultCSPForRedirect(originalUri, newUri, loadInfo, cancelCode);
if (cancelCode) {
oldChannel->Cancel(*cancelCode);
}
if (NS_FAILED(rv)) {
autoCallback.DontCallback();
oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
return NS_BINDING_FAILED;
}
return rv;
@ -310,15 +311,15 @@ CSPService::AsyncOnChannelRedirect(nsIChannel* oldChannel,
nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI,
nsIURI* aNewURI,
nsILoadInfo* aLoadInfo,
int16_t* aDecision) {
Maybe<nsresult>& aCancelCode) {
nsCOMPtr<nsICSPEventListener> cspEventListener;
nsresult rv =
aLoadInfo->GetCspEventListener(getter_AddRefs(cspEventListener));
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ALWAYS_SUCCEEDS(rv);
nsAutoString cspNonce;
rv = aLoadInfo->GetCspNonce(cspNonce);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ALWAYS_SUCCEEDS(rv);
nsContentPolicyType policyType = aLoadInfo->InternalContentPolicyType();
bool isPreload = nsContentUtils::IsPreloadType(policyType);
@ -330,6 +331,7 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI,
policyType =
nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(policyType);
int16_t decision = nsIContentPolicy::ACCEPT;
nsCOMPtr<nsISupports> requestContext = aLoadInfo->GetLoadingContext();
// 1) Apply speculative CSP for preloads
if (isPreload) {
@ -346,12 +348,13 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI,
aOriginalURI, // Original nsIURI
true, // aSendViolationReports
cspNonce, // nonce
aDecision);
&decision);
// if the preload policy already denied the load, then there
// is no point in checking the real policy
if (NS_CP_REJECTED(*aDecision)) {
return NS_OK;
if (NS_CP_REJECTED(decision)) {
aCancelCode = Some(NS_ERROR_DOM_BAD_URI);
return NS_BINDING_FAILED;
}
}
}
@ -369,7 +372,11 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI,
aOriginalURI, // Original nsIURI
true, // aSendViolationReports
cspNonce, // nonce
aDecision);
&decision);
if (NS_CP_REJECTED(decision)) {
aCancelCode = Some(NS_ERROR_DOM_BAD_URI);
return NS_BINDING_FAILED;
}
}
return NS_OK;

View File

@ -34,9 +34,13 @@ class CSPService : public nsIContentPolicy, public nsIChannelEventSink {
const nsACString& aMimeTypeGuess,
int16_t* aDecision);
// Static helper to check CSP when doing a channel redirect.
// Returns the results to returns from
// AsyncOnChannelRedirect/nsIAsyncVerifyRedirectCallback. Optionally returns
// an nsresult to Cancel the old channel with.
static nsresult ConsultCSPForRedirect(nsIURI* aOriginalURI, nsIURI* aNewURI,
nsILoadInfo* aLoadInfo,
int16_t* aDecision);
Maybe<nsresult>& aCancelCode);
protected:
virtual ~CSPService();

View File

@ -412,22 +412,15 @@ IPCResult DocumentChannelChild::RecvConfirmRedirect(
nsCOMPtr<nsIURI> originalUri;
nsresult rv = GetOriginalURI(getter_AddRefs(originalUri));
if (NS_FAILED(rv)) {
aResolve(rv);
aResolve(Tuple<const nsresult&, const Maybe<nsresult>&>(NS_BINDING_FAILED,
Some(rv)));
return IPC_OK();
}
int16_t decision = nsIContentPolicy::ACCEPT;
Maybe<nsresult> cancelCode;
rv = CSPService::ConsultCSPForRedirect(originalUri, aNewUri, mLoadInfo,
&decision);
if (NS_FAILED(rv)) {
aResolve(rv);
return IPC_OK();
}
if (NS_CP_REJECTED(decision)) {
aResolve(NS_BINDING_FAILED);
} else {
aResolve(NS_OK);
}
cancelCode);
aResolve(Tuple<const nsresult&, const Maybe<nsresult>&>(rv, cancelCode));
return IPC_OK();
}

View File

@ -240,8 +240,8 @@ void DocumentChannelParent::FinishReplacementChannelSetup(bool aSucceeded) {
newChannel->Cancel(NS_BINDING_ABORTED);
}
}
// Release all previously registered channels, they are no longer needed to be
// kept in the registrar from this moment.
// Release all previously registered channels, they are no longer needed to
// be kept in the registrar from this moment.
registrar->DeregisterChannels(mRedirectChannelId);
mRedirectChannelId = 0;
@ -809,11 +809,11 @@ DocumentChannelParent::AsyncOnChannelRedirect(
nsCOMPtr<nsIChannel> oldChannel(aOldChannel);
SendConfirmRedirect(newUri)->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[callback, oldChannel](nsresult aRv) {
if (NS_FAILED(aRv)) {
oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
[callback, oldChannel](const Tuple<nsresult, Maybe<nsresult>>& aResult) {
if (Get<1>(aResult)) {
oldChannel->Cancel(*Get<1>(aResult));
}
callback->OnRedirectVerifyCallback(aRv);
callback->OnRedirectVerifyCallback(Get<0>(aResult));
},
[callback, oldChannel](const mozilla::ipc::ResponseRejectReason) {
oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);

View File

@ -75,7 +75,7 @@ child:
uint32_t? aContentDisposition,
nsString? aContentDispositionFilename) returns(nsresult rv);
async ConfirmRedirect(nsIURI aNewURI) returns(nsresult rv);
async ConfirmRedirect(nsIURI aNewURI) returns(nsresult rv, nsresult? cancelCode);
// Tell child to delete channel (all IPDL deletes must be done from child to
// avoid races: see bug 591708).