Merge b-s to m-c.
authorKyle Huey <khuey@kylehuey.com>
Wed, 22 Feb 2012 19:00:04 -0800
changeset 87454 5e756e59a794f0f95d5dd853a0232e7d400f5983
parent 87452 c827c52c4603e3ccdf3800f340d0b4f7f7484d3c (current diff)
parent 87453 b7582d84aa151e0cd6b4f592ecf79659696724a1 (diff)
child 87507 15d7708672c1c5a355c3e647317ad8a4d7211c32
child 105873 83cb9381de53b1f9feb7dc15364b8f9955a432b2
push id22121
push userkhuey@mozilla.com
push dateThu, 23 Feb 2012 03:02:36 +0000
treeherdermozilla-central@5e756e59a794 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.0a1
first release with
nightly linux32
5e756e59a794 / 13.0a1 / 20120223031236 / files
nightly linux64
5e756e59a794 / 13.0a1 / 20120223031236 / files
nightly mac
5e756e59a794 / 13.0a1 / 20120223031236 / files
nightly win32
5e756e59a794 / 13.0a1 / 20120223031236 / files
nightly win64
5e756e59a794 / 13.0a1 / 20120223031236 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b-s to m-c.
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1755,16 +1755,20 @@ main(int argc, char **argv, char **envp)
     nsresult rv;
 
 #ifdef HAVE_SETBUF
     // unbuffer stdout so that output is in the correct order; note that stderr
     // is unbuffered by default
     setbuf(stdout, 0);
 #endif
 
+#ifdef XRE_HAS_DLL_BLOCKLIST
+    XRE_SetupDllBlocklist();
+#endif
+
     gErrFile = stderr;
     gOutFile = stdout;
     gInFile = stdin;
 
     NS_LogInit();
 
     nsCOMPtr<nsILocalFile> appFile;
     rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile));
--- a/toolkit/xre/nsWindowsDllBlocklist.cpp
+++ b/toolkit/xre/nsWindowsDllBlocklist.cpp
@@ -45,16 +45,17 @@
 
 #ifdef XRE_WANT_DLL_BLOCKLIST
 #define XRE_SetupDllBlocklist SetupDllBlocklist
 #else
 #include "nsXULAppAPI.h"
 #endif
 
 #include "nsAutoPtr.h"
+#include "nsThreadUtils.h"
 
 #include "prlog.h"
 
 #include "nsWindowsDllInterceptor.h"
 
 #if defined(MOZ_CRASHREPORTER) && !defined(NO_BLOCKLIST_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #endif
@@ -146,22 +147,86 @@ static DllBlockInfo sWindowsDllBlocklist
 
 #ifndef STATUS_DLL_NOT_FOUND
 #define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
 #endif
 
 // define this for very verbose dll load debug spew
 #undef DEBUG_very_verbose
 
+extern bool gInXPCOMLoadOnMainThread;
+
 namespace {
 
 typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle);
 
 static LdrLoadDll_func stub_LdrLoadDll = 0;
 
+template <class T>
+struct RVAMap {
+  RVAMap(HANDLE map, DWORD offset) {
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+
+    DWORD alignedOffset = (offset / info.dwAllocationGranularity) *
+                          info.dwAllocationGranularity;
+
+    NS_ASSERTION(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
+
+    mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset,
+                                sizeof(T) + (offset - alignedOffset));
+
+    mMappedView = reinterpret_cast<T*>((char*)mRealView + (offset - alignedOffset));
+  }
+  ~RVAMap() {
+    if (mRealView) {
+      ::UnmapViewOfFile(mRealView);
+    }
+  }
+  operator const T*() const { return mMappedView; }
+  const T* operator->() const { return mMappedView; }
+private:
+  const T* mMappedView;
+  void* mRealView;
+};
+
+bool
+CheckASLR(const wchar_t* path)
+{
+  bool retval = false;
+
+  HANDLE file = ::CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
+                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+                              NULL);
+  if (file != INVALID_HANDLE_VALUE) {
+    HANDLE map = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
+    if (map) {
+      RVAMap<IMAGE_DOS_HEADER> peHeader(map, 0);
+      if (peHeader) {
+        RVAMap<IMAGE_NT_HEADERS> ntHeader(map, peHeader->e_lfanew);
+        if (ntHeader) {
+          // If the DLL has no code, permit it regardless of ASLR status.
+          if (ntHeader->OptionalHeader.SizeOfCode == 0) {
+            retval = true;
+          }
+          // Check to see if the DLL supports ASLR
+          else if ((ntHeader->OptionalHeader.DllCharacteristics &
+                    IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0) {
+            retval = true;
+          }
+        }
+      }
+      ::CloseHandle(map);
+    }
+    ::CloseHandle(file);
+  }
+
+  return retval;
+}
+
 /**
  * Some versions of Windows call LoadLibraryEx to get the version information
  * for a DLL, which causes our patched LdrLoadDll implementation to re-enter
  * itself and cause infinite recursion and a stack-exhaustion crash. We protect
  * against reentrancy by allowing recursive loads of the same DLL.
  *
  * Note that we don't use __declspec(thread) because that doesn't work in DLLs
  * loaded via LoadLibrary and there can be a limited number of TLS slots, so
@@ -220,16 +285,39 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
 #define DLLNAME_MAX 128
   char dllName[DLLNAME_MAX+1];
   wchar_t *dll_part;
   DllBlockInfo *info;
 
   int len = moduleFileName->Length / 2;
   wchar_t *fname = moduleFileName->Buffer;
 
+  // In Windows 8, the first parameter seems to be used for more than just the
+  // path name.  For example, its numerical value can be 1.  Passing a non-valid
+  // pointer to SearchPathW will cause a crash, so we need to check to see if we
+  // are handed a valid pointer, and otherwise just pass NULL to SearchPathW.
+  PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? NULL : filePath;
+
+  // figure out the length of the string that we need
+  DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, NULL, NULL);
+  if (pathlen == 0) {
+    // uh, we couldn't find the DLL at all, so...
+    printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
+    return STATUS_DLL_NOT_FOUND;
+  }
+
+  nsAutoArrayPtr<wchar_t> full_fname(new wchar_t[pathlen+1]);
+  if (!full_fname) {
+    // couldn't allocate memory?
+    return STATUS_DLL_NOT_FOUND;
+  }
+
+  // now actually grab it
+  SearchPathW(sanitizedFilePath, fname, L".dll", pathlen+1, full_fname, NULL);
+
   // The filename isn't guaranteed to be null terminated, but in practice
   // it always will be; ensure that this is so, and bail if not.
   // This is done instead of the more robust approach because of bug 527122,
   // where lots of weird things were happening when we tried to make a copy.
   if (moduleFileName->MaximumLength < moduleFileName->Length+2 ||
       fname[len] != 0)
   {
 #ifdef DEBUG
@@ -300,39 +388,16 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
 #endif
 
     if (info->maxVersion != ALL_VERSIONS) {
       ReentrancySentinel sentinel(dllName);
       if (sentinel.BailOut()) {
         goto continue_loading;
       }
 
-      // In Windows 8, the first parameter seems to be used for more than just the
-      // path name.  For example, its numerical value can be 1.  Passing a non-valid
-      // pointer to SearchPathW will cause a crash, so we need to check to see if we
-      // are handed a valid pointer, and otherwise just pass NULL to SearchPathW.
-      PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? NULL : filePath;
-
-      // figure out the length of the string that we need
-      DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, NULL, NULL);
-      if (pathlen == 0) {
-        // uh, we couldn't find the DLL at all, so...
-        printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
-        return STATUS_DLL_NOT_FOUND;
-      }
-
-      wchar_t *full_fname = (wchar_t*) malloc(sizeof(wchar_t)*(pathlen+1));
-      if (!full_fname) {
-        // couldn't allocate memory?
-        return STATUS_DLL_NOT_FOUND;
-      }
-
-      // now actually grab it
-      SearchPathW(sanitizedFilePath, fname, L".dll", pathlen+1, full_fname, NULL);
-
       DWORD zero;
       DWORD infoSize = GetFileVersionInfoSizeW(full_fname, &zero);
 
       // If we failed to get the version information, we block.
 
       if (infoSize != 0) {
         nsAutoArrayPtr<unsigned char> infoData(new unsigned char[infoSize]);
         VS_FIXEDFILEINFO *vInfo;
@@ -346,33 +411,39 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
             ((unsigned long long)vInfo->dwFileVersionLS);
 
           // finally do the version check, and if it's greater than our block
           // version, keep loading
           if (fVersion > info->maxVersion)
             load_ok = true;
         }
       }
-
-      free(full_fname);
     }
 
     if (!load_ok) {
       printf_stderr("LdrLoadDll: Blocking load of '%s' -- see http://www.mozilla.com/en-US/blocklist/\n", dllName);
       return STATUS_DLL_NOT_FOUND;
     }
   }
 
 continue_loading:
 #ifdef DEBUG_very_verbose
   printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
 #endif
 
   NS_SetHasLoadedNewDLLs();
 
+  if (gInXPCOMLoadOnMainThread && NS_IsMainThread()) {
+    // Check to ensure that the DLL has ASLR.
+    if (!CheckASLR(full_fname)) {
+      printf_stderr("LdrLoadDll: Blocking load of '%s'.  XPCOM components must support ASLR.\n", dllName);
+      return STATUS_DLL_NOT_FOUND;
+    }
+  }
+
   return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
 }
 
 WindowsDllInterceptor NtDllIntercept;
 
 } // anonymous namespace
 
 void
--- a/xpcom/components/nsNativeComponentLoader.cpp
+++ b/xpcom/components/nsNativeComponentLoader.cpp
@@ -82,16 +82,18 @@
 #define IMPLEMENT_BREAK_AFTER_LOAD
 #endif
 
 using namespace mozilla;
 
 static PRLogModuleInfo *nsNativeModuleLoaderLog =
     PR_NewLogModule("nsNativeModuleLoader");
 
+bool gInXPCOMLoadOnMainThread = false;
+
 #define LOG(level, args) PR_LOG(nsNativeModuleLoaderLog, level, args)
 
 NS_IMPL_QUERY_INTERFACE1(nsNativeModuleLoader, 
                          mozilla::ModuleLoader)
 
 NS_IMPL_ADDREF_USING_AGGREGATOR(nsNativeModuleLoader,
                                 nsComponentManagerImpl::gComponentManager)
 NS_IMPL_RELEASE_USING_AGGREGATOR(nsNativeModuleLoader,
@@ -162,17 +164,19 @@ nsNativeModuleLoader::LoadModule(FileLoc
         LOG(PR_LOG_DEBUG,
             ("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache",
              filePath.get()));
         return data.module;
     }
 
     // We haven't loaded this module before
 
+    gInXPCOMLoadOnMainThread = true;
     rv = file->Load(&data.library);
+    gInXPCOMLoadOnMainThread = false;
 
     if (NS_FAILED(rv)) {
         char errorMsg[1024] = "<unknown; can't get error from NSPR>";
 
         if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
             PR_GetErrorText(errorMsg);
 
         LogMessage("Failed to load native module at path '%s': (%lx) %s",
--- a/xpcom/tests/Makefile.in
+++ b/xpcom/tests/Makefile.in
@@ -40,17 +40,22 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir = xpcom/tests
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xpcom
 
-DIRS		= external component bug656331_component
+DIRS		= \
+  external \
+  component \
+  bug656331_component \
+  component_no_aslr \
+  $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 DIRS		+= windows
 endif
 
 ifdef DEHYDRA_PATH
 DIRS += static-checker
 endif
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/component_no_aslr/Makefile.in
@@ -0,0 +1,81 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Benjamin Smedberg <benjamin@smedbergs.us>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME	= testcompnoaslr
+IS_COMPONENT	= 1
+CPPSRCS	= TestComponent.cpp
+NO_DIST_INSTALL = 1
+FORCE_SHARED_LIB = 1
+
+include $(topsrcdir)/config/config.mk
+
+MANIFEST_FILE = testcompnoaslr.manifest
+
+EXTRA_DSO_LDOPTS = \
+		$(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
+		$(XPCOM_FROZEN_LDOPTS) \
+		$(NSPR_LIBS) \
+		$(NULL)
+
+# Need to link with CoreFoundation on Mac
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+EXTRA_DSO_LDOPTS += \
+		$(TK_LIBS) \
+		$(NULL)
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+LDFLAGS := $(filter-out -DYNAMICBASE,$(LDFLAGS)) -DYNAMICBASE:NO
+
+DEFINES += -DLIBRARY_FILENAME="$(SHARED_LIBRARY)"
+
+unittestlocation = xpcom/tests/unit
+
+libs:: $(SHARED_LIBRARY)
+	$(INSTALL) $^ $(testxpcobjdir)/$(unittestlocation)
+
+libs:: $(MANIFEST_FILE)
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $< > $(testxpcobjdir)/$(unittestlocation)/$(<F)
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/component_no_aslr/TestComponent.cpp
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Suresh Duddu <dp@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/ModuleUtils.h"
+
+#define NS_TESTING_CID \
+{ 0x335fb596, 0xe52d, 0x418f, \
+  { 0xb0, 0x1c, 0x1b, 0xf1, 0x6c, 0xe5, 0xe7, 0xe4 } }
+
+NS_DEFINE_NAMED_CID(NS_TESTING_CID);
+
+static nsresult
+DummyConstructorFunc(nsISupports* aOuter, const nsIID& aIID, void** aResult)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static const mozilla::Module::CIDEntry kTestCIDs[] = {
+  { &kNS_TESTING_CID, false, NULL, DummyConstructorFunc },
+  { NULL }
+};
+
+static const mozilla::Module kTestModule = {
+  mozilla::Module::kVersion,
+  kTestCIDs
+};
+
+NSMODULE_DEFN(dummy) = &kTestModule;
+
+  
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/component_no_aslr/testcompnoaslr.manifest
@@ -0,0 +1,2 @@
+#filter substitution
+binary-component @LIBRARY_FILENAME@
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/unit/test_comp_no_aslr.js
@@ -0,0 +1,10 @@
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function run_test() {
+  let manifest = do_get_file('testcompnoaslr.manifest');
+  Components.manager.autoRegister(manifest);
+  do_check_false("{335fb596-e52d-418f-b01c-1bf16ce5e7e4}" in Components.classesByID);
+}
--- a/xpcom/tests/unit/xpcshell.ini
+++ b/xpcom/tests/unit/xpcshell.ini
@@ -37,8 +37,10 @@ skip-if = os == "win" # See bug: 676412
 [test_stringstream.js]
 [test_symlinks.js]
 # Bug 676998: test fails consistently on Android
 fail-if = os == "android"
 [test_systemInfo.js]
 # Bug 676998: test fails consistently on Android
 fail-if = os == "android"
 [test_versioncomparator.js]
+[test_comp_no_aslr.js]
+fail-if = os != "win"