Bug 1320124 - don't allow privileged loads inside unprivileged loads, r?bz
MozReview-Commit-ID: 3zoknjtslHI
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -273,16 +273,20 @@
using namespace mozilla;
using namespace mozilla::dom;
typedef nsTArray<Link*> LinkArray;
static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
static LazyLogModule gCspPRLog("CSP");
+static const char kChromeInContentPref[] = "security.allow_chrome_frames_inside_content";
+static bool sChromeInContentAllowed = false;
+static bool sChromeInContentPrefCached = false;
+
static nsresult
GetHttpChannelHelper(nsIChannel* aChannel, nsIHttpChannel** aHttpChannel)
{
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
httpChannel.forget(aHttpChannel);
return NS_OK;
}
@@ -2074,16 +2078,18 @@ nsDocument::Reset(nsIChannel* aChannel,
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
if (securityManager) {
securityManager->GetChannelResultPrincipal(aChannel,
getter_AddRefs(principal));
}
}
+ principal = MaybeDowngradePrincipal(principal);
+
ResetToURI(uri, aLoadGroup, principal);
// Note that, since mTiming does not change during a reset, the
// navigationStart time remains unchanged and therefore any future new
// timeline will have the same global clock time as the old one.
mDocumentTimeline = nullptr;
nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
@@ -2220,16 +2226,53 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
}
// Refresh the principal on the compartment.
if (nsPIDOMWindowInner* win = GetInnerWindow()) {
nsGlobalWindow::Cast(win)->RefreshCompartmentPrincipal();
}
}
+already_AddRefed<nsIPrincipal>
+nsDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
+{
+ if (!aPrincipal) {
+ return nullptr;
+ }
+
+ if (!sChromeInContentPrefCached) {
+ sChromeInContentPrefCached = true;
+ Preferences::AddBoolVarCache(&sChromeInContentAllowed,
+ kChromeInContentPref, false);
+ }
+ if (!sChromeInContentAllowed &&
+ nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+ // We basically want the parent document here, but because this is very
+ // early in the load, GetParentDocument() returns null, so we use the
+ // docshell hierarchy to get this information instead.
+ if (mDocumentContainer) {
+ nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
+ mDocumentContainer->GetParent(getter_AddRefs(parentDocShellItem));
+ nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
+ if (parentDocShell) {
+ nsCOMPtr<nsIDocument> parentDoc;
+ parentDoc = parentDocShell->GetDocument();
+ if (!parentDoc ||
+ !nsContentUtils::IsSystemPrincipal(parentDoc->NodePrincipal())) {
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1");
+ return nullPrincipal.forget();
+ }
+ }
+ }
+ }
+ nsCOMPtr<nsIPrincipal> principal(aPrincipal);
+ return principal.forget();
+}
+
void
nsDocument::RemoveDocStyleSheetsFromStyleSets()
{
// The stylesheets should forget us
for (StyleSheet* sheet : Reversed(mStyleSheets)) {
sheet->ClearAssociatedDocument();
if (sheet->IsApplicable()) {
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -509,16 +509,18 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_SIZEOF_EXCLUDING_THIS
virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup) override;
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
nsIPrincipal* aPrincipal) override;
+ already_AddRefed<nsIPrincipal> MaybeDowngradePrincipal(nsIPrincipal* aPrincipal);
+
// StartDocumentLoad is pure virtual so that subclasses must override it.
// The nsDocument StartDocumentLoad does some setup, but does NOT set
// *aDocListener; this is the job of subclasses.
virtual nsresult StartDocumentLoad(const char* aCommand,
nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,
nsISupports* aContainer,
nsIStreamListener **aDocListener,
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -398,17 +398,25 @@ XULDocument::StartDocumentLoad(const cha
mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
mChannel = aChannel;
// Get the URI. Note that this should match nsDocShell::OnLoadingSite
nsresult rv =
NS_GetFinalChannelURI(aChannel, getter_AddRefs(mDocumentURI));
NS_ENSURE_SUCCESS(rv, rv);
-
+
+ mOriginalURI = mDocumentURI;
+
+ // Get the document's principal
+ nsCOMPtr<nsIPrincipal> principal;
+ nsContentUtils::GetSecurityManager()->
+ GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
+ principal = MaybeDowngradePrincipal(principal);
+
ResetStylesheetsToURI(mDocumentURI);
RetrieveRelevantHeaders(aChannel);
// Look in the chrome cache: we've got this puppy loaded
// already.
nsXULPrototypeDocument* proto = IsChromeURI(mDocumentURI) ?
nsXULPrototypeCache::GetInstance()->GetPrototype(mDocumentURI) :
@@ -455,18 +463,18 @@ XULDocument::StartDocumentLoad(const cha
bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
bool fillXULCache = (useXULCache && IsChromeURI(mDocumentURI));
// It's just a vanilla document load. Create a parser to deal
// with the stream n' stuff.
nsCOMPtr<nsIParser> parser;
- rv = PrepareToLoad(aContainer, aCommand, aChannel, aLoadGroup,
- getter_AddRefs(parser));
+ rv = PrepareToLoadPrototype(mDocumentURI, aCommand, principal,
+ getter_AddRefs(parser));
if (NS_FAILED(rv)) return rv;
// Predicate mIsWritingFastLoad on the XUL cache being enabled,
// so we don't have to re-check whether the cache is enabled all
// the time.
mIsWritingFastLoad = useXULCache;
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser, &rv);
@@ -1967,31 +1975,16 @@ XULDocument::MatchAttribute(Element* aEl
*attrValue, eCaseMatters);
}
}
return false;
}
nsresult
-XULDocument::PrepareToLoad(nsISupports* aContainer,
- const char* aCommand,
- nsIChannel* aChannel,
- nsILoadGroup* aLoadGroup,
- nsIParser** aResult)
-{
- // Get the document's principal
- nsCOMPtr<nsIPrincipal> principal;
- nsContentUtils::GetSecurityManager()->
- GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
- return PrepareToLoadPrototype(mDocumentURI, aCommand, principal, aResult);
-}
-
-
-nsresult
XULDocument::PrepareToLoadPrototype(nsIURI* aURI, const char* aCommand,
nsIPrincipal* aDocumentPrincipal,
nsIParser** aResult)
{
nsresult rv;
// Create a new prototype document.
rv = NS_NewXULPrototypeDocument(getter_AddRefs(mCurrentPrototype));
@@ -4433,16 +4426,17 @@ XULDocument::ParserObserver::OnStartRequ
// Guard against buggy channels calling OnStartRequest multiple times.
if (mPrototype) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
if (channel && secMan) {
nsCOMPtr<nsIPrincipal> principal;
secMan->GetChannelResultPrincipal(channel, getter_AddRefs(principal));
+ principal = mDocument->MaybeDowngradePrincipal(principal);
// Failure there is ok -- it'll just set a (safe) null principal
mPrototype->SetDocumentPrincipal(principal);
}
// Make sure to avoid cycles
mPrototype = nullptr;
}