Bug 1173171 - Disable external jar: via preference. r=jduell
☠☠ backed out by 8f75b5361f6e ☠ ☠
authorJeff Gibat <jgibat@isecpartners.com>
Thu, 30 Jul 2015 13:10:00 +0200
changeset 287935 bf18c1865e7dc4cc101a1013d253134e8cd42f5b
parent 287934 db744be4dc3d775cda38b3f8ac80ad4b32978a84
child 287936 253c0c16689397b42dbebe1d1282d07363bd9f9b
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1173171
milestone42.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 1173171 - Disable external jar: via preference. r=jduell
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
modules/libjar/test/mochitest/mochitest.ini
modules/libjar/test/mochitest/test_bug1173171.html
modules/libpref/init/all.js
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -199,20 +199,23 @@ nsJARChannel::nsJARChannel()
     , mContentLength(-1)
     , mLoadFlags(LOAD_NORMAL)
     , mStatus(NS_OK)
     , mIsPending(false)
     , mIsUnsafe(true)
     , mOpeningRemote(false)
     , mSynthesizedStreamLength(0)
     , mForceNoIntercept(false)
+    , mBlockRemoteFiles(false)
 {
     if (!gJarProtocolLog)
         gJarProtocolLog = PR_NewLogModule("nsJarProtocol");
 
+    mBlockRemoteFiles = Preferences::GetBool("network.jar.block-remote-files", false);
+
     // hold an owning reference to the jar handler
     NS_ADDREF(gJarHandler);
 }
 
 nsJARChannel::~nsJARChannel()
 {
     NS_ReleaseOnMainThread(mLoadInfo);
 
@@ -1001,16 +1004,23 @@ nsJARChannel::ContinueAsyncOpen()
         mListener = nullptr;
         return rv;
     }
 
     nsCOMPtr<nsIChannel> channel;
 
     if (!mJarFile) {
         // Not a local file...
+
+        // Check preferences to see if all remote jar support should be disabled
+        if (mBlockRemoteFiles) {
+            mIsUnsafe = true;
+            return NS_ERROR_UNSAFE_CONTENT_TYPE;
+        }
+
         // kick off an async download of the base URI...
         nsCOMPtr<nsIStreamListener> downloader = new MemoryDownloader(this);
         uint32_t loadFlags =
             mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS);
         rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                    mJarBaseURI,
                                    mLoadInfo,
                                    mLoadGroup,
@@ -1180,16 +1190,20 @@ nsJARChannel::OnDownloadComplete(MemoryD
                 mIsUnsafe = unsafe;
             }
         }
 
         channel->GetContentDispositionHeader(mContentDispositionHeader);
         mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
     }
 
+    // This is a defense-in-depth check for the preferences to see if all remote jar
+    // support should be disabled. This check may not be needed.
+    MOZ_RELEASE_ASSERT(!mBlockRemoteFiles);
+
     if (NS_SUCCEEDED(status) && mIsUnsafe &&
         !Preferences::GetBool("network.jar.open-unsafe-types", false)) {
         status = NS_ERROR_UNSAFE_CONTENT_TYPE;
     }
 
     if (NS_SUCCEEDED(status)) {
         // Refuse to unpack view-source: jars even if open-unsafe-types is set.
         nsCOMPtr<nsIViewSourceChannel> viewSource = do_QueryInterface(channel);
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -134,12 +134,14 @@ private:
     nsCString                       mInnerJarEntry;
 
     nsRefPtr<nsInputStreamPump>     mSynthesizedResponsePump;
     int64_t                         mSynthesizedStreamLength;
 
     // True if this channel should skip any interception checks.
     bool                            mForceNoIntercept;
 
+    // True if this channel should not download any remote files.
+    bool                            mBlockRemoteFiles;
     friend class mozilla::net::InterceptedJARChannel;
 };
 
 #endif // nsJARChannel_h__
--- a/modules/libjar/test/mochitest/mochitest.ini
+++ b/modules/libjar/test/mochitest/mochitest.ini
@@ -3,8 +3,9 @@ skip-if = buildapp == 'b2g'
 support-files =
   bug403331.zip
   bug403331.zip^headers^
   openredirect.sjs
 
 [test_bug403331.html]
 [test_bug1034143_mapped.html]
 run-if = os == 'linux'
+[test_bug1173171.html]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/modules/libjar/test/mochitest/test_bug1173171.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1173171
+-->
+<head>
+  <title>Test for Bug 1173171</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe id="testFrame"></iframe>
+
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+/** Test for Bug 1173171 **/
+
+SimpleTest.waitForExplicitFinish();
+
+// __setPref(key, value)__.
+// Set a pref value asynchronously, returning a prmoise that resolves
+// when it succeeds.
+let pushPref = function (key, value) {
+  return new Promise(function(resolve, reject) {
+    SpecialPowers.pushPrefEnv({"set": [[key, value]]}, resolve);
+  });
+};
+
+// __xhr(method, url, responseType__.
+// A simple async XMLHttpRequest call.
+// Returns a promise with the response.
+let xhr = function (method, url, responseType) {
+  return new Promise(function (resolve, reject) {
+    let xhr = new XMLHttpRequest();
+    xhr.open(method, url, true);
+    xhr.onload = function () {
+      resolve(xhr.response);
+    };
+    xhr.responseType = responseType;
+    xhr.send();
+  });
+};
+
+let jarURL = "jar:http://mochi.test:8888/tests/modules/libjar/test/mochitest/bug403331.zip!/test.html";
+
+// Test behavior when blocking is deactivated and activated.
+spawnTask(function* () {
+  for (let shouldBlock of [false, true]) {
+    yield pushPref("network.jar.block-remote-files", shouldBlock);
+    try {
+      let response = yield xhr("GET", jarURL, "document");
+      didBlock = false;
+    } catch (e) {
+      didBlock = true;
+    }
+    ok(didBlock === shouldBlock,
+       "Remote jars should be blocked if and only if the 'network.jar.block-remote-files' pref is active.");
+  }
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+
+</body>
+</html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1498,16 +1498,18 @@ pref("network.websocket.delay-failed-rec
 pref("dom.server-events.enabled", true);
 // Equal to the DEFAULT_RECONNECTION_TIME_VALUE value in nsEventSource.cpp
 pref("dom.server-events.default-reconnection-time", 5000); // in milliseconds
 
 // If false, remote JAR files that are served with a content type other than
 // application/java-archive or application/x-jar will not be opened
 // by the jar channel.
 pref("network.jar.open-unsafe-types", false);
+// If true, loading remote JAR files using the jar: protocol will be prevented.
+pref("network.jar.block-remote-files", false);
 
 // This preference, if true, causes all UTF-8 domain names to be normalized to
 // punycode.  The intention is to allow UTF-8 domain names as input, but never
 // generate them from punycode.
 pref("network.IDN_show_punycode", false);
 
 // If "network.IDN.use_whitelist" is set to true, TLDs with
 // "network.IDN.whitelist.tld" explicitly set to true are treated as