Skip to content

Commit

Permalink
Merge mozilla-inbound to mozilla-central. a=merge
Browse files Browse the repository at this point in the history
  • Loading branch information
CosminSabou committed Jan 9, 2019
2 parents 8519596 + 7de2c58 commit ad04ab5
Show file tree
Hide file tree
Showing 89 changed files with 2,586 additions and 2,391 deletions.
2 changes: 1 addition & 1 deletion browser/base/content/utilityOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ function openLinkIn(url, where, params) {
userContextId: aUserContextId,
privateBrowsingId: aIsPrivate || (w && PrivateBrowsingUtils.isWindowPrivate(w)),
};
return Services.scriptSecurityManager.createCodebasePrincipal(principal.URI, attrs);
return Services.scriptSecurityManager.principalWithOA(principal, attrs);
}
return principal;
}
Expand Down
29 changes: 29 additions & 0 deletions caps/BasePrincipal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/ChromeUtils.h"
#include "mozilla/dom/CSPDictionariesBinding.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/dom/ToJSValue.h"

namespace mozilla {
Expand Down Expand Up @@ -494,6 +495,34 @@ void BasePrincipal::FinishInit(const nsACString& aOriginNoSuffix,
mOriginNoSuffix = NS_Atomize(aOriginNoSuffix);
}

void BasePrincipal::FinishInit(BasePrincipal* aOther,
const OriginAttributes& aOriginAttributes) {
mInitialized = true;
mOriginAttributes = aOriginAttributes;

// First compute the origin suffix since it's infallible.
nsAutoCString originSuffix;
mOriginAttributes.CreateSuffix(originSuffix);
mOriginSuffix = NS_Atomize(originSuffix);

mOriginNoSuffix = aOther->mOriginNoSuffix;
mHasExplicitDomain = aOther->mHasExplicitDomain;

if (aOther->mPreloadCSP) {
mPreloadCSP = do_CreateInstance("@mozilla.org/cspcontext;1");
nsCSPContext* preloadCSP = static_cast<nsCSPContext*>(mPreloadCSP.get());
preloadCSP->InitFromOther(
static_cast<nsCSPContext*>(aOther->mPreloadCSP.get()), nullptr, this);
}

if (aOther->mCSP) {
mCSP = do_CreateInstance("@mozilla.org/cspcontext;1");
nsCSPContext* csp = static_cast<nsCSPContext*>(mCSP.get());
csp->InitFromOther(static_cast<nsCSPContext*>(aOther->mCSP.get()), nullptr,
this);
}
}

bool SiteIdentifier::Equals(const SiteIdentifier& aOther) const {
MOZ_ASSERT(IsInitialized());
MOZ_ASSERT(aOther.IsInitialized());
Expand Down
8 changes: 5 additions & 3 deletions caps/BasePrincipal.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,13 @@ class BasePrincipal : public nsJSPrincipals {

void SetHasExplicitDomain() { mHasExplicitDomain = true; }

// This function should be called as the last step of the initialization of
// the principal objects. It's typically called as the last step from the
// Init() method of the child classes.
// Either of these functions should be called as the last step of the
// initialization of the principal objects. It's typically called as the
// last step from the Init() method of the child classes.
void FinishInit(const nsACString& aOriginNoSuffix,
const OriginAttributes& aOriginAttributes);
void FinishInit(BasePrincipal* aOther,
const OriginAttributes& aOriginAttributes);

nsCOMPtr<nsIContentSecurityPolicy> mCSP;
nsCOMPtr<nsIContentSecurityPolicy> mPreloadCSP;
Expand Down
12 changes: 12 additions & 0 deletions caps/ContentPrincipal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ nsresult ContentPrincipal::Init(nsIURI* aCodebase,
return NS_OK;
}

nsresult ContentPrincipal::Init(ContentPrincipal* aOther,
const OriginAttributes& aOriginAttributes) {
NS_ENSURE_ARG(aOther);

mCodebase = aOther->mCodebase;
FinishInit(aOther, aOriginAttributes);

mDomain = aOther->mDomain;
mAddon = aOther->mAddon;
return NS_OK;
}

nsresult ContentPrincipal::GetScriptLocation(nsACString& aStr) {
return mCodebase->GetSpec(aStr);
}
Expand Down
2 changes: 2 additions & 0 deletions caps/ContentPrincipal.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class ContentPrincipal final : public BasePrincipal {
// Init() must be called before the principal is in a usable state.
nsresult Init(nsIURI* aCodebase, const OriginAttributes& aOriginAttributes,
const nsACString& aOriginNoSuffix);
nsresult Init(ContentPrincipal* aOther,
const OriginAttributes& aOriginAttributes);

virtual nsresult GetScriptLocation(nsACString& aStr) override;

Expand Down
8 changes: 8 additions & 0 deletions caps/nsIScriptSecurityManager.idl
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ interface nsIScriptSecurityManager : nsISupports
nsIPrincipal getDocShellCodebasePrincipal(in nsIURI uri,
in nsIDocShell docShell);

/**
* If this is a codebase principal, return a copy with different
* origin attributes.
*/
[implicit_jscontext]
nsIPrincipal principalWithOA(in nsIPrincipal principal,
in jsval originAttributes);

/**
* Returns a principal whose origin is composed of |uri| and |originAttributes|.
* See nsIPrincipal.idl for a description of origin attributes, and
Expand Down
85 changes: 66 additions & 19 deletions caps/nsJSPrincipals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ JS_PUBLIC_API void JSPrincipals::dump() {
return ReadKnownPrincipalType(aCx, aReader, tag, aOutPrincipals);
}

static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader,
OriginAttributes& aAttrs, nsACString& aSpec,
nsACString& aOriginNoSuffix) {
static bool ReadPrincipalInfo(
JSStructuredCloneReader* aReader, OriginAttributes& aAttrs,
nsACString& aSpec, nsACString& aOriginNoSuffix,
nsTArray<ContentSecurityPolicy>* aPolicies = nullptr) {
uint32_t suffixLength, specLength;
if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
return false;
Expand All @@ -149,12 +150,14 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader,
return false;
}

uint32_t originNoSuffixLength, dummy;
if (!JS_ReadUint32Pair(aReader, &originNoSuffixLength, &dummy)) {
uint32_t originNoSuffixLength, policyCount;
if (!JS_ReadUint32Pair(aReader, &originNoSuffixLength, &policyCount)) {
return false;
}

MOZ_ASSERT(dummy == 0);
if (!aPolicies) {
MOZ_ASSERT(policyCount == 0);
}

if (!aOriginNoSuffix.SetLength(originNoSuffixLength, fallible)) {
return false;
Expand All @@ -165,6 +168,29 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader,
return false;
}

for (uint32_t i = 0; i < policyCount; i++) {
uint32_t policyLength, reportAndMeta;
if (!JS_ReadUint32Pair(aReader, &policyLength, &reportAndMeta)) {
return false;
}
bool reportOnly = reportAndMeta & 1;
bool deliveredViaMetaTag = reportAndMeta & 2;

nsAutoCString policyStr;
if (!policyStr.SetLength(policyLength, fallible)) {
return false;
}

if (!JS_ReadBytes(aReader, policyStr.BeginWriting(), policyLength)) {
return false;
}

if (aPolicies) {
aPolicies->AppendElement(ContentSecurityPolicy(
NS_ConvertUTF8toUTF16(policyStr), reportOnly, deliveredViaMetaTag));
}
}

return true;
}

Expand Down Expand Up @@ -206,7 +232,8 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,
OriginAttributes attrs;
nsAutoCString spec;
nsAutoCString originNoSuffix;
if (!ReadPrincipalInfo(aReader, attrs, spec, originNoSuffix)) {
nsTArray<ContentSecurityPolicy> policies;
if (!ReadPrincipalInfo(aReader, attrs, spec, originNoSuffix, &policies)) {
return false;
}

Expand All @@ -218,7 +245,8 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,

MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty());

aInfo = ContentPrincipalInfo(attrs, originNoSuffix, spec);
aInfo =
ContentPrincipalInfo(attrs, originNoSuffix, spec, std::move(policies));
} else {
#ifdef FUZZING
return false;
Expand Down Expand Up @@ -259,19 +287,37 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,
return true;
}

static bool WritePrincipalInfo(JSStructuredCloneWriter* aWriter,
const OriginAttributes& aAttrs,
const nsCString& aSpec,
const nsCString& aOriginNoSuffix) {
static bool WritePrincipalInfo(
JSStructuredCloneWriter* aWriter, const OriginAttributes& aAttrs,
const nsCString& aSpec, const nsCString& aOriginNoSuffix,
const nsTArray<ContentSecurityPolicy>* aPolicies = nullptr) {
nsAutoCString suffix;
aAttrs.CreateSuffix(suffix);
size_t policyCount = aPolicies ? aPolicies->Length() : 0;

if (!(JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) &&
JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length()) &&
JS_WriteUint32Pair(aWriter, aOriginNoSuffix.Length(), policyCount) &&
JS_WriteBytes(aWriter, aOriginNoSuffix.get(),
aOriginNoSuffix.Length()))) {
return false;
}

return JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) &&
JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length()) &&
JS_WriteUint32Pair(aWriter, aOriginNoSuffix.Length(), 0) &&
JS_WriteBytes(aWriter, aOriginNoSuffix.get(),
aOriginNoSuffix.Length());
for (uint32_t i = 0; i < policyCount; i++) {
nsCString policy;
CopyUTF16toUTF8((*aPolicies)[i].policy(), policy);
uint32_t reportAndMeta =
((*aPolicies)[i].reportOnlyFlag() ? 1 : 0) |
((*aPolicies)[i].deliveredViaMetaTagFlag() ? 2 : 0);
if (!(JS_WriteUint32Pair(aWriter, policy.Length(), reportAndMeta) &&
JS_WriteBytes(aWriter, PromiseFlatCString(policy).get(),
policy.Length()))) {
return false;
}
}

return true;
}

static bool WritePrincipalInfo(JSStructuredCloneWriter* aWriter,
Expand Down Expand Up @@ -304,7 +350,8 @@ static bool WritePrincipalInfo(JSStructuredCloneWriter* aWriter,
const ContentPrincipalInfo& cInfo = aInfo;
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL, 0) &&
WritePrincipalInfo(aWriter, cInfo.attrs(), cInfo.spec(),
cInfo.originNoSuffix());
cInfo.originNoSuffix(),
&(cInfo.securityPolicies()));
}

bool nsJSPrincipals::write(JSContext* aCx, JSStructuredCloneWriter* aWriter) {
Expand Down
29 changes: 29 additions & 0 deletions caps/nsScriptSecurityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,35 @@ nsScriptSecurityManager::GetDocShellCodebasePrincipal(
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
}

NS_IMETHODIMP
nsScriptSecurityManager::PrincipalWithOA(
nsIPrincipal* aPrincipal, JS::Handle<JS::Value> aOriginAttributes,
JSContext* aCx, nsIPrincipal** aReturnPrincipal) {
if (!aPrincipal) {
return NS_OK;
}
if (aPrincipal->GetIsCodebasePrincipal()) {
OriginAttributes attrs;
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<ContentPrincipal> copy = new ContentPrincipal();
ContentPrincipal* contentPrincipal =
static_cast<ContentPrincipal*>(aPrincipal);
nsresult rv = copy->Init(contentPrincipal, attrs);
NS_ENSURE_SUCCESS(rv, rv);
copy.forget(aReturnPrincipal);
} else {
// We do this for null principals, system principals (both fine)
// ... and expanded principals, where we should probably do something
// cleverer, but I also don't think we care too much.
nsCOMPtr<nsIPrincipal> prin = aPrincipal;
prin.forget(aReturnPrincipal);
}

return *aReturnPrincipal ? NS_OK : NS_ERROR_FAILURE;
}

NS_IMETHODIMP
nsScriptSecurityManager::CanCreateWrapper(JSContext* cx, const nsIID& aIID,
nsISupports* aObj,
Expand Down
Binary file modified config/external/icu/data/icudt63l.dat
Binary file not shown.
2 changes: 2 additions & 0 deletions docshell/test/browser/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ support-files =
browser_timelineMarkers-frame-05.js
head.js
frame-head.js
file_data_load_inherit_csp.html
file_click_link_within_view_source.html
onload_message.html
onpageshow_message.html
Expand Down Expand Up @@ -92,6 +93,7 @@ skip-if = verify
[browser_bug852909.js]
skip-if = (verify && debug && (os == 'win'))
[browser_bug92473.js]
[browser_data_load_inherit_csp.js]
[browser_dataURI_unique_opaque_origin.js]
[browser_uriFixupIntegration.js]
[browser_uriFixupAlternateRedirects.js]
Expand Down
82 changes: 82 additions & 0 deletions docshell/test/browser/browser_data_load_inherit_csp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use strict";

const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
const HTML_URI = TEST_PATH + "file_data_load_inherit_csp.html";
const DATA_URI = "data:text/html;html,<html><body>foo</body></html>";

function setDataHrefOnLink(aBrowser, aDataURI) {
return ContentTask.spawn(aBrowser, aDataURI, function(uri) {
let link = content.document.getElementById("testlink");
link.href = uri;
});
};

function verifyCSP(aTestName, aBrowser, aDataURI) {
return ContentTask.spawn(aBrowser, {aTestName, aDataURI}, async function ({aTestName, aDataURI}) {
let channel = content.docShell.currentDocumentChannel;
is(channel.URI.spec, aDataURI, "testing CSP for " + aTestName);
let principal = channel.loadInfo.triggeringPrincipal;
let cspJSON = principal.cspJSON;
let cspOBJ = JSON.parse(cspJSON);
let policies = cspOBJ["csp-policies"];
is(policies.length, 1, "should be one policy");
let policy = policies[0];
is(policy['script-src'], "'unsafe-inline'", "script-src directive matches");
});
};

add_task(async function setup() {
// allow top level data: URI navigations, otherwise clicking data: link fails
await SpecialPowers.pushPrefEnv({
"set": [["security.data_uri.block_toplevel_data_uri_navigations", false]],
});
});

add_task(async function test_data_csp_inheritance_regular_click() {
await BrowserTestUtils.withNewTab(HTML_URI, async function(browser) {
let loadPromise = BrowserTestUtils.browserLoaded(browser, false, DATA_URI);
// set the data href + simulate click
await setDataHrefOnLink(gBrowser.selectedBrowser, DATA_URI);
BrowserTestUtils.synthesizeMouseAtCenter("#testlink", {},
gBrowser.selectedBrowser);
await loadPromise;
await verifyCSP("click()", gBrowser.selectedBrowser, DATA_URI);
});
});

add_task(async function test_data_csp_inheritance_ctrl_click() {
await BrowserTestUtils.withNewTab(HTML_URI, async function(browser) {
let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, DATA_URI);
// set the data href + simulate ctrl+click
await setDataHrefOnLink(gBrowser.selectedBrowser, DATA_URI);
BrowserTestUtils.synthesizeMouseAtCenter("#testlink",
{ ctrlKey: true, metaKey: true },
gBrowser.selectedBrowser);
let tab = await loadPromise;
gBrowser.selectTabAtIndex(2);
await verifyCSP("ctrl-click()", gBrowser.selectedBrowser, DATA_URI);
await BrowserTestUtils.removeTab(tab);
});
});

add_task(async function test_data_csp_inheritance_right_click_open_link_in_new_tab() {
await BrowserTestUtils.withNewTab(HTML_URI, async function(browser) {
let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, DATA_URI);
// set the data href + simulate right-click open link in tab
await setDataHrefOnLink(gBrowser.selectedBrowser, DATA_URI);
BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
// These are operations that must be executed synchronously with the event.
document.getElementById("context-openlinkintab").doCommand();
event.target.hidePopup();
return true;
});
BrowserTestUtils.synthesizeMouseAtCenter("#testlink",
{ type: "contextmenu", button: 2 },
gBrowser.selectedBrowser);

let tab = await loadPromise;
gBrowser.selectTabAtIndex(2);
await verifyCSP("right-click-open-in-new-tab()", gBrowser.selectedBrowser, DATA_URI);
await BrowserTestUtils.removeTab(tab);
});
});
11 changes: 11 additions & 0 deletions docshell/test/browser/file_data_load_inherit_csp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Bug 1358009 - Inherit CSP into data URI</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-inline'">
</head>
<body>
<a id="testlink">testlink</a>
</body>
</html>
Loading

0 comments on commit ad04ab5

Please sign in to comment.