Bug 709173 - updater.exe needs to be verified to be an updater, not just an executable signed by Mozilla. r=rstrong.
authorBrian R. Bondy <netzen@gmail.com>
Wed, 04 Jan 2012 23:19:16 -0500
changeset 83774 df4ba8bfc9caf08eb89c4dcd09561e394a8d2cfe
parent 83773 7fbfb0e7256533952fe9544fc79d518cfa2c86e9
child 83775 c20c8ef8f0f4d989105dbd10984090ffea14dcee
push id21792
push userbbondy@mozilla.com
push dateThu, 05 Jan 2012 04:20:59 +0000
treeherdermozilla-central@10894668e37f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstrong
bugs709173
milestone12.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 709173 - updater.exe needs to be verified to be an updater, not just an executable signed by Mozilla. r=rstrong.
toolkit/components/maintenanceservice/servicebase.h
toolkit/components/maintenanceservice/workmonitor.cpp
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/updater/resource.h
toolkit/mozapps/update/updater/updater.rc
--- a/toolkit/components/maintenanceservice/servicebase.h
+++ b/toolkit/components/maintenanceservice/servicebase.h
@@ -40,8 +40,16 @@
 
 BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
 BOOL VerifySameFiles(LPCWSTR file1Path, LPCWSTR file2Path, BOOL &sameContent);
 
 // 32KiB for comparing files at a time seems reasonable.
 // The bigger the better for speed, but this will be used
 // on the stack so I don't want it to be too big.
 #define COMPARE_BLOCKSIZE 32768
+
+// The following string resource value is used to uniquely identify the signed
+// Mozilla application as an updater.  Before the maintenance service will 
+// execute the updater it must have this updater identity string in its string
+// table.  No other signed Mozilla product will have this string table value.
+#define UPDATER_IDENTITY_STRING \
+  "moz-updater.exe-4cdccec4-5ee0-4a06-9817-4cd899a9db49"
+#define IDS_UPDATER_IDENTITY 1006
--- a/toolkit/components/maintenanceservice/workmonitor.cpp
+++ b/toolkit/components/maintenanceservice/workmonitor.cpp
@@ -67,16 +67,17 @@ BOOL PathGetSiblingFilePath(LPWSTR desti
                             LPCWSTR newFileName);
 
 // The error codes start from 16000 since Windows system error 
 // codes only go up to 15999
 const int SERVICE_UPDATER_COULD_NOT_BE_STARTED = 16000;
 const int SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 16001;
 const int SERVICE_UPDATER_SIGN_ERROR = 16002;
 const int SERVICE_UPDATER_COMPARE_ERROR = 16003;
+const int SERVICE_UPDATER_IDENTITY_ERROR = 16004;
 
 /**
  * Runs an update process as the service using the SYSTEM account.
  *
  * @param  updaterPath    The path to the update process to start.
  * @param  workingDir     The working directory to execute the update process in
  * @param  cmdLine        The command line parameters to pass to updater.exe
  * @param  processStarted Set to TRUE if the process was started.
@@ -373,16 +374,52 @@ ProcessWorkItem(LPCWSTR monitoringBasePa
     if (argcTmp < 2 || 
         !WriteStatusFailure(argvTmp[1], 
                             SERVICE_UPDATER_COMPARE_ERROR)) {
       LOG(("Could not write update.status updater compare failure.\n"));
     }
     return TRUE;
   }
 
+  // Check to make sure the udpater.exe module has the unique updater identity.
+  // This is a security measure to make sure that the signed executable that
+  // we will run is actually an updater.
+  HMODULE updaterModule = LoadLibrary(updaterPath);
+  if (!updaterModule) {
+    LOG(("updater.exe module could not be loaded. (%d)\n", GetLastError()));
+    result = FALSE;
+  } else {
+    char updaterIdentity[64];
+    if (!LoadStringA(updaterModule, IDS_UPDATER_IDENTITY, 
+                     updaterIdentity, sizeof(updaterIdentity))) {
+      LOG(("The updater.exe application does not contain the Mozilla"
+           " updater identity.\n"));
+      result = FALSE;
+    }
+
+    if (strcmp(updaterIdentity, UPDATER_IDENTITY_STRING)) {
+      LOG(("The updater.exe identity string is not valid.\n"));
+      result = FALSE;
+    }
+    FreeLibrary(updaterModule);
+  }
+
+  if (result) {
+    LOG(("The updater.exe application contains the Mozilla"
+          " updater identity.\n"));
+  } else {
+    SetEvent(serviceRunningEvent);
+    if (argcTmp < 2 || 
+        !WriteStatusFailure(argvTmp[1], 
+                            SERVICE_UPDATER_IDENTITY_ERROR)) {
+      LOG(("Could not write update.status no updater identity.\n"));
+    }
+    return TRUE;
+  }
+
   // Check for updater.exe sign problems
   BOOL updaterSignProblem = FALSE;
 #ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
   if (argcTmp > 2) {
     updaterSignProblem = !DoesBinaryMatchAllowedCertificates(argvTmp[2], 
                                                              updaterPath);
   }
 #endif
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -142,16 +142,17 @@ const STATE_FAILED          = "failed";
 // From updater/errors.h:
 const WRITE_ERROR        = 7;
 const UNEXPECTED_ERROR   = 8;
 const ELEVATION_CANCELED = 9;
 const SERVICE_UPDATER_COULD_NOT_BE_STARTED = 16000;
 const SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 16001;
 const SERVICE_UPDATER_SIGN_ERROR           = 16002;
 const SERVICE_UPDATER_COMPARE_ERROR        = 16003;
+const SERVICE_UPDATER_IDENTITY_ERROR       = 16004;
 
 const CERT_ATTR_CHECK_FAILED_NO_UPDATE  = 100;
 const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101;
 const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
 
 const DOWNLOAD_CHUNK_SIZE           = 300000; // bytes
 const DOWNLOAD_BACKGROUND_INTERVAL  = 600;    // seconds
 const DOWNLOAD_FOREGROUND_INTERVAL  = 0;
@@ -1432,17 +1433,18 @@ UpdateService.prototype = {
         if (update.errorCode == ELEVATION_CANCELED) {
           writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
           return;
         }
 
         if (update.errorCode == SERVICE_UPDATER_COULD_NOT_BE_STARTED ||
             update.errorCode == SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS ||
             update.errorCode == SERVICE_UPDATER_SIGN_ERROR ||
-            update.errorCode == SERVICE_UPDATER_COMPARE_ERROR) {
+            update.errorCode == SERVICE_UPDATER_COMPARE_ERROR ||
+            update.errorCode == SERVICE_UPDATER_IDENTITY_ERROR) {
           var failCount = getPref("getIntPref", 
                                   PREF_APP_UPDATE_SERVICE_ERRORS, 0);
           var maxFail = getPref("getIntPref", 
                                 PREF_APP_UPDATE_SERVICE_MAX_ERRORS, 
                                 DEFAULT_SERVICE_MAX_ERRORS);
 
           // As a safety, when the service reaches maximum failures, it will
           // disable itself and fallback to using the normal update mechanism
--- a/toolkit/mozapps/update/updater/resource.h
+++ b/toolkit/mozapps/update/updater/resource.h
@@ -1,19 +1,20 @@
 //{{NO_DEPENDENCIES}}
 // Microsoft Visual C++ generated include file.
 // Used by updater.rc
 //
 #define IDD_DIALOG                      101
 #define IDC_PROGRESS                    1000
 #define IDC_INFO                        1002
 #define IDI_DIALOG                      1003
+#define IDS_UPDATER_IDENTITY            1006
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        102
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1003
+#define _APS_NEXT_CONTROL_VALUE         1007
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
--- a/toolkit/mozapps/update/updater/updater.rc
+++ b/toolkit/mozapps/update/updater/updater.rc
@@ -30,16 +30,28 @@ 1                       RT_MANIFEST     
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Icon
 //
 
 IDI_DIALOG ICON "updater.ico"
 
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Embedded an identifier to uniquely identiy this as a Mozilla updater.
+//
+
+STRINGTABLE
+{
+  IDS_UPDATER_IDENTITY, "moz-updater.exe-4cdccec4-5ee0-4a06-9817-4cd899a9db49"
+} 
+
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // Dialog
 //
 
 IDD_DIALOG DIALOGEX 0, 0, 253, 41
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
 FONT 8, "MS Shell Dlg", 400, 0, 0x1