Landing followup fix for bug 402983 and re-enabling the new stricter file URI security policies. r+sr=bzbarsky@mit.edu

This commit is contained in:
jst@mozilla.org 2008-03-22 09:50:47 -07:00
parent 6329269a7d
commit a4d3a2e2e3
9 changed files with 123 additions and 71 deletions

View File

@ -410,6 +410,13 @@ public:
CheckSameOriginPrincipal(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRBool aIsCheckConnect);
static PRBool
GetStrictFileOriginPolicy()
{
return sStrictFileOriginPolicy;
}
private:
// GetScriptSecurityManager is the only call that can make one

View File

@ -45,6 +45,8 @@
#include "plstr.h"
#include "nsCRT.h"
#include "nsIURI.h"
#include "nsIFileURL.h"
#include "nsIProtocolHandler.h"
#include "nsNetUtil.h"
#include "nsJSPrincipals.h"
#include "nsVoidArray.h"
@ -304,10 +306,92 @@ nsPrincipal::Subsumes(nsIPrincipal *aOther, PRBool *aResult)
return Equals(aOther, aResult);
}
static PRBool
URIIsLocalFile(nsIURI *aURI)
{
PRBool isFile;
nsCOMPtr<nsINetUtil> util = do_GetIOService();
return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
nsIProtocolHandler::URI_IS_LOCAL_FILE,
&isFile)) &&
isFile;
}
NS_IMETHODIMP
nsPrincipal::CheckMayLoad(nsIURI* aURI, PRBool aReport)
{
if (!nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
URIIsLocalFile(aURI)) {
nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(aURI));
if (!URIIsLocalFile(mCodebase)) {
// If the codebase is not also a file: uri then forget it
// (don't want resource: principals in a file: doc)
//
// note: we're not de-nesting jar: uris here, we want to
// keep archive content bottled up in its own little island
if (aReport) {
nsScriptSecurityManager::ReportError(
nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
}
return NS_ERROR_DOM_BAD_URI;
}
//
// pull out the internal files
//
nsCOMPtr<nsIFileURL> codebaseFileURL(do_QueryInterface(mCodebase));
nsCOMPtr<nsIFile> targetFile;
nsCOMPtr<nsIFile> codebaseFile;
PRBool targetIsDir;
// Make sure targetFile is not a directory (bug 209234)
// and that it exists w/out unescaping (bug 395343)
if (!codebaseFileURL || !fileURL ||
NS_FAILED(fileURL->GetFile(getter_AddRefs(targetFile))) ||
NS_FAILED(codebaseFileURL->GetFile(getter_AddRefs(codebaseFile))) ||
!targetFile || !codebaseFile ||
NS_FAILED(targetFile->Normalize()) ||
NS_FAILED(codebaseFile->Normalize()) ||
NS_FAILED(targetFile->IsDirectory(&targetIsDir)) ||
targetIsDir) {
if (aReport) {
nsScriptSecurityManager::ReportError(
nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
}
return NS_ERROR_DOM_BAD_URI;
}
//
// If the file to be loaded is in a subdirectory of the codebase
// (or same-dir if codebase is not a directory) then it will
// inherit its codebase principal and be scriptable by that codebase.
//
PRBool codebaseIsDir;
PRBool contained = PR_FALSE;
nsresult rv = codebaseFile->IsDirectory(&codebaseIsDir);
if (NS_SUCCEEDED(rv) && codebaseIsDir) {
rv = codebaseFile->Contains(targetFile, PR_TRUE, &contained);
}
else {
nsCOMPtr<nsIFile> codebaseParent;
rv = codebaseFile->GetParent(getter_AddRefs(codebaseParent));
if (NS_SUCCEEDED(rv) && codebaseParent) {
rv = codebaseParent->Contains(targetFile, PR_TRUE, &contained);
}
}
if (NS_SUCCEEDED(rv) && contained) {
return NS_OK;
}
}
if (aReport) {
nsScriptSecurityManager::ReportError(
nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);

View File

@ -1163,6 +1163,11 @@ public:
*/
static void HidePopupsInDocument(nsIDocument* aDocument);
/**
* Return true if aURI is a local file URI (i.e. file://).
*/
static PRBool URIIsLocalFile(nsIURI *aURI);
/**
* Get the application manifest URI for this context. The manifest URI
* is specified in the manifest= attribute of the root element of the

View File

@ -4065,6 +4065,19 @@ nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
#endif
}
/* static */
PRBool
nsContentUtils::URIIsLocalFile(nsIURI *aURI)
{
PRBool isFile;
nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
nsIProtocolHandler::URI_IS_LOCAL_FILE,
&isFile)) &&
isFile;
}
/* static */
void
nsAutoGCRoot::Shutdown()

View File

@ -1245,7 +1245,10 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&inheritPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
if (inheritPrincipal || IsAboutBlank(aURI)) {
if (inheritPrincipal || IsAboutBlank(aURI) ||
(nsContentUtils::URIIsLocalFile(aURI) &&
NS_SUCCEEDED(thisContent->NodePrincipal()->CheckMayLoad(aURI,
PR_FALSE)))) {
chan->SetOwner(thisContent->NodePrincipal());
}

View File

@ -290,7 +290,6 @@ nsDocShell::nsDocShell():
mObserveErrorPages(PR_TRUE),
mAllowAuth(PR_TRUE),
mAllowKeywordFixup(PR_FALSE),
mStrictFilePolicy(PR_TRUE),
mFiredUnloadEvent(PR_FALSE),
mEODForCurrentDocument(PR_FALSE),
mURIResultedInDocument(PR_FALSE),
@ -3593,10 +3592,6 @@ nsDocShell::Create()
}
}
rv = mPrefs->GetBoolPref("security.fileuri.strict_origin_policy", &tmpbool);
if (NS_SUCCEEDED(rv))
mStrictFilePolicy = tmpbool;
// Should we use XUL error pages instead of alerts if possible?
rv = mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool);
if (NS_SUCCEEDED(rv))
@ -7357,66 +7352,10 @@ nsDocShell::DoURILoad(nsIURI * aURI,
// If we don't set the owner explicitly then each file: gets an owner
// based on its own codebase later.
//
if (mStrictFilePolicy && URIIsLocalFile(aURI)) {
nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(aURI));
nsCOMPtr<nsIPrincipal> ownerPrincipal(do_QueryInterface(aOwner));
nsCOMPtr<nsIURI> ownerURI;
if (ownerPrincipal) {
ownerPrincipal->GetURI(getter_AddRefs(ownerURI));
}
if (!URIIsLocalFile(ownerURI)) {
// If the owner is not also a file: uri then forget it
// (don't want resource: principals in a file: doc)
//
// note: we're not de-nesting jar: uris here, we want to
// keep archive content bottled up in its own little island
ownerURI = nsnull;
}
//
// pull out the internal files
//
nsCOMPtr<nsIFileURL> ownerFileURL(do_QueryInterface(ownerURI));
nsCOMPtr<nsIFile> targetFile;
nsCOMPtr<nsIFile> ownerFile;
if (ownerFileURL &&
NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(targetFile))) &&
NS_SUCCEEDED(ownerFileURL->GetFile(getter_AddRefs(ownerFile)))) {
//
// Make sure targetFile is not a directory (bug 209234)
// and that it exists w/out unescaping (bug 395343)
//
PRBool targetIsDir;
if (targetFile && ownerFile &&
NS_SUCCEEDED(targetFile->Normalize()) &&
NS_SUCCEEDED(ownerFile->Normalize()) &&
NS_SUCCEEDED(targetFile->IsDirectory(&targetIsDir)) &&
!targetIsDir) {
//
// If the file to be loaded is in a subdirectory of the owner
// (or same-dir if owner is not a directory) then it will
// inherit its owner principal and be scriptable by that owner.
//
PRBool ownerIsDir;
PRBool contained = PR_FALSE;
rv = ownerFile->IsDirectory(&ownerIsDir);
if (NS_SUCCEEDED(rv) && ownerIsDir) {
rv = ownerFile->Contains(targetFile, PR_TRUE, &contained);
}
else {
nsCOMPtr<nsIFile> ownerParent;
rv = ownerFile->GetParent(getter_AddRefs(ownerParent));
if (NS_SUCCEEDED(rv) && ownerParent) {
rv = ownerParent->Contains(targetFile, PR_TRUE, &contained);
}
}
if (NS_SUCCEEDED(rv) && contained) {
channel->SetOwner(aOwner);
}
}
}
nsCOMPtr<nsIPrincipal> ownerPrincipal(do_QueryInterface(aOwner));
if (URIIsLocalFile(aURI) && ownerPrincipal &&
NS_SUCCEEDED(ownerPrincipal->CheckMayLoad(aURI, PR_FALSE))) {
channel->SetOwner(aOwner);
}
nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);

View File

@ -551,7 +551,6 @@ protected:
PRPackedBool mObserveErrorPages;
PRPackedBool mAllowAuth;
PRPackedBool mAllowKeywordFixup;
PRPackedBool mStrictFilePolicy;
// This boolean is set to true right before we fire pagehide and generally
// unset when we embed a new content viewer. While it's true no navigation

View File

@ -1436,7 +1436,10 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
rv = NS_URIChainHasFlags(aLoadData->mURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&inherit);
if (NS_SUCCEEDED(rv) && inherit) {
if ((NS_SUCCEEDED(rv) && inherit) ||
(nsContentUtils::URIIsLocalFile(aLoadData->mURI) &&
NS_SUCCEEDED(aLoadData->mLoaderPrincipal->
CheckMayLoad(aLoadData->mURI, PR_FALSE)))) {
channel->SetOwner(aLoadData->mLoaderPrincipal);
}
}
@ -1445,8 +1448,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
// model is: Necko owns the stream loader, which owns the load data,
// which owns us
nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader),
aLoadData);
rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
if (NS_SUCCEEDED(rv))
rv = channel->AsyncOpen(streamLoader, nsnull);

View File

@ -501,7 +501,7 @@ pref("advanced.mailftp", false);
pref("image.animation_mode", "normal");
// Same-origin policy for file URIs, "false" is traditional
pref("security.fileuri.strict_origin_policy", false);
pref("security.fileuri.strict_origin_policy", true);
// If there is ever a security firedrill that requires
// us to block certian ports global, this is the pref