Bug 475636: Disallow refresh to javascript uris. r/sr=bz a=dveditz

git-svn-id: svn://10.0.0.236/trunk@256571 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jonas%sicking.cc
2009-03-18 03:19:04 +00:00
parent f01cfaa6b4
commit fb2a645b5f
7 changed files with 285 additions and 93 deletions

View File

@@ -692,6 +692,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
nsCOMPtr<nsIInputStream> headersStream;
nsCOMPtr<nsISupports> owner;
PRBool inheritOwner = PR_FALSE;
PRBool ownerIsExplicit = PR_FALSE;
PRBool sendReferrer = PR_TRUE;
nsCOMPtr<nsISHEntry> 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<nsIDocShellLoadInfo_1_9_0_BRANCH> 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<nsIScriptSecurityManager> 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<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (owner && mItemType != typeChrome) {
nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
PRBool isSystem;
rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem);
NS_ENSURE_SUCCESS(rv, rv);
if (owner && mItemType != typeChrome) {
nsCOMPtr<nsIPrincipal> 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<nsIDocShellLoadInfo_1_9_0_BRANCH> 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<nsIURI> 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<nsIURI> 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<nsIURI> 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.

View File

@@ -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);

View File

@@ -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<nsIURI> mReferrer;
nsCOMPtr<nsISupports> mOwner;
PRPackedBool mInheritOwner;
PRPackedBool mOwnerIsExplicit;
PRPackedBool mSendReferrer;
nsDocShellInfoLoadType mLoadType;
nsCOMPtr<nsISHEntry> mSHEntry;

View File

@@ -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;
};