Bug 1530854: Always create CSP on Principal so the explicit CSP in the nsISHEntry holds a reference to the potentially dynamically modified CSP in case of a meta CSP. r=bzbarsky

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Christoph Kerschbaumer 2019-03-14 06:26:29 +00:00
Родитель 9ccb997cf4
Коммит 980f75a172
4 изменённых файлов: 90 добавлений и 17 удалений

Просмотреть файл

@ -289,12 +289,69 @@ static void InheritAndSetCSPOnPrincipalIfNeeded(nsIChannel* aChannel,
nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
aPrincipal->GetCsp(getter_AddRefs(nullPrincipalCSP));
if (nullPrincipalCSP) {
MOZ_ASSERT(nullPrincipalCSP == originalCSP,
"There should be no other CSP here.");
#ifdef DEBUG
{
uint32_t nullPrincipalCSPCount = 0;
nullPrincipalCSP->GetPolicyCount(&nullPrincipalCSPCount);
uint32_t originalCSPCount = 0;
originalCSP->GetPolicyCount(&originalCSPCount);
MOZ_ASSERT(nullPrincipalCSPCount == originalCSPCount,
"There should be no other CSP here.");
nsAutoString nullPrincipalCSPStr, originalCSPStr;
for (uint32_t i = 0; i < originalCSPCount; ++i) {
originalCSP->GetPolicyString(i, originalCSPStr);
nullPrincipalCSP->GetPolicyString(i, nullPrincipalCSPStr);
MOZ_ASSERT(originalCSPStr.Equals(nullPrincipalCSPStr),
"There should be no other CSP string here.");
}
}
#endif
// CSPs are equal, no need to set it again.
return;
}
aPrincipal->SetCsp(originalCSP);
// After 965637 all that magical CSP inheritance goes away. For now,
// we have to create a clone of the current CSP and have to manually
// set it on the Principal.
uint32_t count = 0;
rv = originalCSP->GetPolicyCount(&count);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
if (count == 0) {
// fast path: if there is nothing to inherit, we can return here.
return;
}
RefPtr<nsCSPContext> newCSP = new nsCSPContext();
nsWeakPtr loadingContext =
static_cast<nsCSPContext*>(originalCSP.get())->GetLoadingContext();
nsCOMPtr<Document> doc = do_QueryReferent(loadingContext);
rv = doc ? newCSP->SetRequestContext(doc, nullptr)
: newCSP->SetRequestContext(nullptr, aPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
for (uint32_t i = 0; i < count; ++i) {
const nsCSPPolicy* policy = originalCSP->GetPolicy(i);
MOZ_ASSERT(policy);
nsAutoString policyString;
policy->toString(policyString);
rv = newCSP->AppendPolicy(policyString, policy->getReportOnlyFlag(),
policy->getDeliveredViaMetaTagFlag());
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
aPrincipal->SetCsp(newCSP);
}
nsresult nsScriptSecurityManager::GetChannelResultPrincipal(

Просмотреть файл

@ -2545,14 +2545,11 @@ nsresult Document::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
}
}
// If this is not a data document, set CSP.
if (!mLoadedAsData) {
nsresult rv = InitCSP(aChannel);
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv = InitCSP(aChannel);
NS_ENSURE_SUCCESS(rv, rv);
// Initialize FeaturePolicy
nsresult rv = InitFeaturePolicy(aChannel);
rv = InitFeaturePolicy(aChannel);
NS_ENSURE_SUCCESS(rv, rv);
// XFO needs to be checked after CSP because it is ignored if
@ -2650,6 +2647,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
return NS_OK;
}
// If this is a data document - no need to set CSP.
if (mLoadedAsData) {
return NS_OK;
}
nsAutoCString tCspHeaderValue, tCspROHeaderValue;
nsCOMPtr<nsIHttpChannel> httpChannel;
@ -2673,6 +2675,20 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
auto addonPolicy = BasePrincipal::Cast(principal)->AddonPolicy();
// Unless the NodePrincipal is a SystemPrincipal, which currently can not
// hold a CSP, we always call EnsureCSP() on the Principal. We do this
// so that a Meta CSP does not have to create a new CSP object. This is
// important because history entries hold a reference to the CSP object,
// which then gets dynamically updated in case a meta CSP is present.
// Note that after Bug 965637 we can remove that carve out, because the
// CSP will hang off the Client/Document and not the Principal anymore.
if (principal->IsSystemPrincipal()) {
return NS_OK;
}
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->EnsureCSP(this, getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
// Check if this is a signed content to apply default CSP.
bool applySignedContentCSP = false;
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
@ -2698,10 +2714,6 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
MOZ_LOG(gCspPRLog, LogLevel::Debug,
("Document is an add-on or CSP header specified %p", this));
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->EnsureCSP(this, getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
// ----- if the doc is an addon, apply its CSP.
if (addonPolicy) {
nsCOMPtr<nsIAddonPolicyService> aps =

Просмотреть файл

@ -382,7 +382,14 @@ nsCSPContext::AppendPolicy(const nsAString& aPolicyString, bool aReportOnly,
}
mPolicies.AppendElement(policy);
// set the flag on the document for CSP telemetry
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
if (doc) {
doc->SetHasCSP(true);
}
}
return NS_OK;
}
@ -672,9 +679,6 @@ nsCSPContext::SetRequestContext(Document* aDocument, nsIPrincipal* aPrincipal) {
// console messages until it becomes available, see flushConsoleMessages
mQueueUpMessages = !mInnerWindowID;
mCallingChannelLoadGroup = aDocument->GetDocumentLoadGroup();
// set the flag on the document for CSP telemetry
aDocument->SetHasCSP(true);
mEventTarget = aDocument->EventTargetFor(TaskCategory::Other);
} else {
CSPCONTEXTLOG(

Просмотреть файл

@ -26,7 +26,7 @@ function receiveMessage(event) {
var frame = document.getElementById("testframe");
var principal = SpecialPowers.wrap(frame.contentDocument).nodePrincipal;
var cspJSON = principal.cspJSON;
is(cspJSON, "{}", "there should be no CSP attached to the iframe");
is(cspJSON, "{\"csp-policies\":[]}", "there should be no CSP attached to the iframe");
SimpleTest.finish();
}