Bug 1570062 - Whitelist what's new "moments" pages. r=k88hudson, a=RyanVM
authorEd Lee <edilee@mozilla.com>
Thu, 08 Aug 2019 19:22:38 +0000
changeset 541946 8107e7f68e126fb10e697ee135c4589a8b72dd73
parent 541945 3a71ae2fd8258a8323a9ced755e4536a79ef44a6
child 541947 feeaf170fca669a675eff2cb16bd56b0a329b508
push id11788
push userryanvm@gmail.com
push dateThu, 15 Aug 2019 13:21:51 +0000
treeherdermozilla-beta@8107e7f68e12 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersk88hudson, RyanVM
bugs1570062
milestone69.0
Bug 1570062 - Whitelist what's new "moments" pages. r=k88hudson, a=RyanVM Use URL to parse and eTLD to extract allowed domains Differential Revision: https://phabricator.services.mozilla.com/D41123
browser/components/BrowserContentHandler.jsm
browser/components/tests/browser/browser_startup_homepage.js
--- a/browser/components/BrowserContentHandler.jsm
+++ b/browser/components/BrowserContentHandler.jsm
@@ -36,16 +36,20 @@ XPCOMUtils.defineLazyServiceGetter(
 
 XPCOMUtils.defineLazyGetter(this, "gSystemPrincipal", () =>
   Services.scriptSecurityManager.getSystemPrincipal()
 );
 XPCOMUtils.defineLazyGlobalGetters(this, [URL]);
 
 const NEWINSTALL_PAGE = "about:newinstall";
 
+// One-time startup homepage override configurations
+const ONCE_DOMAINS = ["mozilla.org", "firefox.com"];
+const ONCE_PREF = "browser.startup.homepage_override.once";
+
 function shouldLoadURI(aURI) {
   if (aURI && !aURI.schemeIs("chrome")) {
     return true;
   }
 
   dump("*** Preventing external load of chrome: URI into browser window\n");
   dump("    Use --chrome <uri> instead\n");
   return false;
@@ -693,28 +697,54 @@ nsBrowserContentHandler.prototype = {
     } catch (ex) {}
 
     // formatURLPref might return "about:blank" if getting the pref fails
     if (overridePage == "about:blank") {
       overridePage = "";
     }
 
     // Allow showing a one-time startup override if we're not showing one
-    const ONCE_PREF = "browser.startup.homepage_override.once";
     if (isStartup && overridePage == "" && prefb.prefHasUserValue(ONCE_PREF)) {
       try {
         // Show if we haven't passed the expiration or there's no expiration
         const { expire, url } = JSON.parse(
           Services.urlFormatter.formatURLPref(ONCE_PREF)
         );
-        if (!(Date.now() > expire) && typeof url == "string") {
-          overridePage = url;
+        if (!(Date.now() > expire)) {
+          // Only set allowed urls as override pages
+          overridePage = url
+            .split("|")
+            .map(val => {
+              try {
+                return new URL(val);
+              } catch (ex) {
+                // Invalid URL, so filter out below
+                Cu.reportError(`Invalid once url: ${ex}`);
+                return null;
+              }
+            })
+            .filter(
+              parsed =>
+                parsed &&
+                parsed.protocol == "https:" &&
+                // Only accept exact hostname or subdomain; without port
+                ONCE_DOMAINS.includes(
+                  Services.eTLD.getBaseDomainFromHost(parsed.host)
+                )
+            )
+            .join("|");
+
+          // Be noisy as properly configured urls should be unchanged
+          if (overridePage != url) {
+            Cu.reportError(`Mismatched once urls: ${url}`);
+          }
         }
       } catch (ex) {
         // Invalid json pref, so ignore (and clear below)
+        Cu.reportError(`Invalid once pref: ${ex}`);
       } finally {
         prefb.clearUserPref(ONCE_PREF);
       }
     }
 
     if (!additionalPage) {
       additionalPage = LaterRun.getURL() || "";
     }
--- a/browser/components/tests/browser/browser_startup_homepage.js
+++ b/browser/components/tests/browser/browser_startup_homepage.js
@@ -42,16 +42,51 @@ add_task(async function test_once_expire
 add_task(async function test_once_invalid() {
   await checkArgs("not json", "about:blank", {
     "browser.startup.homepage_override.once": "https://not.json",
   });
 
   await checkArgs("not string", "about:blank", {
     "browser.startup.homepage_override.once": { url: 5 },
   });
+
+  await checkArgs("not https", "about:blank", {
+    "browser.startup.homepage_override.once": {
+      url: "http://www.mozilla.org/",
+    },
+  });
+
+  await checkArgs("not portless", "about:blank", {
+    "browser.startup.homepage_override.once": {
+      url: "https://www.mozilla.org:123/",
+    },
+  });
+
+  await checkArgs("invalid protocol", "about:blank", {
+    "browser.startup.homepage_override.once": {
+      url: "data:text/plain,hello world",
+    },
+  });
+
+  await checkArgs("invalid domain", "about:blank", {
+    "browser.startup.homepage_override.once": {
+      url: "https://wwwmozilla.org/",
+    },
+  });
+
+  await checkArgs(
+    "invalid second domain",
+    "https://valid.firefox.com/|https://mozilla.org/",
+    {
+      "browser.startup.homepage_override.once": {
+        url:
+          "https://valid.firefox.com|https://invalidfirefox.com|https://mozilla.org",
+      },
+    }
+  );
 });
 
 add_task(async function test_once() {
   await checkArgs("initial test prefs (no homepage)", "about:blank");
 
   const url = "https://www.mozilla.org/";
   await checkArgs("override once", url, {
     "browser.startup.homepage_override.once": { url },