From 1f25d963d24d8aeca56eb97e0c7be2f41aa19be0 Mon Sep 17 00:00:00 2001 From: "jst%mozilla.jstenback.com" Date: Tue, 15 Jun 2004 08:28:52 +0000 Subject: [PATCH] Fixing bug 246448. Prevent loading of content into a frame from a origin different than the one owning the frame. r=dveditz@cruzio.com, sr=brendan@mozilla.org git-svn-id: svn://10.0.0.236/trunk@157903 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/content/src/nsHTMLFormElement.cpp | 6 +- mozilla/docshell/base/nsDocShell.cpp | 138 +++++++++++++++++- mozilla/docshell/base/nsDocShell.h | 3 + mozilla/docshell/base/nsWebShell.cpp | 79 +++++++--- mozilla/docshell/base/nsWebShell.h | 9 ++ 5 files changed, 211 insertions(+), 24 deletions(-) diff --git a/mozilla/content/html/content/src/nsHTMLFormElement.cpp b/mozilla/content/html/content/src/nsHTMLFormElement.cpp index 05706e9a08a..4512764c6fb 100644 --- a/mozilla/content/html/content/src/nsHTMLFormElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLFormElement.cpp @@ -726,7 +726,7 @@ nsHTMLFormElement::HandleDOMEvent(nsIPresContext* aPresContext, // to forget it and the form element will build a new one ForgetPendingSubmission(); } - rv = DoSubmitOrReset(aPresContext, aEvent, aEvent->message); + DoSubmitOrReset(aPresContext, aEvent, aEvent->message); } break; } @@ -833,9 +833,7 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent) // // perform the submission // - SubmitSubmission(aPresContext, submission); - - return NS_OK; + return SubmitSubmission(aPresContext, submission); } nsresult diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index ae57becd3c6..2904c7c7304 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -73,6 +73,8 @@ #include "nsIUploadChannel.h" #include "nsISecurityEventSink.h" #include "nsIScriptSecurityManager.h" +#include "nsIJSContextStack.h" +#include "nsIScriptObjectPrincipal.h" #include "nsDocumentCharsetInfoCID.h" #include "nsICanvasFrame.h" #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...) @@ -4937,6 +4939,135 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) } +nsresult +nsDocShell::CheckLoadingPermissions(nsISupports *aOwner) +{ + nsresult rv = NS_OK; + + if (mPrefs) { + PRBool frameLoadCheckDisabled = PR_FALSE; + rv = mPrefs->GetBoolPref("docshell.frameloadcheck.disabled", + &frameLoadCheckDisabled); + + if (NS_SUCCEEDED(rv) && frameLoadCheckDisabled) { + return rv; + } + } + + // Check to see if we're a frame in a frameset frame, or iframe, + // and make sure the caller has the right to load a new uri into + // this frame. + nsCOMPtr parentItem; + rv = GetSameTypeParent(getter_AddRefs(parentItem)); + + if (NS_FAILED(rv) || !parentItem) { + return rv; + } + + // We're a frame. Check that the caller has write permission to + // the parent before allowing it to load anything into this + // docshell. + + nsCOMPtr securityManager = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr caller(do_QueryInterface(aOwner)); + + if (!caller) { + rv = securityManager->GetSubjectPrincipal(getter_AddRefs(caller)); + + if (NS_FAILED(rv) || !caller) { + // No principal reachable, permit load (assuming the above + // call didn't fail) + + return rv; + } + } + + if (!aOwner && caller) { + // We were *not* passed a principal, but we found a subject + // principal. That means that JS is running. Check if + // "UniversalBrowserWrite" is enabled, and allow the load if + // it is. + + PRBool ubwEnabled = PR_FALSE; + rv = securityManager->IsCapabilityEnabled("UniversalBrowserWrite", + &ubwEnabled); + if (NS_FAILED(rv) || ubwEnabled) { + return rv; + } + } + + nsCOMPtr sgo(do_GetInterface(parentItem)); + + nsCOMPtr sop(do_QueryInterface(sgo)); + + nsIPrincipal *parentPrincipal; + if (!sop || !(parentPrincipal = sop->GetPrincipal())) { + return NS_ERROR_UNEXPECTED; + } + + // Check if the caller is from the same origin as our parent. + rv = securityManager->CheckSameOriginPrincipal(caller, parentPrincipal); + if (NS_SUCCEEDED(rv)) { + // Same origin, permit load + + return rv; + } + + sop = do_QueryInterface(mScriptGlobal); + + nsIPrincipal *principal; + if (!sop || !(principal = sop->GetPrincipal())) { + return NS_ERROR_UNEXPECTED; + } + + // Check if the caller is from the same origin as we are. + rv = securityManager->CheckSameOriginPrincipal(caller, principal); + if (NS_SUCCEEDED(rv)) { + // Same origin, permit load + + return rv; + } + + // Caller and callee are not from the same origin. Only permit + // loading content if both are part of the same window, assuming + // we can find the window of the caller. + + nsCOMPtr sameTypeCalleeRoot; + GetSameTypeRootTreeItem(getter_AddRefs(sameTypeCalleeRoot)); + + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + if (!stack) { + return rv; + } + + JSContext *cx = nsnull; + stack->Peek(&cx); + + if (!cx) { + // No caller docshell reachable, disallow load. + + return rv; + } + + nsIScriptContext *currentCX = + GetScriptContextFromJSContext(cx); + if (currentCX && + (sgo = currentCX->GetGlobalObject())) { + nsCOMPtr sameTypeCallerRoot = + do_QueryInterface(sgo->GetDocShell()); + + if (sameTypeCalleeRoot == sameTypeCallerRoot) { + rv = NS_OK; + } + } + + return rv; +} + //***************************************************************************** // nsDocShell: Site Loading //***************************************************************************** @@ -5199,7 +5330,12 @@ nsDocShell::InternalLoad(nsIURI * aURI, if (mIsBeingDestroyed) { return NS_ERROR_FAILURE; } - + + rv = CheckLoadingPermissions(aOwner); + if (NS_FAILED(rv)) { + return rv; + } + mURIResultedInDocument = PR_FALSE; // reset the clock... // diff --git a/mozilla/docshell/base/nsDocShell.h b/mozilla/docshell/base/nsDocShell.h index b7fd65137e6..1a7010030db 100644 --- a/mozilla/docshell/base/nsDocShell.h +++ b/mozilla/docshell/base/nsDocShell.h @@ -325,6 +325,9 @@ protected: virtual nsresult EndPageLoad(nsIWebProgress * aProgress, nsIChannel * aChannel, nsresult aResult); + + nsresult CheckLoadingPermissions(nsISupports *aOwner); + protected: PRPackedBool mAllowSubframes; PRPackedBool mAllowPlugins; diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index 7d05132dd61..1bd45e2719b 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -58,6 +58,7 @@ #include "nsIRefreshURI.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObjectOwner.h" +#include "nsIScriptSecurityManager.h" #include "nsIDOMEvent.h" #include "nsIPresContext.h" #include "nsIComponentManager.h" @@ -423,15 +424,17 @@ nsWebShell::SetRendering(PRBool aRender) struct OnLinkClickEvent : public PLEvent { OnLinkClickEvent(nsWebShell* aHandler, nsIContent* aContent, nsLinkVerb aVerb, nsIURI* aURI, - const PRUnichar* aTargetSpec, nsIInputStream* aPostDataStream = 0, - nsIInputStream* aHeadersDataStream = 0); + const PRUnichar* aTargetSpec, + nsIInputStream* aPostDataStream, + nsIInputStream* aHeadersDataStream, + nsISupports *aOwner); ~OnLinkClickEvent(); void HandleEvent() { - mHandler->OnLinkClickSync(mContent, mVerb, mURI, - mTargetSpec.get(), mPostDataStream, - mHeadersDataStream, - nsnull, nsnull); + mHandler->OnLinkClickSyncInternal(mContent, mVerb, mURI, + mTargetSpec.get(), mPostDataStream, + mHeadersDataStream, + nsnull, nsnull, mOwner); } nsWebShell* mHandler; @@ -441,6 +444,7 @@ struct OnLinkClickEvent : public PLEvent { nsCOMPtr mHeadersDataStream; nsCOMPtr mContent; nsLinkVerb mVerb; + nsCOMPtr mOwner; }; static void PR_CALLBACK HandlePLEvent(OnLinkClickEvent* aEvent) @@ -459,7 +463,8 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler, nsIURI* aURI, const PRUnichar* aTargetSpec, nsIInputStream* aPostDataStream, - nsIInputStream* aHeadersDataStream) + nsIInputStream* aHeadersDataStream, + nsISupports *aOwner) { mHandler = aHandler; NS_ADDREF(aHandler); @@ -469,6 +474,7 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler, mHeadersDataStream = aHeadersDataStream; mContent = aContent; mVerb = aVerb; + mOwner = aOwner; PL_InitEvent(this, nsnull, (PLHandleEventProc) ::HandlePLEvent, @@ -496,10 +502,20 @@ nsWebShell::OnLinkClick(nsIContent* aContent, nsIInputStream* aPostDataStream, nsIInputStream* aHeadersDataStream) { - OnLinkClickEvent* ev; + nsCOMPtr securityManager = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + NS_ENSURE_TRUE(securityManager, NS_ERROR_UNEXPECTED); - ev = new OnLinkClickEvent(this, aContent, aVerb, aURI, - aTargetSpec, aPostDataStream, aHeadersDataStream); + nsCOMPtr principal; + securityManager->GetSubjectPrincipal(getter_AddRefs(principal)); + + if (!principal && aContent && aContent->GetDocument()) { + principal = aContent->GetDocument()->GetPrincipal(); + } + + OnLinkClickEvent* ev = + new OnLinkClickEvent(this, aContent, aVerb, aURI, aTargetSpec, + aPostDataStream, aHeadersDataStream, principal); if (!ev) { return NS_ERROR_OUT_OF_MEMORY; } @@ -518,7 +534,7 @@ nsWebShell::GetEventQueue(nsIEventQueue **aQueue) return *aQueue ? NS_OK : NS_ERROR_FAILURE; } -NS_IMETHODIMP +nsresult nsWebShell::OnLinkClickSync(nsIContent *aContent, nsLinkVerb aVerb, nsIURI* aURI, @@ -528,7 +544,33 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent, nsIDocShell** aDocShell, nsIRequest** aRequest) { - PRBool earlyReturn = PR_FALSE; + nsCOMPtr securityManager = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + NS_ENSURE_TRUE(securityManager, NS_ERROR_UNEXPECTED); + + nsCOMPtr principal; + securityManager->GetSubjectPrincipal(getter_AddRefs(principal)); + + if (!principal && aContent && aContent->GetDocument()) { + principal = aContent->GetDocument()->GetPrincipal(); + } + + return OnLinkClickSyncInternal(aContent, aVerb, aURI, aTargetSpec, + aPostDataStream, aHeadersDataStream, + aDocShell, aRequest, principal); +} + +nsresult +nsWebShell::OnLinkClickSyncInternal(nsIContent *aContent, + nsLinkVerb aVerb, + nsIURI* aURI, + const PRUnichar* aTargetSpec, + nsIInputStream* aPostDataStream, + nsIInputStream* aHeadersDataStream, + nsIDocShell** aDocShell, + nsIRequest** aRequest, + nsISupports *aOwner) +{ { // defer to an external protocol handler if necessary... nsCOMPtr extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID); @@ -542,16 +584,15 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent, nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed); if (NS_SUCCEEDED(rv) && !isExposed) { rv = extProtService->LoadUrl(aURI); + if (NS_SUCCEEDED(rv)) - earlyReturn = PR_TRUE; - else - NS_WARNING("failed to launch external protocol handler"); + return NS_OK; + + NS_WARNING("failed to launch external protocol handler"); } } } } - if (earlyReturn) - return NS_OK; nsCOMPtr node(do_QueryInterface(aContent)); NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED); @@ -563,7 +604,7 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent, aURI->SchemeIs("data", &isData); if (isJS || isData) { - nsCOMPtr sourceDoc = aContent->GetDocument(); + nsIDocument *sourceDoc = aContent->GetDocument(); if (!sourceDoc) { // The source is in a 'zombie' document, or not part of a @@ -631,7 +672,7 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent, { return InternalLoad(aURI, // New URI referer, // Referer URI - nsnull, // No onwer + aOwner, // Owner (nsIPrincipal) PR_TRUE, // Inherit owner from document target.get(), // Window target NS_LossyConvertUCS2toASCII(typeHint).get(), diff --git a/mozilla/docshell/base/nsWebShell.h b/mozilla/docshell/base/nsWebShell.h index 80e5a9a4322..b0e73653118 100644 --- a/mozilla/docshell/base/nsWebShell.h +++ b/mozilla/docshell/base/nsWebShell.h @@ -115,6 +115,15 @@ public: // NS_IMETHOD SetURL(const PRUnichar* aURL); + nsresult OnLinkClickSyncInternal(nsIContent* aContent, nsLinkVerb aVerb, + nsIURI* aURI, + const PRUnichar* aTargetSpec, + nsIInputStream* aPostDataStream, + nsIInputStream* aHeadersDataStream, + nsIDocShell** aDocShell, + nsIRequest** aRequest, + nsISupports *aOwner); + protected: // void GetRootWebShellEvenIfChrome(nsIWebShell** aResult); void InitFrameData();