Bug 995295 part 1. Create console events in the junk scope, not the untrusted content scope. r=baku
☠☠ backed out by 0d37b75f8cd3 ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 16 Apr 2014 15:09:23 -0400
changeset 197341 0b3a14bbfd81231756c88255ea3563a0760a2acc
parent 197340 8a13590ce482280ea38a5c886e9812d918ed6848
child 197342 c674dc13ef8505550c603c32b2d5385def4b6614
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs995295
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 995295 part 1. Create console events in the junk scope, not the untrusted content scope. r=baku
dom/base/Console.cpp
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -145,30 +145,27 @@ public:
   }
 
   ~ConsoleCallData()
   {
     MOZ_COUNT_DTOR(ConsoleCallData);
   }
 
   void
-  Initialize(JSContext* aCx, Console::MethodName aName,
+  Initialize(Console::MethodName aName,
              const nsAString& aString, const Sequence<JS::Value>& aArguments)
   {
-    mGlobal = JS::CurrentGlobalOrNull(aCx);
     mMethodName = aName;
     mMethodString = aString;
 
     for (uint32_t i = 0; i < aArguments.Length(); ++i) {
       mArguments.AppendElement(aArguments[i]);
     }
   }
 
-  JS::Heap<JSObject*> mGlobal;
-
   Console::MethodName mMethodName;
   bool mPrivate;
   int64_t mTimeStamp;
   DOMHighResTimeStamp mMonotonicTimer;
 
   nsString mMethodString;
   nsTArray<JS::Heap<JS::Value>> mArguments;
   Sequence<ConsoleStackEntry> mStack;
@@ -202,31 +199,29 @@ public:
   }
 
   virtual
   ~ConsoleRunnable()
   {
   }
 
   bool
-  Dispatch()
+  Dispatch(JSContext* aCx)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
 
-    JSContext* cx = mWorkerPrivate->GetJSContext();
-
-    if (!PreDispatch(cx)) {
+    if (!PreDispatch(aCx)) {
       return false;
     }
 
     AutoSyncLoopHolder syncLoop(mWorkerPrivate);
     mSyncLoopTarget = syncLoop.EventTarget();
 
     if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
-      JS_ReportError(cx,
+      JS_ReportError(aCx,
                      "Failed to dispatch to main thread for the Console API!");
       return false;
     }
 
     return syncLoop.Run();
   }
 
 private:
@@ -270,17 +265,16 @@ public:
   {
   }
 
 private:
   bool
   PreDispatch(JSContext* aCx) MOZ_OVERRIDE
   {
     ClearException ce(aCx);
-    JSAutoCompartment ac(aCx, mCallData->mGlobal);
 
     JS::Rooted<JSObject*> arguments(aCx,
       JS_NewArrayObject(aCx, mCallData->mArguments.Length()));
     if (!arguments) {
       return false;
     }
 
     for (uint32_t i = 0; i < mCallData->mArguments.Length(); ++i) {
@@ -292,17 +286,16 @@ private:
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
 
     if (!mArguments.write(aCx, value, &gConsoleCallbacks, &mStrings)) {
       return false;
     }
 
     mCallData->mArguments.Clear();
-    mCallData->mGlobal = nullptr;
     return true;
   }
 
   void
   RunConsole() MOZ_OVERRIDE
   {
     // Walk up to our containing page
     WorkerPrivate* wp = mWorkerPrivate;
@@ -347,17 +340,16 @@ private:
         return;
       }
 
       mCallData->mArguments.AppendElement(value);
     }
 
     MOZ_ASSERT(mCallData->mArguments.Length() == length);
 
-    mCallData->mGlobal = JS::CurrentGlobalOrNull(cx);
     console->AppendCallData(mCallData.forget());
   }
 
 private:
   nsAutoPtr<ConsoleCallData> mCallData;
 
   JSAutoStructuredCloneBuffer mArguments;
   nsTArray<nsString> mStrings;
@@ -497,20 +489,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 
   for (ConsoleCallData* data = tmp->mQueuedCalls.getFirst(); data != nullptr;
        data = data->getNext()) {
-    if (data->mGlobal) {
-      aCallbacks.Trace(&data->mGlobal, "data->mGlobal", aClosure);
-    }
-
     for (uint32_t i = 0; i < data->mArguments.Length(); ++i) {
       aCallbacks.Trace(&data->mArguments[i], "data->mArguments[i]", aClosure);
     }
   }
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Console)
@@ -667,17 +655,17 @@ void
 Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
                        const Sequence<JS::Value>& aData,
                        ErrorResult& aRv)
 {
   if (!NS_IsMainThread()) {
     // Here we are in a worker thread.
     nsRefPtr<ConsoleProfileRunnable> runnable =
       new ConsoleProfileRunnable(aAction, aData);
-    runnable->Dispatch();
+    runnable->Dispatch(aCx);
     return;
   }
 
   RootedDictionary<ConsoleProfileEvent> event(aCx);
   event.mAction = aAction;
 
   event.mArguments.Construct();
   Sequence<JS::Value>& sequence = event.mArguments.Value();
@@ -767,17 +755,17 @@ Console::Method(JSContext* aCx, MethodNa
   private:
     LinkedList<ConsoleCallData>& mList;
     bool mUnfinished;
   };
 
   ConsoleCallData* callData = new ConsoleCallData();
   mQueuedCalls.insertBack(callData);
 
-  callData->Initialize(aCx, aMethodName, aMethodString, aData);
+  callData->Initialize(aMethodName, aMethodString, aData);
   RAII raii(mQueuedCalls);
 
   if (mWindow) {
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
     if (!webNav) {
       Throw(aCx, NS_ERROR_FAILURE);
       return;
     }
@@ -866,17 +854,17 @@ Console::Method(JSContext* aCx, MethodNa
   if (!NS_IsMainThread()) {
     // Here we are in a worker thread. The ConsoleCallData has to been removed
     // from the list and it will be deleted by the ConsoleCallDataRunnable or
     // by the Main-Thread Console object.
     mQueuedCalls.popLast();
 
     nsRefPtr<ConsoleCallDataRunnable> runnable =
       new ConsoleCallDataRunnable(callData);
-    runnable->Dispatch();
+    runnable->Dispatch(aCx);
     return;
   }
 
   if (!mTimer) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     mTimer->InitWithCallback(this, CALL_DELAY,
                              nsITimer::TYPE_REPEATING_SLACK);
   }
@@ -927,17 +915,27 @@ Console::ProcessCallData(ConsoleCallData
   if (!aData->mStack.IsEmpty()) {
     frame = aData->mStack[0];
   }
 
   AutoSafeJSContext cx;
   ClearException ce(cx);
   RootedDictionary<ConsoleEvent> event(cx);
 
-  JSAutoCompartment ac(cx, aData->mGlobal);
+  // We want to create a console event object and pass it to our
+  // nsIConsoleAPIStorage implementation.  We want to define some accessor
+  // properties on this object, and those will need to keep an nsIStackFrame
+  // alive.  But nsIStackFrame cannot be wrapped in an untrusted scope.  And
+  // further, passing untrusted objects to system code is likely to run afoul of
+  // Object Xrays.  So we want to wrap in a system-principal scope here.  But
+  // which one?  We could cheat and try to get the underlying JSObject* of
+  // mStorage, but that's a bit fragile.  Instead, we just use the junk scope,
+  // with explicit permission from the XPConnect module owner.  If you're
+  // tempted to do that anywhere else, talk to said module owner first.
+  JSAutoCompartment ac(cx, xpc::GetJunkScope());
 
   event.mID.Construct();
   event.mInnerID.Construct();
   if (mWindow) {
     event.mID.Value().SetAsUnsignedLong() = mOuterID;
     event.mInnerID.Value().SetAsUnsignedLong() = mInnerID;
   } else {
     // If we are in a JSM, the window doesn't exist.