diff --git a/content/base/src/nsInProcessTabChildGlobal.cpp b/content/base/src/nsInProcessTabChildGlobal.cpp index 2784152826a..9b7da728d37 100644 --- a/content/base/src/nsInProcessTabChildGlobal.cpp +++ b/content/base/src/nsInProcessTabChildGlobal.cpp @@ -61,7 +61,7 @@ bool SendSyncMessageToParent(void* aCallbackData, nsTArray > asyncMessages; asyncMessages.SwapElements(tabChild->mASyncMessages); PRUint32 len = asyncMessages.Length(); - for (PRInt32 i = 0; i < len; ++i) { + for (PRUint32 i = 0; i < len; ++i) { nsCOMPtr async = asyncMessages[i]; async->Run(); } @@ -286,8 +286,9 @@ nsInProcessTabChildGlobal::InitTabChildGlobal() nsresult rv = xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports, - NS_GET_IID(nsISupports), flags, - getter_AddRefs(mGlobal)); + NS_GET_IID(nsISupports), + GetPrincipal(), EmptyCString(), + flags, getter_AddRefs(mGlobal)); NS_ENSURE_SUCCESS(rv, false); JSObject* global = nsnull; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 9ddbb00b838..ccc64e7f898 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1302,7 +1302,10 @@ nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptCont aScriptContext->SetGCOnDestruction(PR_FALSE); } - aScriptContext->CreateOuterObject(this); + nsCOMPtr principal = + do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); + + aScriptContext->CreateOuterObject(this, principal); aScriptContext->DidInitializeContext(); mJSObject = (JSObject *)aScriptContext->GetNativeGlobal(); } @@ -1617,6 +1620,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, Thaw(); } + // XXX Brain transplant outer window JSObject and create new one! + NS_ASSERTION(!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDocument() == mDocument, "Uh, mDocument doesn't match the current inner window " @@ -1815,6 +1820,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, void *&newGlobal = (void *&)newInnerWindow->mJSObject; nsCOMPtr &holder = mInnerWindowHolder; rv = mContext->CreateNativeGlobalForInner(sgo, isChrome, + aDocument->NodePrincipal(), &newGlobal, getter_AddRefs(holder)); NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder, diff --git a/dom/base/nsIScriptContext.h b/dom/base/nsIScriptContext.h index 4ba446a2d7f..dd9480ab4e6 100644 --- a/dom/base/nsIScriptContext.h +++ b/dom/base/nsIScriptContext.h @@ -72,10 +72,10 @@ public: NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal, NS_ISCRIPTCONTEXTPRINCIPAL_IID) -// 5a5d683e-f387-4694-9ff0-3a90b3e6749e +// 5b6d04a3-f095-4924-ad84-4f44f9b3fae0 #define NS_ISCRIPTCONTEXT_IID \ -{ 0x5a5d683e, 0xf387, 0x4694, \ - { 0x9f, 0xf0, 0x3a, 0x90, 0xb3, 0xe6, 0x74, 0x9e } } +{ 0x5b6d04a3, 0xf095, 0x4924, \ + { 0xad, 0x84, 0x4f, 0x44, 0xf9, 0xb3, 0xfa, 0xe0 } } /* This MUST match JSVERSION_DEFAULT. This version stuff if we don't know what language we have is a little silly... */ @@ -320,6 +320,7 @@ public: virtual nsresult CreateNativeGlobalForInner( nsIScriptGlobalObject *aNewInner, PRBool aIsChrome, + nsIPrincipal *aPrincipal, void **aNativeGlobal, nsISupports **aHolder) = 0; @@ -342,7 +343,8 @@ public: * * @param aGlobalObject The script global object to use as our global. */ - virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject) = 0; + virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject, + nsIPrincipal *aPrincipal) = 0; /** * Prepares this context for use with the current inner window for the diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 8341b9947c4..8441a1b54f6 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1590,6 +1590,13 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript, JSAutoRequest ar(mContext); nsJSVersionSetter setVersion(mContext, aVersion); + JSAutoCrossCompartmentCall accc; + if (!accc.enter(mContext, (JSObject *)aScopeObject)) { + JSPRINCIPALS_DROP(mContext, jsprin); + stack->Pop(nsnull); + return NS_ERROR_FAILURE; + } + ++mExecuteDepth; ok = ::JS_EvaluateUCScriptForPrincipals(mContext, @@ -1777,6 +1784,13 @@ nsJSContext::EvaluateString(const nsAString& aScript, // check it isn't JSVERSION_UNKNOWN. if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) { JSAutoRequest ar(mContext); + JSAutoCrossCompartmentCall accc; + if (!accc.enter(mContext, (JSObject *)aScopeObject)) { + stack->Pop(nsnull); + JSPRINCIPALS_DROP(mContext, jsprin); + return NS_ERROR_FAILURE; + } + nsJSVersionSetter setVersion(mContext, aVersion); ok = ::JS_EvaluateUCScriptForPrincipals(mContext, @@ -2202,6 +2216,12 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval funval = OBJECT_TO_JSVAL(static_cast(aHandler)); JSAutoRequest ar(mContext); + JSAutoCrossCompartmentCall accc; + if (!accc.enter(mContext, target)) { + stack->Pop(nsnull); + return NS_ERROR_FAILURE; + } + ++mExecuteDepth; PRBool ok = ::JS_CallFunctionValue(mContext, target, funval, argc, argv, &rval); @@ -2517,6 +2537,7 @@ nsresult nsJSContext::CreateNativeGlobalForInner( nsIScriptGlobalObject *aNewInner, PRBool aIsChrome, + nsIPrincipal *aPrincipal, void **aNativeGlobal, nsISupports **aHolder) { nsIXPConnect *xpc = nsContentUtils::XPConnect(); @@ -2525,6 +2546,7 @@ nsJSContext::CreateNativeGlobalForInner( nsresult rv = xpc-> InitClassesWithNewWrappedGlobal(mContext, aNewInner, NS_GET_IID(nsISupports), + aPrincipal, EmptyCString(), flags, getter_AddRefs(jsholder)); if (NS_FAILED(rv)) @@ -2605,7 +2627,8 @@ nsJSContext::InitContext() } nsresult -nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject) +nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject, + nsIPrincipal *aPrincipal) { NS_PRECONDITION(!JS_GetGlobalObject(mContext), "Outer window already initialized"); @@ -2631,6 +2654,7 @@ nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject) nsresult rv = xpc->InitClassesWithNewWrappedGlobal(mContext, aGlobalObject, NS_GET_IID(nsISupports), + aPrincipal, EmptyCString(), flags, getter_AddRefs(holder)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index e01a05d9e0b..df0255c45ec 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -135,12 +135,14 @@ public: virtual nsresult CreateNativeGlobalForInner( nsIScriptGlobalObject *aGlobal, PRBool aIsChrome, + nsIPrincipal *aPrincipal, void **aNativeGlobal, nsISupports **aHolder); virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal); virtual nsresult InitContext(); - virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject); + virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject, + nsIPrincipal *aPrincipal); virtual nsresult InitOuterWindow(); virtual PRBool IsContextInitialized(); virtual void FinalizeContext(); diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 8591b52c281..6fbe17705a0 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -993,8 +993,9 @@ TabChild::InitTabChildGlobal() nsresult rv = xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports, - NS_GET_IID(nsISupports), flags, - getter_AddRefs(mRootGlobal)); + NS_GET_IID(nsISupports), + scope->GetPrincipal(), EmptyCString(), + flags, getter_AddRefs(mRootGlobal)); NS_ENSURE_SUCCESS(rv, false); nsCOMPtr root = do_QueryInterface(chromeHandler); diff --git a/dom/src/threads/nsDOMWorker.cpp b/dom/src/threads/nsDOMWorker.cpp index 61e8fe9405e..a5d07718d03 100644 --- a/dom/src/threads/nsDOMWorker.cpp +++ b/dom/src/threads/nsDOMWorker.cpp @@ -1611,10 +1611,14 @@ nsDOMWorker::CompileGlobalObject(JSContext* aCx) const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES | nsIXPConnect::OMIT_COMPONENTS_OBJECT; + nsCAutoString origin("DOM worker: "); + origin.AppendInt((PRUint64)this); + nsCOMPtr globalWrapper; nsresult rv = xpc->InitClassesWithNewWrappedGlobal(aCx, scopeSupports, - NS_GET_IID(nsISupports), flags, + NS_GET_IID(nsISupports), nsnull, + origin, flags, getter_AddRefs(globalWrapper)); NS_ENSURE_SUCCESS(rv, PR_FALSE); diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp index 907b5296ddc..0d4ccab5fd6 100644 --- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -270,7 +270,7 @@ GetLine(char *bufp, const char *prompt) { char line[256]; - fprintf(stdout, prompt); + fputs(prompt, stdout); fflush(stdout); if (!fgets(line, sizeof line, file)) return JS_FALSE; @@ -1171,6 +1171,8 @@ XPCShellEnvironment::Init() nsCOMPtr holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass, NS_GET_IID(nsISupports), + principal, + EmptyCString(), nsIXPConnect:: FLAG_SYSTEM_GLOBAL_OBJECT, getter_AddRefs(holder)); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index aeb9ebcc85e..2ab2ace8967 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1081,6 +1081,14 @@ JS_GetImplementationVersion(void) return "JavaScript-C 1.8.0 pre-release 1 2007-10-03"; } +JS_PUBLIC_API(JSCompartmentCallback) +JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback) +{ + JSCompartmentCallback old = rt->compartmentCallback; + rt->compartmentCallback = callback; + return old; +} + JS_PUBLIC_API(JSWrapObjectCallback) JS_SetWrapObjectCallback(JSContext *cx, JSWrapObjectCallback callback) { @@ -1115,6 +1123,50 @@ JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call) delete realcall; } +bool +JSAutoCrossCompartmentCall::enter(JSContext *cx, JSObject *target) +{ + JS_ASSERT(!call); + if (cx->compartment == target->getCompartment(cx)) + return true; + call = JS_EnterCrossCompartmentCall(cx, target); + return call != NULL; +} + +JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx, + JSCompartment *newCompartment) + : cx(cx), compartment(cx->compartment) +{ + cx->compartment = newCompartment; +} + +JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx, JSObject *target) + : cx(cx), compartment(cx->compartment) +{ + cx->compartment = target->getCompartment(cx); +} + +JSAutoEnterCompartment::~JSAutoEnterCompartment() +{ + cx->compartment = compartment; +} + +JS_PUBLIC_API(void *) +JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data) +{ + CHECK_REQUEST(cx); + void *old = compartment->data; + compartment->data = data; + return old; +} + +JS_PUBLIC_API(void *) +JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment) +{ + CHECK_REQUEST(cx); + return compartment->data; +} + JS_PUBLIC_API(JSObject *) JS_GetGlobalObject(JSContext *cx) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 657311b550d..881f86019fe 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -937,6 +937,9 @@ JS_ToggleOptions(JSContext *cx, uint32 options); extern JS_PUBLIC_API(const char *) JS_GetImplementationVersion(void); +extern JS_PUBLIC_API(JSCompartmentCallback) +JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback); + extern JS_PUBLIC_API(JSWrapObjectCallback) JS_SetWrapObjectCallback(JSContext *cx, JSWrapObjectCallback callback); @@ -946,20 +949,22 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target); extern JS_PUBLIC_API(void) JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call); +extern JS_PUBLIC_API(void *) +JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data); + +extern JS_PUBLIC_API(void *) +JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment); + #ifdef __cplusplus JS_END_EXTERN_C -class JSAutoCrossCompartmentCall +class JS_PUBLIC_API(JSAutoCrossCompartmentCall) { JSCrossCompartmentCall *call; public: JSAutoCrossCompartmentCall() : call(NULL) {} - bool enter(JSContext *cx, JSObject *target) { - JS_ASSERT(!call); - call = JS_EnterCrossCompartmentCall(cx, target); - return call != NULL; - } + bool enter(JSContext *cx, JSObject *target); ~JSAutoCrossCompartmentCall() { if (call) @@ -967,6 +972,16 @@ class JSAutoCrossCompartmentCall } }; +class JS_FRIEND_API(JSAutoEnterCompartment) +{ + JSContext *cx; + JSCompartment *compartment; + public: + JSAutoEnterCompartment(JSContext *cx, JSCompartment *newCompartment); + JSAutoEnterCompartment(JSContext *cx, JSObject *target); + ~JSAutoEnterCompartment(); +}; + JS_BEGIN_EXTERN_C #endif diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index c15e2df1138..3a81cf7a68a 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1183,6 +1183,7 @@ class AutoIdVector; struct JSCompartment { JSRuntime *rt; JSPrincipals *principals; + void *data; bool marked; js::WrapperMap crossCompartmentWrappers; @@ -1220,6 +1221,9 @@ struct JSRuntime { /* Context create/destroy callback. */ JSContextCallback cxCallback; + /* Compartment create/destroy callback. */ + JSCompartmentCallback compartmentCallback; + /* * Shape regenerated whenever a prototype implicated by an "add property" * property cache fill and induced trace guard has a readonly property or a diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 1a7d9527e55..140c8ef15fb 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2967,6 +2967,7 @@ static void SweepCompartments(JSContext *cx) { JSRuntime *rt = cx->runtime; + JSCompartmentCallback callback = rt->compartmentCallback; JSCompartment **read = rt->compartments.begin(); JSCompartment **end = rt->compartments.end(); JSCompartment **write = read; @@ -2978,6 +2979,8 @@ SweepCompartments(JSContext *cx) /* Remove dead wrappers from the compartment map. */ compartment->sweep(cx); } else { + if (callback) + (void) callback(cx, compartment, JSCOMPARTMENT_DESTROY); if (compartment->principals) JSPRINCIPALS_DROP(cx, compartment->principals); delete compartment; @@ -3568,7 +3571,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals) JSCompartment *compartment = new JSCompartment(rt); if (!compartment || !compartment->init()) { JS_ReportOutOfMemory(cx); - return false; + return NULL; } if (principals) { @@ -3576,12 +3579,21 @@ NewCompartment(JSContext *cx, JSPrincipals *principals) JSPRINCIPALS_HOLD(cx, principals); } - AutoLockGC lock(rt); + { + AutoLockGC lock(rt); - if (!rt->compartments.append(compartment)) { - AutoUnlockGC unlock(rt); - JS_ReportOutOfMemory(cx); - return false; + if (!rt->compartments.append(compartment)) { + AutoUnlockGC unlock(rt); + JS_ReportOutOfMemory(cx); + return NULL; + } + } + + JSCompartmentCallback callback = rt->compartmentCallback; + if (callback && !callback(cx, compartment, JSCOMPARTMENT_NEW)) { + AutoLockGC lock(rt); + rt->compartments.popBack(); + return NULL; } return compartment; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index c030ee972e6..5b44c866ae8 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -594,6 +594,14 @@ typedef JSBool typedef JSObject * (* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, uintN flags); +typedef enum { + JSCOMPARTMENT_NEW, /* XXX Does it make sense to have a NEW? */ + JSCOMPARTMENT_DESTROY +} JSCompartmentOp; + +typedef JSBool +(* JSCompartmentCallback)(JSContext *cx, JSCompartment *compartment, uintN compartmentOp); + JS_END_EXTERN_C #endif /* jspubtd_h___ */ diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index d776d980541..45ad64ffbaa 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -289,7 +289,7 @@ TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, u } JSCompartment::JSCompartment(JSRuntime *rt) - : rt(rt), principals(NULL), marked(false) + : rt(rt), principals(NULL), data(NULL), marked(false) { } diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 814a180f621..2cb412b61e5 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -144,7 +144,7 @@ class JSCrossCompartmentWrapper : public JSWrapper { namespace js { -class AutoCompartment +class JS_FRIEND_API(AutoCompartment) { public: JSContext * const context; diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index f384ec58d85..921b8c21d5b 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -397,7 +397,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[uuid(c53c54ac-afc1-458a-98f5-cadb52574e40)] +[uuid(68090BF7-EA5A-4C9E-BAF9-DB7AF857AC09)] interface nsIXPConnect : nsISupports { %{ C++ @@ -427,12 +427,27 @@ interface nsIXPConnect : nsISupports * below). If you do not pass INIT_JS_STANDARD_CLASSES, then aCOMObj * must implement nsIXPCScriptable so it can resolve the standard * classes when asked by the JS engine. + * + * @param aJSContext the context to use while creating the global object. + * @param aCOMObj the native object that represents the global object. + * @param aIID the IID used to wrap the global object. + * @param aPrincipal the principal of the code that will run in this + * compartment. Can be null. If no specific origin is + * passed, will be used to compute the origin. + * @param aOrigin must be passed if aPrincipal is null. If non-empty, + * overrides aPrincipal's origin. (can be used to separate + * code from the same principals into different + * comartments, like sandboxes). + * @param aFlags one of the flags below specifying what options this + * global object wants. */ nsIXPConnectJSObjectHolder initClassesWithNewWrappedGlobal( in JSContextPtr aJSContext, in nsISupports aCOMObj, in nsIIDRef aIID, + in nsIPrincipal aPrincipal, + in ACString aOrigin, in PRUint32 aFlags); const PRUint32 INIT_JS_STANDARD_CLASSES = 1 << 0; diff --git a/js/src/xpconnect/loader/mozJSComponentLoader.cpp b/js/src/xpconnect/loader/mozJSComponentLoader.cpp index f131abad4e6..1d6b7d9e099 100644 --- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp @@ -1208,6 +1208,8 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile, nsCOMPtr holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass, NS_GET_IID(nsISupports), + mSystemPrincipal, + EmptyCString(), nsIXPConnect:: FLAG_SYSTEM_GLOBAL_OBJECT, getter_AddRefs(holder)); diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index ac01e8faebd..af37d98a704 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -1867,25 +1867,26 @@ main(int argc, char **argv) xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF); #ifndef XPCONNECT_STANDALONE + nsCOMPtr systemprincipal; + // Fetch the system principal and store it away in a global, to use for // script compilation in Load() and ProcessFile() (including interactive // eval loop) { - nsCOMPtr princ; nsCOMPtr securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && securityManager) { - rv = securityManager->GetSystemPrincipal(getter_AddRefs(princ)); + rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal)); if (NS_FAILED(rv)) { fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n"); } else { // fetch the JS principals and stick in a global - rv = princ->GetJSPrincipals(cx, &gJSPrincipals); + rv = systemprincipal->GetJSPrincipals(cx, &gJSPrincipals); if (NS_FAILED(rv)) { fprintf(gErrFile, "+++ Failed to obtain JS principals from SystemPrincipal.\n"); } - secman->SetSystemPrincipal(princ); + secman->SetSystemPrincipal(systemprincipal); } } else { fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals"); @@ -1921,6 +1922,8 @@ main(int argc, char **argv) nsCOMPtr holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass, NS_GET_IID(nsISupports), + systemprincipal, + EmptyCString(), nsIXPConnect:: FLAG_SYSTEM_GLOBAL_OBJECT, getter_AddRefs(holder)); diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 5d7c2b3ccfd..c58fc3feda2 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -1102,17 +1102,60 @@ static JSClass xpcTempGlobalClass = { JSCLASS_NO_OPTIONAL_MEMBERS }; +nsresult +xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp, + const nsACString &origin, nsIPrincipal *principal, + JSObject **global, JSCompartment **compartment) +{ + XPCCompartmentMap& map = nsXPConnect::GetRuntimeInstance()->GetCompartmentMap(); + JSObject *tempGlobal; + if(!map.Get(origin, compartment)) + { + JSPrincipals *principals = nsnull; + if(principal) + principal->GetJSPrincipals(cx, &principals); + tempGlobal = JS_NewCompartmentAndGlobalObject(cx, clasp, principals); + if(principals) + JSPRINCIPALS_DROP(cx, principals); + + if(!tempGlobal) + return UnexpectedFailure(NS_ERROR_FAILURE); + + JSAutoEnterCompartment autocompartment(cx, tempGlobal); + + *global = tempGlobal; + *compartment = tempGlobal->getCompartment(cx); + + JS_SetCompartmentPrivate(cx, *compartment, ToNewCString(origin)); + map.Put(origin, *compartment); + } + else + { + JSAutoEnterCompartment autocompartment(cx, *compartment); + + tempGlobal = JS_NewGlobalObject(cx, clasp); + if(!tempGlobal) + return UnexpectedFailure(NS_ERROR_FAILURE); + *global = tempGlobal; + } + + return NS_OK; +} + /* nsIXPConnectJSObjectHolder initClassesWithNewWrappedGlobal (in JSContextPtr aJSContext, in nsISupports aCOMObj, in nsIIDRef aIID, in PRUint32 aFlags); */ NS_IMETHODIMP nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, nsISupports *aCOMObj, const nsIID & aIID, + nsIPrincipal * aPrincipal, + const nsACString & aOrigin, PRUint32 aFlags, nsIXPConnectJSObjectHolder **_retval) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aCOMObj, "bad param"); NS_ASSERTION(_retval, "bad param"); + NS_ASSERTION(!aOrigin.IsEmpty() || aPrincipal, "must be able to assign an origin"); // XXX This is not pretty. We make a temporary global object and // init it with all the Components object junk just so we have a @@ -1121,13 +1164,25 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, XPCCallContext ccx(NATIVE_CALLER, aJSContext); - PRBool system = (aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT) != 0; - JSObject* tempGlobal = JS_NewGlobalObject(aJSContext, &xpcTempGlobalClass); + nsCString origin; + if(aOrigin.IsEmpty()) + aPrincipal->GetOrigin(getter_Copies(origin)); + else + origin = aOrigin; - if(!tempGlobal || - (system && !JS_MakeSystemObject(aJSContext, tempGlobal)) || - !JS_SetParent(aJSContext, tempGlobal, nsnull) || - !JS_SetPrototype(aJSContext, tempGlobal, nsnull)) + SaveFrame sf(ccx); + + JSCompartment* compartment; + JSObject* tempGlobal; + + nsresult rv = xpc_CreateGlobalObject(ccx, &xpcTempGlobalClass, origin, + aPrincipal, &tempGlobal, &compartment); + NS_ENSURE_SUCCESS(rv, rv); + + JSAutoEnterCompartment autocompartment(ccx, compartment); + + PRBool system = (aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT) != 0; + if(system && !JS_MakeSystemObject(aJSContext, tempGlobal)) return UnexpectedFailure(NS_ERROR_FAILURE); jsval v; @@ -1140,7 +1195,6 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, if(NS_FAILED(InitClasses(aJSContext, tempGlobal))) return UnexpectedFailure(NS_ERROR_FAILURE); - nsresult rv; if(!XPCConvert::NativeInterface2JSObject(ccx, &v, getter_AddRefs(holder), aCOMObj, &aIID, nsnull, @@ -1193,7 +1247,6 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, if(!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) { // XPCCallContext gives us an active request needed to save/restore. - SaveFrame sf(ccx); if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, globalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE); diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 6920ee6c74d..bc4956bcb68 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -3242,15 +3242,20 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop) return NS_ERROR_OUT_OF_MEMORY; } - JSPrincipals *jsPrincipals; - rv = sop->GetPrincipal()->GetJSPrincipals(cx, &jsPrincipals); - if (NS_FAILED(rv)) - return rv; - JSObject *sandbox = JS_NewCompartmentAndGlobalObject(cx, &SandboxClass, jsPrincipals); - if (jsPrincipals) - JSPRINCIPALS_DROP(cx, jsPrincipals); - if (!sandbox) - return NS_ERROR_XPC_UNEXPECTED; + nsIPrincipal *principal = sop->GetPrincipal(); + nsAdoptingCString principalorigin; + principal->GetOrigin(getter_Copies(principalorigin)); + + nsCAutoString origin("sandbox:"); + origin.Append(principalorigin); + + JSCompartment *compartment; + JSObject *sandbox; + + rv = xpc_CreateGlobalObject(cx, &SandboxClass, origin, principal, &sandbox, + &compartment); + NS_ENSURE_SUCCESS(rv, rv); + js::AutoObjectRooter tvr(cx, sandbox); { diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 2c2b537db40..05714e54d8f 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -243,6 +243,32 @@ ContextCallback(JSContext *cx, uintN operation) return JS_TRUE; } +static JSBool +CompartmentCallback(JSContext *cx, JSCompartment *compartment, uintN op) +{ + if(op == JSCOMPARTMENT_NEW) + return JS_TRUE; + + XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance(); + if(!self) + return JS_TRUE; + + XPCCompartmentMap& map = self->GetCompartmentMap(); + nsAdoptingCString origin; + origin.Adopt(static_cast(JS_SetCompartmentPrivate(cx, compartment, nsnull))); + +#ifdef DEBUG + { + JSCompartment *current; + NS_ASSERTION(map.Get(origin, ¤t), "no compartment?"); + NS_ASSERTION(current == compartment, "compartment mismatch"); + } +#endif + + map.Remove(origin); + return JS_TRUE; +} + struct ObjectHolder : public JSDHashEntryHdr { void *holder; @@ -1092,6 +1118,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) // the GC's allocator. JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff); JS_SetContextCallback(mJSRuntime, ContextCallback); + JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback); JS_SetGCCallbackRT(mJSRuntime, GCCallback); JS_SetExtraGCRoots(mJSRuntime, TraceJS, this); mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock); @@ -1105,6 +1132,8 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) sizeof(ObjectHolder), 512)) mJSHolders.ops = nsnull; + mCompartmentMap.Init(); + // Install a JavaScript 'debugger' keyword handler in debug builds only #ifdef DEBUG if(mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler) diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index e3ff6173db6..d53332eaf29 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -95,6 +95,7 @@ #include "nsXPIDLString.h" #include "nsAutoJSValHolder.h" #include "mozilla/AutoRestore.h" +#include "nsDataHashtable.h" #include "nsThreadUtils.h" #include "nsIJSContextStack.h" @@ -243,6 +244,8 @@ extern const char XPC_SCRIPT_ERROR_CONTRACTID[]; extern const char XPC_ID_CONTRACTID[]; extern const char XPC_XPCONNECT_CONTRACTID[]; +typedef nsDataHashtableMT XPCCompartmentMap; + /***************************************************************************/ // useful macros... @@ -623,6 +626,9 @@ public: XPCNativeWrapperMap* GetExplicitNativeWrapperMap() const {return mExplicitNativeWrapperMap;} + XPCCompartmentMap& GetCompartmentMap() + {return mCompartmentMap;} + XPCLock* GetMapLock() const {return mMapLock;} JSBool OnJSContextNew(JSContext* cx); @@ -741,6 +747,7 @@ private: XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap; XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap; XPCNativeWrapperMap* mExplicitNativeWrapperMap; + XPCCompartmentMap mCompartmentMap; XPCLock* mMapLock; PRThread* mThreadRunningGC; nsTArray mWrappedJSToReleaseArray; @@ -3778,6 +3785,11 @@ xpc_DumpJSObject(JSObject* obj); extern JSBool xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt); +nsresult +xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp, + const nsACString &origin, nsIPrincipal *principal, + JSObject **global, JSCompartment **compartment); + /***************************************************************************/ // Definition of nsScriptError, defined here because we lack a place to put diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index a36ca758187..db17283427f 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -1308,6 +1308,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, obj = thisObj = wrapper->GetJSObject(); + JSAutoEnterCompartment autoCompartment(ccx, obj); + // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this. paramCount = info->num_args; argc = paramCount -