This commit is contained in:
jst%mozilla.org 2007-12-12 23:02:26 +00:00
Родитель a36f59651d
Коммит d05eccb938
6 изменённых файлов: 174 добавлений и 50 удалений

Просмотреть файл

@ -409,8 +409,11 @@ private:
// Returns null if a principal cannot be found; generally callers
// should error out at that point.
static nsIPrincipal*
doGetObjectPrincipal(JSContext *cx, JSObject *obj,
PRBool aAllowShortCircuit = PR_FALSE);
doGetObjectPrincipal(JSContext *cx, JSObject *obj
#ifdef DEBUG
, PRBool aAllowShortCircuit = PR_TRUE
#endif
);
// Returns null if a principal cannot be found. Note that rv can be NS_OK
// when this happens -- this means that there was no JS running.

Просмотреть файл

@ -57,6 +57,8 @@
#include "nsDOMError.h"
#include "nsDOMCID.h"
#include "jsdbgapi.h"
#include "jsarena.h"
#include "jsfun.h"
#include "nsIXPConnect.h"
#include "nsIXPCSecurityManager.h"
#include "nsTextFormatter.h"
@ -96,6 +98,14 @@ nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
JSRuntime *nsScriptSecurityManager::sRuntime = 0;
// Info we need about the JSClasses used by XPConnects wrapped
// natives, to avoid having to QI to nsIXPConnectWrappedNative all the
// time when doing security checks.
static const JSClass *sXPCWrappedNativeJSClass;
static JSGetObjectOps sXPCWrappedNativeGetObjOps1;
static JSGetObjectOps sXPCWrappedNativeGetObjOps2;
///////////////////////////
// Convenience Functions //
///////////////////////////
@ -2286,8 +2296,11 @@ nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
// static
nsIPrincipal*
nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj,
PRBool aAllowShortCircuit)
nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj
#ifdef DEBUG
, PRBool aAllowShortCircuit
#endif
)
{
NS_ASSERTION(aCx && aObj, "Bad call to doGetObjectPrincipal()!");
nsIPrincipal* result = nsnull;
@ -2296,58 +2309,125 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj,
JSObject* origObj = aObj;
#endif
do
{
const JSClass *jsClass = JS_GetClass(aCx, aObj);
const JSClass *jsClass = JS_GET_CLASS(aCx, aObj);
if (jsClass && !(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
JSCLASS_PRIVATE_IS_NSISUPPORTS)))
{
// No need to refcount |priv| here.
nsISupports *priv = (nsISupports *)JS_GetPrivate(aCx, aObj);
// A common case seen in this code is that we enter this function
// with aObj being a Function object, whose parent is a Call
// object. Neither of those have object principals, so we can skip
// those objects here before we enter the below loop. That way we
// avoid wasting time checking properties of their classes etc in
// the loop.
/*
* If it's a wrapped native (as most
* JSCLASS_PRIVATE_IS_NSISUPPORTS objects are in mozilla),
* check the underlying native instead.
*/
nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
do_QueryInterface(priv);
if (jsClass == &js_FunctionClass) {
aObj = JS_GetParent(aCx, aObj);
if (NS_LIKELY(xpcWrapper != nsnull))
{
if (NS_UNLIKELY(aAllowShortCircuit))
{
result = xpcWrapper->GetObjectPrincipal();
}
else
{
nsCOMPtr<nsIScriptObjectPrincipal> objPrin;
objPrin = do_QueryWrappedNative(xpcWrapper);
if (objPrin)
{
result = objPrin->GetPrincipal();
}
}
}
else
{
nsCOMPtr<nsIScriptObjectPrincipal> objPrin;
objPrin = do_QueryInterface(priv);
if (objPrin)
{
result = objPrin->GetPrincipal();
if (!aObj)
return nsnull;
jsClass = JS_GET_CLASS(aCx, aObj);
if (jsClass == &js_CallClass) {
aObj = JS_GetParent(aCx, aObj);
if (!aObj)
return nsnull;
jsClass = JS_GET_CLASS(aCx, aObj);
}
}
if (result)
{
do {
// Note: jsClass is set before this loop, and also at the
// *end* of this loop.
// NOTE: These class and getObjectOps hook checks better match
// what IS_WRAPPER_CLASS() does in xpconnect!
if (jsClass == sXPCWrappedNativeJSClass ||
jsClass->getObjectOps == sXPCWrappedNativeGetObjOps1 ||
jsClass->getObjectOps == sXPCWrappedNativeGetObjOps2) {
nsIXPConnectWrappedNative *xpcWrapper =
(nsIXPConnectWrappedNative *)JS_GetPrivate(aCx, aObj);
if (xpcWrapper) {
nsISupports *native = xpcWrapper->Native();
char ch = jsClass->name[0];
// XXXjst: Ideally this code would simply call into
// xpcWrapper->GetObjectPrincipal() and use that if we
// find a principal through that. If not, we can fall
// back to the below code. See bug 317240.
// For classes that are unlikely to be window object
// classes (Window, ModalContentWindow, and
// ChromeWindow), check if the native pointer is an
// nsINode. Note that this is merely a performance
// optimization, so missing this optimization is
// non-critical and must result in us finding the same
// principal that we would have gotten by asking the
// nsINode here.
if (ch != 'W' && ch != 'M' && ch != 'C'
#ifdef DEBUG
&& aAllowShortCircuit
#endif
) {
nsCOMPtr<nsINode> node = do_QueryInterface(native);
if (node) {
result = node->NodePrincipal();
// NodePrincipal() *always* returns a
// principal.
break;
}
}
// If not, check if it points to an
// nsIScriptObjectPrincipal
nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
do_QueryInterface(native);
if (objPrin) {
result = objPrin->GetPrincipal();
if (result) {
break;
}
}
}
} else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
nsISupports *priv = (nsISupports *)JS_GetPrivate(aCx, aObj);
#ifdef DEBUG
if (aAllowShortCircuit) {
nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
do_QueryInterface(priv);
NS_ASSERTION(!xpcWrapper,
"Uh, an nsIXPConnectWrappedNative with the "
"wrong JSClass or getObjectOps hooks!");
}
#endif
nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
do_QueryInterface(priv);
if (objPrin) {
result = objPrin->GetPrincipal();
if (result) {
break;
}
}
}
aObj = JS_GetParent(aCx, aObj);
} while (aObj);
if (!aObj)
break;
jsClass = JS_GET_CLASS(aCx, aObj);
} while (1);
NS_ASSERTION(!aAllowShortCircuit ||
result == doGetObjectPrincipal(aCx, origObj, PR_FALSE),
@ -3232,6 +3312,10 @@ nsresult nsScriptSecurityManager::Init()
#endif
JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);
sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass,
&sXPCWrappedNativeGetObjOps1,
&sXPCWrappedNativeGetObjOps2);
// For now, assert that no callback was set previously
NS_ASSERTION(!oldCallback, "Someone already set a JS CheckObjectAccess callback");
return NS_OK;

Просмотреть файл

@ -102,7 +102,7 @@ struct JSFunction {
: (fun)->nargs)
extern JSClass js_ArgumentsClass;
extern JSClass js_CallClass;
extern JS_FRIEND_DATA(JSClass) js_CallClass;
/* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */
extern JS_FRIEND_DATA(JSClass) js_FunctionClass;

Просмотреть файл

@ -62,6 +62,8 @@
[ptr] native JSObjectPtr(JSObject);
[ptr] native JSValPtr(jsval);
native JSVal(jsval);
[ptr] native JSClassConstPtr(const JSClass);
native JSGetObjectOps(JSGetObjectOps);
native JSID(jsid);
[ptr] native voidPtrPtr(void*);
[ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
@ -445,7 +447,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
%}
[uuid(9f45711b-bf4f-4af6-a71d-d165f042986d)]
[uuid(256a41a5-10e6-40a1-8392-8baa4adfabe2)]
interface nsIXPConnect : nsISupports
{
%{ C++
@ -751,4 +753,14 @@ interface nsIXPConnect : nsISupports
*/
[noscript,notxpcom] void noteJSContext(in JSContextPtr aJSContext,
in nsCCTraversalCallbackRef aCb);
/**
* Get the JSClass and JSGetObjectOps pointers to use for
* identifying JSObjects that hold nsIXPConnectWrappedNative
* pointers in their private date. See IS_WRAPPER_CLASS in
* xpcprivate.h for details.
*/
void GetXPCWrappedNativeJSClassInfo(out JSClassConstPtr clazz,
out JSGetObjectOps ops1,
out JSGetObjectOps ops2);
};

Просмотреть файл

@ -1861,6 +1861,23 @@ nsXPConnect::EvalInSandboxObject(const nsAString& source, JSContext *cx,
#endif /* XPCONNECT_STANDALONE */
}
/* void GetXPCWrappedNativeJSClassInfo(out JSClassConstPtr clazz, out JSObjectOpsConstPtr ops1, out JSObjectOpsConstPtr ops2); */
NS_IMETHODIMP
nsXPConnect::GetXPCWrappedNativeJSClassInfo(const JSClass **clazz,
JSGetObjectOps *ops1,
JSGetObjectOps *ops2)
{
// Expose the JSClass and JSGetObjectOps pointers used by
// IS_WRAPPER_CLASS(). If that macro ever changes, this function
// needs to stay in sync.
*clazz = &XPC_WN_NoHelper_JSClass.base;
*ops1 = XPC_WN_GetObjectOpsNoCall;
*ops2 = XPC_WN_GetObjectOpsWithCall;
return NS_OK;
}
/* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */
NS_IMETHODIMP
nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,

Просмотреть файл

@ -251,6 +251,14 @@ extern const char XPC_XPCONNECT_CONTRACTID[];
*dest = result; \
return (result || !src) ? NS_OK : NS_ERROR_OUT_OF_MEMORY
// NOTE!!!
//
// If this ever changes,
// nsScriptSecurityManager::doGetObjectPrincipal() *must* be updated
// also!
//
// NOTE!!!
#define IS_WRAPPER_CLASS(clazz) \
((clazz) == &XPC_WN_NoHelper_JSClass.base || \
(clazz)->getObjectOps == XPC_WN_GetObjectOpsNoCall || \