Finally kill off CheckSameOriginPrincipal, fix remaining callers to do the checks they really want to be doing. Fix screw-up in nsPrincipal::Equals if one principal has a cert and the other does not. Bug 418996, r=mrbkap,dveditz, sr=jst

This commit is contained in:
2008-03-18 14:14:49 -07:00
parent 6b7fbb8590
commit d8f62e65bf
6 changed files with 63 additions and 58 deletions

View File

@@ -42,7 +42,7 @@ interface nsIURI;
interface nsIChannel; interface nsIChannel;
[scriptable, uuid(ce216cf7-3bcb-48ab-9ff8-d03a24f19ca5)] [scriptable, uuid(3fffd8e8-3fea-442e-a0ed-2ba81ae197d5)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager interface nsIScriptSecurityManager : nsIXPCSecurityManager
{ {
///////////////// Security Checks ////////////////// ///////////////// Security Checks //////////////////
@@ -291,13 +291,6 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
in nsIURI aTargetURI, in nsIURI aTargetURI,
in boolean reportError); in boolean reportError);
/**
* Returns OK if aSourcePrincipal and aTargetPrincipal
* have the same "origin" (scheme, host, and port).
*/
void checkSameOriginPrincipal(in nsIPrincipal aSourcePrincipal,
in nsIPrincipal aTargetPrincipal);
/** /**
* Returns the principal of the global object of the given context, or null * Returns the principal of the global object of the given context, or null
* if no global or no principal. * if no global or no principal.

View File

@@ -406,7 +406,10 @@ public:
static nsresult static nsresult
ReportError(JSContext* cx, const nsAString& messageTag, ReportError(JSContext* cx, const nsAString& messageTag,
nsIURI* aSource, nsIURI* aTarget); nsIURI* aSource, nsIURI* aTarget);
static nsresult
CheckSameOriginPrincipal(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRBool aIsCheckConnect);
private: private:
// GetScriptSecurityManager is the only call that can make one // GetScriptSecurityManager is the only call that can make one
@@ -441,11 +444,6 @@ private:
const char* aClassName, jsval aProperty, const char* aClassName, jsval aProperty,
void** aCachedClassPolicy); void** aCachedClassPolicy);
nsresult
CheckSameOriginPrincipalInternal(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRBool aIsCheckConnect);
nsresult nsresult
CheckSameOriginDOMProp(nsIPrincipal* aSubject, CheckSameOriginDOMProp(nsIPrincipal* aSubject,
nsIPrincipal* aObject, nsIPrincipal* aObject,

View File

@@ -249,13 +249,14 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
} }
if (this != aOther) { if (this != aOther) {
if (mCert) {
PRBool otherHasCert; PRBool otherHasCert;
aOther->GetHasCertificate(&otherHasCert); aOther->GetHasCertificate(&otherHasCert);
if (!otherHasCert) { if (otherHasCert != (mCert != nsnull)) {
// One has a cert while the other doesn't. Not equal.
return NS_OK; return NS_OK;
} }
if (mCert) {
nsCAutoString str; nsCAutoString str;
aOther->GetFingerprint(str); aOther->GetFingerprint(str);
*aResult = str.Equals(mCert->fingerprint); *aResult = str.Equals(mCert->fingerprint);
@@ -292,8 +293,9 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
// Codebases are equal if they have the same origin. // Codebases are equal if they have the same origin.
*aResult = *aResult =
NS_SUCCEEDED(nsScriptSecurityManager::GetScriptSecurityManager() NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
->CheckSameOriginPrincipal(this, aOther)); aOther,
PR_FALSE));
return NS_OK; return NS_OK;
} }

View File

@@ -726,16 +726,6 @@ nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSourcePrincipal,
nsIPrincipal* aTargetPrincipal)
{
return CheckSameOriginPrincipalInternal(aSourcePrincipal,
aTargetPrincipal,
PR_FALSE);
}
nsresult nsresult
nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
nsAXPCNativeCallContext* aCallContext, nsAXPCNativeCallContext* aCallContext,
@@ -962,8 +952,9 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
return rv; return rv;
} }
/* static */
nsresult nsresult
nsScriptSecurityManager::CheckSameOriginPrincipalInternal(nsIPrincipal* aSubject, nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
nsIPrincipal* aObject, nsIPrincipal* aObject,
PRBool aIsCheckConnect) PRBool aIsCheckConnect)
{ {
@@ -1035,8 +1026,19 @@ nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
PRUint32 aAction, PRUint32 aAction,
PRBool aIsCheckConnect) PRBool aIsCheckConnect)
{ {
nsresult rv = CheckSameOriginPrincipalInternal(aSubject, aObject, nsresult rv;
aIsCheckConnect); if (aIsCheckConnect) {
// Don't do equality compares, just do a same-origin compare,
// since the object principal isn't a real principal, just a
// GetCodebasePrincipal() on whatever URI we started with.
rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect);
} else {
PRBool subsumes;
rv = aSubject->Subsumes(aObject, &subsumes);
if (NS_SUCCEEDED(rv) && !subsumes) {
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
}
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
return NS_OK; return NS_OK;
@@ -1696,9 +1698,12 @@ nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
if (!object) if (!object)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
// Note that CheckSameOriginPrincipalInternal already does an equality PRBool subsumes;
// comparison on subject and object, so no need for us to do it. rv = subject->Subsumes(object, &subsumes);
return CheckSameOriginPrincipalInternal(subject, object, PR_TRUE); if (NS_SUCCEEDED(rv) && !subsumes) {
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP

View File

@@ -250,14 +250,14 @@ IsValFrame(JSObject *obj, jsval v, XPCWrappedNative *wn)
return domwin != nsnull; return domwin != nsnull;
} }
// Returns whether the currently executing code has the same origin as the // Returns whether the currently executing code is allowed to access
// wrapper. Uses nsIScriptSecurityManager::CheckSameOriginPrincipal. // the wrapper. Uses nsIPrincipal::Subsumes.
// |cx| must be the top context on the context stack. // |cx| must be the top context on the context stack.
// If the two principals have the same origin, returns NS_OK. If they differ, // If the subject is allowed to access the object returns NS_OK. If not,
// returns NS_ERROR_DOM_PROP_ACCESS_DENIED, returns another error code on // returns NS_ERROR_DOM_PROP_ACCESS_DENIED, returns another error code on
// failure. // failure.
nsresult nsresult
IsWrapperSameOrigin(JSContext *cx, JSObject *wrappedObj) CanAccessWrapper(JSContext *cx, JSObject *wrappedObj)
{ {
// Get the subject principal from the execution stack. // Get the subject principal from the execution stack.
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
@@ -279,6 +279,8 @@ IsWrapperSameOrigin(JSContext *cx, JSObject *wrappedObj)
// If we somehow end up being called from chrome, just allow full access. // If we somehow end up being called from chrome, just allow full access.
// This can happen from components with xpcnativewrappers=no. // This can happen from components with xpcnativewrappers=no.
// Note that this is just an optimization to avoid getting the
// object principal in this case, since Subsumes() would return true.
if (isSystem) { if (isSystem) {
return NS_OK; return NS_OK;
} }
@@ -296,7 +298,12 @@ IsWrapperSameOrigin(JSContext *cx, JSObject *wrappedObj)
} }
// Now, we have our two principals, compare them! // Now, we have our two principals, compare them!
return ssm->CheckSameOriginPrincipal(subjectPrin, objectPrin); PRBool subsumes;
rv = subjectPrin->Subsumes(objectPrin, &subsumes);
if (NS_SUCCEEDED(rv) && !subsumes) {
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
return rv;
} }
static JSBool static JSBool
@@ -333,7 +340,7 @@ XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
} }
nsresult rv = IsWrapperSameOrigin(cx, JSVAL_TO_OBJECT(funToCall)); nsresult rv = CanAccessWrapper(cx, JSVAL_TO_OBJECT(funToCall));
if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
return ThrowException(rv, cx); return ThrowException(rv, cx);
} }
@@ -551,7 +558,7 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
if (!wrappedObj) { if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
// Can't override properties on foreign objects. // Can't override properties on foreign objects.
@@ -571,7 +578,7 @@ XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
if (!wrappedObj) { if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
// Can't delete properties on foreign objects. // Can't delete properties on foreign objects.
@@ -620,7 +627,7 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
if (!wrappedObj) { if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
return JS_FALSE; return JS_FALSE;
@@ -734,7 +741,7 @@ XPC_XOW_Enumerate(JSContext *cx, JSObject *obj)
// Nothing to enumerate. // Nothing to enumerate.
return JS_TRUE; return JS_TRUE;
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
// Can't enumerate on foreign objects. // Can't enumerate on foreign objects.
@@ -760,7 +767,7 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return JS_TRUE; return JS_TRUE;
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
return JS_FALSE; return JS_FALSE;
@@ -840,7 +847,7 @@ XPC_XOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
} }
// Note: JSTYPE_VOID and JSTYPE_STRING are equivalent. // Note: JSTYPE_VOID and JSTYPE_STRING are equivalent.
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv) && if (NS_FAILED(rv) &&
(rv != NS_ERROR_DOM_PROP_ACCESS_DENIED || (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED ||
(type != JSTYPE_STRING && type != JSTYPE_VOID))) { (type != JSTYPE_STRING && type != JSTYPE_VOID))) {
@@ -908,7 +915,7 @@ XPC_XOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
// Nothing to call. // Nothing to call.
return JS_TRUE; return JS_TRUE;
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
// Can't call. // Can't call.
@@ -939,7 +946,7 @@ XPC_XOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
// Nothing to construct. // Nothing to construct.
return JS_TRUE; return JS_TRUE;
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
// Can't construct. // Can't construct.
@@ -963,7 +970,7 @@ JS_STATIC_DLL_CALLBACK(JSBool)
XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
{ {
JSObject *iface = GetWrappedObject(cx, obj); JSObject *iface = GetWrappedObject(cx, obj);
nsresult rv = IsWrapperSameOrigin(cx, iface); nsresult rv = CanAccessWrapper(cx, iface);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
// Don't do this test across origins. // Don't do this test across origins.
@@ -1093,7 +1100,7 @@ XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_TRUE; return JS_TRUE;
} }
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (!ssm) { if (!ssm) {

View File

@@ -79,7 +79,7 @@ XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
XPCWrappedNativeScope *newScope); XPCWrappedNativeScope *newScope);
nsresult nsresult
IsWrapperSameOrigin(JSContext *cx, JSObject *wrappedObj); CanAccessWrapper(JSContext *cx, JSObject *wrappedObj);
inline JSBool inline JSBool
XPC_XOW_ClassNeedsXOW(const char *name) XPC_XOW_ClassNeedsXOW(const char *name)
@@ -208,7 +208,7 @@ public:
} }
JSObject *wrappedObj = JSVAL_TO_OBJECT(v); JSObject *wrappedObj = JSVAL_TO_OBJECT(v);
nsresult rv = IsWrapperSameOrigin(cx, wrappedObj); nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
JS_ClearPendingException(cx); JS_ClearPendingException(cx);
return nsnull; return nsnull;