Bug 1052089 - Swap out the SafeJSContextGlobal for the new UnprivilegedJunkScope. r=billm

This commit is contained in:
Bobby Holley 2014-08-18 10:57:30 -07:00
parent 4c2d9e0211
commit 0cb72d2e6c
8 changed files with 35 additions and 107 deletions

View File

@ -499,7 +499,7 @@ ThreadsafeAutoJSContext::operator JSContext*() const
AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
, mAc(mCx, XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContextGlobal())
, mAc(mCx, xpc::UnprivilegedJunkScope())
{
}

View File

@ -124,7 +124,7 @@ nsJSUtils::ReportPendingException(JSContext *aContext)
// The SafeJSContext has no default object associated with it.
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContext == nsContentUtils::GetSafeJSContext());
scope = xpc::GetSafeJSContextGlobal();
scope = xpc::UnprivilegedJunkScope(); // Usage approved by bholley
}
JSAutoCompartment ac(aContext, scope);
JS_ReportPendingException(aContext);

View File

@ -11104,7 +11104,7 @@ class CGDictionary(CGThing):
AutoJSAPI jsapi;
jsapi.Init();
JSContext *cx = jsapi.cx();
JSAutoCompartment ac(cx, xpc::GetSafeJSContextGlobal()); // Usage approved by bholley
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope()); // Usage approved by bholley
JS::Rooted<JS::Value> obj(cx);
return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON);
"""))
@ -11892,7 +11892,7 @@ class CGBindingRoot(CGThing):
bindingHeaders["WrapperFactory.h"] = descriptors
bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::GetSafeJSContextGlobal
bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::UnprivilegedJunkScope
# Do codegen for all the dictionaries. We have to be a bit careful
# here, because we have to generate these in order from least derived

View File

@ -22,7 +22,6 @@ using mozilla::dom::DestroyProtoAndIfaceCache;
XPCJSContextStack::~XPCJSContextStack()
{
if (mSafeJSContext) {
mSafeJSContextGlobal = nullptr;
JS_DestroyContextNoGC(mSafeJSContext);
mSafeJSContext = nullptr;
}
@ -109,31 +108,6 @@ XPCJSContextStack::HasJSContext(JSContext *cx)
return false;
}
static bool
SafeGlobalResolve(JSContext *cx, HandleObject obj, HandleId id)
{
bool resolved;
return JS_ResolveStandardClass(cx, obj, id, &resolved);
}
static void
SafeFinalize(JSFreeOp *fop, JSObject* obj)
{
SandboxPrivate* sop =
static_cast<SandboxPrivate*>(xpc_GetJSPrivate(obj));
sop->ForgetGlobalObject();
NS_IF_RELEASE(sop);
DestroyProtoAndIfaceCache(obj);
}
const JSClass xpc::SafeJSContextGlobalClass = {
"global_for_XPCJSContextStack_SafeJSContext",
XPCONNECT_GLOBAL_FLAGS,
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize,
nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook
};
JSContext*
XPCJSContextStack::GetSafeJSContext()
{
@ -141,55 +115,14 @@ XPCJSContextStack::GetSafeJSContext()
return mSafeJSContext;
}
JSObject*
XPCJSContextStack::GetSafeJSContextGlobal()
{
MOZ_ASSERT(mSafeJSContextGlobal);
return mSafeJSContextGlobal;
}
JSContext*
XPCJSContextStack::InitSafeJSContext()
{
MOZ_ASSERT(!mSafeJSContext);
// Start by getting the principal holder and principal for this
// context. If we can't manage that, don't bother with the rest.
nsRefPtr<nsNullPrincipal> principal = new nsNullPrincipal();
nsresult rv = principal->Init();
if (NS_FAILED(rv))
MOZ_CRASH();
nsXPConnect* xpc = nsXPConnect::XPConnect();
JSRuntime *rt = xpc->GetRuntime()->Runtime();
if (!rt)
MOZ_CRASH();
mSafeJSContext = JS_NewContext(rt, 8192);
mSafeJSContext = JS_NewContext(XPCJSRuntime::Get()->Runtime(), 8192);
if (!mSafeJSContext)
MOZ_CRASH();
JSAutoRequest req(mSafeJSContext);
ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true);
JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);
// Note - We intentionally avoid firing OnNewGlobalObject while
// simultaneously skipping the call to setInvisibleToDebugger(true) here.
// This lets us piggy-back on the assertions in the JS engine (which make
// sure that, for non-invisible globals, we always fire onNewGlobalObject
// before creating scripts), to assert that we never create scripts with
// the SafeJSContextGlobal. This is all happening way before anyone could be
// listening for debugger notifications anyway.
JS::CompartmentOptions options;
options.setZone(JS::SystemZone)
.setTrace(TraceXPCGlobal);
mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext,
&SafeJSContextGlobalClass,
principal, options);
if (!mSafeJSContextGlobal)
MOZ_CRASH();
nsRefPtr<SandboxPrivate> sp = new SandboxPrivate(principal, mSafeJSContextGlobal);
JS_SetPrivate(mSafeJSContextGlobal, sp.forget().take());
return mSafeJSContext;
}

View File

@ -560,6 +560,12 @@ EnableUniversalXPConnect(JSContext *cx)
return scope->AttachComponentsObject(cx);
}
JSObject *
UnprivilegedJunkScope()
{
return XPCJSRuntime::Get()->UnprivilegedJunkScope();
}
JSObject *
PrivilegedJunkScope()
{
@ -572,12 +578,6 @@ CompilationScope()
return XPCJSRuntime::Get()->CompilationScope();
}
JSObject *
GetSafeJSContextGlobal()
{
return XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContextGlobal();
}
nsGlobalWindow*
WindowOrNull(JSObject *aObj)
{
@ -3115,6 +3115,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
mWrappedJSRoots(nullptr),
mObjectHolderRoots(nullptr),
mWatchdogManager(new WatchdogManager(MOZ_THIS_IN_INITIALIZER_LIST())),
mUnprivilegedJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr),
mPrivilegedJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr),
mCompilationScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr),
mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite())
@ -3545,7 +3546,15 @@ XPCJSRuntime::InitSingletonScopes()
RootedValue v(cx);
nsresult rv;
// Create the Junk Scope.
// Create the Unprivileged Junk Scope.
SandboxOptions unprivilegedJunkScopeOptions;
unprivilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Junk Compartment");
unprivilegedJunkScopeOptions.invisibleToDebugger = true;
rv = CreateSandboxObject(cx, &v, nullptr, unprivilegedJunkScopeOptions);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
mUnprivilegedJunkScope = js::UncheckedUnwrap(&v.toObject());
// Create the Privileged Junk Scope.
SandboxOptions privilegedJunkScopeOptions;
privilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Privileged Junk Compartment");
privilegedJunkScopeOptions.invisibleToDebugger = true;
@ -3567,6 +3576,7 @@ XPCJSRuntime::InitSingletonScopes()
void
XPCJSRuntime::DeleteSingletonScopes()
{
mUnprivilegedJunkScope = nullptr;
mPrivilegedJunkScope = nullptr;
mCompilationScope = nullptr;
}

View File

@ -52,15 +52,11 @@ RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal)
{
MOZ_ASSERT(aPrincipal);
// The SafeJSContext is lazily created, and tends to be created at really
// weird times, at least for xpcshell (often very early in startup or late
// in shutdown). Its scope isn't system principal, so if we proceeded we'd
// end up calling into AllowXULXBLForPrincipal, which depends on all kinds
// of persistent storage and permission machinery that may or not be running.
// We know the answer to the question here, so just short-circuit.
//
// We do the same for sandboxes, for similar reasons.
if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass || IsSandbox(aGlobal))
// Certain singleton sandoxes are created very early in startup - too early
// to call into AllowXULXBLForPrincipal. We never create XBL scopes for
// sandboxes anway, and certainly not for these singleton scopes. So we just
// short-circuit here.
if (IsSandbox(aGlobal))
return false;
// AllowXULXBLForPrincipal will return true for system principal, but we

View File

@ -619,6 +619,7 @@ public:
AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;}
JSObject* UnprivilegedJunkScope() { return mUnprivilegedJunkScope; }
JSObject* PrivilegedJunkScope() { return mPrivilegedJunkScope; }
JSObject* CompilationScope() { return mCompilationScope; }
@ -663,6 +664,7 @@ private:
nsTArray<xpcContextCallback> extraContextCallbacks;
nsRefPtr<WatchdogManager> mWatchdogManager;
JS::GCSliceCallback mPrevGCSliceCallback;
JS::PersistentRootedObject mUnprivilegedJunkScope;
JS::PersistentRootedObject mPrivilegedJunkScope;
JS::PersistentRootedObject mCompilationScope;
nsRefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
@ -2857,7 +2859,6 @@ public:
explicit XPCJSContextStack(XPCJSRuntime *aRuntime)
: mRuntime(aRuntime)
, mSafeJSContext(nullptr)
, mSafeJSContextGlobal(aRuntime->Runtime(), nullptr)
{ }
virtual ~XPCJSContextStack();
@ -2874,7 +2875,6 @@ public:
JSContext *InitSafeJSContext();
JSContext *GetSafeJSContext();
JSObject *GetSafeJSContextGlobal();
bool HasJSContext(JSContext *cx);
const InfallibleTArray<XPCJSContextInfo>* GetStack()
@ -2893,7 +2893,6 @@ private:
AutoInfallibleTArray<XPCJSContextInfo, 16> mStack;
XPCJSRuntime* mRuntime;
JSContext* mSafeJSContext;
JS::PersistentRootedObject mSafeJSContextGlobal;
};
/***************************************************************************/
@ -3730,8 +3729,6 @@ ObjectScope(JSObject *obj)
return CompartmentPrivate::Get(obj)->scope;
}
extern const JSClass SafeJSContextGlobalClass;
JSObject* NewOutObject(JSContext* cx, JSObject* scope);
bool IsOutObject(JSContext* cx, JSObject* obj);

View File

@ -437,16 +437,15 @@ nsISupports *
UnwrapReflectorToISupports(JSObject *reflector);
/**
* In some cases a native object does not really belong to any compartment (XBL,
* document created from by XHR of a worker, etc.). But when for some reason we
* have to wrap these natives (because of an event for example) instead of just
* wrapping them into some random compartment we find on the context stack (like
* we did previously) a default compartment is used. This function returns that
* compartment's global. It is a singleton on the runtime.
* If you find yourself wanting to use this compartment, you're probably doing
* Singleton scopes for stuff that really doesn't fit anywhere else.
*
* If you find yourself wanting to use these compartments, you're probably doing
* something wrong. Callers MUST consult with the XPConnect module owner before
* using this compartment. If you don't, bholley will hunt you down.
*/
JSObject *
UnprivilegedJunkScope();
JSObject *
PrivilegedJunkScope();
@ -465,13 +464,6 @@ CompilationScope();
nsGlobalWindow*
WindowOrNull(JSObject *aObj);
/*
* Returns the dummy global associated with the SafeJSContext. Callers MUST
* consult with the XPConnect module owner before using this function.
*/
JSObject *
GetSafeJSContextGlobal();
/**
* If |aObj| has a window for a global, returns the associated nsGlobalWindow.
* Otherwise, returns null.