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 84999 df4ba8bfc9caf08eb89c4dcd09561e394a8d2cfe
parent 84998 7fbfb0e7256533952fe9544fc79d518cfa2c86e9
child 85000 c20c8ef8f0f4d989105dbd10984090ffea14dcee
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstrong
bugs709173
milestone12.0a1
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