зеркало из https://github.com/mozilla/pjs.git
Bug 483672 - Give regular JS objects that have been reflected into C++ a security policy that follows the same-origin model. Also teach caps about "same origin" for these cases. r=jst sr=bzbarsky
This commit is contained in:
Родитель
8fb9af0917
Коммит
ea991f3d87
|
@ -529,13 +529,46 @@ private:
|
|||
nsresult
|
||||
SavePrincipal(nsIPrincipal* aToSave);
|
||||
|
||||
/**
|
||||
* Check capability levels for an |aObj| that implements
|
||||
* nsISecurityCheckedComponent.
|
||||
*
|
||||
* NB: This function also checks to see if aObj is a plugin and the user
|
||||
* has set the "security.xpconnect.plugin.unrestricted" pref to allow
|
||||
* anybody to script plugin objects from anywhere.
|
||||
*
|
||||
* @param cx The context we're running on.
|
||||
* NB: If null, "sameOrigin" does not have any effect.
|
||||
* @param aObj The nsISupports representation of the object in question
|
||||
* object, possibly null.
|
||||
* @param aJSObject The JSObject representation of the object in question
|
||||
* if |cx| is non-null and |aObjectSecurityLevel| is
|
||||
* "sameOrigin". If null will be calculated from aObj (if
|
||||
* non-null) if and only if aObj is an XPCWrappedJS. The
|
||||
* rationale behind this is that if we're creating a JS
|
||||
* wrapper for an XPCWrappedJS, this object definitely
|
||||
* expects to be exposed to JS.
|
||||
* @param aSubjectPrincipal The nominal subject principal used when
|
||||
* aObjectSecurityLevel is "sameOrigin". If null,
|
||||
* this is calculated if it's needed.
|
||||
* @param aObjectSecurityLevel Can be one of three values:
|
||||
* - allAccess: Allow access no matter what.
|
||||
* - noAccess: Deny access no matter what.
|
||||
* - sameOrigin: If |cx| is null, behave like noAccess.
|
||||
* Otherwise, possibly compute a subject
|
||||
* and object principal and return true if
|
||||
* and only if the subject has greater than
|
||||
* or equal privileges to the object.
|
||||
*/
|
||||
nsresult
|
||||
CheckXPCPermissions(nsISupports* aObj,
|
||||
CheckXPCPermissions(JSContext* cx,
|
||||
nsISupports* aObj, JSObject* aJSObject,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
const char* aObjectSecurityLevel);
|
||||
|
||||
nsresult
|
||||
Init();
|
||||
|
||||
|
||||
nsresult
|
||||
InitPrefs();
|
||||
|
||||
|
|
|
@ -784,7 +784,8 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
|
|||
}
|
||||
}
|
||||
}
|
||||
rv = CheckXPCPermissions(aObj, objectSecurityLevel);
|
||||
rv = CheckXPCPermissions(cx, aObj, aJSObject, subjectPrincipal,
|
||||
objectSecurityLevel);
|
||||
#ifdef DEBUG_CAPS_CheckPropertyAccessImpl
|
||||
if(NS_SUCCEEDED(rv))
|
||||
printf("CheckXPCPerms GRANTED.\n");
|
||||
|
@ -2858,7 +2859,7 @@ nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
|
|||
if (checkedComponent)
|
||||
checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
|
||||
|
||||
nsresult rv = CheckXPCPermissions(aObj, objectSecurityLevel);
|
||||
nsresult rv = CheckXPCPermissions(cx, aObj, nsnull, nsnull, objectSecurityLevel);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
//-- Access denied, report an error
|
||||
|
@ -2969,7 +2970,7 @@ nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
|
|||
nsCRT::free(cidStr);
|
||||
#endif
|
||||
|
||||
nsresult rv = CheckXPCPermissions(nsnull, nsnull);
|
||||
nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
#ifdef XPC_IDISPATCH_SUPPORT
|
||||
{
|
||||
|
@ -3006,7 +3007,7 @@ nsScriptSecurityManager::CanGetService(JSContext *cx,
|
|||
nsCRT::free(cidStr);
|
||||
#endif
|
||||
|
||||
nsresult rv = CheckXPCPermissions(nsnull, nsnull);
|
||||
nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
//-- Access denied, report an error
|
||||
|
@ -3045,7 +3046,9 @@ nsScriptSecurityManager::CanAccess(PRUint32 aAction,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsScriptSecurityManager::CheckXPCPermissions(nsISupports* aObj,
|
||||
nsScriptSecurityManager::CheckXPCPermissions(JSContext* cx,
|
||||
nsISupports* aObj, JSObject* aJSObject,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
const char* aObjectSecurityLevel)
|
||||
{
|
||||
//-- Check for the all-powerful UniversalXPConnect privilege
|
||||
|
@ -3058,6 +3061,42 @@ nsScriptSecurityManager::CheckXPCPermissions(nsISupports* aObj,
|
|||
{
|
||||
if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
|
||||
return NS_OK;
|
||||
if (cx && PL_strcasecmp(aObjectSecurityLevel, "sameOrigin") == 0)
|
||||
{
|
||||
nsresult rv;
|
||||
if (!aJSObject)
|
||||
{
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> xpcwrappedjs =
|
||||
do_QueryInterface(aObj);
|
||||
if (xpcwrappedjs)
|
||||
{
|
||||
rv = xpcwrappedjs->GetJSObject(&aJSObject);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
if (!aSubjectPrincipal)
|
||||
{
|
||||
// No subject principal passed in. Compute it.
|
||||
aSubjectPrincipal = GetSubjectPrincipal(cx, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
if (aSubjectPrincipal && aJSObject)
|
||||
{
|
||||
nsIPrincipal* objectPrincipal = doGetObjectPrincipal(aJSObject);
|
||||
|
||||
// Only do anything if we have both a subject and object
|
||||
// principal.
|
||||
if (objectPrincipal)
|
||||
{
|
||||
PRBool subsumes;
|
||||
rv = aSubjectPrincipal->Subsumes(objectPrincipal, &subsumes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (subsumes)
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
|
||||
{
|
||||
PRBool canAccess = PR_FALSE;
|
||||
|
|
|
@ -554,6 +554,67 @@ GetContextFromObject(JSObject *obj)
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
#ifndef XPCONNECT_STANDALONE
|
||||
class SameOriginCheckedComponent : public nsISecurityCheckedComponent
|
||||
{
|
||||
public:
|
||||
SameOriginCheckedComponent(nsXPCWrappedJS* delegate)
|
||||
: mDelegate(delegate)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISECURITYCHECKEDCOMPONENT
|
||||
|
||||
private:
|
||||
nsRefPtr<nsXPCWrappedJS> mDelegate;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(SameOriginCheckedComponent)
|
||||
NS_IMPL_RELEASE(SameOriginCheckedComponent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(SameOriginCheckedComponent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISecurityCheckedComponent)
|
||||
NS_INTERFACE_MAP_END_AGGREGATED(mDelegate)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SameOriginCheckedComponent::CanCreateWrapper(const nsIID * iid,
|
||||
char **_retval NS_OUTPARAM)
|
||||
{
|
||||
// XXX This doesn't actually work because nsScriptSecurityManager doesn't
|
||||
// know what to do with "sameOrigin" for canCreateWrapper.
|
||||
*_retval = NS_strdup("sameOrigin");
|
||||
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SameOriginCheckedComponent::CanCallMethod(const nsIID * iid,
|
||||
const PRUnichar *methodName,
|
||||
char **_retval NS_OUTPARAM)
|
||||
{
|
||||
*_retval = NS_strdup("sameOrigin");
|
||||
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SameOriginCheckedComponent::CanGetProperty(const nsIID * iid,
|
||||
const PRUnichar *propertyName,
|
||||
char **_retval NS_OUTPARAM)
|
||||
{
|
||||
*_retval = NS_strdup("sameOrigin");
|
||||
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SameOriginCheckedComponent::CanSetProperty(const nsIID * iid,
|
||||
const PRUnichar *propertyName,
|
||||
char **_retval NS_OUTPARAM)
|
||||
{
|
||||
*_retval = NS_strdup("sameOrigin");
|
||||
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
||||
REFNSIID aIID,
|
||||
|
@ -659,6 +720,14 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
|||
// Before calling out, ensure that we're not about to claim to implement
|
||||
// nsISecurityCheckedComponent for an untrusted object. Doing so causes
|
||||
// problems. See bug 352882.
|
||||
// But if this is a content object, then we might be wrapping it for
|
||||
// content. If our JS object isn't a double-wrapped object (that is, we
|
||||
// don't have XPCWrappedJS(XPCWrappedNative(some C++ object))), then it
|
||||
// definitely will not have classinfo (and therefore won't be a DOM
|
||||
// object). Since content wants to be able to use these objects (directly
|
||||
// or indirectly, see bug 483672), we implement nsISecurityCheckedComponent
|
||||
// for them and tell caps that they are also bound by the same origin
|
||||
// model.
|
||||
|
||||
if(aIID.Equals(NS_GET_IID(nsISecurityCheckedComponent)))
|
||||
{
|
||||
|
@ -666,29 +735,36 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
|||
// known as system) principals. It really wants to do a
|
||||
// UniversalXPConnect type check.
|
||||
|
||||
*aInstancePtr = nsnull;
|
||||
|
||||
if(!XPCPerThreadData::IsMainThread(ccx.GetJSContext()))
|
||||
return NS_NOINTERFACE;
|
||||
|
||||
nsXPConnect *xpc = nsXPConnect::GetXPConnect();
|
||||
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
||||
do_QueryInterface(xpc->GetDefaultSecurityManager());
|
||||
if(!secMan)
|
||||
{
|
||||
*aInstancePtr = nsnull;
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
nsCOMPtr<nsIPrincipal> objPrin;
|
||||
nsresult rv = secMan->GetObjectPrincipal(ccx, self->GetJSObject(),
|
||||
getter_AddRefs(objPrin));
|
||||
if(NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> systemPrin;
|
||||
rv = secMan->GetSystemPrincipal(getter_AddRefs(systemPrin));
|
||||
if(systemPrin != objPrin)
|
||||
rv = NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
JSObject *selfObj = self->GetJSObject();
|
||||
nsCOMPtr<nsIPrincipal> objPrin;
|
||||
nsresult rv = secMan->GetObjectPrincipal(ccx, selfObj,
|
||||
getter_AddRefs(objPrin));
|
||||
if(NS_FAILED(rv))
|
||||
{
|
||||
*aInstancePtr = nsnull;
|
||||
return rv;
|
||||
|
||||
PRBool isSystem;
|
||||
rv = secMan->IsSystemPrincipal(objPrin, &isSystem);
|
||||
if((NS_FAILED(rv) || !isSystem) &&
|
||||
!IS_WRAPPER_CLASS(STOBJ_GET_CLASS(selfObj)))
|
||||
{
|
||||
// A content object.
|
||||
nsRefPtr<SameOriginCheckedComponent> checked =
|
||||
new SameOriginCheckedComponent(self);
|
||||
if(!checked)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
*aInstancePtr = checked.forget().get();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче