tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DOMSecurityMonitor.cpp (5118B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "DOMSecurityMonitor.h"
      8 
      9 #include "mozilla/BasePrincipal.h"
     10 #include "mozilla/StaticPrefs_dom.h"
     11 #include "nsContentUtils.h"
     12 #include "nsIChannel.h"
     13 #include "nsILoadInfo.h"
     14 #include "nsIPrincipal.h"
     15 #include "nsIURI.h"
     16 #include "nsJSUtils.h"
     17 #include "xpcpublic.h"
     18 
     19 /* static */
     20 void DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(
     21    nsIPrincipal* aPrincipal, const nsAString& aFragment) {
     22  // if the fragment parser (e.g. innerHTML()) is not called in chrome: code
     23  // or any of our about: pages, then there is nothing to do here.
     24  if (!aPrincipal->IsSystemPrincipal() && !aPrincipal->SchemeIs("about")) {
     25    return;
     26  }
     27 
     28  // check if the fragment is empty, if so, we can return early.
     29  if (aFragment.IsEmpty()) {
     30    return;
     31  }
     32 
     33  // check if there is a JS caller, if not, then we can can return early here
     34  // because we only care about calls to the fragment parser (e.g. innerHTML)
     35  // originating from JS code.
     36  auto loc = mozilla::JSCallingLocation::Get();
     37  if (!loc) {
     38    return;
     39  }
     40 
     41  // check if we should skip assertion. Please only ever set this pref to
     42  // true if really needed for testing purposes.
     43  if (mozilla::StaticPrefs::dom_security_skip_html_fragment_assertion()) {
     44    return;
     45  }
     46 
     47  /*
     48   * WARNING: Do not add any new entries to the htmlFragmentAllowlist
     49   * without proper review from a dom:security peer!
     50   */
     51  static nsLiteralCString htmlFragmentAllowlist[] = {
     52      "chrome://global/content/elements/marquee.js"_ns,
     53      nsLiteralCString("chrome://devtools/content/shared/sourceeditor/"
     54                       "codemirror/codemirror.bundle.js"),
     55      nsLiteralCString(
     56          "resource://newtab/data/content/activity-stream.bundle.js"),
     57      nsLiteralCString("resource://devtools/client/debugger/src/components/"
     58                       "Editor/Breakpoint.js"),
     59      nsLiteralCString("resource://devtools/client/debugger/src/components/"
     60                       "Editor/ColumnBreakpoint.js"),
     61      nsLiteralCString(
     62          "resource://devtools/client/shared/vendor/fluent-react.js"),
     63      "resource://devtools/client/shared/vendor/react-dom.mjs"_ns,
     64      nsLiteralCString(
     65          "resource://devtools/client/shared/vendor/react-dom-dev.mjs"),
     66      nsLiteralCString(
     67          "resource://devtools/client/shared/widgets/FilterWidget.js"),
     68      nsLiteralCString("resource://devtools/client/shared/widgets/tooltip/"
     69                       "inactive-css-tooltip-helper.js"),
     70      "resource://devtools/client/shared/widgets/Spectrum.js"_ns,
     71      "resource://gre/modules/narrate/VoiceSelect.sys.mjs"_ns,
     72      "chrome://global/content/vendor/react-dom.js"_ns,
     73      // ------------------------------------------------------------------
     74      // test pages
     75      // ------------------------------------------------------------------
     76      "chrome://mochikit/content/browser-harness.xhtml"_ns,
     77      "chrome://mochikit/content/harness.xhtml"_ns,
     78      "chrome://mochikit/content/tests/"_ns,
     79      "chrome://mochitests/content/"_ns,
     80      "chrome://reftest/content/"_ns,
     81  };
     82 
     83  for (const nsLiteralCString& allowlistEntry : htmlFragmentAllowlist) {
     84    if (StringBeginsWith(loc.FileName(), allowlistEntry)) {
     85      return;
     86    }
     87  }
     88 
     89  nsAutoCString uriSpec;
     90  aPrincipal->GetAsciiSpec(uriSpec);
     91 
     92  // Ideally we should not call the fragment parser (e.g. innerHTML()) in
     93  // chrome: code or any of our about: pages. If you hit that assertion,
     94  // please do *not* add your filename to the allowlist above, but rather
     95  // refactor your code.
     96  fprintf(stderr,
     97          "Do not call the fragment parser (e.g innerHTML()) in chrome code "
     98          "or in about: pages, (uri: %s), (caller: %s, line: %d, col: %d), "
     99          "(fragment: %s)",
    100          uriSpec.get(), loc.FileName().get(), loc.mLine, loc.mColumn,
    101          NS_ConvertUTF16toUTF8(aFragment).get());
    102 
    103  xpc_DumpJSStack(true, true, false);
    104  MOZ_ASSERT(false);
    105 }
    106 
    107 /* static */
    108 void DOMSecurityMonitor::AuditUseOfJavaScriptURI(nsIChannel* aChannel) {
    109  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    110  nsCOMPtr<nsIPrincipal> loadingPrincipal = loadInfo->GetLoadingPrincipal();
    111 
    112  // We only ever have no loadingPrincipal in case of a new top-level load.
    113  // The purpose of this assertion is to make sure we do not allow loading
    114  // javascript: URIs in system privileged contexts. Hence there is nothing
    115  // to do here in case there is no loadingPrincipal.
    116  if (!loadingPrincipal) {
    117    return;
    118  }
    119 
    120  // if the javascript: URI is not loaded by a system privileged context
    121  // or an about: page, there there is nothing to do here.
    122  if (!loadingPrincipal->IsSystemPrincipal() &&
    123      !loadingPrincipal->SchemeIs("about")) {
    124    return;
    125  }
    126 
    127  MOZ_ASSERT(false,
    128             "Do not use javascript: URIs in chrome code or in about: pages");
    129 }