Bug 1316616 part 2. Add an nsContentUtils API for getting the CallerType of a JSContext. r=bholley
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 18 Nov 2016 16:13:06 -0500
changeset 323489 d9c4800ffba6692543bcda18e12b1cc197a70d63
parent 323488 e70b0fb180a3444285502a5ecff5c2634c6f0cab
child 323490 491ce96f65477289e4891b14ff5da700d0677779
push id30978
push usercbook@mozilla.com
push dateMon, 21 Nov 2016 14:44:46 +0000
treeherdermozilla-central@0534254e9a40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1316616
milestone53.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 1316616 part 2. Add an nsContentUtils API for getting the CallerType of a JSContext. r=bholley
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -2120,25 +2120,16 @@ nsContentUtils::ShouldResistFingerprinti
 {
   if (!aDocShell) {
     return false;
   }
   bool isChrome = nsContentUtils::IsChromeDoc(aDocShell->GetDocument());
   return !isChrome && sPrivacyResistFingerprinting;
 }
 
-namespace mozilla {
-namespace dom {
-namespace workers {
-extern bool IsCurrentThreadRunningChromeWorker();
-extern JSContext* GetCurrentThreadJSContext();
-} // namespace workers
-} // namespace dom
-} // namespace mozilla
-
 bool
 nsContentUtils::ThreadsafeIsCallerChrome()
 {
   return NS_IsMainThread() ?
     IsCallerChrome() :
     mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
 }
 
@@ -2156,16 +2147,41 @@ nsContentUtils::IsCallerContentXBL()
     if (!xpc::AllowContentXBLScope(c)) {
       MOZ_ASSERT(nsContentUtils::AllowXULXBLForPrincipal(xpc::GetCompartmentPrincipal(c)));
       return true;
     }
 
     return xpc::IsContentXBLScope(c);
 }
 
+bool
+nsContentUtils::IsSystemCaller(JSContext* aCx)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // This is similar to what SubjectPrincipal() does, except we do in fact
+  // assume that we're in a compartment here; anyone who calls this function in
+  // situations where that's not the case is doing it wrong.
+  JSCompartment *compartment = js::GetContextCompartment(aCx);
+  MOZ_ASSERT(compartment);
+
+  JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
+  return nsJSPrincipals::get(principals) == sSystemPrincipal;
+}
+
+bool
+nsContentUtils::ThreadsafeIsSystemCaller(JSContext* aCx)
+{
+  if (NS_IsMainThread()) {
+    return IsSystemCaller(aCx);
+  }
+
+  return workers::GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal();
+}
+
 // static
 bool
 nsContentUtils::LookupBindingMember(JSContext* aCx, nsIContent *aContent,
                                     JS::Handle<jsid> aId,
                                     JS::MutableHandle<JS::PropertyDescriptor> aDesc)
 {
   nsXBLBinding* binding = aContent->GetXBLBinding();
   if (!binding)
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -194,16 +194,33 @@ class nsContentUtils
 
 public:
   static nsresult Init();
 
   static bool     IsCallerChrome();
   static bool     ThreadsafeIsCallerChrome();
   static bool     IsCallerContentXBL();
 
+  // The APIs for checking whether the caller is system (in the sense of system
+  // principal) should only be used when the JSContext is known to accurately
+  // represent the caller.  In practice, that means you should only use them in
+  // two situations at the moment:
+  //
+  // 1) Functions used in WebIDL Func annotations.
+  // 2) Bindings code.
+  //
+  // Use pretty much anywhere else is almost certainly wrong and should be
+  // replaced with [NeedsCallerType] annotations in bindings.
+
+  // Check whether the caller is system if you know you're on the main thread.
+  static bool IsSystemCaller(JSContext* aCx);
+
+  // Check whether the caller is system if you might be on a worker thread.
+  static bool ThreadsafeIsSystemCaller(JSContext* aCx);
+
   // In the traditional Gecko architecture, both C++ code and untrusted JS code
   // needed to rely on the same XPCOM method/getter/setter to get work done.
   // This required lots of security checks in the various exposed methods, which
   // in turn created difficulty in determining whether the caller was script
   // (whose access needed to be checked) and internal C++ platform code (whose
   // access did not need to be checked). To address this problem, Gecko had a
   // convention whereby the absence of script on the stack was interpretted as
   // "System Caller" and always granted unfettered access.