Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 475636: Disallow refresh to javascript uris. r/sr=bz
--HG--
extra : rebase_source : 1fdfc3148c257aee22001be045258cc985ee027a
  • Loading branch information
sicking committed Mar 10, 2009
1 parent 85dc493 commit 86a18a5
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 90 deletions.
208 changes: 119 additions & 89 deletions docshell/base/nsDocShell.cpp
Expand Up @@ -727,6 +727,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;
Expand All @@ -745,6 +746,7 @@ nsDocShell::LoadURI(nsIURI * aURI,

aLoadInfo->GetOwner(getter_AddRefs(owner));
aLoadInfo->GetInheritOwner(&inheritOwner);
aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
aLoadInfo->GetTarget(getter_Copies(target));
aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
Expand Down Expand Up @@ -862,84 +864,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;
PRUint32 flags = 0;

if (inheritOwner)
flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
if (inheritOwner)
flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;

if (!sendReferrer)
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
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
}
if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;

return rv;
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
Expand Down Expand Up @@ -4576,41 +4593,42 @@ nsDocShell::ForceRefreshURI(nsIURI * aURI,
*/
loadInfo->SetReferrer(mCurrentURI);

/* Don't ever "guess" on which owner to use to avoid picking
* the current owner.
*/
loadInfo->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;
Expand Down Expand Up @@ -4826,6 +4844,18 @@ nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
CheckLoadURI(aBaseURI, uri,
nsIScriptSecurityManager::
LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);

if (NS_SUCCEEDED(rv)) {
PRBool isjs = PR_TRUE;
rv = NS_URIChainHasFlags(uri,
nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &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.
Expand Down
13 changes: 13 additions & 0 deletions docshell/base/nsDocShellLoadInfo.cpp
Expand Up @@ -49,6 +49,7 @@

nsDocShellLoadInfo::nsDocShellLoadInfo()
: mInheritOwner(PR_FALSE),
mOwnerIsExplicit(PR_FALSE),
mSendReferrer(PR_TRUE),
mLoadType(nsIDocShellLoadInfo::loadNormal)
{
Expand Down Expand Up @@ -118,6 +119,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);
Expand Down
1 change: 1 addition & 0 deletions docshell/base/nsDocShellLoadInfo.h
Expand Up @@ -66,6 +66,7 @@ class nsDocShellLoadInfo : public nsIDocShellLoadInfo
nsCOMPtr<nsIURI> mReferrer;
nsCOMPtr<nsISupports> mOwner;
PRPackedBool mInheritOwner;
PRPackedBool mOwnerIsExplicit;
PRPackedBool mSendReferrer;
nsDocShellInfoLoadType mLoadType;
nsCOMPtr<nsISHEntry> mSHEntry;
Expand Down
10 changes: 9 additions & 1 deletion docshell/base/nsIDocShellLoadInfo.idl
Expand Up @@ -51,7 +51,7 @@ interface nsISHEntry;

typedef long nsDocShellInfoLoadType;

[scriptable, uuid(4f813a88-7aca-4607-9896-d97270cdf15e)]
[scriptable, uuid(92a0a637-373e-4647-9476-ead11e005c75)]
interface nsIDocShellLoadInfo : nsISupports
{
/** This is the referrer for the load. */
Expand All @@ -67,6 +67,14 @@ interface nsIDocShellLoadInfo : nsISupports
*/
attribute boolean inheritOwner;

/** 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;

/* these are load type enums... */
const long loadNormal = 0; // Normal Load
const long loadNormalReplace = 1; // Normal Load but replaces current history slot
Expand Down
2 changes: 2 additions & 0 deletions docshell/test/Makefile.in
Expand Up @@ -69,6 +69,8 @@ _TEST_FILES = \
bug413310-subframe.html \
bug413310-post.sjs \
test_bug402210.html \
test_bug475636.html \
file_bug475636.sjs \
$(NULL)

libs:: $(_TEST_FILES)
Expand Down

0 comments on commit 86a18a5

Please sign in to comment.