Fix bug 657267. r=bz

This commit is contained in:
Blake Kaplan 2011-05-19 13:31:54 +02:00
parent a572e3fb87
commit fbea73993b
12 changed files with 157 additions and 53 deletions

View File

@ -52,7 +52,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSContext(JSContext);
[ptr] native JSPrincipals(JSPrincipals);
[scriptable, uuid(799ab95c-0038-4e0f-b705-74c21f185bb5)]
[scriptable, uuid(B406A2DB-E547-4C95-B8E2-AD09ECB54CE0)]
interface nsIPrincipal : nsISerializable
{
/**
@ -86,6 +86,11 @@ interface nsIPrincipal : nsISerializable
*/
boolean equals(in nsIPrincipal other);
/**
* Like equals, but doesn't take document.domain changes into account.
*/
boolean equalsIgnoringDomain(in nsIPrincipal other);
/**
* Returns a hash value for the principal.
*/

View File

@ -131,6 +131,9 @@ protected:
const nsACString& aPrettyName,
nsISupports* aCert);
// Checks whether this principal's certificate equals aOther's.
PRBool CertificateEquals(nsIPrincipal *aOther);
// Keep this is a pointer, even though it may slightly increase the
// cost of keeping a certificate, this is a good tradeoff though since
// it is very rare that we actually have a certificate.

View File

@ -162,6 +162,12 @@ nsNullPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::EqualsIgnoringDomain(nsIPrincipal *aOther, PRBool *aResult)
{
return Equals(aOther, aResult);
}
NS_IMETHODIMP
nsNullPrincipal::GetHashValue(PRUint32 *aResult)
{

View File

@ -309,42 +309,52 @@ nsPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
return NS_OK;
}
PRBool
nsPrincipal::CertificateEquals(nsIPrincipal *aOther)
{
PRBool otherHasCert;
aOther->GetHasCertificate(&otherHasCert);
if (otherHasCert != (mCert != nsnull)) {
// One has a cert while the other doesn't. Not equal.
return PR_FALSE;
}
if (!mCert)
return PR_TRUE;
nsCAutoString str;
aOther->GetFingerprint(str);
if (!str.Equals(mCert->fingerprint))
return PR_FALSE;
// If either subject name is empty, just let the result stand (so that
// nsScriptSecurityManager::SetCanEnableCapability works), but if they're
// both non-empty, only claim equality if they're equal.
if (!mCert->subjectName.IsEmpty()) {
// Check the other principal's subject name
aOther->GetSubjectName(str);
return str.Equals(mCert->subjectName) || str.IsEmpty();
}
return PR_TRUE;
}
NS_IMETHODIMP
nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
{
*aResult = PR_FALSE;
if (!aOther) {
NS_WARNING("Need a principal to compare this to!");
*aResult = PR_FALSE;
return NS_OK;
}
if (this != aOther) {
PRBool otherHasCert;
aOther->GetHasCertificate(&otherHasCert);
if (otherHasCert != (mCert != nsnull)) {
// One has a cert while the other doesn't. Not equal.
if (!CertificateEquals(aOther)) {
*aResult = PR_FALSE;
return NS_OK;
}
if (mCert) {
nsCAutoString str;
aOther->GetFingerprint(str);
*aResult = str.Equals(mCert->fingerprint);
// If either subject name is empty, just let the result stand (so that
// nsScriptSecurityManager::SetCanEnableCapability works), but if they're
// both non-empty, only claim equality if they're equal.
if (*aResult && !mCert->subjectName.IsEmpty()) {
// Check the other principal's subject name
aOther->GetSubjectName(str);
*aResult = str.Equals(mCert->subjectName) || str.IsEmpty();
}
if (!*aResult) {
return NS_OK;
}
// If either principal has no URI, it's the saved principal from
// preferences; in that case, test true. Do NOT test true if the two
// principals have URIs with different codebases.
@ -356,6 +366,7 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
}
if (!otherURI || !mCodebase) {
*aResult = PR_TRUE;
return NS_OK;
}
@ -373,6 +384,34 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::EqualsIgnoringDomain(nsIPrincipal *aOther, PRBool *aResult)
{
if (this == aOther) {
*aResult = PR_TRUE;
return NS_OK;
}
*aResult = PR_FALSE;
if (!CertificateEquals(aOther)) {
return NS_OK;
}
nsCOMPtr<nsIURI> otherURI;
nsresult rv = aOther->GetURI(getter_AddRefs(otherURI));
if (NS_FAILED(rv)) {
return rv;
}
NS_ASSERTION(mCodebase,
"shouldn't be calling this on principals from preferences");
// Compare codebases.
*aResult = nsScriptSecurityManager::SecurityCompareURIs(mCodebase,
otherURI);
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::Subsumes(nsIPrincipal *aOther, PRBool *aResult)
{

View File

@ -110,6 +110,12 @@ nsSystemPrincipal::Equals(nsIPrincipal *other, PRBool *result)
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::EqualsIgnoringDomain(nsIPrincipal *other, PRBool *result)
{
return Equals(other, result);
}
NS_IMETHODIMP
nsSystemPrincipal::Subsumes(nsIPrincipal *other, PRBool *result)
{

View File

@ -1039,17 +1039,12 @@ xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
NS_ABORT_IF_FALSE(NS_IsMainThread(), "using a principal off the main thread?");
NS_ABORT_IF_FALSE(principal, "bad key");
nsCOMPtr<nsIURI> uri;
nsresult rv = principal->GetURI(getter_AddRefs(uri));
if(NS_FAILED(rv))
return UnexpectedFailure(rv);
XPCCompartmentMap& map = nsXPConnect::GetRuntimeInstance()->GetCompartmentMap();
xpc::PtrAndPrincipalHashKey key(ptr, uri);
xpc::PtrAndPrincipalHashKey key(ptr, principal);
if(!map.Get(&key, compartment))
{
xpc::PtrAndPrincipalHashKey *priv_key =
new xpc::PtrAndPrincipalHashKey(ptr, uri);
new xpc::PtrAndPrincipalHashKey(ptr, principal);
xpc::CompartmentPrivate *priv =
new xpc::CompartmentPrivate(priv_key, wantXrays, NS_IsMainThread());
if(!CreateNewCompartment(cx, clasp, principal, priv,

View File

@ -1,4 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=79:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -47,14 +48,19 @@
PRBool
xpc::PtrAndPrincipalHashKey::KeyEquals(const PtrAndPrincipalHashKey* aKey) const
{
if(aKey->mPtr != mPtr)
return PR_FALSE;
if(aKey->mPtr != mPtr)
return PR_FALSE;
if(aKey->mPrincipal == mPrincipal)
return PR_TRUE;
if(!mURI || !aKey->mURI)
return mURI == aKey->mURI;
PRBool equals;
if(NS_FAILED(mPrincipal->EqualsIgnoringDomain(aKey->mPrincipal, &equals)))
{
NS_ERROR("we failed, guessing!");
return PR_FALSE;
}
nsIScriptSecurityManager *ssm = nsXPConnect::gScriptSecurityManager;
return !ssm || NS_SUCCEEDED(ssm->CheckSameOriginURI(mURI, aKey->mURI, PR_FALSE));
return equals;
}
inline void

View File

@ -247,17 +247,20 @@ class PtrAndPrincipalHashKey : public PLDHashEntryHdr
typedef const PtrAndPrincipalHashKey *KeyTypePointer;
PtrAndPrincipalHashKey(const PtrAndPrincipalHashKey *aKey)
: mPtr(aKey->mPtr), mURI(aKey->mURI), mSavedHash(aKey->mSavedHash)
: mPtr(aKey->mPtr), mPrincipal(aKey->mPrincipal),
mSavedHash(aKey->mSavedHash)
{
MOZ_COUNT_CTOR(PtrAndPrincipalHashKey);
}
PtrAndPrincipalHashKey(nsISupports *aPtr, nsIURI *aURI)
: mPtr(aPtr), mURI(aURI)
PtrAndPrincipalHashKey(nsISupports *aPtr, nsIPrincipal *aPrincipal)
: mPtr(aPtr), mPrincipal(aPrincipal)
{
MOZ_COUNT_CTOR(PtrAndPrincipalHashKey);
mSavedHash = mURI
? NS_SecurityHashURI(mURI)
nsCOMPtr<nsIURI> uri;
aPrincipal->GetURI(getter_AddRefs(uri));
mSavedHash = uri
? NS_SecurityHashURI(uri)
: (NS_PTR_TO_UINT32(mPtr.get()) >> 2);
}
@ -285,7 +288,7 @@ class PtrAndPrincipalHashKey : public PLDHashEntryHdr
protected:
nsCOMPtr<nsISupports> mPtr;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
// During shutdown, when we GC, we need to remove these keys from the hash
// table. However, computing the saved hash, NS_SecurityHashURI calls back

View File

@ -91,6 +91,8 @@ _TEST_FILES = bug500931_helper.html \
test_bug636097.html \
test_bug650273.html \
file_bug650273.html \
test_bug657267.html \
bug657267.jar \
$(NULL)
#test_bug484107.html \

Binary file not shown.

View File

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=657267
-->
<head>
<title>Test for Bug 657267</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=657267">Mozilla Bug 657267</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 657267 **/
function go() {
var win = $('ifr').contentWindow;
try {
win.a();
var thrown = false;
} catch (e) {
thrown = /Permission denied/i.test(e);
}
ok(thrown, "Should have thrown");
}
</script>
</pre>
<iframe src="jar:http://mochi.test:8888/tests/js/src/xpconnect/tests/mochitest/bug657267.jar!/file_bug657267.html"
id="ifr"
onload="go()">
</iframe>
</body>
</html>

View File

@ -72,17 +72,14 @@ AccessCheck::isSameOrigin(JSCompartment *a, JSCompartment *b)
if (!aprin || !bprin)
return true;
nsCOMPtr<nsIURI> auri;
aprin->GetURI(getter_AddRefs(auri));
PRBool equals;
nsresult rv = aprin->EqualsIgnoringDomain(bprin, &equals);
if (NS_FAILED(rv)) {
NS_ERROR("unable to ask about equality");
return false;
}
nsCOMPtr<nsIURI> buri;
bprin->GetURI(getter_AddRefs(buri));
if (!auri || !buri)
return aprin == bprin;
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
return !ssm || NS_SUCCEEDED(ssm->CheckSameOriginURI(auri, buri, PR_FALSE));
return equals;
}
bool