Includes fixes for CVE-2018-12363, CVE-2018-12364, CVE-2018-12366, the remaining 1 out of 2 changesets for CVE-2018-5156, and the remaining 7 out of 17 changesets for CVE-2018-5188. * gnu/packages/gnuzilla.scm (icecat)[source]: Add selected fixes from the upstream mozilla-esr52 repository. * gnu/packages/patches/icecat-bug-1413868-pt1.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it.
		
			
				
	
	
		
			663 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			663 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
Based on <https://hg.mozilla.org/releases/mozilla-esr52/rev/431fa5dd4016>
 | 
						|
Adapted to apply cleanly to GNU IceCat.
 | 
						|
 | 
						|
# HG changeset patch
 | 
						|
# User Honza Bambas <honzab.moz@firemni.cz>
 | 
						|
# Date 1528830658 14400
 | 
						|
# Node ID 431fa5dd4016bdab7e4bb0d3c4df85468fe337b0
 | 
						|
# Parent  e8e9e1ef79f2a18c61ec1b87cfb214c8d4960f8e
 | 
						|
Bug 1413868. r=valentin, a=RyanVM
 | 
						|
 | 
						|
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
 | 
						|
--- a/toolkit/xre/nsAppRunner.cpp
 | 
						|
+++ b/toolkit/xre/nsAppRunner.cpp
 | 
						|
@@ -4,16 +4,17 @@
 | 
						|
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 
 | 
						|
 #include "mozilla/dom/ContentParent.h"
 | 
						|
 #include "mozilla/dom/ContentChild.h"
 | 
						|
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 | 
						|
 
 | 
						|
 #include "mozilla/ArrayUtils.h"
 | 
						|
 #include "mozilla/Attributes.h"
 | 
						|
+#include "mozilla/FilePreferences.h"
 | 
						|
 #include "mozilla/ChaosMode.h"
 | 
						|
 #include "mozilla/IOInterposer.h"
 | 
						|
 #include "mozilla/Likely.h"
 | 
						|
 #include "mozilla/MemoryChecking.h"
 | 
						|
 #include "mozilla/Poison.h"
 | 
						|
 #include "mozilla/Preferences.h"
 | 
						|
 #include "mozilla/ScopeExit.h"
 | 
						|
 #include "mozilla/Services.h"
 | 
						|
@@ -4304,16 +4305,20 @@ XREMain::XRE_mainRun()
 | 
						|
       // Need to write out the fact that the profile has been removed and potentially
 | 
						|
       // that the selected/default profile changed.
 | 
						|
       mProfileSvc->Flush();
 | 
						|
     }
 | 
						|
   }
 | 
						|
 
 | 
						|
   mDirProvider.DoStartup();
 | 
						|
 
 | 
						|
+  // As FilePreferences need the profile directory, we must initialize right here.
 | 
						|
+  mozilla::FilePreferences::InitDirectoriesWhitelist();
 | 
						|
+  mozilla::FilePreferences::InitPrefs();
 | 
						|
+
 | 
						|
   OverrideDefaultLocaleIfNeeded();
 | 
						|
 
 | 
						|
 #ifdef MOZ_CRASHREPORTER
 | 
						|
   nsCString userAgentLocale;
 | 
						|
   // Try a localized string first. This pref is always a localized string in
 | 
						|
   // IceCatMobile, and might be elsewhere, too.
 | 
						|
   if (NS_SUCCEEDED(Preferences::GetLocalizedCString("general.useragent.locale", &userAgentLocale))) {
 | 
						|
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale);
 | 
						|
diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp
 | 
						|
--- a/toolkit/xre/nsEmbedFunctions.cpp
 | 
						|
+++ b/toolkit/xre/nsEmbedFunctions.cpp
 | 
						|
@@ -46,16 +46,17 @@
 | 
						|
 #include "nsX11ErrorHandler.h"
 | 
						|
 #include "nsGDKErrorHandler.h"
 | 
						|
 #include "base/at_exit.h"
 | 
						|
 #include "base/command_line.h"
 | 
						|
 #include "base/message_loop.h"
 | 
						|
 #include "base/process_util.h"
 | 
						|
 #include "chrome/common/child_process.h"
 | 
						|
 
 | 
						|
+#include "mozilla/FilePreferences.h"
 | 
						|
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 | 
						|
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 | 
						|
 #include "mozilla/ipc/IOThreadChild.h"
 | 
						|
 #include "mozilla/ipc/ProcessChild.h"
 | 
						|
 #include "ScopedXREEmbed.h"
 | 
						|
 
 | 
						|
 #include "mozilla/plugins/PluginProcessChild.h"
 | 
						|
 #include "mozilla/dom/ContentProcess.h"
 | 
						|
@@ -680,16 +681,18 @@ XRE_InitChildProcess(int aArgc,
 | 
						|
       ::SetProcessShutdownParameters(0x280 - 1, SHUTDOWN_NORETRY);
 | 
						|
 #endif
 | 
						|
 
 | 
						|
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
 | 
						|
       // We need to do this after the process has been initialised, as
 | 
						|
       // InitLoggingIfRequired may need access to prefs.
 | 
						|
       mozilla::sandboxing::InitLoggingIfRequired(aChildData->ProvideLogFunction);
 | 
						|
 #endif
 | 
						|
+      mozilla::FilePreferences::InitDirectoriesWhitelist();
 | 
						|
+      mozilla::FilePreferences::InitPrefs();
 | 
						|
 
 | 
						|
       OverrideDefaultLocaleIfNeeded();
 | 
						|
 
 | 
						|
 #if defined(MOZ_CRASHREPORTER)
 | 
						|
 #if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK)
 | 
						|
       AddContentSandboxLevelAnnotation();
 | 
						|
 #endif
 | 
						|
 #endif
 | 
						|
diff --git a/xpcom/io/FilePreferences.cpp b/xpcom/io/FilePreferences.cpp
 | 
						|
new file mode 100644
 | 
						|
--- /dev/null
 | 
						|
+++ b/xpcom/io/FilePreferences.cpp
 | 
						|
@@ -0,0 +1,271 @@
 | 
						|
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
+/* 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 "FilePreferences.h"
 | 
						|
+
 | 
						|
+#include "mozilla/Preferences.h"
 | 
						|
+#include "nsAppDirectoryServiceDefs.h"
 | 
						|
+#include "nsDirectoryServiceDefs.h"
 | 
						|
+#include "nsDirectoryServiceUtils.h"
 | 
						|
+
 | 
						|
+namespace mozilla {
 | 
						|
+namespace FilePreferences {
 | 
						|
+
 | 
						|
+static bool sBlockUNCPaths = false;
 | 
						|
+typedef nsTArray<nsString> Paths;
 | 
						|
+
 | 
						|
+static Paths& PathArray()
 | 
						|
+{
 | 
						|
+  static Paths sPaths;
 | 
						|
+  return sPaths;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void AllowDirectory(char const* directory)
 | 
						|
+{
 | 
						|
+  nsCOMPtr<nsIFile> file;
 | 
						|
+  NS_GetSpecialDirectory(directory, getter_AddRefs(file));
 | 
						|
+  if (!file) {
 | 
						|
+    return;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  nsString path;
 | 
						|
+  if (NS_FAILED(file->GetTarget(path))) {
 | 
						|
+    return;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  // The whitelist makes sense only for UNC paths, because this code is used
 | 
						|
+  // to block only UNC paths, hence, no need to add non-UNC directories here
 | 
						|
+  // as those would never pass the check.
 | 
						|
+  if (!StringBeginsWith(path, NS_LITERAL_STRING("\\\\"))) {
 | 
						|
+    return;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (!PathArray().Contains(path)) {
 | 
						|
+    PathArray().AppendElement(path);
 | 
						|
+  }
 | 
						|
+}
 | 
						|
+
 | 
						|
+void InitPrefs()
 | 
						|
+{
 | 
						|
+  sBlockUNCPaths = Preferences::GetBool("network.file.disable_unc_paths", false);
 | 
						|
+}
 | 
						|
+
 | 
						|
+void InitDirectoriesWhitelist()
 | 
						|
+{
 | 
						|
+  // NS_GRE_DIR is the installation path where the binary resides.
 | 
						|
+  AllowDirectory(NS_GRE_DIR);
 | 
						|
+  // NS_APP_USER_PROFILE_50_DIR and NS_APP_USER_PROFILE_LOCAL_50_DIR are the two
 | 
						|
+  // parts of the profile we store permanent and local-specific data.
 | 
						|
+  AllowDirectory(NS_APP_USER_PROFILE_50_DIR);
 | 
						|
+  AllowDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR);
 | 
						|
+}
 | 
						|
+
 | 
						|
+namespace { // anon
 | 
						|
+
 | 
						|
+class Normalizer
 | 
						|
+{
 | 
						|
+public:
 | 
						|
+  Normalizer(const nsAString& aFilePath, const char16_t aSeparator);
 | 
						|
+  bool Get(nsAString& aNormalizedFilePath);
 | 
						|
+
 | 
						|
+private:
 | 
						|
+  bool ConsumeItem();
 | 
						|
+  bool ConsumeSeparator();
 | 
						|
+  bool IsEOF() { return mFilePathCursor == mFilePathEnd; }
 | 
						|
+
 | 
						|
+  bool ConsumeName();
 | 
						|
+  bool CheckParentDir();
 | 
						|
+  bool CheckCurrentDir();
 | 
						|
+
 | 
						|
+  nsString::const_char_iterator mFilePathCursor;
 | 
						|
+  nsString::const_char_iterator mFilePathEnd;
 | 
						|
+
 | 
						|
+  nsDependentSubstring mItem;
 | 
						|
+  char16_t const mSeparator;
 | 
						|
+  nsTArray<nsDependentSubstring> mStack;
 | 
						|
+};
 | 
						|
+
 | 
						|
+Normalizer::Normalizer(const nsAString& aFilePath, const char16_t aSeparator)
 | 
						|
+  : mFilePathCursor(aFilePath.BeginReading())
 | 
						|
+  , mFilePathEnd(aFilePath.EndReading())
 | 
						|
+  , mSeparator(aSeparator)
 | 
						|
+{
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool Normalizer::ConsumeItem()
 | 
						|
+{
 | 
						|
+  if (IsEOF()) {
 | 
						|
+    return false;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  nsString::const_char_iterator nameBegin = mFilePathCursor;
 | 
						|
+  while (mFilePathCursor != mFilePathEnd) {
 | 
						|
+    if (*mFilePathCursor == mSeparator) {
 | 
						|
+      break; // don't include the separator
 | 
						|
+    }
 | 
						|
+    ++mFilePathCursor;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  mItem.Rebind(nameBegin, mFilePathCursor);
 | 
						|
+  return true;
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool Normalizer::ConsumeSeparator()
 | 
						|
+{
 | 
						|
+  if (IsEOF()) {
 | 
						|
+    return false;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (*mFilePathCursor != mSeparator) {
 | 
						|
+    return false;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  ++mFilePathCursor;
 | 
						|
+  return true;
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool Normalizer::Get(nsAString& aNormalizedFilePath)
 | 
						|
+{
 | 
						|
+  aNormalizedFilePath.Truncate();
 | 
						|
+
 | 
						|
+  if (IsEOF()) {
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+  if (ConsumeSeparator()) {
 | 
						|
+    aNormalizedFilePath.Append(mSeparator);
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (IsEOF()) {
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+  if (ConsumeSeparator()) {
 | 
						|
+    aNormalizedFilePath.Append(mSeparator);
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  while (!IsEOF()) {
 | 
						|
+    if (!ConsumeName()) {
 | 
						|
+      return false;
 | 
						|
+    }
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  for (auto const& name : mStack) {
 | 
						|
+    aNormalizedFilePath.Append(name);
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  return true;
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool Normalizer::ConsumeName()
 | 
						|
+{
 | 
						|
+  if (!ConsumeItem()) {
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (CheckCurrentDir()) {
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (CheckParentDir()) {
 | 
						|
+    if (!mStack.Length()) {
 | 
						|
+      // This means there are more \.. than valid names
 | 
						|
+      return false;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    mStack.RemoveElementAt(mStack.Length() - 1);
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (mItem.IsEmpty()) {
 | 
						|
+    // this means an empty name (a lone slash), which is illegal
 | 
						|
+    return false;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (ConsumeSeparator()) {
 | 
						|
+    mItem.Rebind(mItem.BeginReading(), mFilePathCursor);
 | 
						|
+  }
 | 
						|
+  mStack.AppendElement(mItem);
 | 
						|
+
 | 
						|
+  return true;
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool Normalizer::CheckCurrentDir()
 | 
						|
+{
 | 
						|
+  if (mItem == NS_LITERAL_STRING(".")) {
 | 
						|
+    ConsumeSeparator();
 | 
						|
+    // EOF is acceptable
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  return false;
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool Normalizer::CheckParentDir()
 | 
						|
+{
 | 
						|
+  if (mItem == NS_LITERAL_STRING("..")) {
 | 
						|
+    ConsumeSeparator();
 | 
						|
+    // EOF is acceptable
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  return false;
 | 
						|
+}
 | 
						|
+
 | 
						|
+} // anon
 | 
						|
+
 | 
						|
+bool IsBlockedUNCPath(const nsAString& aFilePath)
 | 
						|
+{
 | 
						|
+  if (!sBlockUNCPaths) {
 | 
						|
+    return false;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  if (!StringBeginsWith(aFilePath, NS_LITERAL_STRING("\\\\"))) {
 | 
						|
+    return false;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  nsAutoString normalized;
 | 
						|
+  if (!Normalizer(aFilePath, L'\\').Get(normalized)) {
 | 
						|
+    // Broken paths are considered invalid and thus inaccessible
 | 
						|
+    return true;
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  for (const auto& allowedPrefix : PathArray()) {
 | 
						|
+    if (StringBeginsWith(normalized, allowedPrefix)) {
 | 
						|
+      if (normalized.Length() == allowedPrefix.Length()) {
 | 
						|
+        return false;
 | 
						|
+      }
 | 
						|
+      if (normalized[allowedPrefix.Length()] == L'\\') {
 | 
						|
+        return false;
 | 
						|
+      }
 | 
						|
+
 | 
						|
+      // When we are here, the path has a form "\\path\prefixevil"
 | 
						|
+      // while we have an allowed prefix of "\\path\prefix".
 | 
						|
+      // Note that we don't want to add a slash to the end of a prefix
 | 
						|
+      // so that opening the directory (no slash at the end) still works.
 | 
						|
+      break;
 | 
						|
+    }
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  return true;
 | 
						|
+}
 | 
						|
+
 | 
						|
+void testing::SetBlockUNCPaths(bool aBlock)
 | 
						|
+{
 | 
						|
+  sBlockUNCPaths = aBlock;
 | 
						|
+}
 | 
						|
+
 | 
						|
+void testing::AddDirectoryToWhitelist(nsAString const & aPath)
 | 
						|
+{
 | 
						|
+  PathArray().AppendElement(aPath);
 | 
						|
+}
 | 
						|
+
 | 
						|
+bool testing::NormalizePath(nsAString const & aPath, nsAString & aNormalized)
 | 
						|
+{
 | 
						|
+  Normalizer normalizer(aPath, L'\\');
 | 
						|
+  return normalizer.Get(aNormalized);
 | 
						|
+}
 | 
						|
+
 | 
						|
+} // ::FilePreferences
 | 
						|
+} // ::mozilla
 | 
						|
diff --git a/xpcom/io/FilePreferences.h b/xpcom/io/FilePreferences.h
 | 
						|
new file mode 100644
 | 
						|
--- /dev/null
 | 
						|
+++ b/xpcom/io/FilePreferences.h
 | 
						|
@@ -0,0 +1,25 @@
 | 
						|
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
+/* 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 "nsIObserver.h"
 | 
						|
+
 | 
						|
+namespace mozilla {
 | 
						|
+namespace FilePreferences {
 | 
						|
+
 | 
						|
+void InitPrefs();
 | 
						|
+void InitDirectoriesWhitelist();
 | 
						|
+bool IsBlockedUNCPath(const nsAString& aFilePath);
 | 
						|
+
 | 
						|
+namespace testing {
 | 
						|
+
 | 
						|
+void SetBlockUNCPaths(bool aBlock);
 | 
						|
+void AddDirectoryToWhitelist(nsAString const& aPath);
 | 
						|
+bool NormalizePath(nsAString const & aPath, nsAString & aNormalized);
 | 
						|
+
 | 
						|
+}
 | 
						|
+
 | 
						|
+} // FilePreferences
 | 
						|
+} // mozilla
 | 
						|
diff --git a/xpcom/io/moz.build b/xpcom/io/moz.build
 | 
						|
--- a/xpcom/io/moz.build
 | 
						|
+++ b/xpcom/io/moz.build
 | 
						|
@@ -79,24 +79,26 @@ EXPORTS += [
 | 
						|
     'nsUnicharInputStream.h',
 | 
						|
     'nsWildCard.h',
 | 
						|
     'SlicedInputStream.h',
 | 
						|
     'SpecialSystemDirectory.h',
 | 
						|
 ]
 | 
						|
 
 | 
						|
 EXPORTS.mozilla += [
 | 
						|
     'Base64.h',
 | 
						|
+    'FilePreferences.h',
 | 
						|
     'SnappyCompressOutputStream.h',
 | 
						|
     'SnappyFrameUtils.h',
 | 
						|
     'SnappyUncompressInputStream.h',
 | 
						|
 ]
 | 
						|
 
 | 
						|
 UNIFIED_SOURCES += [
 | 
						|
     'Base64.cpp',
 | 
						|
     'crc32c.c',
 | 
						|
+    'FilePreferences.cpp',
 | 
						|
     'nsAnonymousTemporaryFile.cpp',
 | 
						|
     'nsAppFileLocationProvider.cpp',
 | 
						|
     'nsBinaryStream.cpp',
 | 
						|
     'nsDirectoryService.cpp',
 | 
						|
     'nsEscape.cpp',
 | 
						|
     'nsInputStreamTee.cpp',
 | 
						|
     'nsIOUtil.cpp',
 | 
						|
     'nsLinebreakConverter.cpp',
 | 
						|
diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp
 | 
						|
--- a/xpcom/io/nsLocalFileWin.cpp
 | 
						|
+++ b/xpcom/io/nsLocalFileWin.cpp
 | 
						|
@@ -41,16 +41,17 @@
 | 
						|
 #include  <stdio.h>
 | 
						|
 #include  <stdlib.h>
 | 
						|
 #include  <mbstring.h>
 | 
						|
 
 | 
						|
 #include "nsXPIDLString.h"
 | 
						|
 #include "prproces.h"
 | 
						|
 #include "prlink.h"
 | 
						|
 
 | 
						|
+#include "mozilla/FilePreferences.h"
 | 
						|
 #include "mozilla/Mutex.h"
 | 
						|
 #include "SpecialSystemDirectory.h"
 | 
						|
 
 | 
						|
 #include "nsTraceRefcnt.h"
 | 
						|
 #include "nsXPCOMCIDInternal.h"
 | 
						|
 #include "nsThreadUtils.h"
 | 
						|
 #include "nsXULAppAPI.h"
 | 
						|
 
 | 
						|
@@ -1162,16 +1163,20 @@ nsLocalFile::InitWithPath(const nsAStrin
 | 
						|
   char16_t secondChar = *(++begin);
 | 
						|
 
 | 
						|
   // just do a sanity check.  if it has any forward slashes, it is not a Native path
 | 
						|
   // on windows.  Also, it must have a colon at after the first char.
 | 
						|
   if (FindCharInReadable(L'/', begin, end)) {
 | 
						|
     return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 | 
						|
   }
 | 
						|
 
 | 
						|
+  if (FilePreferences::IsBlockedUNCPath(aFilePath)) {
 | 
						|
+    return NS_ERROR_FILE_ACCESS_DENIED;
 | 
						|
+  }
 | 
						|
+
 | 
						|
   if (secondChar != L':' && (secondChar != L'\\' || firstChar != L'\\')) {
 | 
						|
     return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 | 
						|
   }
 | 
						|
 
 | 
						|
   if (secondChar == L':') {
 | 
						|
     // Make sure we have a valid drive, later code assumes the drive letter
 | 
						|
     // is a single char a-z or A-Z.
 | 
						|
     if (PathGetDriveNumberW(aFilePath.Data()) == -1) {
 | 
						|
@@ -1974,16 +1979,20 @@ nsLocalFile::CopySingleFile(nsIFile* aSo
 | 
						|
     bool path1Remote, path2Remote;
 | 
						|
     if (!IsRemoteFilePath(filePath.get(), path1Remote) ||
 | 
						|
         !IsRemoteFilePath(destPath.get(), path2Remote) ||
 | 
						|
         path1Remote || path2Remote) {
 | 
						|
       dwCopyFlags |= COPY_FILE_NO_BUFFERING;
 | 
						|
     }
 | 
						|
   }
 | 
						|
 
 | 
						|
+  if (FilePreferences::IsBlockedUNCPath(destPath)) {
 | 
						|
+    return NS_ERROR_FILE_ACCESS_DENIED;
 | 
						|
+  }
 | 
						|
+
 | 
						|
   if (!move) {
 | 
						|
     copyOK = ::CopyFileExW(filePath.get(), destPath.get(), nullptr,
 | 
						|
                            nullptr, nullptr, dwCopyFlags);
 | 
						|
   } else {
 | 
						|
     copyOK = ::MoveFileExW(filePath.get(), destPath.get(),
 | 
						|
                            MOVEFILE_REPLACE_EXISTING);
 | 
						|
 
 | 
						|
     // Check if copying the source file to a different volume,
 | 
						|
diff --git a/xpcom/tests/gtest/TestFilePreferencesWin.cpp b/xpcom/tests/gtest/TestFilePreferencesWin.cpp
 | 
						|
new file mode 100644
 | 
						|
--- /dev/null
 | 
						|
+++ b/xpcom/tests/gtest/TestFilePreferencesWin.cpp
 | 
						|
@@ -0,0 +1,141 @@
 | 
						|
+#include "gtest/gtest.h"
 | 
						|
+
 | 
						|
+#include "mozilla/FilePreferences.h"
 | 
						|
+#include "nsIFile.h"
 | 
						|
+#include "nsXPCOMCID.h"
 | 
						|
+
 | 
						|
+TEST(FilePreferencesWin, Normalization)
 | 
						|
+{
 | 
						|
+  nsAutoString normalized;
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("foo"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("foo"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\foo"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\foo"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("foo\\some"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("foo\\some"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\.\\foo"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\."), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\.\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\.\\."), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo\\bar"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo\\bar\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\."), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo\\bar\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\.\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo\\bar\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\..\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\.."), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\foo\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\..\\bar\\..\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\..\\bar"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\bar"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\..\\..\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\"));
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\.\\..\\.\\..\\"), normalized);
 | 
						|
+  ASSERT_TRUE(normalized == NS_LITERAL_STRING("\\\\"));
 | 
						|
+
 | 
						|
+  bool result;
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\.."), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\..\\"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\.\\..\\"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\\\bar"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\foo\\bar\\..\\..\\..\\..\\"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\\\"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\.\\\\"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+
 | 
						|
+  result = mozilla::FilePreferences::testing::NormalizePath(
 | 
						|
+    NS_LITERAL_STRING("\\\\..\\\\"), normalized);
 | 
						|
+  ASSERT_FALSE(result);
 | 
						|
+}
 | 
						|
+
 | 
						|
+TEST(FilePreferencesWin, AccessUNC)
 | 
						|
+{
 | 
						|
+  nsCOMPtr<nsIFile> lf = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
 | 
						|
+
 | 
						|
+  nsresult rv;
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::SetBlockUNCPaths(false);
 | 
						|
+
 | 
						|
+  rv = lf->InitWithPath(NS_LITERAL_STRING("\\\\nice\\..\\evil\\share"));
 | 
						|
+  ASSERT_EQ(rv, NS_OK);
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::SetBlockUNCPaths(true);
 | 
						|
+
 | 
						|
+  rv = lf->InitWithPath(NS_LITERAL_STRING("\\\\nice\\..\\evil\\share"));
 | 
						|
+  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
 | 
						|
+
 | 
						|
+  mozilla::FilePreferences::testing::AddDirectoryToWhitelist(NS_LITERAL_STRING("\\\\nice"));
 | 
						|
+
 | 
						|
+  rv = lf->InitWithPath(NS_LITERAL_STRING("\\\\nice\\share"));
 | 
						|
+  ASSERT_EQ(rv, NS_OK);
 | 
						|
+
 | 
						|
+  rv = lf->InitWithPath(NS_LITERAL_STRING("\\\\nice\\..\\evil\\share"));
 | 
						|
+  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
 | 
						|
+}
 | 
						|
diff --git a/xpcom/tests/gtest/moz.build b/xpcom/tests/gtest/moz.build
 | 
						|
--- a/xpcom/tests/gtest/moz.build
 | 
						|
+++ b/xpcom/tests/gtest/moz.build
 | 
						|
@@ -51,16 +51,21 @@ UNIFIED_SOURCES += [
 | 
						|
 if CONFIG['MOZ_DEBUG'] and CONFIG['OS_ARCH'] not in ('WINNT') and CONFIG['OS_TARGET'] != 'Android':
 | 
						|
     # FIXME bug 523392: TestDeadlockDetector doesn't like Windows
 | 
						|
     # Bug 1054249: Doesn't work on Android
 | 
						|
     UNIFIED_SOURCES += [
 | 
						|
         'TestDeadlockDetector.cpp',
 | 
						|
         'TestDeadlockDetectorScalability.cpp',
 | 
						|
     ]
 | 
						|
 
 | 
						|
+if CONFIG['OS_TARGET'] == 'WINNT':
 | 
						|
+    UNIFIED_SOURCES += [
 | 
						|
+        'TestFilePreferencesWin.cpp',
 | 
						|
+    ]
 | 
						|
+
 | 
						|
 if CONFIG['WRAP_STL_INCLUDES'] and not CONFIG['CLANG_CL']:
 | 
						|
     UNIFIED_SOURCES += [
 | 
						|
         'TestSTLWrappers.cpp',
 | 
						|
     ]
 | 
						|
 
 | 
						|
 # Compile TestAllocReplacement separately so Windows headers don't pollute
 | 
						|
 # the global namespace for other files.
 | 
						|
 SOURCES += [
 | 
						|
 |