Bug 1507702 - Don't make about:crash* accessible to web content r=Ehsan,bzbarsky a=jcristau
authorJames Willcox <snorp@snorp.net>
Thu, 29 Nov 2018 08:35:07 -0600
changeset 501456 0d9074318f9c
parent 501455 69b56f092ceb
child 501457 319052b37637
push id1870
push userjcristau@mozilla.com
push dateWed, 05 Dec 2018 21:35:46 +0000
treeherdermozilla-release@319052b37637 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan, bzbarsky, jcristau
bugs1507702
milestone64.0
Bug 1507702 - Don't make about:crash* accessible to web content r=Ehsan,bzbarsky a=jcristau Differential Revision: https://phabricator.services.mozilla.com/D12133
docshell/base/nsAboutRedirector.cpp
docshell/test/mochitest/mochitest.ini
docshell/test/mochitest/test_bug1507702.html
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -2,28 +2,59 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAboutRedirector.h"
 #include "nsNetUtil.h"
 #include "nsAboutProtocolUtils.h"
+#include "nsBaseChannel.h"
 #include "mozilla/ArrayUtils.h"
 #include "nsIProtocolHandler.h"
 
 NS_IMPL_ISUPPORTS(nsAboutRedirector, nsIAboutModule)
 
 struct RedirEntry
 {
   const char* id;
   const char* url;
   uint32_t flags;
 };
 
+class CrashChannel final : public nsBaseChannel
+{
+public:
+  explicit CrashChannel(nsIURI* aURI)
+  {
+    SetURI(aURI);
+  }
+
+  nsresult OpenContentStream(bool async, nsIInputStream **stream,
+                             nsIChannel** channel) override
+  {
+    nsAutoCString spec;
+    mURI->GetSpec(spec);
+
+    if (spec.EqualsASCII("about:crashparent") && XRE_IsParentProcess()) {
+      MOZ_CRASH("Crash via about:crashparent");
+    }
+
+    if (spec.EqualsASCII("about:crashcontent") && XRE_IsContentProcess()) {
+      MOZ_CRASH("Crash via about:crashcontent");
+    }
+
+    NS_WARNING("Unhandled about:crash* URI or wrong process");
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+protected:
+  virtual ~CrashChannel() = default;
+};
+
 /*
   Entries which do not have URI_SAFE_FOR_UNTRUSTED_CONTENT will run with chrome
   privileges. This is potentially dangerous. Please use
   URI_SAFE_FOR_UNTRUSTED_CONTENT in the third argument to each map item below
   unless your about: page really needs chrome privileges. Security review is
   required before adding new map entries without
   URI_SAFE_FOR_UNTRUSTED_CONTENT.
 
@@ -132,22 +163,20 @@ static const RedirEntry kRedirMap[] = {
   {
     "printpreview", "about:blank",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT |
     nsIAboutModule::URI_CAN_LOAD_IN_CHILD
   },
   {
     "crashparent", "about:blank",
-    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT
   },
   {
     "crashcontent", "about:blank",
-    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT |
     nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD
   }
 };
 static const int kRedirTotal = mozilla::ArrayLength(kRedirMap);
 
 NS_IMETHODIMP
@@ -161,22 +190,20 @@ nsAboutRedirector::NewChannel(nsIURI* aU
 
   nsAutoCString path;
   nsresult rv = NS_GetAboutModuleName(aURI, path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (XRE_IsParentProcess() && path.EqualsASCII("crashparent")) {
-    MOZ_CRASH("Crash via about:crashparent");
-  }
-
-  if (XRE_IsContentProcess() && path.EqualsASCII("crashcontent")) {
-    MOZ_CRASH("Crash via about:crashcontent");
+  if (path.EqualsASCII("crashparent") || path.EqualsASCII("crashcontent")) {
+    nsCOMPtr<nsIChannel> channel = new CrashChannel(aURI);
+    channel.forget(aResult);
+    return NS_OK;
   }
 
   for (int i = 0; i < kRedirTotal; i++) {
     if (!strcmp(path.get(), kRedirMap[i].id)) {
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
       rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/docshell/test/mochitest/mochitest.ini
+++ b/docshell/test/mochitest/mochitest.ini
@@ -110,8 +110,9 @@ support-files = file_bug675587.html
 [test_close_onpagehide_by_window_close.html]
 [test_forceinheritprincipal_overrule_owner.html]
 [test_framedhistoryframes.html]
 skip-if = toolkit == 'android' # bug 784321
 support-files = file_framedhistoryframes.html
 [test_pushState_after_document_open.html]
 [test_windowedhistoryframes.html]
 [test_triggeringprincipal_location_seturi.html]
+[test_bug1507702.html]
new file mode 100644
--- /dev/null
+++ b/docshell/test/mochitest/test_bug1507702.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1507702
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1507702</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <link rel="icon" href="about:crashparent"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1507702">Mozilla Bug 1507702</a>
+<img src="about:crashparent">
+<img src="about:crashcontent">
+<iframe src="about:crashparent"></iframe>
+<iframe src="about:crashcontent"></iframe>
+<script>
+  let urls = ["about:crashparent", "about:crashcontent"];
+  async function testFetch() {
+    const url = urls.shift();
+    if (!url) {
+      return Promise.resolve();
+    }
+
+    let threw;
+    try {
+      await fetch(url);
+      threw = false;
+    } catch (e) {
+      threw = true;
+    };
+
+    ok(threw === true, "fetch should reject");
+    return testFetch();
+  }
+
+  document.body.onload = async () => {
+    for (const url of ["about:crashparent", "about:crashcontent"]) {
+      SimpleTest.doesThrow(() => {
+        top.location.href = url;
+      }, "navigation should throw");
+
+      SimpleTest.doesThrow(() => {
+        location.href = url;
+      }, "navigation should throw");
+    }
+
+    await testFetch();
+    SimpleTest.finish();
+  };
+
+  SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>