diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index 73b5fe3b2ae..c68d450016a 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -692,6 +692,7 @@ nsDocShell::LoadURI(nsIURI * aURI, nsCOMPtr headersStream; nsCOMPtr owner; PRBool inheritOwner = PR_FALSE; + PRBool ownerIsExplicit = PR_FALSE; PRBool sendReferrer = PR_TRUE; nsCOMPtr shEntry; nsXPIDLString target; @@ -715,6 +716,12 @@ nsDocShell::LoadURI(nsIURI * aURI, aLoadInfo->GetPostDataStream(getter_AddRefs(postStream)); aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream)); aLoadInfo->GetSendReferrer(&sendReferrer); + + nsCOMPtr info19 = + do_QueryInterface(aLoadInfo); + if (info19) { + info19->GetOwnerIsExplicit(&ownerIsExplicit); + } } #if defined(PR_LOGGING) && defined(DEBUG) @@ -827,84 +834,99 @@ nsDocShell::LoadURI(nsIURI * aURI, ("nsDocShell[%p]: loading from session history", this)); #endif - rv = LoadHistoryEntry(shEntry, loadType); + return LoadHistoryEntry(shEntry, loadType); } + // Perform the load... - else { - // We need an owner (a referring principal). 4 possibilities: - // (1) If the system principal was passed in and we're a typeContent - // docshell, inherit the principal from the current document - // instead. - // (2) In all other cases when the principal passed in is not null, - // use that principal. - // (3) If the caller has allowed inheriting from the current document, - // or if we're being called from system code (eg chrome JS or pure - // C++) then inheritOwner should be true and InternalLoad will get - // an owner from the current document. If none of these things are - // true, then - // (4) we pass a null owner into the channel, and an owner will be - // created later from the channel's internal data. - // - // NOTE: This all only works because the only thing the owner is used - // for in InternalLoad is data:, javascript:, and about:blank - // URIs. For other URIs this would all be dead wrong! - nsCOMPtr secMan = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + + // We need an owner (a referring principal). + // + // If ownerIsExplicit is not set there are 4 possibilities: + // (1) If the system principal was passed in and we're a typeContent + // docshell, inherit the principal from the current document + // instead. + // (2) In all other cases when the principal passed in is not null, + // use that principal. + // (3) If the caller has allowed inheriting from the current document, + // or if we're being called from system code (eg chrome JS or pure + // C++) then inheritOwner should be true and InternalLoad will get + // an owner from the current document. If none of these things are + // true, then + // (4) we pass a null owner into the channel, and an owner will be + // created later from the channel's internal data. + // + // If ownerIsExplicit *is* set, there are 4 possibilities + // (1) If the system principal was passed in and we're a typeContent + // docshell, return an error. + // (2) In all other cases when the principal passed in is not null, + // use that principal. + // (3) If the caller has allowed inheriting from the current document, + // then inheritOwner should be true and InternalLoad will get an owner + // from the current document. If none of these things are true, then + // (4) we pass a null owner into the channel, and an owner will be + // created later from the channel's internal data. + // + // NOTE: This all only works because the only thing the owner is used + // for in InternalLoad is data:, javascript:, and about:blank + // URIs. For other URIs this would all be dead wrong! + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + if (owner && mItemType != typeChrome) { + nsCOMPtr ownerPrincipal = do_QueryInterface(owner); + PRBool isSystem; + rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem); NS_ENSURE_SUCCESS(rv, rv); - if (owner && mItemType != typeChrome) { - nsCOMPtr ownerPrincipal = do_QueryInterface(owner); - PRBool isSystem; - rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem); - NS_ENSURE_SUCCESS(rv, rv); - - if (isSystem) { - owner = nsnull; - inheritOwner = PR_TRUE; + if (isSystem) { + if (ownerIsExplicit) { + return NS_ERROR_DOM_SECURITY_ERR; } + owner = nsnull; + inheritOwner = PR_TRUE; } - if (!owner && !inheritOwner) { - // See if there's system or chrome JS code running - rv = secMan->SubjectPrincipalIsSystem(&inheritOwner); - if (NS_FAILED(rv)) { - // Set it back to false - inheritOwner = PR_FALSE; - } + } + if (!owner && !inheritOwner && !ownerIsExplicit) { + // See if there's system or chrome JS code running + rv = secMan->SubjectPrincipalIsSystem(&inheritOwner); + if (NS_FAILED(rv)) { + // Set it back to false + inheritOwner = PR_FALSE; } - - PRUint32 flags = 0; - - if (inheritOwner) - flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; - - if (!sendReferrer) - flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; - - if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) - flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; - - if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) - flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; - - if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) - flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; - - rv = InternalLoad(aURI, - referrer, - owner, - flags, - target.get(), - nsnull, // No type hint - postStream, - headersStream, - loadType, - nsnull, // No SHEntry - aFirstParty, - nsnull, // No nsIDocShell - nsnull); // No nsIRequest } - return rv; + PRUint32 flags = 0; + + if (inheritOwner) + flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; + + if (!sendReferrer) + flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; + + if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) + flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; + + if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) + flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; + + if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) + flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; + + return InternalLoad(aURI, + referrer, + owner, + flags, + target.get(), + nsnull, // No type hint + postStream, + headersStream, + loadType, + nsnull, // No SHEntry + aFirstParty, + nsnull, // No nsIDocShell + nsnull); // No nsIRequest } NS_IMETHODIMP @@ -4440,41 +4462,45 @@ nsDocShell::ForceRefreshURI(nsIURI * aURI, */ loadInfo->SetReferrer(mCurrentURI); + /* Don't ever "guess" on which owner to use to avoid picking + * the current owner. + */ + nsCOMPtr info19 = + do_QueryInterface(loadInfo); + NS_ENSURE_TRUE(info19, NS_ERROR_NO_INTERFACE); + info19->SetOwnerIsExplicit(PR_TRUE); + /* Check if this META refresh causes a redirection * to another site. */ PRBool equalUri = PR_FALSE; nsresult rv = aURI->Equals(mCurrentURI, &equalUri); - if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh) { + if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh && + aDelay <= REFRESH_REDIRECT_TIMER) { - /* It is a META refresh based redirection. Now check if it happened - within the threshold time we have in mind(15000 ms as defined by - REFRESH_REDIRECT_TIMER). If so, pass a REPLACE flag to LoadURI(). + /* It is a META refresh based redirection within the threshold time + * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER). + * Pass a REPLACE flag to LoadURI(). */ - if (aDelay <= REFRESH_REDIRECT_TIMER) { - loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); + loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); - /* for redirects we mimic HTTP, which passes the - * original referrer - */ - nsCOMPtr internalReferrer; - GetReferringURI(getter_AddRefs(internalReferrer)); - if (internalReferrer) { - loadInfo->SetReferrer(internalReferrer); - } - } - else - loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); - /* - * LoadURI(...) will cancel all refresh timers... This causes the - * Timer and its refreshData instance to be released... + /* for redirects we mimic HTTP, which passes the + * original referrer */ - LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE); - return NS_OK; + nsCOMPtr internalReferrer; + GetReferringURI(getter_AddRefs(internalReferrer)); + if (internalReferrer) { + loadInfo->SetReferrer(internalReferrer); + } } - else + else { loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); + } + /* + * LoadURI(...) will cancel all refresh timers... This causes the + * Timer and its refreshData instance to be released... + */ LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE); return NS_OK; @@ -4690,6 +4716,20 @@ nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI, CheckLoadURI(aBaseURI, uri, nsIScriptSecurityManager:: LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr innerURI = NS_GetInnermostURI(uri); + NS_ENSURE_TRUE(innerURI, NS_ERROR_FAILURE); + + PRBool isjs = PR_TRUE; + rv = innerURI->SchemeIs("javascript", &isjs); + NS_ENSURE_SUCCESS(rv, rv); + + if (isjs) { + return NS_ERROR_FAILURE; + } + } + if (NS_SUCCEEDED(rv)) { // Since we can't travel back in time yet, just pretend // negative numbers do nothing at all. diff --git a/mozilla/docshell/base/nsDocShellLoadInfo.cpp b/mozilla/docshell/base/nsDocShellLoadInfo.cpp index e1d634f2ae8..c919e60a2ba 100644 --- a/mozilla/docshell/base/nsDocShellLoadInfo.cpp +++ b/mozilla/docshell/base/nsDocShellLoadInfo.cpp @@ -49,6 +49,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo() : mInheritOwner(PR_FALSE), + mOwnerIsExplicit(PR_FALSE), mSendReferrer(PR_TRUE), mLoadType(nsIDocShellLoadInfo::loadNormal) { @@ -68,6 +69,7 @@ NS_IMPL_RELEASE(nsDocShellLoadInfo) NS_INTERFACE_MAP_BEGIN(nsDocShellLoadInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellLoadInfo) NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo) + NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo_1_9_0_BRANCH) NS_INTERFACE_MAP_END //***************************************************************************** @@ -118,6 +120,18 @@ NS_IMETHODIMP nsDocShellLoadInfo::SetInheritOwner(PRBool aInheritOwner) return NS_OK; } +NS_IMETHODIMP nsDocShellLoadInfo::GetOwnerIsExplicit(PRBool* aOwnerIsExplicit) +{ + *aOwnerIsExplicit = mOwnerIsExplicit; + return NS_OK; +} + +NS_IMETHODIMP nsDocShellLoadInfo::SetOwnerIsExplicit(PRBool aOwnerIsExplicit) +{ + mOwnerIsExplicit = aOwnerIsExplicit; + return NS_OK; +} + NS_IMETHODIMP nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType * aLoadType) { NS_ENSURE_ARG_POINTER(aLoadType); diff --git a/mozilla/docshell/base/nsDocShellLoadInfo.h b/mozilla/docshell/base/nsDocShellLoadInfo.h index c3701a68833..e7d2cb541d5 100644 --- a/mozilla/docshell/base/nsDocShellLoadInfo.h +++ b/mozilla/docshell/base/nsDocShellLoadInfo.h @@ -51,13 +51,14 @@ #include "nsIInputStream.h" #include "nsISHEntry.h" -class nsDocShellLoadInfo : public nsIDocShellLoadInfo +class nsDocShellLoadInfo : public nsIDocShellLoadInfo_1_9_0_BRANCH { public: nsDocShellLoadInfo(); NS_DECL_ISUPPORTS NS_DECL_NSIDOCSHELLLOADINFO + NS_DECL_NSIDOCSHELLLOADINFO_1_9_0_BRANCH protected: virtual ~nsDocShellLoadInfo(); @@ -66,6 +67,7 @@ protected: nsCOMPtr mReferrer; nsCOMPtr mOwner; PRPackedBool mInheritOwner; + PRPackedBool mOwnerIsExplicit; PRPackedBool mSendReferrer; nsDocShellInfoLoadType mLoadType; nsCOMPtr mSHEntry; diff --git a/mozilla/docshell/base/nsIDocShellLoadInfo.idl b/mozilla/docshell/base/nsIDocShellLoadInfo.idl index bf0b30d739a..0d7d82a1a11 100644 --- a/mozilla/docshell/base/nsIDocShellLoadInfo.idl +++ b/mozilla/docshell/base/nsIDocShellLoadInfo.idl @@ -106,3 +106,15 @@ interface nsIDocShellLoadInfo : nsISupports */ attribute boolean sendReferrer; }; + +[scriptable, uuid(b66d94ba-4457-41b1-9507-79c1cd873da0)] +interface nsIDocShellLoadInfo_1_9_0_BRANCH : nsIDocShellLoadInfo +{ + /** If this attribute is true only ever use the owner specify by + * the owner and inheritOwner attributes. + * If there are security reasons for why this is unsafe, such + * as trying to use a systemprincipal owner for a content docshell + * the load fails. + */ + attribute boolean ownerIsExplicit; +}; diff --git a/mozilla/docshell/test/Makefile.in b/mozilla/docshell/test/Makefile.in index 2078525a546..5566f3f69cc 100644 --- a/mozilla/docshell/test/Makefile.in +++ b/mozilla/docshell/test/Makefile.in @@ -68,6 +68,8 @@ _TEST_FILES = \ bug413310-subframe.html \ bug413310-post.sjs \ test_bug402210.html \ + test_bug475636.html \ + file_bug475636.sjs \ $(NULL) libs:: $(_TEST_FILES) diff --git a/mozilla/docshell/test/file_bug475636.sjs b/mozilla/docshell/test/file_bug475636.sjs new file mode 100644 index 00000000000..0cf8df55136 --- /dev/null +++ b/mozilla/docshell/test/file_bug475636.sjs @@ -0,0 +1,69 @@ +jsURL = "javascript:" + escape('window.parent.postMessage("JS uri ran", "*");\ +return \'\ +\''); + +tests = [ +// Plain document should work as normal +'\ +', + +// refresh to plain doc +{ refresh: "file_bug475636.sjs?1", + doc: '' }, + +// meta-refresh to plain doc +'\ +\ + \ +', + +// refresh to js url should not be followed +{ refresh: jsURL, + doc: +'\ +' }, + +// meta refresh to js url should not be followed +'\ +\ + \ +\ +' +]; + + +function handleRequest(request, response) +{ + test = tests[parseInt(request.queryString, 10) - 1]; + response.setHeader("Content-Type", "text/html"); + + if (!test) { + response.write(''); + } + else if (typeof test == "string") { + response.write(test); + } + else if (test.refresh) { + response.setHeader("Refresh", "0; url=" + test.refresh); + response.write(test.doc); + } +} diff --git a/mozilla/docshell/test/test_bug475636.html b/mozilla/docshell/test/test_bug475636.html new file mode 100644 index 00000000000..6da02219085 --- /dev/null +++ b/mozilla/docshell/test/test_bug475636.html @@ -0,0 +1,53 @@ + + + + + Test for Bug 475636 + + + + + + +Mozilla Bug 475636 + + + +
+
+
+ +