bug 580128 - Avoid using the parent chain of proxies for anything because it's often wrong. r=jst

This commit is contained in:
Blake Kaplan 2010-09-24 18:00:58 -07:00
parent cb84d63788
commit 11e65685b7
9 changed files with 94 additions and 65 deletions

View File

@ -52,6 +52,7 @@
#include "nsString.h"
#include "nsNetCID.h"
#include "nsIClassInfoImpl.h"
#include "jsobj.h"
///////////////////////
// nsSecurityNameSet //
@ -294,6 +295,7 @@ nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
{
JSContext *cx = (JSContext *) aScriptContext->GetNativeContext();
JSObject *global = JS_GetGlobalObject(cx);
OBJ_TO_INNER_OBJECT(cx, global);
/*
* Find Object.prototype's class by walking up the global object's

View File

@ -5253,9 +5253,17 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
frameWin->EnsureInnerWindow();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
jsval v;
rv = WrapNative(cx, frameWin->GetGlobalJSObject(), frame,
&NS_GET_IID(nsIDOMWindow), PR_TRUE, vp,
&NS_GET_IID(nsIDOMWindow), PR_TRUE, &v,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
if (!JS_WrapValue(cx, &v)) {
return NS_ERROR_FAILURE;
}
*vp = v;
}
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
@ -6800,8 +6808,9 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// from it.
jsval v;
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, document, &NS_GET_IID(nsIDOMDocument), PR_FALSE,
&v, getter_AddRefs(holder));
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), document,
&NS_GET_IID(nsIDOMDocument), PR_FALSE, &v,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
// The PostCreate hook for the document will handle defining the
@ -7318,7 +7327,8 @@ nsNodeSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, obj, uri, &NS_GET_IID(nsIURI), PR_TRUE, vp,
nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri,
&NS_GET_IID(nsIURI), PR_TRUE, vp,
getter_AddRefs(holder));
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
@ -7328,9 +7338,9 @@ nsNodeSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, obj, node->NodePrincipal(),
&NS_GET_IID(nsIPrincipal), PR_TRUE, vp,
getter_AddRefs(holder));
nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx),
node->NodePrincipal(), &NS_GET_IID(nsIPrincipal),
PR_TRUE, vp, getter_AddRefs(holder));
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
@ -7948,7 +7958,8 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
if (array_item) {
rv = WrapNative(cx, obj, array_item, cache, PR_TRUE, vp);
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), array_item, cache,
PR_TRUE, vp);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_SUCCESS_I_DID_SOMETHING;
@ -8068,7 +8079,8 @@ nsNamedArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
if (item) {
rv = WrapNative(cx, obj, item, cache, PR_TRUE, vp);
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), item, cache,
PR_TRUE, vp);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_SUCCESS_I_DID_SOMETHING;
@ -8243,8 +8255,9 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
jsval v;
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, location, &NS_GET_IID(nsIDOMLocation), PR_TRUE,
&v, getter_AddRefs(holder));
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
&NS_GET_IID(nsIDOMLocation), PR_TRUE, &v,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
@ -8280,7 +8293,8 @@ nsDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, obj, uri, &NS_GET_IID(nsIURI), PR_TRUE, vp,
nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri,
&NS_GET_IID(nsIURI), PR_TRUE, vp,
getter_AddRefs(holder));
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
@ -8312,8 +8326,9 @@ nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, location, &NS_GET_IID(nsIDOMLocation), PR_TRUE,
vp, getter_AddRefs(holder));
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
&NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
getter_AddRefs(holder));
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -8466,11 +8481,7 @@ nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
}
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, retval, PR_FALSE, vp,
getter_AddRefs(holder));
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to wrap native!");
*vp = OBJECT_TO_JSVAL(obj);
return NS_SUCCEEDED(rv);
}
@ -8546,7 +8557,8 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx, JSObject *obj,
}
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv |= nsDOMClassInfo::WrapNative(cx, obj, static_cast<nsINodeList*>(list),
rv |= nsDOMClassInfo::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
static_cast<nsINodeList*>(list),
list, PR_FALSE, &collection,
getter_AddRefs(holder));
@ -8559,7 +8571,7 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx, JSObject *obj,
}
if (NS_FAILED(rv)) {
nsDOMClassInfo::ThrowJSException(cx, rv);
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_FAILURE);
return JS_FALSE;
}
@ -8649,7 +8661,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj,
}
if (result) {
rv = WrapNative(cx, obj, result, cache, PR_TRUE, vp);
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), result, cache, PR_TRUE, vp);
if (NS_FAILED(rv)) {
nsDOMClassInfo::ThrowJSException(cx, rv);
@ -8922,7 +8934,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
if (tags) {
jsval v;
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = nsDOMClassInfo::WrapNative(cx, obj,
nsresult rv = nsDOMClassInfo::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
static_cast<nsINodeList*>(tags),
tags, PR_TRUE, &v,
getter_AddRefs(holder));
@ -9180,7 +9192,8 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
if (control) {
Element *element =
static_cast<nsGenericHTMLFormElement*>(form->GetElementAt(n));
nsresult rv = WrapNative(cx, obj, element, element, PR_TRUE, vp);
nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), element,
element, PR_TRUE, vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -9285,7 +9298,8 @@ nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
if (options) {
nsISupports *node = options->GetNodeAt(n, &rv);
rv = WrapNative(cx, obj, node, &NS_GET_IID(nsIDOMNode), PR_TRUE, vp);
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), node,
&NS_GET_IID(nsIDOMNode), PR_TRUE, vp);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}

View File

@ -1943,9 +1943,25 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
mJSObject = outerObject;
SetWrapper(mJSObject);
{
JSAutoEnterCompartment ac;
if (!ac.enter(cx, mJSObject)) {
NS_ERROR("unable to enter a compartment");
return NS_ERROR_FAILURE;
}
JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
}
mContext->SetOuterObject(mJSObject);
}
JSAutoEnterCompartment ac;
if (!ac.enter(cx, mJSObject)) {
NS_ERROR("unable to enter a compartment");
return NS_ERROR_FAILURE;
}
// XXX Not sure if this is needed.
if (aState) {
JSObject *proto;
@ -1974,16 +1990,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// Loading a new page and creating a new inner window, *not*
// restoring from session history.
// InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner)
// for the new inner window
// sets the global object in cx to be the new wrapped global. We
// don't want that, but re-initializing the outer window will
// fix that for us. And perhaps more importantly, this will
// ensure that the outer window gets a new prototype so we don't
// leak prototype properties from the old inner window to the
// new one.
mContext->InitOuterWindow();
// Now that both the the inner and outer windows are initialized
// let the script context do its magic to hook them together.
mContext->ConnectToInner(newInnerWindow, mJSObject);
@ -2042,7 +2048,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ENSURE_SUCCESS(rv, rv);
// Initialize DOM classes etc on the inner window.
rv = mContext->InitClasses(mJSObject);
rv = mContext->InitClasses(newInnerWindow->mJSObject);
NS_ENSURE_SUCCESS(rv, rv);
if (navigatorHolder) {

View File

@ -2525,6 +2525,12 @@ nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal
// outer (through the JSExtendedClass hook outerObject), so this
// prototype sharing works.
// Now that we're connecting the outer global to the inner one,
// we must have transplanted it. The JS engine tries to maintain
// the global object's compartment as its default compartment,
// so update that now since it might have changed.
JS_SetGlobalObject(mContext, outerGlobal);
// We do *not* want to use anything else out of the outer
// object's prototype chain than the first prototype, which is
// the XPConnect prototype. The rest we want from the inner
@ -2539,11 +2545,6 @@ nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal
JS_SetPrototype(mContext, newInnerJSObject, proto);
JS_SetPrototype(mContext, proto, innerProtoProto);
// Now that we're connecting the outer global to the inner one,
// we must have transplanted it. The JS engine tries to maintain
// the global object's compartment as its default compartment,
// so update that now since it might have changed.
JS_SetGlobalObject(mContext, outerGlobal);
return NS_OK;
}
@ -2639,6 +2640,7 @@ nsresult
nsJSContext::InitOuterWindow()
{
JSObject *global = JS_GetGlobalObject(mContext);
OBJ_TO_INNER_OBJECT(mContext, global);
nsresult rv = InitClasses(global); // this will complete global object initialization
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -45,6 +45,7 @@
#include "nsArrayEnumerator.h"
#include "nsWrapperCache.h"
#include "XPCWrapper.h"
#include "AccessCheck.h"
NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
@ -257,22 +258,9 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
// interface (i.e. whether the interface is scriptable) and most content
// objects don't have QI implementations anyway. Also see bug 503926.
if(XPCPerThreadData::IsMainThread(ccx) &&
!JS_GetGlobalForObject(ccx, jsobj)->isSystem())
!xpc::AccessCheck::isChrome(jsobj->getCompartment(ccx)))
{
nsCOMPtr<nsIPrincipal> objprin;
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if(ssm)
{
nsresult rv = ssm->GetObjectPrincipal(ccx, jsobj, getter_AddRefs(objprin));
NS_ENSURE_SUCCESS(rv, nsnull);
PRBool isSystem;
rv = ssm->IsSystemPrincipal(objprin, &isSystem);
NS_ENSURE_SUCCESS(rv, nsnull);
if(!isSystem)
return nsnull;
}
return nsnull;
}
// check upfront for the existence of the function property
@ -1335,11 +1323,12 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
if(XPCPerThreadData::IsMainThread(ccx))
{
// TODO Remove me in favor of security wrappers.
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if(ssm)
{
nsCOMPtr<nsIPrincipal> objPrincipal;
ssm->GetObjectPrincipal(ccx, obj, getter_AddRefs(objPrincipal));
nsIPrincipal *objPrincipal =
xpc::AccessCheck::getPrincipal(obj->getCompartment(ccx));
if(objPrincipal)
{
JSStackFrame* fp = nsnull;
@ -1515,6 +1504,13 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
}
// build the args
// NB: This assignment *looks* wrong because we haven't yet called our
// function. However, we *have* already entered the compartmen that we're
// about to call, and that's the global that we want here. In other words:
// we're trusting the JS engine to come up with a good global to use for
// our object (whatever it was).
JSObject *scopeobj;
scopeobj = JS_GetGlobalForScopeChain(ccx);
for(i = 0; i < argc; i++)
{
const nsXPTParamInfo& param = info->params[i];
@ -1575,7 +1571,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
if(!XPCConvert::NativeArray2JS(lccx, &val,
(const void**)&pv->val,
datum_type, &param_iid,
array_count, obj, nsnull))
array_count, scopeobj, nsnull))
goto pre_call_clean_up;
}
else if(isSizedString)
@ -1589,7 +1585,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
else
{
if(!XPCConvert::NativeData2JS(ccx, &val, &pv->val, type,
&param_iid, obj, nsnull))
&param_iid, scopeobj, nsnull))
goto pre_call_clean_up;
}
}
@ -1597,7 +1593,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
if(param.IsOut() || param.IsDipper())
{
// create an 'out' object
JSObject* out_obj = NewOutObject(cx, obj);
JSObject* out_obj = NewOutObject(cx, scopeobj);
if(!out_obj)
{
retval = NS_ERROR_OUT_OF_MEMORY;

View File

@ -51,6 +51,7 @@
#include "nsINode.h"
#include "xpcquickstubs.h"
#include "jsproxy.h"
#include "AccessCheck.h"
/***************************************************************************/
@ -518,9 +519,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
JSObject *obj;
wrappedjs->GetJSObject(&obj);
if((obj->isSystem() ||
JS_GetGlobalForObject(ccx, obj)->isSystem()) &&
!Scope->GetGlobalJSObject()->isSystem())
if(xpc::AccessCheck::isChrome(obj->getCompartment(ccx)) &&
!xpc::AccessCheck::isChrome(Scope->GetGlobalJSObject()->getCompartment(ccx)))
{
needsCOW = JS_TRUE;
}

View File

@ -76,6 +76,12 @@ AccessCheck::isChrome(JSCompartment *compartment)
return NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged;
}
nsIPrincipal *
AccessCheck::getPrincipal(JSCompartment *compartment)
{
return GetCompartmentPrincipal(compartment);
}
#define NAME(ch, str, cases) case ch: if (!strcmp(name, str)) switch (prop[0]) { cases }; break;
#define PROP(ch, actions) case ch: { actions }; break;
#define RW(str) if (!strcmp(prop, str)) return true;

View File

@ -40,12 +40,15 @@
#include "jsapi.h"
#include "jswrapper.h"
class nsIPrincipal;
namespace xpc {
class AccessCheck {
public:
static bool isSameOrigin(JSCompartment *a, JSCompartment *b);
static bool isChrome(JSCompartment *compartment);
static nsIPrincipal *getPrincipal(JSCompartment *compartment);
static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id,
JSWrapper::Action act);
static bool isSystemOnlyAccessPermitted(JSContext *cx);

View File

@ -138,7 +138,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
}
}
JSObject *wrapperObj = JSWrapper::New(cx, obj, wrappedProto, NULL, wrapper);
JSObject *wrapperObj = JSWrapper::New(cx, obj, wrappedProto, parent, wrapper);
if (!wrapperObj || !xrayHolder)
return wrapperObj;
wrapperObj->setProxyExtra(js::ObjectValue(*xrayHolder));