Bug 1541858, AssertEvalNotUsingSystemPrincipal into the ContentSecurityManager and also call it for worker code r=ckerschb
authorJonas Allmann <jallmann@mozilla.com>
Thu, 18 Apr 2019 13:54:43 +0000
changeset 470181 5be51df44c5c75a8ffd199f9dccb2c614ecb7be2
parent 470180 580a7e38c60491123f3e7bba82904008ab0262d1
child 470182 da464aa8549f6031a68ed6577a1eb890a936a19e
push id83569
push userapavel@mozilla.com
push dateFri, 19 Apr 2019 04:14:16 +0000
treeherderautoland@5be51df44c5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb
bugs1541858
milestone68.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 1541858, AssertEvalNotUsingSystemPrincipal into the ContentSecurityManager and also call it for worker code r=ckerschb Bug 1541858 - Extended eval()-Assertion whitelist, r=ckerschb Differential Revision: https://phabricator.services.mozilla.com/D28052
caps/nsScriptSecurityManager.cpp
dom/security/CSPEvalChecker.cpp
dom/security/nsContentSecurityManager.cpp
dom/security/nsContentSecurityManager.h
modules/libpref/init/all.js
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -24,16 +24,17 @@
 #include "nsJSPrincipals.h"
 #include "mozilla/BasePrincipal.h"
 #include "ExpandedPrincipal.h"
 #include "SystemPrincipal.h"
 #include "DomainPolicy.h"
 #include "nsString.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
+#include "nsContentSecurityManager.h"
 #include "nsDocShell.h"
 #include "nsError.h"
 #include "nsGlobalWindowInner.h"
 #include "nsDOMCID.h"
 #include "nsTextFormatter.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsIEffectiveTLDService.h"
@@ -485,69 +486,24 @@ nsScriptSecurityManager::GetChannelURIPr
 NS_IMPL_ISUPPORTS(nsScriptSecurityManager, nsIScriptSecurityManager)
 
 ///////////////////////////////////////////////////
 // Methods implementing nsIScriptSecurityManager //
 ///////////////////////////////////////////////////
 
 ///////////////// Security Checks /////////////////
 
-#if defined(DEBUG) && !defined(ANDROID)
-static void AssertEvalNotUsingSystemPrincipal(nsIPrincipal* subjectPrincipal,
-                                              JSContext* cx) {
-  if (!subjectPrincipal->IsSystemPrincipal()) {
-    return;
-  }
-
-  if (Preferences::GetBool("security.allow_eval_with_system_principal")) {
-    return;
-  }
-
-  static StaticAutoPtr<nsTArray<nsCString>> sUrisAllowEval;
-  JS::AutoFilename scriptFilename;
-  if (JS::DescribeScriptedCaller(cx, &scriptFilename)) {
-    if (!sUrisAllowEval) {
-      sUrisAllowEval = new nsTArray<nsCString>();
-      nsAutoCString urisAllowEval;
-      Preferences::GetCString("security.uris_using_eval_with_system_principal",
-                              urisAllowEval);
-      for (const nsACString& filenameString : urisAllowEval.Split(',')) {
-        sUrisAllowEval->AppendElement(filenameString);
-      }
-      ClearOnShutdown(&sUrisAllowEval);
-    }
-
-    nsAutoCString fileName;
-    fileName = nsAutoCString(scriptFilename.get());
-    // Extract file name alone if scriptFilename contains line number
-    // separated by multiple space delimiters in few cases.
-    int32_t fileNameIndex = fileName.FindChar(' ');
-    if (fileNameIndex != -1) {
-      fileName = Substring(fileName, 0, fileNameIndex);
-    }
-    ToLowerCase(fileName);
-
-    for (auto& uriEntry : *sUrisAllowEval) {
-      if (StringEndsWith(fileName, uriEntry)) {
-        return;
-      }
-    }
-  }
-
-  MOZ_ASSERT(false, "do not use eval with system privileges");
-}
-#endif
-
 bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
     JSContext* cx, JS::HandleValue aValue) {
   MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
   nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
 
 #if defined(DEBUG) && !defined(ANDROID)
-  AssertEvalNotUsingSystemPrincipal(subjectPrincipal, cx);
+  nsContentSecurityManager::AssertEvalNotUsingSystemPrincipal(subjectPrincipal,
+                                                              cx);
 #endif
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   nsresult rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
   NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
 
   // don't do anything unless there's a CSP
   if (!csp) return true;
--- a/dom/security/CSPEvalChecker.cpp
+++ b/dom/security/CSPEvalChecker.cpp
@@ -5,32 +5,43 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/CSPEvalChecker.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/ErrorResult.h"
 #include "nsGlobalWindowInner.h"
 #include "mozilla/dom/Document.h"
+#include "nsContentSecurityManager.h"
+#include "nsContentUtils.h"
 #include "nsCOMPtr.h"
 #include "nsJSUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace {
 
+// We use the subjectPrincipal to assert that eval() is never
+// executed in system privileged context.
 nsresult CheckInternal(nsIContentSecurityPolicy* aCSP,
                        nsICSPEventListener* aCSPEventListener,
+                       nsIPrincipal* aSubjectPrincipal,
                        const nsAString& aExpression,
                        const nsAString& aFileNameString, uint32_t aLineNum,
                        uint32_t aColumnNum, bool* aAllowed) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aAllowed);
 
+#if defined(DEBUG) && !defined(ANDROID)
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  nsContentSecurityManager::AssertEvalNotUsingSystemPrincipal(aSubjectPrincipal,
+                                                              cx);
+#endif
+
   // The value is set at any "return", but better to have a default value here.
   *aAllowed = false;
 
   if (!aCSP) {
     *aAllowed = true;
     return NS_OK;
   }
 
@@ -64,17 +75,18 @@ class WorkerCSPCheckRunnable final : pub
         mFileNameString(aFileNameString),
         mLineNum(aLineNum),
         mColumnNum(aColumnNum),
         mEvalAllowed(false) {}
 
   bool MainThreadRun() override {
     mResult = CheckInternal(
         mWorkerPrivate->GetCSP(), mWorkerPrivate->CSPEventListener(),
-        mExpression, mFileNameString, mLineNum, mColumnNum, &mEvalAllowed);
+        mWorkerPrivate->GetLoadingPrincipal(), mExpression, mFileNameString,
+        mLineNum, mColumnNum, &mEvalAllowed);
     return true;
   }
 
   nsresult GetResult(bool* aAllowed) {
     MOZ_ASSERT(aAllowed);
     *aAllowed = mEvalAllowed;
     return mResult;
   }
@@ -123,18 +135,18 @@ nsresult CSPEvalChecker::CheckForWindow(
   uint32_t columnNum = 0;
   nsAutoString fileNameString;
   if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
                                      &columnNum)) {
     fileNameString.AssignLiteral("unknown");
   }
 
   rv = CheckInternal(csp, nullptr /* no CSPEventListener for window */,
-                     aExpression, fileNameString, lineNum, columnNum,
-                     aAllowEval);
+                     doc->NodePrincipal(), aExpression, fileNameString, lineNum,
+                     columnNum, aAllowEval);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     *aAllowEval = false;
     return rv;
   }
 
   return NS_OK;
 }
 
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -16,16 +16,17 @@
 #include "nsContentUtils.h"
 #include "nsCORSListenerProxy.h"
 #include "nsIStreamListener.h"
 #include "nsIURIFixup.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIRedirectHistoryEntry.h"
 
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/nsMixedContentBlocker.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Components.h"
 #include "mozilla/Logging.h"
 #include "xpcpublic.h"
 
 NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager,
@@ -155,16 +156,61 @@ bool nsContentSecurityManager::AllowInse
   nsContentUtils::ReportToConsole(
       nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DATA_URI_BLOCKED"), doc,
       nsContentUtils::eSECURITY_PROPERTIES, "BlockSubresourceRedirectToData",
       params, ArrayLength(params));
   return false;
 }
 
 /* static */
+void nsContentSecurityManager::AssertEvalNotUsingSystemPrincipal(
+    nsIPrincipal* subjectPrincipal, JSContext* cx) {
+  if (!subjectPrincipal->IsSystemPrincipal()) {
+    return;
+  }
+
+  if (Preferences::GetBool("security.allow_eval_with_system_principal")) {
+    return;
+  }
+
+  static StaticAutoPtr<nsTArray<nsCString>> sUrisAllowEval;
+  JS::AutoFilename scriptFilename;
+  if (JS::DescribeScriptedCaller(cx, &scriptFilename)) {
+    if (!sUrisAllowEval) {
+      sUrisAllowEval = new nsTArray<nsCString>();
+      nsAutoCString urisAllowEval;
+      Preferences::GetCString("security.uris_using_eval_with_system_principal",
+                              urisAllowEval);
+      for (const nsACString& filenameString : urisAllowEval.Split(',')) {
+        sUrisAllowEval->AppendElement(filenameString);
+      }
+      ClearOnShutdown(&sUrisAllowEval);
+    }
+
+    nsAutoCString fileName;
+    fileName = nsAutoCString(scriptFilename.get());
+    // Extract file name alone if scriptFilename contains line number
+    // separated by multiple space delimiters in few cases.
+    int32_t fileNameIndex = fileName.FindChar(' ');
+    if (fileNameIndex != -1) {
+      fileName = Substring(fileName, 0, fileNameIndex);
+    }
+    ToLowerCase(fileName);
+
+    for (auto& uriEntry : *sUrisAllowEval) {
+      if (StringEndsWith(fileName, uriEntry)) {
+        return;
+      }
+    }
+  }
+
+  MOZ_ASSERT(false, "do not use eval with system privileges");
+}
+
+/* static */
 nsresult nsContentSecurityManager::CheckFTPSubresourceLoad(
     nsIChannel* aChannel) {
   // We dissallow using FTP resources as a subresource almost everywhere.
   // The only valid way to use FTP resources is loading it as
   // a top level document.
   if (!mozilla::net::nsIOService::BlockFTPSubresources()) {
     return NS_OK;
   }
--- a/dom/security/nsContentSecurityManager.h
+++ b/dom/security/nsContentSecurityManager.h
@@ -33,16 +33,19 @@ class nsContentSecurityManager : public 
   nsContentSecurityManager() {}
 
   static nsresult doContentSecurityCheck(
       nsIChannel* aChannel, nsCOMPtr<nsIStreamListener>& aInAndOutListener);
 
   static bool AllowTopLevelNavigationToDataURI(nsIChannel* aChannel);
   static bool AllowInsecureRedirectToDataURI(nsIChannel* aNewChannel);
 
+  static void AssertEvalNotUsingSystemPrincipal(nsIPrincipal* subjectPrincipal,
+                                                JSContext* cx);
+
  private:
   static nsresult CheckChannel(nsIChannel* aChannel);
   static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel);
 
   virtual ~nsContentSecurityManager() {}
 };
 
 #endif /* nsContentSecurityManager_h___ */
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2707,17 +2707,17 @@ pref("security.notification_enable_delay
 
 #if defined(DEBUG) && !defined(ANDROID)
 pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,about,addons,cache-entry,config,crashes,debugging,devtools,downloads,home,memory,networking,newtab,performance,plugins,policies,profiles,restartrequired,serviceworkers,sessionrestore,support,sync-log,telemetry,url-classifier,webrtc,welcomeback");
 // the following prefs are for testing purposes only.
 pref("csp.overrule_about_uris_without_csp_whitelist", false);
 pref("csp.skip_about_page_has_csp_assert", false);
 // assertion flag will be set to false after fixing Bug 1473549
 pref("security.allow_eval_with_system_principal", false);
-pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,preferencesbindings.js,lodash.js,jszip.js,sinon-7.2.7.js,ajv-4.1.1.js,setup,jsol.js,parent_utils.js,chrometask_chromescript");
+pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,preferencesbindings.js,lodash.js,jszip.js,sinon-7.2.7.js,ajv-4.1.1.js,setup,jsol.js,parent_utils.js,chrometask_chromescript,simpletest/testrunner.js,simpletest/simpletest.js,file_bug1018265.xul,helperappdlg.jsm,test_execute_async_script.py");
 #endif
 
 #if defined(DEBUG) || defined(FUZZING)
 // Disallow web documents loaded with the SystemPrincipal
 pref("security.disallow_non_local_systemprincipal_in_tests", false);
 #endif
 
 // Default Content Security Policy to apply to signed contents.