Bug 995295 part 1. Create console events in the junk scope, not the untrusted content scope. r=baku
☠☠ backed out by 8a13590ce482 ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 16 Apr 2014 15:09:23 -0400
changeset 179244 df5a68af3d309f3f5aef99777852d3d6d73acc9f
parent 179243 1b7eef53c08abb7f48386e64fd412cb5139656f8
child 179245 6acacaa75fadf036b43906fe9cf6c4840f540dc8
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersbaku
bugs995295
milestone31.0a1
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.