[Pkg-mozext-commits] [no-resource-uri-leak] 06/09: Added a redirect checker (based on Torbutton code by Yawning); UI improvement; Refactored to allow policy reloading.

Hema Prathaban hemaprathaban-guest at moszumanska.debian.org
Tue Jul 4 17:19:13 UTC 2017


This is an automated email from the git hooks/post-receive script.

hemaprathaban-guest pushed a commit to branch upstream
in repository no-resource-uri-leak.

commit a12d0867d3719a6476243e6dfdd2d7af505cc730
Author: nord-stream <nord-stream at ochaken.jp.eu.org>
Date:   Sun Jul 24 16:05:16 2016 +0000

    Added a redirect checker (based on Torbutton code by Yawning); UI improvement; Refactored to allow policy reloading.
---
 preferences.json                              |  54 ++++++++++-
 src/main.js                                   |  36 ++++++--
 src/resource-filter/content-policy.js         |  95 --------------------
 src/resource-filter/init.js                   |  33 ++++---
 src/resource-filter/process/content-policy.js |  61 +++++++++++++
 src/resource-filter/process/filter.js         | 124 ++++++++++++++++++++++++++
 version_info                                  |   2 +-
 7 files changed, 285 insertions(+), 120 deletions(-)

diff --git a/preferences.json b/preferences.json
index 989f9ed..eb000bd 100644
--- a/preferences.json
+++ b/preferences.json
@@ -1,9 +1,57 @@
 [
 	{
-		"name": "blockChromeURIs"
+		"name": "uri.resource.enableBlocking"
 		,"type": "bool"
-		,"value": false
+		,"value": true
+		,"title": "Block access to resource:// URIs from Web"
+		,"description": "This is the extesion's main feature."
+	}
+	,{
+		"name": "uri.chrome.enableBlocking"
+		,"type": "bool"
+		,"value": true
 		,"title": "Block Web-exposed subset of chrome:// URIs"
-		,"description": "Enabling it may break certain extensions or badly designed Web sites. (Requires a restart)"
+		,"description": "RECOMMENDED for privacy. Enabling it may break certain extensions or badly designed Web sites."
+	}
+	,{
+		"name": "redirect.enableMasking"
+		,"type": "bool"
+		,"value": true
+		,"title": "Uniformly filter disallowed redirects"
+		,"description": "This eliminates one known source of an information leak"
+	}
+	,{
+		"name": "uri.resource.exposedList"
+		,"type": "string"
+		,"value": ""
+		,"title": "Exposed resource:// domains"
+		,"description": "This may harm your privacy: Only for debugging and as temporary measures (Separated with spaces and/or commas)"
+	}
+	,{
+		"name": "uri.chrome.exposedList"
+		,"type": "string"
+		,"value": ""
+		,"title": "Exposed chrome:// domains"
+		,"description": "This may harm your privacy: Only for debugging and as temporary measures (Separated with spaces and/or commas)"
+	}
+	,{
+		"name": "uri.about.restricted"
+		,"type": "bool"
+		,"value": false
+		,"title": "Restrict about: pages by default (for paranoids)"
+		,"description": "This may break certain add-ons or the browser's internal pages"
+	}
+	,{
+		"name": "debug.enabled"
+		,"type": "bool"
+		,"value": false
+		,"title": "Enable debugging messages (for hackers)"
+	}
+	,{
+		"name": "control.update"
+		,"type": "control"
+		,"label": "Update"
+		,"title": "Update the policy"
+		,"description": "Push this button for changes to take effect."
 	}
 ]
diff --git a/src/main.js b/src/main.js
index 414e80d..6692acf 100644
--- a/src/main.js
+++ b/src/main.js
@@ -25,11 +25,33 @@ vim: ts=4 noet ai */
 
 'use strict';
 
-// Stop all access attempts to resource:// URIs from the Web
-const filteredDomain = void 0; // everything
-const blockChromeURIs = !!require ('sdk/simple-prefs').prefs.blockChromeURIs;
-
-console.log (require ('sdk/simple-prefs').prefs);
-// The core code is under MPL-2.0
-require ('./resource-filter/init').addFilter (filteredDomain, blockChromeURIs);
+// We are using a library under MPL-2.0 here
+const {enablePolicy} = require ('./resource-filter/init');
+
+
+/* Preferences keys */
+const PREF_REDIRECT_MASKED = 'redirect.enableMasking';
+const PREF_URI_RESOURCE_BLOCKED = 'uri.resource.enableBlocking';
+const PREF_URI_CHROME_BLOCKED = 'uri.chrome.enableBlocking';
+const PREF_URI_CHROME_WHITELIST = 'uri.chrome.exposedList';
+const PREF_URI_RESOURCE_WHITELIST = 'uri.resource.exposedList';
+const PREF_RESTRICT_ABOUT = 'uri.about.restricted';
+const PREF_DEBUG_ENABLED = 'debug.enabled';
+
+const _$prefs = require ('sdk/simple-prefs').prefs;
+
+const update = $prefs => enablePolicy ({__proto__: null
+	,enableDebug: !!$prefs[PREF_DEBUG_ENABLED]
+	,blockResourceURIs: !!$prefs[PREF_URI_RESOURCE_BLOCKED]
+	,blockChromeURIs: !!$prefs[PREF_URI_CHROME_BLOCKED]
+	,enableRedirectMasking: !!$prefs[PREF_REDIRECT_MASKED]
+	,restrictAboutPages: !!$prefs[PREF_RESTRICT_ABOUT]
+	,exposedResourceDomains:
+		String ($prefs[PREF_URI_RESOURCE_WHITELIST]).split (/[,\s]+/)
+	,exposedChromeDomains:
+		String ($prefs[PREF_URI_CHROME_WHITELIST]).split (/[,\s]+/)
+});
+
+update (_$prefs);
+require ('sdk/simple-prefs').on ('control.update', () => void update (_$prefs));
 
diff --git a/src/resource-filter/content-policy.js b/src/resource-filter/content-policy.js
deleted file mode 100644
index dd47683..0000000
--- a/src/resource-filter/content-policy.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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/. */
-
-/* ResourceFilter: A direct workaround for https://bugzil.la/863246 */
-
-/* Internal script: Loaded into every process (parent or content) */
-
-const {components, Cc, Ci, Cm, Cr} = require ('chrome');
-const unload = require ('sdk/system/unload');
-const {XPCOMUtils} = require ('resource://gre/modules/XPCOMUtils.jsm');
-
-const domains = new Set; // disallowed domains: any if empty
-const isDenied = domain => 1 > domains.size || domains.has ('' + domain);
-let allowChromeURIs = true;
-
-const policy = {__proto__: null
-  /* nsISupports */
-  ,QueryInterface: XPCOMUtils.generateQI (['nsIContentPolicy', 'nsIFactory'])
-  
-  /* nsIFactory */
-  ,createInstance (outer, id) {
-    if (outer) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
-    return this.QueryInterface (id);
-  }
-  
-  /* nsIContentPolicy */
-  ,shouldLoad (typeCode, uri, originUri, node, expectedMime, extra, principal) {
-    // Note: view-source: scheme is no longer accessible from content (thus no leaks)
-    if (!uri || !uri.schemeIs ('resource') || !originUri
-      || originUri.schemeIs ('chrome') || originUri.schemeIs ('resource')
-      || originUri.schemeIs ('view-source')) {
-      
-      if (allowChromeURIs || !uri.schemeIs ('chrome')) {
-        return Ci.nsIContentPolicy.ACCEPT;
-      }
-    }
-    
-    // Non-matching domain or a resource directly loaded into a tab
-    if (!isDenied (uri.host) || Ci.nsIContentPolicy.TYPE_DOCUMENT === typeCode) {
-      return Ci.nsIContentPolicy.ACCEPT;
-    }
-    
-    // Whitelist about:addons (Add-ons compatibility)
-    if (originUri.schemeIs ('about') && 'addons' === originUri.path) {
-      return Ci.nsIContentPolicy.ACCEPT;
-    }
-    
-    return Ci.nsIContentPolicy.REJECT_REQUEST;
-  }
-  ,shouldProcess (typeCode, uri, originUri, node, expectedMime, extra) {
-    return Ci.nsIContentPolicy.ACCEPT;
-  }
-};
-
-const contractId = '@addons.mozilla.org/resource-masking-policy;1';
-const classId = components.ID ('{ee3ec15e-6743-47a4-96a7-b551935c93c6}');
-const description = 'Masks resource URIs against content';
-const category = 'content-policy';
-
-const init = (... args) => {
-  const registrar = Cm.QueryInterface (Ci.nsIComponentRegistrar);
-  const categoryManager = Cc['@mozilla.org/categorymanager;1']
-    .getService (Ci.nsICategoryManager);
-  
-  const {resourceDomain, blockChromeURIs} = args.pop ();
-  try {
-    if ('string' === typeof resourceDomain) throw void 0;
-    [... resourceDomain].forEach (domain => domains.add ('' + domain));
-  } catch (e) {
-    resourceDomain && domains.add ('' + resourceDomain);
-  }
-  
-  if (blockChromeURIs) {
-    allowChromeURIs = false;
-  }
-  
-  registrar.registerFactory (classId, description, contractId, policy);
-  categoryManager.addCategoryEntry (category, contractId, contractId, false, true);
-  
-  unload.when (() => {
-    categoryManager.deleteCategoryEntry (category, contractId, false);
-    registrar.unregisterFactory (classId, policy);
-  });
-};
-
-try {
-  require ('sdk/remote/child').process.port.on ('init', init);
-} catch (e) {
-  // Not multiprocess
-  exports.init = init;
-}
diff --git a/src/resource-filter/init.js b/src/resource-filter/init.js
index 74ca34c..62895dc 100644
--- a/src/resource-filter/init.js
+++ b/src/resource-filter/init.js
@@ -1,25 +1,30 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+/* -*- indent-tabs-mode: nil; js-indent-level: 2; tab-width: 2 -*-
  * 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/. */
 
-/* ResourceFilter: A direct workaround for https://bugzil.la/863246 */
-
-/**
-  Prevents content from loading resource:// URIs without breaking add-ons.
-  @param resourceDomain (optional) e.g. 'gre' for resource://gre/
-  @param blockChromeURIs (optional) set to block chrome:// resources
+/*
+  ResourceFilter: A direct workaround for https://bugzil.la/863246
+  API revision: 2
 */
-exports.addFilter = (resourceDomain, blockChromeURIs) => {
+
+const setPolicy = (() => {
   try {
     const {processes, remoteRequire} = require ('sdk/remote/parent');
-    remoteRequire ('./content-policy', module);
-    
+    remoteRequire ('./process/filter', module);
     // For every current and future process
-    processes.forEvery (process => void process.port.emit ('init'
-        , {resourceDomain, blockChromeURIs}));
+    return options =>
+      processes.forEvery (process => void process.port.emit ('setPolicy', options));
   } catch (e) {
     // Not multiprocess
-    require ('./content-policy').init ({resourceDomain, blockChromeURIs});
+    return require ('./process/filter').setPolicy;
   }
-};
+}) ();
+
+
+/**
+  Prevents content from loading resource:// URIs without breaking add-ons.
+  Can be called multiple times to update the policy.
+*/
+exports.enablePolicy = options => void setPolicy (options || {});
+
diff --git a/src/resource-filter/process/content-policy.js b/src/resource-filter/process/content-policy.js
new file mode 100644
index 0000000..bcf921d
--- /dev/null
+++ b/src/resource-filter/process/content-policy.js
@@ -0,0 +1,61 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2; tab-width: 2 -*-
+ * 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/. */
+
+/* ResourceFilter: A direct workaround for https://bugzil.la/863246 */
+
+const unload = require ('sdk/system/unload');
+const {components, Cc, Ci, Cm, Cr} = require ('chrome');
+const {XPCOMUtils} = require ('resource://gre/modules/XPCOMUtils.jsm');
+
+const registrar = Cm.QueryInterface (Ci.nsIComponentRegistrar);
+const categoryManager = Cc['@mozilla.org/categorymanager;1']
+  .getService (Ci.nsICategoryManager);
+
+/**
+  The 'evaluate' callback must not perform any blocking processing.
+*/
+exports.registerContentPolicy = ({evaluate, contractId, uuid, description}) => {
+  if ('function' != typeof evaluate) {
+    throw new TypeError ('evaluate must be a function');
+  }
+  
+  const policy = {__proto__: null
+    /* nsISupports */
+    ,QueryInterface: XPCOMUtils.generateQI (['nsIContentPolicy', 'nsIFactory'])
+    
+    /* nsIFactory */
+    ,createInstance (outer, id) {
+      if (outer) {
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      }
+      return this.QueryInterface (id);
+    }
+    
+    /* nsIContentPolicy */
+    ,shouldLoad (... args) {
+      try {
+        if (evaluate (... args)) {
+          return Ci.nsIContentPolicy.ACCEPT;
+        }
+      } catch (e) {
+        console.exception (e);
+      }
+      return Ci.nsIContentPolicy.REJECT_REQUEST;
+    }
+    ,shouldProcess () {
+      return Ci.nsIContentPolicy.ACCEPT;
+    }
+  };
+  
+  const classId = components.ID (uuid);
+  const category = 'content-policy';
+  registrar.registerFactory (classId, description, contractId, policy);
+  categoryManager.addCategoryEntry (category, contractId, contractId, false, true);
+  
+  unload.when (() => {
+    categoryManager.deleteCategoryEntry (category, contractId, false);
+    registrar.unregisterFactory (classId, policy);
+  });
+};
diff --git a/src/resource-filter/process/filter.js b/src/resource-filter/process/filter.js
new file mode 100644
index 0000000..f2f295a
--- /dev/null
+++ b/src/resource-filter/process/filter.js
@@ -0,0 +1,124 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2; tab-width: 2 -*-
+ * 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/. */
+
+/* ResourceFilter: A direct workaround for https://bugzil.la/863246 */
+
+/* Internal script: Loaded into every process (parent or content) */
+
+const {Ci, Cr} = require ('chrome');
+const unload = require ('sdk/system/unload');
+const {io: ioService, obs: observerService}
+	= require ('resource://gre/modules/Services.jsm').Services;
+
+const {registerContentPolicy} = require ('./content-policy');
+
+// Default values
+const policyState = {__proto__: null
+  ,debug: false
+  ,exposedResourceDomains: new Set
+  ,exposedChromeDomains: new Set
+  ,blockResourceUris: true
+  ,blockChromeUris: true
+  ,filterRedirects: true
+  ,whitelistAboutUris: false
+  ,secureAboutUris: new Set (['addons', 'home', 'preferences', 'support', 'newtab', 'debugging', 'config', 'downloads', 'profiles', 'sessionrestore', 'privatebrowsing', 'plugins'])
+  ,veryInsecureAboutUris: new Set (['blank', 'srcdoc'])
+};
+
+
+// Note: view-source: scheme is no longer accessible from content (thus no leaks)
+const isWhitelistedOrigin = u => (!u)
+  || u.schemeIs ('chrome') || u.schemeIs ('resource') || u.schemeIs ('view-source')
+  || u.schemeIs ('about') && (!policyState.veryInsecureAboutUris.has (u.path))
+    && (policyState.secureAboutUris.has (u.path) || policyState.whitelistAboutUris);
+
+const shouldBeBlocked = u => (!u)
+  || policyState.blockResourceUris
+    && u.schemeIs ('resource') && (!policyState.exposedResourceDomains.has (u.host))
+  || policyState.blockChromeUris
+    && u.schemeIs ('chrome') && (!policyState.exposedChromeDomains.has (u.host));
+
+registerContentPolicy ({__proto__: null
+  ,contractId: '@addons.mozilla.org/resource-masking-policy;1'
+  ,uuid: '{ee3ec15e-6743-47a4-96a7-b551935c93c6}'
+  ,description: 'Masks resource URIs against content'
+  ,evaluate (typeCode, uri, originUri, node, expectedMime, extra, principal) {
+    if (!shouldBeBlocked (uri) || isWhitelistedOrigin (originUri)) {
+      return true;
+    }
+    
+    // Allow documents directly loaded into a tab
+    if (Ci.nsIContentPolicy.TYPE_DOCUMENT === typeCode) {
+      return true;
+    }
+    
+    policyState.debug && console.warn ('ResourceFilter: Rejected'
+      , uri.spec, originUri.spec, node, principal);
+    return false;
+  }
+});
+
+/*
+  Based on TorButton code, by Yawning Angel
+  From https://git.schwanenlied.me/yawning/torbutton/src/fa67687df5fc72c0b6085d9941331277d32319f3/src/components/content-policy.js
+*/
+
+// Install a HTTP response handler to check for redirects to URLs with schemes
+// that should be internal to the browser.  There's various safeguards and
+// checks that cause the body to be unavailable, but the `onLoad()` behavior
+// is inconsistent, which results in leaking information about the specific
+// user agent instance (eg: what addons are installed).
+const requestObserver = {__proto__: null
+  ,observe (aSubject, aTopic, aData) {
+    const aChannel = aSubject.QueryInterface (Ci.nsIHttpChannel);
+    const aStatus = aChannel.responseStatus;
+    
+    try {
+      // If this is a redirect...
+      //
+      // Note: Technically `304 Not Modifed` isn't a redirect, but receiving that
+      // to the proscribed schemes is nonsensical.
+      if (aStatus >= 300 && aStatus < 400) {
+        const location = aChannel.getResponseHeader ('Location');
+        const aUri = ioService.newURI (location, null, null);
+        // And it's redirecting into the browser or addon's internal URLs...
+        if (shouldBeBlocked (aUri) || aUri.schemeIs ('about')) {
+          // Cancel the request.
+          policyState.debug && console.warn ('ResourceFilter: Cancelled redirect'
+            , aUri.spec, aChannel.owner);
+          aSubject.cancel (Cr.NS_BINDING_ABORTED);
+        }
+      }
+    } catch (e) {
+      console.exception (e);
+    }
+  }
+};
+
+try {
+  observerService.addObserver (requestObserver, 'http-on-examine-response', false);
+  unload.when (() =>
+    observerService.removeObserver (requestObserver, 'http-on-examine-response'));
+} catch (e) {}
+
+const setPolicy = ({enableRedirectMasking, blockChromeURIs, blockResourceURIs
+  , enableDebug, restrictAboutPages, exposedResourceDomains, exposedChromeDomains}) =>
+{
+  policyState.filterRedirects = !!enableRedirectMasking;
+  policyState.blockChromeUris = !!blockChromeURIs;
+  policyState.blockResourceUris = !!blockResourceURIs;
+  policyState.debug = !!enableDebug;
+  policyState.whitelistAboutUris = !restrictAboutPages;
+  policyState.exposedResourceDomains = new Set (exposedResourceDomains || []);
+  policyState.exposedChromeDomains = new Set (exposedChromeDomains || []);
+};
+
+try {
+  require ('sdk/remote/child').process.port.on ('setPolicy'
+    , (_, options) => setPolicy (options));
+} catch (e) {
+  // Not multiprocess
+  exports.setPolicy = setPolicy;
+}
diff --git a/version_info b/version_info
index eaa0efa..5b2b92d 100644
--- a/version_info
+++ b/version_info
@@ -22,7 +22,7 @@
 addon_id="no-resource-uri-leak"
 
 # Canonical version of the addon (may be converted into different formats on build)
-addon_version="0.2.1"
+addon_version="1.0.0"
 
 # Alpha versions (may not be feature complete): x.y.z~a1, x.y.z~a2, ...
 # Beta versions (feature-frozen): x.y.z~b1, x.y.z~b2, ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/no-resource-uri-leak.git



More information about the Pkg-mozext-commits mailing list