Bug 1507702 - Don't make about:crash* accessible to web content r=Ehsan,bzbarsky
☠☠ backed out by beffa3a1e854 ☠ ☠
authorJames Willcox <snorp@snorp.net>
Thu, 29 Nov 2018 08:35:07 -0600
changeset 507985 50171af401fc178eb7ebc37e95730791b2328f24
parent 507984 871b06663b0d85566feecce311f9c77a31b279be
child 507986 beffa3a1e854d93a60caef290c03b4fb33a627a0
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan, bzbarsky
bugs1507702
milestone65.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 1507702 - Don't make about:crash* accessible to web content r=Ehsan,bzbarsky 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,16 +2,17 @@
 /* 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"
 
 #if defined(MOZ_WIDGET_ANDROID) && defined(RELEASE_OR_BETA)
 #define ABOUT_CONFIG_BLOCKED_GV
 #endif
 
 #ifdef ABOUT_CONFIG_BLOCKED_GV
@@ -22,16 +23,46 @@ NS_IMPL_ISUPPORTS(nsAboutRedirector, nsI
 
 struct RedirEntry
 {
   const char* id;
   const char* url;
   uint32_t flags;
 };
 
+class CrashChannel final : public nsBaseChannel
+{
+public:
+  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.
 
@@ -140,22 +171,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
@@ -169,22 +198,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;
   }
 
 #ifdef ABOUT_CONFIG_BLOCKED_GV
   // We don't want to allow access to about:config from
   // GeckoView on release or beta, but it's fine for Fennec.
   if (path.EqualsASCII("config") && !mozilla::jni::IsFennec()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
--- 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>