Bug 973933 - New updater-xpcshell binary for updater tests. r=rstrong
authorBrian R. Bondy <netzen@gmail.com>
Mon, 06 Apr 2015 12:03:18 -0400 (2015-04-06)
changeset 237695 a0d5f4706bd24be060f97c3d88d72c7d842eb174
parent 237694 71c747f84d03a3f7e50e349f1848d9641b2029ae
child 237696 c3dc05ca2b4a1b1971e9c380151974d792b35148
push id28546
push usernetzen@gmail.com
push dateMon, 06 Apr 2015 16:08:39 +0000 (2015-04-06)
treeherdermozilla-central@883e17fc475f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstrong
bugs973933
milestone40.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 973933 - New updater-xpcshell binary for updater tests. r=rstrong This is a rollup of recent work. Changes include: - Creating an xpcshell only updater binary. This binary has an embedded xpcshell only cert for verifying test only mars. It is only used by tests and is not signed w/ authenticode certs. - Modifying tests to use that new binary - Adding a check-cert option to the maintenance service - Using that new cert-check option in new tests to test the authenticode path - No longer doing an authenticode check during service updater tests on the xpcshell binary. - Enables more tests for other platforms
toolkit/components/maintenanceservice/maintenanceservice.cpp
toolkit/components/maintenanceservice/registrycertificates.cpp
toolkit/components/maintenanceservice/registrycertificates.h
toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini
toolkit/mozapps/update/tests/unit_service_updater/checkUpdaterSigSvc.js
toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini
toolkit/mozapps/update/updater/Makefile.in
toolkit/mozapps/update/updater/archivereader.cpp
toolkit/mozapps/update/updater/dep1.der
toolkit/mozapps/update/updater/dep2.der
toolkit/mozapps/update/updater/moz.build
toolkit/mozapps/update/updater/updater-common.build
toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
toolkit/mozapps/update/updater/updater-xpcshell/moz.build
toolkit/mozapps/update/updater/updater.cpp
toolkit/mozapps/update/updater/updater.rc
--- a/toolkit/components/maintenanceservice/maintenanceservice.cpp
+++ b/toolkit/components/maintenanceservice/maintenanceservice.cpp
@@ -9,16 +9,17 @@
 #include <shlobj.h>
 
 #include "serviceinstall.h"
 #include "maintenanceservice.h"
 #include "servicebase.h"
 #include "workmonitor.h"
 #include "uachelper.h"
 #include "updatehelper.h"
+#include "registrycertificates.h"
 
 // Link w/ subsystem window so we don't get a console when executing
 // this binary through the installer.
 #pragma comment(linker, "/SUBSYSTEM:windows")
 
 SERVICE_STATUS gSvcStatus = { 0 }; 
 SERVICE_STATUS_HANDLE gSvcStatusHandle = nullptr; 
 HANDLE gWorkDoneEvent = nullptr;
@@ -97,16 +98,20 @@ wmain(int argc, WCHAR **argv)
       LogFinish();
       return 1;
     }
     LOG(("The service was uninstalled successfully"));
     LogFinish();
     return 0;
   }
 
+  if (!lstrcmpi(argv[1], L"check-cert") && argc > 2) {
+    return DoesBinaryMatchAllowedCertificates(argv[2], argv[3], FALSE) ? 0 : 1;
+  }
+
   SERVICE_TABLE_ENTRYW DispatchTable[] = { 
     { SVC_NAME, (LPSERVICE_MAIN_FUNCTIONW) SvcMain }, 
     { nullptr, nullptr } 
   }; 
 
   // This call returns when the service has stopped. 
   // The process should simply terminate when the call returns.
   if (!StartServiceCtrlDispatcherW(DispatchTable)) {
--- a/toolkit/components/maintenanceservice/registrycertificates.cpp
+++ b/toolkit/components/maintenanceservice/registrycertificates.cpp
@@ -12,20 +12,27 @@
 #include "servicebase.h"
 #include "updatehelper.h"
 #define MAX_KEY_LENGTH 255
 
 /**
  * Verifies if the file path matches any certificate stored in the registry.
  *
  * @param  filePath The file path of the application to check if allowed.
+ * @param  allowFallbackKeySkip when this is TRUE the fallback registry key will
+ *   be used to skip the certificate check.  This is the default since the
+ *   fallback registry key is located under HKEY_LOCAL_MACHINE which can't be
+ *   written to by a low integrity process.
+ *   Note: the maintenance service binary can be used to perform this check for
+ *   testing or troubleshooting.
  * @return TRUE if the binary matches any of the allowed certificates.
  */
 BOOL
-DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath)
+DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
+                                   BOOL allowFallbackKeySkip)
 { 
   WCHAR maintenanceServiceKey[MAX_PATH + 1];
   if (!CalculateRegistryPathFromFilePath(basePathForUpdate, 
                                          maintenanceServiceKey)) {
     return FALSE;
   }
 
   // We use KEY_WOW64_64KEY to always force 64-bit view.
@@ -44,16 +51,21 @@ DoesBinaryMatchAllowedCertificates(LPCWS
     // We use this registry key on our test slaves to store the 
     // allowed name/issuers.
     retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 
                             TEST_ONLY_FALLBACK_KEY_PATH, 0,
                             KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw);
     if (retCode != ERROR_SUCCESS) {
       LOG_WARN(("Could not open fallback key.  (%d)", retCode));
       return FALSE;
+    } else if (allowFallbackKeySkip) {
+      LOG_WARN(("Fallback key present, skipping VerifyCertificateTrustForFile "
+                "check and the certificate attribute registry matching "
+                "check."));
+      return TRUE;
     }
   }
   nsAutoRegKey baseKey(baseKeyRaw);
 
   // Get the number of subkeys.
   DWORD subkeyCount = 0;
   retCode = RegQueryInfoKeyW(baseKey, nullptr, nullptr, nullptr, &subkeyCount,
                              nullptr, nullptr, nullptr, nullptr, nullptr,
--- a/toolkit/components/maintenanceservice/registrycertificates.h
+++ b/toolkit/components/maintenanceservice/registrycertificates.h
@@ -3,11 +3,12 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _REGISTRYCERTIFICATES_H_
 #define _REGISTRYCERTIFICATES_H_
 
 #include "certificatecheck.h"
 
 BOOL DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate,
-                                        LPCWSTR filePath);
+                                        LPCWSTR filePath,
+                                        BOOL allowFallbackKeySkip = TRUE);
 
 #endif
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -1157,22 +1157,25 @@ function getTestDirPath() {
 /**
  * Helper function for getting the nsIFile for a file in the test data
  * directory.
  *
  * @param   aRelPath (optional)
  *          The relative path to the file or directory to get from the root of
  *          the test's data directory. If not specified the test's data
  *          directory will be returned.
+ * @param   aAllowNonExists (optional)
+ *          Whether or not to throw an error if the path exists.
+ *          If not specified, then false is used.
  * @return  The nsIFile for the file in the test data directory.
  * @throws  If the file or directory does not exist.
  */
-function getTestDirFile(aRelPath) {
+function getTestDirFile(aRelPath, aAllowNonExists) {
   let relpath = getTestDirPath() + (aRelPath ? aRelPath : "");
-  return do_get_file(relpath, false);
+  return do_get_file(relpath, !!aAllowNonExists);
 }
 
 function getSpecialFolderDir(aCSIDL) {
   if (!IS_WIN) {
     do_throw("Windows only function called by a different platform!");
   }
 
   let lib = ctypes.open("shell32");
@@ -1421,21 +1424,22 @@ function unlockDirectory(aDir) {
  *          A callback function that will be called when this function finishes.
  *          If null no function will be called when this function finishes.
  *          If not specified the checkUpdateApplied function will be called when
  *          this function finishes.
  */
 function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) {
   // Copy the updater binary to the updates directory.
   let binDir = gGREBinDirOrig.clone();
-  let updater = binDir.clone();
-  updater.append("updater.app");
+  let updater = getTestDirFile("updater.app", true);
   if (!updater.exists()) {
-    updater = binDir.clone();
-    updater.append(FILE_UPDATER_BIN);
+    updater = getTestDirFile(FILE_UPDATER_BIN);
+    if (!updater.exists()) {
+      do_throw("Unable to find updater binary!");
+    }
   }
   Assert.ok(updater.exists(), "updater or updater.app should exist");
 
   let updatesDir = getUpdatesPatchDir();
   updater.copyToFollowingLinks(updatesDir, updater.leafName);
   let updateBin = updatesDir.clone();
   updateBin.append(updater.leafName);
   if (updateBin.leafName == "updater.app") {
@@ -1683,18 +1687,16 @@ function setupAppFiles() {
       do_throw(e);
     }
   }
 
   // Required files for the application or the test that aren't listed in the
   // dependentlibs.list file.
   let appFiles = [ { relPath  : FILE_APP_BIN,
                      inGreDir : false },
-                   { relPath  : FILE_UPDATER_BIN,
-                     inGreDir : false },
                    { relPath  : FILE_APPLICATION_INI,
                      inGreDir : true },
                    { relPath  : "dependentlibs.list",
                      inGreDir : true } ];
 
   // On Linux the updater.png must also be copied
   if (IS_UNIX && !IS_MACOSX) {
     appFiles.push( { relPath  : "icons/updater.png",
@@ -1719,16 +1721,27 @@ function setupAppFiles() {
   } while(hasMore);
 
   istream.close();
 
   appFiles.forEach(function CMAF_FLN_FE(aAppFile) {
     copyFileToTestAppDir(aAppFile.relPath, aAppFile.inGreDir);
   });
 
+  // Copy the xpcshell updater binary
+  let updater = getTestDirFile("updater.app", true);
+  if (!updater.exists()) {
+    updater = getTestDirFile(FILE_UPDATER_BIN);
+    if (!updater.exists()) {
+      do_throw("Unable to find updater binary!");
+    }
+  }
+  let testBinDir = getGREBinDir()
+  updater.copyToFollowingLinks(testBinDir, updater.leafName);
+
   debugDump("finish - copying or creating symlinks to application files " +
             "for the test");
 }
 
 /**
  * Copies the specified files from the dist/bin directory into the test's
  * application directory.
  *
@@ -2010,20 +2023,23 @@ function runUpdateUsingService(aInitialS
 
   if (gSwitchApp) {
     // We want to set the env vars again
     gShouldResetEnv = undefined;
   }
 
   setEnvironment();
 
-  // There is a security check done by the service to make sure the updater
-  // we are executing is the same as the one in the apply-to dir.
-  // To make sure they match from tests we copy updater.exe to the apply-to dir.
-  copyFileToTestAppDir(FILE_UPDATER_BIN, false);
+  let updater = getTestDirFile(FILE_UPDATER_BIN);
+  if (!updater.exists()) {
+    do_throw("Unable to find updater binary!");
+  }
+  let testBinDir = getGREBinDir()
+  updater.copyToFollowingLinks(testBinDir, updater.leafName);
+  updater.copyToFollowingLinks(updatesDir, updater.leafName);
 
   // The service will execute maintenanceservice_installer.exe and
   // will copy maintenanceservice.exe out of the same directory from
   // the installation directory.  So we need to make sure both of those
   // bins always exist in the installation directory.
   copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false);
   copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false);
 
--- a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini
+++ b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini
@@ -14,19 +14,19 @@ skip-if = toolkit == 'android'
 [marSuccessComplete.js]
 [marSuccessPartial.js]
 [marFailurePartial.js]
 [marStageSuccessComplete.js]
 skip-if = toolkit == 'gonk'
 reason = bug 820380
 [marStageSuccessPartial.js]
 [marVersionDowngrade.js]
-skip-if = os != 'win'
+skip-if = os != 'win' && os != 'mac' && os != 'linux'
 [marWrongChannel.js]
-skip-if = os != 'win'
+skip-if = os != 'win' && os != 'mac' && os != 'linux'
 [marStageFailurePartial.js]
 [marCallbackAppSuccessComplete_win.js]
 skip-if = os != 'win'
 [marCallbackAppSuccessPartial_win.js]
 skip-if = os != 'win'
 [marCallbackAppStageSuccessComplete_win.js]
 skip-if = os != 'win'
 [marCallbackAppStageSuccessPartial_win.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_service_updater/checkUpdaterSigSvc.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * We skip authenticode cert checks from the service udpates
+ * so that we can use updater-xpcshell with the wrong certs for testing.
+ * This tests that code path.  */
+
+function run_test() {
+  if (!IS_AUTHENTICODE_CHECK_ENABLED) {
+    return;
+  }
+
+  let binDir = getGREBinDir();
+  let maintenanceServiceBin = binDir.clone();
+  maintenanceServiceBin.append(FILE_MAINTENANCE_SERVICE_BIN);
+
+  let updaterBin = binDir.clone();
+  updaterBin.append(FILE_UPDATER_BIN);
+
+  logTestInfo("Launching maintenance service bin: " +
+              maintenanceServiceBin.path + " to check updater: " +
+              updaterBin.path + " signature.");
+
+  // Bypass the manifest and run as invoker
+  let env = Cc["@mozilla.org/process/environment;1"].
+            getService(Ci.nsIEnvironment);
+  env.set("__COMPAT_LAYER", "RunAsInvoker");
+
+  let dummyInstallPath = "---";
+  let maintenanceServiceBinArgs = ["check-cert", dummyInstallPath,
+                                   updaterBin.path];
+  let maintenanceServiceBinProcess = Cc["@mozilla.org/process/util;1"].
+                                     createInstance(Ci.nsIProcess);
+  maintenanceServiceBinProcess.init(maintenanceServiceBin);
+  maintenanceServiceBinProcess.run(true, maintenanceServiceBinArgs,
+                                   maintenanceServiceBinArgs.length);
+  do_check_eq(maintenanceServiceBinProcess.exitValue, 0);
+}
--- a/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini
+++ b/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini
@@ -75,8 +75,9 @@ run-sequentially = Uses the Mozilla Main
 [marAppApplyDirLockedStageFailureSvc_win.js]
 run-sequentially = Uses the Mozilla Maintenance Service.
 [marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js]
 run-sequentially = Uses the Mozilla Maintenance Service.
 [marAppApplyUpdateSuccessSvc.js]
 run-sequentially = Uses the Mozilla Maintenance Service.
 [marAppApplyUpdateStageSuccessSvc.js]
 run-sequentially = Uses the Mozilla Maintenance Service.
+[checkUpdaterSigSvc.js]
--- a/toolkit/mozapps/update/updater/Makefile.in
+++ b/toolkit/mozapps/update/updater/Makefile.in
@@ -1,13 +1,15 @@
 # vim:set ts=8 sw=8 sts=8 noet:
 # 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/.
 
+# For changes here, also consider ./updater-xpcshell/Makefile.in
+
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
@@ -15,27 +17,32 @@ include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter beta release esr,$(MOZ_UPDATE_CHANNEL)))
 	PRIMARY_CERT = release_primary.der
 	SECONDARY_CERT = release_secondary.der
 else ifneq (,$(filter nightly aurora nightly-elm nightly-profiling nightly-oak nightly-ux,$(MOZ_UPDATE_CHANNEL)))
 	PRIMARY_CERT = nightly_aurora_level3_primary.der
 	SECONDARY_CERT = nightly_aurora_level3_secondary.der
 else
-	PRIMARY_CERT = xpcshellCertificate.der
-	SECONDARY_CERT = xpcshellCertificate.der
+	PRIMARY_CERT = dep1.der
+	SECONDARY_CERT = dep2.der
 endif
 
-CERT_HEADERS := primaryCert.h secondaryCert.h
+CERT_HEADERS := primaryCert.h secondaryCert.h xpcshellCert.h
 
 export:: $(CERT_HEADERS)
 
 primaryCert.h: $(PRIMARY_CERT)
 secondaryCert.h: $(SECONDARY_CERT)
 
+# This is how the xpcshellCertificate.der file is generated, in case we ever
+# have to regenerate it.
+# ./certutil -L -d modules/libmar/tests/unit/data -n mycert -r > xpcshellCertificate.der
+xpcshellCert.h: xpcshellCertificate.der
+
 $(CERT_HEADERS): gen_cert_header.py
 	$(PYTHON) $< $(@:.h=Data) $(filter-out $<,$^) > $@
 
 ifdef MOZ_WIDGET_GTK
 libs:: updater.png
 	$(NSINSTALL) -D $(DIST)/bin/icons
 	$(INSTALL) $(IFLAGS1) $^ $(DIST)/bin/icons
 endif
--- a/toolkit/mozapps/update/updater/archivereader.cpp
+++ b/toolkit/mozapps/update/updater/archivereader.cpp
@@ -12,18 +12,24 @@
 #include "errors.h"
 #ifdef XP_WIN
 #include "nsAlgorithm.h" // Needed by nsVersionComparator.cpp
 #include "updatehelper.h"
 #endif
 
 // These are generated at compile time based on the DER file for the channel
 // being used
+#ifdef MOZ_VERIFY_MAR_SIGNATURE
+#ifdef UPDATER_XPCSHELL_CERT
+#include "../xpcshellCert.h"
+#else
 #include "primaryCert.h"
 #include "secondaryCert.h"
+#endif
+#endif
 
 #define UPDATER_NO_STRING_GLUE_STL
 #include "nsVersionComparator.cpp"
 #undef UPDATER_NO_STRING_GLUE_STL
 
 #if defined(XP_UNIX)
 # include <sys/types.h>
 #elif defined(XP_WIN)
@@ -71,20 +77,27 @@ VerifyLoadedCert(MarFile *archive, const
 */
 int
 ArchiveReader::VerifySignature()
 {
   if (!mArchive) {
     return ARCHIVE_NOT_OPEN;
   }
 
+#ifdef MOZ_VERIFY_MAR_SIGNATURE
+#ifdef UPDATER_XPCSHELL_CERT
+  int rv = VerifyLoadedCert(mArchive, xpcshellCertData);
+#else
   int rv = VerifyLoadedCert(mArchive, primaryCertData);
   if (rv != OK) {
     rv = VerifyLoadedCert(mArchive, secondaryCertData);
   }
+#endif
+#endif
+
   return rv;
 }
 
 /**
  * Verifies that the MAR file matches the current product, channel, and version
  * 
  * @param MARChannelID   The MAR channel name to use, only updates from MARs
  *                       with a matching MAR channel name will succeed.
new file mode 100644
index 0000000000000000000000000000000000000000..95b4ef38c6bf669c964430a93d727415a89b8184
GIT binary patch
literal 671
zc$_n6Vw!Ex#Mr!mnTe5!iIrj6(H(aTc-c6$+C196^D;8BvN9O(8}b@(voVLVFblJ!
zq!t(&$cghB8W|WG8W@@y7?_wxfw?AdE~bViMkQoJ8Ce;an;7{SfZ|+CO^l2T=L|0`
z+#c7-ds62A9ggOekxT!cj$N%kvt#k)iC=eR2~Kyuta?&q`b_5Y)<*wzrmg1rwRpCn
zm)G8pEU#^5*tB^v+?aho@}BYp$ApUb*1z+gcs}V0nK3QZTv~pe+sQR$_iF5>$z9LW
zwP0LOxc*PB&-TiFO9EX!>^WqzFh$SKaY|O>RcDR=Il{tgI*r6jrE8*-;=jzd_<dsG
zva^BjS2~o+EnBedr%W+V#=lJ>ul|WCZmrDR67xpD?b~nn7y7z9$p^Myy!_2+*_m5v
z>-X(H|KYiiRPOPMCNl0uEbP|j3pyU9>83l`zy4qHG*Q^8@0swQYF^!{gMa;ki|?28
z8HlKhyI*EvW@KPQ3wCBuzyvy#?fZK#?S1_T<_6yNkL%7%{#Nfh*;8aub=LLv&Sfm?
zgI>>;eZKm#bH<f|-8SEt!a8>=&9|Pnf=BDVu)%$<y^B{(eKbkq^OLmI#`%XHH+QTE
zjGrSPS2bg+V*THlhPD?<9_a}77GBwI^m=prNqII={YP@24filU2n=$udi>(<PZ=|f
z3$rUb<Q+afe7iW;ZH|NJ&f{vSr&fPwt7pk?JH(uP=4urW`>*p4S6)d;nLBgm37O6L
zPU-U-FRzW#joi`jc)p`TY=FSbf`BE;zyGYB_-Mt#_+KT{UkEq$_WONwQMO<0xmem$
h<g)CO?=w;k|KZ<0eJX1~S7I4M&c&Z^kH}~V0RZ^tAJhN<
new file mode 100644
index 0000000000000000000000000000000000000000..a460d6a16dd16e2bbe0d899479e55f5d4e486a84
GIT binary patch
literal 671
zc$_n6Vw!Ex#Mr!mnTe5!iIrj6(VapDylk9WZ60mkc^Mg5Ss4uY4S5Z?*_cCFn1xwV
zQVWa><ivRmjSLJ84Gc{U3=J%!z+4kJ7gIwMqY|>AjI0dIO^o~uKyfanCPqevt4XZ3
zHs^2h$vpqBah?D4q8pVgek+T&q^=e^^z6e4rDpaMn<Nfz^xU{=d4l_FmKD!#PJI==
z|L=pQlY-|rG;^)FCbaS0k`;5<N)<esmoD6}caMkt58;^Q?D4LCbBokY?>>8L|2}iK
z&bB(MhUYiGo>`OYamGBQDpUKs+00T0!`S}?S1UjNe=E2**>%BNn;*f8G#|5681|cg
zy)1g=+4avRhFy*+!N$(4dxV!4baS4*_}Fn~nTuKMkE5nDm$oJT>X@eH&T#pmN;;Fq
zoU(#D+OO=hLei&wh>YC4H?3oOzV^mAvp`pwsy**Te4Hov9a<J6z?P!A>%4yhQ-r=<
z5qHDGeZ5S~j0}uu!Ojc{7~vypn|;3W-Ft6(Cxh`tmui)UVXGpu`R#=6oBs;jWYxC%
z9{NASOPlTC{|OhI-iUk_*{x|6!C+V+Qs?0v`aVU*jLEYlv+jy9dy3z@@1`YF)^V+H
zW?EEiRH(%;tt+wdQ{k=3=vnn{h0iD0Jy;dJ^l1C4c(?hU+dAh4H@99gcK7l%U0Em5
zzU+j{-2>d~!lrStt-N63d+OFN9@mQ^tm|$r-{qDXu|j5|)~o}`e4dxDPhVTqVYOm)
zboSBhn|DQXeZI71_I`os*=)x?KUgl6{dw6Uv&pABf4jcPJlfDT>x;ag-m|t~@A?pV
eE9H#ETn4e~a)-<W(@SCs&NT7L-}<so%M1X?#S~%y
--- a/toolkit/mozapps/update/updater/moz.build
+++ b/toolkit/mozapps/update/updater/moz.build
@@ -1,130 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 Program('updater')
 
-SOURCES += [
-    'archivereader.cpp',
-    'bspatch.cpp',
-    'updater.cpp',
-]
-
-have_progressui = 0
-
-if CONFIG['MOZ_VERIFY_MAR_SIGNATURE']:
-    USE_LIBS += [
-        'verifymar',
-    ]
-
-if CONFIG['OS_ARCH'] == 'WINNT':
-    have_progressui = 1
-    SOURCES += [
-        'loaddlls.cpp',
-        'progressui_win.cpp',
-        'win_dirent.cpp',
-    ]
-    RCINCLUDE = 'updater.rc'
-    DEFINES['UNICODE'] = True
-    DEFINES['_UNICODE'] = True
-    DEFINES['NOMINMAX'] = True
-    USE_STATIC_LIBS = True
-
-    # Pick up nsWindowsRestart.cpp
-    LOCAL_INCLUDES += [
-        '/toolkit/xre',
-    ]
-    USE_LIBS += [
-        'updatecommon-standalone',
-    ]
-    OS_LIBS += [
-        'comctl32',
-        'ws2_32',
-        'shell32',
-        'shlwapi',
-        'crypt32',
-        'advapi32',
-    ]
-elif CONFIG['OS_ARCH'] == 'Linux':
-    USE_LIBS += [
-        'updatecommon',
-        '/modules/libmar/sign/signmar',
-        '/security/nss/lib/nss/nss3',
-        '/security/nss/lib/util/nssutil3',
-    ]
-    OS_LIBS += CONFIG['NSPR_LIBS']
-else:
-    USE_LIBS += [
-        'updatecommon',
-    ]
-
-USE_LIBS += [
-    'mar',
-]
-
-if CONFIG['MOZ_NATIVE_BZ2']:
-    OS_LIBS += CONFIG['MOZ_BZ2_LIBS']
-else:
-    USE_LIBS += [
-        'bz2',
-    ]
-
-if CONFIG['MOZ_ENABLE_GTK']:
-    have_progressui = 1
-    SOURCES += [
-        'progressui_gtk.cpp',
-    ]
-
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
-    have_progressui = 1
-    SOURCES += [
-        'launchchild_osx.mm',
-        'progressui_osx.mm',
-    ]
-    OS_LIBS += ['-framework Cocoa -framework Security']
-elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    have_progressui = 1
-    SOURCES += [
-        'automounter_gonk.cpp',
-        'progressui_gonk.cpp',
-    ]
-    DISABLE_STL_WRAPPING = True
-    OS_LIBS += [
-        'cutils',
-        'sysutils',
-    ]
-
-if have_progressui == 0:
-    SOURCES += [
-        'progressui_null.cpp',
-    ]
-
-DEFINES['NS_NO_XPCOM'] = True
-DISABLE_STL_WRAPPING = True
-for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'):
-    DEFINES[var] = '"%s"' % CONFIG[var]
-
-LOCAL_INCLUDES += [
-    '../common',
-    '/xpcom/glue',
-]
-
-DELAYLOAD_DLLS += [
-    'crypt32.dll',
-    'comctl32.dll',
-    'userenv.dll',
-    'wsock32.dll',
-]
-
-if CONFIG['_MSC_VER']:
-    WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
-elif CONFIG['OS_ARCH'] == 'WINNT':
-    WIN32_EXE_LDFLAGS += ['-municode']
-
-if CONFIG['MOZ_WIDGET_GTK']:
-    CXXFLAGS += CONFIG['TK_CFLAGS']
-    OS_LIBS += CONFIG['TK_LIBS']
-
+updater_rel_path = ''
+include('updater-common.build')
+DIRS += ['updater-xpcshell']
 FAIL_ON_WARNINGS = True
copy from toolkit/mozapps/update/updater/moz.build
copy to toolkit/mozapps/update/updater/updater-common.build
--- a/toolkit/mozapps/update/updater/moz.build
+++ b/toolkit/mozapps/update/updater/updater-common.build
@@ -1,37 +1,35 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-Program('updater')
-
-SOURCES += [
+srcs = [
     'archivereader.cpp',
     'bspatch.cpp',
     'updater.cpp',
 ]
 
 have_progressui = 0
 
 if CONFIG['MOZ_VERIFY_MAR_SIGNATURE']:
     USE_LIBS += [
         'verifymar',
     ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     have_progressui = 1
-    SOURCES += [
+    srcs += [
         'loaddlls.cpp',
         'progressui_win.cpp',
         'win_dirent.cpp',
     ]
-    RCINCLUDE = 'updater.rc'
+    RCINCLUDE = '%supdater.rc' % updater_rel_path
     DEFINES['UNICODE'] = True
     DEFINES['_UNICODE'] = True
     DEFINES['NOMINMAX'] = True
     USE_STATIC_LIBS = True
 
     # Pick up nsWindowsRestart.cpp
     LOCAL_INCLUDES += [
         '/toolkit/xre',
@@ -42,22 +40,21 @@ if CONFIG['OS_ARCH'] == 'WINNT':
     OS_LIBS += [
         'comctl32',
         'ws2_32',
         'shell32',
         'shlwapi',
         'crypt32',
         'advapi32',
     ]
-elif CONFIG['OS_ARCH'] == 'Linux':
+elif CONFIG['OS_ARCH'] == 'Linux' and CONFIG['MOZ_VERIFY_MAR_SIGNATURE']:
     USE_LIBS += [
+        '/modules/libmar/sign/signmar',
+        'nss',
         'updatecommon',
-        '/modules/libmar/sign/signmar',
-        '/security/nss/lib/nss/nss3',
-        '/security/nss/lib/util/nssutil3',
     ]
     OS_LIBS += CONFIG['NSPR_LIBS']
 else:
     USE_LIBS += [
         'updatecommon',
     ]
 
 USE_LIBS += [
@@ -68,51 +65,54 @@ if CONFIG['MOZ_NATIVE_BZ2']:
     OS_LIBS += CONFIG['MOZ_BZ2_LIBS']
 else:
     USE_LIBS += [
         'bz2',
     ]
 
 if CONFIG['MOZ_ENABLE_GTK']:
     have_progressui = 1
-    SOURCES += [
+    srcs += [
         'progressui_gtk.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     have_progressui = 1
-    SOURCES += [
+    srcs += [
         'launchchild_osx.mm',
         'progressui_osx.mm',
     ]
     OS_LIBS += ['-framework Cocoa -framework Security']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     have_progressui = 1
-    SOURCES += [
+    srcs += [
         'automounter_gonk.cpp',
         'progressui_gonk.cpp',
     ]
     DISABLE_STL_WRAPPING = True
     OS_LIBS += [
         'cutils',
         'sysutils',
     ]
 
 if have_progressui == 0:
-    SOURCES += [
+    srcs += [
         'progressui_null.cpp',
     ]
 
+srcs.sort()
+SOURCES += ['%s%s' % (updater_rel_path, f) for f in srcs]
+
 DEFINES['NS_NO_XPCOM'] = True
 DISABLE_STL_WRAPPING = True
 for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'):
     DEFINES[var] = '"%s"' % CONFIG[var]
 
 LOCAL_INCLUDES += [
-    '../common',
+    '/toolkit/mozapps/update/common',
     '/xpcom/glue',
 ]
 
 DELAYLOAD_DLLS += [
     'crypt32.dll',
     'comctl32.dll',
     'userenv.dll',
     'wsock32.dll',
@@ -121,10 +121,8 @@ DELAYLOAD_DLLS += [
 if CONFIG['_MSC_VER']:
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     WIN32_EXE_LDFLAGS += ['-municode']
 
 if CONFIG['MOZ_WIDGET_GTK']:
     CXXFLAGS += CONFIG['TK_CFLAGS']
     OS_LIBS += CONFIG['TK_LIBS']
-
-FAIL_ON_WARNINGS = True
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
@@ -0,0 +1,50 @@
+# vim:set ts=8 sw=8 sts=8 noet:
+# 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/.
+
+# For changes here, also consider ../Makefile.in
+
+XPCSHELLTESTROOT = $(abspath $(DEPTH))/_tests/xpcshell/toolkit/mozapps/update/tests
+
+ifndef MOZ_PROFILE_GENERATE
+ifdef COMPILE_ENVIRONMENT
+INSTALL_TARGETS += xpcshell-updater
+xpcshell-updater_TARGET  := libs
+xpcshell-updater_DEST    := $(XPCSHELLTESTROOT)/data
+xpcshell-updater_FILES   := $(DIST)/bin/updater-xpcshell$(BIN_SUFFIX)
+endif
+endif # Not MOZ_PROFILE_GENERATE
+
+include $(topsrcdir)/config/rules.mk
+
+ifndef MOZ_WINCONSOLE
+ifdef MOZ_DEBUG
+MOZ_WINCONSOLE = 1
+else
+MOZ_WINCONSOLE = 0
+endif
+endif
+
+ifdef MOZ_WIDGET_GTK
+libs:: ../updater.png
+	$(NSINSTALL) -D $(DIST)/bin/icons
+	$(INSTALL) $(IFLAGS1) $^ $(DIST)/bin/icons
+endif
+
+libs::
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+	$(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app
+	rsync -a -C --exclude '*.in' $(srcdir)/../macbuild/Contents $(XPCSHELLTESTROOT)/data/updater-xpcshell.app
+	sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
+	  iconv -f UTF-8 -t UTF-16 > $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings
+	$(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS/updater-xpcshell
+	$(NSINSTALL) $(XPCSHELLTESTROOT)/data/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS
+	rm -f $(XPCSHELLTESTROOT)/data/updater-xpcshell
+	mv $(XPCSHELLTESTROOT)/data/updater-xpcshell.app $(XPCSHELLTESTROOT)/data/updater.app
+	mv $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/updater
+else
+	mv $(XPCSHELLTESTROOT)/data/updater-xpcshell$(BIN_SUFFIX) $(XPCSHELLTESTROOT)/data/updater$(BIN_SUFFIX)
+endif
+
+CXXFLAGS += $(MOZ_BZ2_CFLAGS)
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/updater/updater-xpcshell/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+Program('updater-xpcshell')
+
+updater_rel_path = '../'
+DEFINES['UPDATER_XPCSHELL_CERT'] = True
+include('../updater-common.build')
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -2189,17 +2189,22 @@ UpdateThreadFunc(void *param)
 #endif
     }
 
     if (rv == OK) {
       if (rv == OK) {
         NS_tchar updateSettingsPath[MAX_TEXT_LEN];
         NS_tsnprintf(updateSettingsPath,
                      sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
-                     NS_T("%s/update-settings.ini"), gWorkingDirPath);
+#ifdef XP_MACOSX
+                     NS_T("%s/Contents/Resources/update-settings.ini"),
+#else
+                     NS_T("%s/update-settings.ini"),
+#endif
+                     gWorkingDirPath);
         MARChannelStringTable MARStrings;
         if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
           // If we can't read from update-settings.ini then we shouldn't impose
           // a MAR restriction.  Some installations won't even include this file.
           MARStrings.MARChannelID[0] = '\0';
         }
 
         rv = gArchiveReader.VerifyProductInformation(MARStrings.MARChannelID,
--- a/toolkit/mozapps/update/updater/updater.rc
+++ b/toolkit/mozapps/update/updater/updater.rc
@@ -1,15 +1,25 @@
 /* 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/. */
 
 // Microsoft Visual C++ generated resource script.
 //
+#ifdef UPDATER_XPCSHELL_CERT
+#include "../resource.h"
+#define MANIFEST_PATH "../updater.exe.manifest"
+#define COMCTL32_MANIFEST_PATH "../updater.exe.comctl32.manifest"
+#define ICON_PATH "../updater.ico"
+#else
 #include "resource.h"
+#define MANIFEST_PATH "updater.exe.manifest"
+#define COMCTL32_MANIFEST_PATH "updater.exe.comctl32.manifest"
+#define ICON_PATH "updater.ico"
+#endif
 
 #define APSTUDIO_READONLY_SYMBOLS
 /////////////////////////////////////////////////////////////////////////////
 //
 // Generated from the TEXTINCLUDE 2 resource.
 //
 #include "winresrc.h"
 
@@ -25,25 +35,25 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_U
 #pragma code_page(1252)
 #endif //_WIN32
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // RT_MANIFEST
 //
 
-1                       RT_MANIFEST             "updater.exe.manifest"
-IDR_COMCTL32_MANIFEST   RT_MANIFEST             "updater.exe.comctl32.manifest"
+1                       RT_MANIFEST             MANIFEST_PATH
+IDR_COMCTL32_MANIFEST   RT_MANIFEST             COMCTL32_MANIFEST_PATH
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Icon
 //
 
-IDI_DIALOG ICON "updater.ico"
+IDI_DIALOG ICON ICON_PATH
 
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Embedded an identifier to uniquely identiy this as a Mozilla updater.
 //
 
 STRINGTABLE