From 0de416e483b73b6576720f5690ab1cbaff27838a Mon Sep 17 00:00:00 2001 From: Robert Strong Date: Fri, 28 Apr 2017 16:36:45 -0700 Subject: [PATCH] Client code - Bug 1342742 - check that the app update patch dir, install dir, and working dir paths are valid. r=mhowell --HG-- rename : toolkit/mozapps/update/common/updatelogging.cpp => toolkit/mozapps/update/common/updatecommon.cpp rename : toolkit/mozapps/update/common/updatelogging.h => toolkit/mozapps/update/common/updatecommon.h --- .../maintenanceservice/servicebase.h | 2 +- .../maintenanceservice/workmonitor.cpp | 113 ++++++++++++++++-- .../update/common/certificatecheck.cpp | 2 +- toolkit/mozapps/update/common/errors.h | 12 +- toolkit/mozapps/update/common/moz.build | 2 +- .../update/common/registrycertificates.cpp | 2 +- .../mozapps/update/common/sources.mozbuild | 2 +- toolkit/mozapps/update/common/uachelper.cpp | 2 +- .../{updatelogging.cpp => updatecommon.cpp} | 78 +++++++++++- .../{updatelogging.h => updatecommon.h} | 6 +- .../mozapps/update/common/updatehelper.cpp | 4 +- .../mozapps/update/updater/launchchild_osx.mm | 7 ++ toolkit/mozapps/update/updater/updater.cpp | 75 +++++++++++- 13 files changed, 273 insertions(+), 34 deletions(-) rename toolkit/mozapps/update/common/{updatelogging.cpp => updatecommon.cpp} (58%) rename toolkit/mozapps/update/common/{updatelogging.h => updatecommon.h} (92%) diff --git a/toolkit/components/maintenanceservice/servicebase.h b/toolkit/components/maintenanceservice/servicebase.h index dfe04ed29273..447981489523 100644 --- a/toolkit/components/maintenanceservice/servicebase.h +++ b/toolkit/components/maintenanceservice/servicebase.h @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include -#include "updatelogging.h" +#include "updatecommon.h" BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra); BOOL VerifySameFiles(LPCWSTR file1Path, LPCWSTR file2Path, BOOL &sameContent); diff --git a/toolkit/components/maintenanceservice/workmonitor.cpp b/toolkit/components/maintenanceservice/workmonitor.cpp index 3529ed2e1cb2..d06db3ca2b98 100644 --- a/toolkit/components/maintenanceservice/workmonitor.cpp +++ b/toolkit/components/maintenanceservice/workmonitor.cpp @@ -22,6 +22,7 @@ #include "registrycertificates.h" #include "uachelper.h" #include "updatehelper.h" +#include "pathhash.h" #include "errors.h" // Wait 15 minutes for an update operation to run at most. @@ -32,6 +33,7 @@ wchar_t* MakeCommandLine(int argc, wchar_t** argv); BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode); BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, LPCWSTR newFileName); +BOOL DoesFallbackKeyExist(); /* * Read the update.status file and sets isApplying to true if @@ -415,8 +417,7 @@ ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv) // We can only update update.status if argv[1] exists. argv[1] is // the directory where the update.status file exists. if (argc < 2 || - !WriteStatusFailure(argv[1], - SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS)) { + !WriteStatusFailure(argv[1], SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS)) { LOG_WARN(("Could not write update.status service update failure. (%d)", GetLastError())); } @@ -426,8 +427,7 @@ ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv) WCHAR installDir[MAX_PATH + 1] = {L'\0'}; if (!GetInstallationDir(argc, argv, installDir)) { LOG_WARN(("Could not get the installation directory")); - if (!WriteStatusFailure(argv[1], - SERVICE_INSTALLDIR_ERROR)) { + if (!WriteStatusFailure(argv[1], SERVICE_INSTALLDIR_ERROR)) { LOG_WARN(("Could not write update.status for GetInstallationDir failure.")); } return FALSE; @@ -587,6 +587,73 @@ ExecuteServiceCommand(int argc, LPWSTR *argv) BOOL result = FALSE; if (!lstrcmpi(argv[2], L"software-update")) { + // This check is also performed in updater.cpp and is performed here + // as well since the maintenance service can be called directly. + if (argc < 4 || !IsValidFullPath(argv[4])) { + // Since the status file is written to the patch directory and the patch + // directory is invalid don't write the status file. + LOG_WARN(("The patch directory path is not valid for this application.")); + return FALSE; + } + + // This check is also performed in updater.cpp and is performed here + // as well since the maintenance service can be called directly. + if (argc < 5 || !IsValidFullPath(argv[5])) { + LOG_WARN(("The install directory path is not valid for this application.")); + if (!WriteStatusFailure(argv[4], SERVICE_INVALID_INSTALL_DIR_PATH_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + + if (!IsOldCommandline(argc - 3, argv + 3)) { + // This check is also performed in updater.cpp and is performed here + // as well since the maintenance service can be called directly. + if (argc < 6 || !IsValidFullPath(argv[6])) { + LOG_WARN(("The working directory path is not valid for this application.")); + if (!WriteStatusFailure(argv[4], SERVICE_INVALID_WORKING_DIR_PATH_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + + // These checks are also performed in updater.cpp and is performed here + // as well since the maintenance service can be called directly. + if (_wcsnicmp(argv[6], argv[5], MAX_PATH) != 0) { + if (wcscmp(argv[7], L"-1") != 0 && !wcsstr(argv[7], L"/replace")) { + LOG_WARN(("Installation directory and working directory must be the " + "same for non-staged updates. Exiting.")); + if (!WriteStatusFailure(argv[4], SERVICE_INVALID_APPLYTO_DIR_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + + NS_tchar workingDirParent[MAX_PATH]; + NS_tsnprintf(workingDirParent, + sizeof(workingDirParent) / sizeof(workingDirParent[0]), + NS_T("%s"), argv[6]); + if (!PathRemoveFileSpecW(workingDirParent)) { + LOG_WARN(("Couldn't remove file spec when attempting to verify the " + "working directory path. (%d)", GetLastError())); + if (!WriteStatusFailure(argv[4], REMOVE_FILE_SPEC_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + + if (_wcsnicmp(workingDirParent, argv[5], MAX_PATH) != 0) { + LOG_WARN(("The apply-to directory must be the same as or " + "a child of the installation directory! Exiting.")); + if (!WriteStatusFailure(argv[4], SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + } + + } + // Use the passed in command line arguments for the update, except for the // path to updater.exe. We always look for updater.exe in the installation // directory, then we copy updater.exe to a the directory of the @@ -596,12 +663,37 @@ ExecuteServiceCommand(int argc, LPWSTR *argv) WCHAR installDir[MAX_PATH + 1] = { L'\0' }; if (!GetInstallationDir(argc - 3, argv + 3, installDir)) { LOG_WARN(("Could not get the installation directory")); - if (!WriteStatusFailure(argv[1], - SERVICE_INSTALLDIR_ERROR)) { - LOG_WARN(("Could not write update.status for GetInstallationDir failure.")); + if (!WriteStatusFailure(argv[4], SERVICE_INSTALLDIR_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); } return FALSE; } + + if (!DoesFallbackKeyExist()) { + WCHAR maintenanceServiceKey[MAX_PATH + 1]; + if (CalculateRegistryPathFromFilePath(installDir, maintenanceServiceKey)) { + LOG(("Checking for Maintenance Service registry. key: '%ls'", + maintenanceServiceKey)); + HKEY baseKey = nullptr; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + maintenanceServiceKey, 0, + KEY_READ | KEY_WOW64_64KEY, + &baseKey) != ERROR_SUCCESS) { + LOG_WARN(("The maintenance service registry key does not exist.")); + if (!WriteStatusFailure(argv[4], SERVICE_INSTALL_DIR_REG_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + RegCloseKey(baseKey); + } else { + if (!WriteStatusFailure(argv[4], SERVICE_CALC_REG_PATH_ERROR)) { + LOG_WARN(("Could not write update.status for previous failure.")); + } + return FALSE; + } + } + WCHAR installDirUpdater[MAX_PATH + 1] = { L'\0' }; wcsncpy(installDirUpdater, installDir, MAX_PATH); if (!PathAppendSafe(installDirUpdater, L"updater.exe")) { @@ -609,7 +701,7 @@ ExecuteServiceCommand(int argc, LPWSTR *argv) result = FALSE; } - result = UpdaterIsValid(installDirUpdater, installDir, argv[5]); + result = UpdaterIsValid(installDirUpdater, installDir, argv[4]); WCHAR secureUpdaterPath[MAX_PATH + 1] = { L'\0' }; if (result) { @@ -617,7 +709,7 @@ ExecuteServiceCommand(int argc, LPWSTR *argv) } if (result) { LOG(("Passed in path: '%ls'; Using this path for updating: '%ls'.", - installDirUpdater, secureUpdaterPath)); + installDirUpdater, secureUpdaterPath)); DeleteSecureUpdater(secureUpdaterPath); result = CopyFileW(installDirUpdater, secureUpdaterPath, FALSE); } @@ -625,8 +717,7 @@ ExecuteServiceCommand(int argc, LPWSTR *argv) if (!result) { LOG_WARN(("Could not copy path to secure location. (%d)", GetLastError())); - if (argc > 4 && !WriteStatusFailure(argv[4], - SERVICE_COULD_NOT_COPY_UPDATER)) { + if (!WriteStatusFailure(argv[4], SERVICE_COULD_NOT_COPY_UPDATER)) { LOG_WARN(("Could not write update.status could not copy updater error")); } } else { diff --git a/toolkit/mozapps/update/common/certificatecheck.cpp b/toolkit/mozapps/update/common/certificatecheck.cpp index f132f2b34a86..afb2e7ee3472 100644 --- a/toolkit/mozapps/update/common/certificatecheck.cpp +++ b/toolkit/mozapps/update/common/certificatecheck.cpp @@ -9,7 +9,7 @@ #include #include "certificatecheck.h" -#include "updatelogging.h" +#include "updatecommon.h" static const int ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; diff --git a/toolkit/mozapps/update/common/errors.h b/toolkit/mozapps/update/common/errors.h index c978d40e1475..1d48d01abd21 100644 --- a/toolkit/mozapps/update/common/errors.h +++ b/toolkit/mozapps/update/common/errors.h @@ -41,7 +41,7 @@ #define MAR_CHANNEL_MISMATCH_ERROR 22 #define VERSION_DOWNGRADE_ERROR 23 -// Error codes 24-33 and 49-51 are for the Windows maintenance service. +// Error codes 24-33 and 49-57 are for the Windows maintenance service. #define SERVICE_UPDATER_COULD_NOT_BE_STARTED 24 #define SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS 25 #define SERVICE_UPDATER_SIGN_ERROR 26 @@ -66,10 +66,16 @@ #define DELETE_ERROR_EXPECTED_FILE 47 #define RENAME_ERROR_EXPECTED_FILE 48 -// Error codes 24-33 and 49-51 are for the Windows maintenance service. +// Error codes 24-33 and 49-57 are for the Windows maintenance service. #define SERVICE_COULD_NOT_COPY_UPDATER 49 #define SERVICE_STILL_APPLYING_TERMINATED 50 #define SERVICE_STILL_APPLYING_NO_EXIT_CODE 51 +#define SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR 52 +#define SERVICE_CALC_REG_PATH_ERROR 53 +#define SERVICE_INVALID_APPLYTO_DIR_ERROR 54 +#define SERVICE_INVALID_INSTALL_DIR_PATH_ERROR 55 +#define SERVICE_INVALID_WORKING_DIR_PATH_ERROR 56 +#define SERVICE_INSTALL_DIR_REG_ERROR 57 #define WRITE_ERROR_FILE_COPY 61 #define WRITE_ERROR_DELETE_FILE 62 @@ -85,6 +91,8 @@ #define INVALID_APPLYTO_DIR_STAGED_ERROR 72 #define LOCK_ERROR_PATCH_FILE 73 #define INVALID_APPLYTO_DIR_ERROR 74 +#define INVALID_INSTALL_DIR_PATH_ERROR 75 +#define INVALID_WORKING_DIR_PATH_ERROR 76 // Error codes 80 through 99 are reserved for nsUpdateService.js diff --git a/toolkit/mozapps/update/common/moz.build b/toolkit/mozapps/update/common/moz.build index 06c1898875e6..cacb0bad21d3 100644 --- a/toolkit/mozapps/update/common/moz.build +++ b/toolkit/mozapps/update/common/moz.build @@ -6,8 +6,8 @@ EXPORTS += [ 'readstrings.h', + 'updatecommon.h', 'updatedefines.h', - 'updatelogging.h', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': diff --git a/toolkit/mozapps/update/common/registrycertificates.cpp b/toolkit/mozapps/update/common/registrycertificates.cpp index e883d139a14f..1c9c4461954b 100644 --- a/toolkit/mozapps/update/common/registrycertificates.cpp +++ b/toolkit/mozapps/update/common/registrycertificates.cpp @@ -8,7 +8,7 @@ #include "registrycertificates.h" #include "pathhash.h" -#include "updatelogging.h" +#include "updatecommon.h" #include "updatehelper.h" #define MAX_KEY_LENGTH 255 diff --git a/toolkit/mozapps/update/common/sources.mozbuild b/toolkit/mozapps/update/common/sources.mozbuild index 6b8a9e31a5a9..cde51e09b076 100644 --- a/toolkit/mozapps/update/common/sources.mozbuild +++ b/toolkit/mozapps/update/common/sources.mozbuild @@ -22,7 +22,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': sources += [ 'readstrings.cpp', - 'updatelogging.cpp', + 'updatecommon.cpp', ] SOURCES += sorted(['%s/%s' % (srcdir, s) for s in sources]) diff --git a/toolkit/mozapps/update/common/uachelper.cpp b/toolkit/mozapps/update/common/uachelper.cpp index 74ae4ca283f1..11647aa72f30 100644 --- a/toolkit/mozapps/update/common/uachelper.cpp +++ b/toolkit/mozapps/update/common/uachelper.cpp @@ -5,7 +5,7 @@ #include #include #include "uachelper.h" -#include "updatelogging.h" +#include "updatecommon.h" // See the MSDN documentation with title: Privilege Constants // At the time of this writing, this documentation is located at: diff --git a/toolkit/mozapps/update/common/updatelogging.cpp b/toolkit/mozapps/update/common/updatecommon.cpp similarity index 58% rename from toolkit/mozapps/update/common/updatelogging.cpp rename to toolkit/mozapps/update/common/updatecommon.cpp index 6b96208f8bea..aff7d7260299 100644 --- a/toolkit/mozapps/update/common/updatelogging.cpp +++ b/toolkit/mozapps/update/common/updatecommon.cpp @@ -12,7 +12,7 @@ #include #include -#include "updatelogging.h" +#include "updatecommon.h" UpdateLog::UpdateLog() : logFP(nullptr) { @@ -34,12 +34,13 @@ void UpdateLog::Init(NS_tchar* sourcePath, (dstFilePathLen < static_cast(sizeof(mDstFilePath)/sizeof(mDstFilePath[0])))) { #ifdef XP_WIN - GetTempFileNameW(sourcePath, L"log", 0, mTmpFilePath); - logFP = NS_tfopen(mTmpFilePath, NS_T("w")); + if (GetTempFileNameW(sourcePath, L"log", 0, mTmpFilePath) != 0) { + logFP = NS_tfopen(mTmpFilePath, NS_T("w")); - // Delete this file now so it is possible to tell from the unelevated - // updater process if the elevated updater process has written the log. - DeleteFileW(mDstFilePath); + // Delete this file now so it is possible to tell from the unelevated + // updater process if the elevated updater process has written the log. + DeleteFileW(mDstFilePath); + } #elif XP_MACOSX logFP = NS_tfopen(mDstFilePath, NS_T("w")); #else @@ -145,3 +146,68 @@ void UpdateLog::WarnPrintf(const char *fmt, ... ) fprintf(logFP, "***\n"); va_end(ap); } + +/** + * Performs checks of a full path for validity for this application. + * + * @param origFullPath + * The full path to check. + * @return true if the path is valid for this application and false otherwise. + */ +bool +IsValidFullPath(NS_tchar* origFullPath) +{ + // Subtract 1 from MAXPATHLEN for null termination. + if (NS_tstrlen(origFullPath) > MAXPATHLEN - 1) { + // The path is longer than acceptable for this application. + return false; + } + +#ifdef XP_WIN + NS_tchar testPath[MAXPATHLEN] = {NS_T('\0')}; + // GetFullPathNameW will replace / with \ which PathCanonicalizeW requires. + if (GetFullPathNameW(origFullPath, MAXPATHLEN, testPath, nullptr) == 0) { + // Unable to get the full name for the path (e.g. invalid path). + return false; + } + + NS_tchar canonicalPath[MAXPATHLEN] = {NS_T('\0')}; + if (!PathCanonicalizeW(canonicalPath, testPath)) { + // Path could not be canonicalized (e.g. invalid path). + return false; + } + + // Check if the path passed in resolves to a differerent path. + if (NS_tstricmp(origFullPath, canonicalPath) != 0) { + // Case insensitive string comparison between the supplied path and the + // canonical path are not equal. This will prevent directory traversal and + // the use of / in paths since they are converted to \. + return false; + } + + NS_tstrncpy(testPath, origFullPath, MAXPATHLEN); + if (!PathStripToRootW(testPath)) { + // It should always be possible to strip a valid path to its root. + return false; + } + + if (origFullPath[0] == NS_T('\\')) { + // Only allow UNC server share paths. + if (!PathIsUNCServerShareW(testPath)) { + return false; + } + } +#else + // Only allow full paths. + if (origFullPath[0] != NS_T('/')) { + return false; + } + + // The path must not traverse directories + if (NS_tstrstr(origFullPath, NS_T("..")) != nullptr || + NS_tstrstr(origFullPath, NS_T("./")) != nullptr) { + return false; + } +#endif + return true; +} diff --git a/toolkit/mozapps/update/common/updatelogging.h b/toolkit/mozapps/update/common/updatecommon.h similarity index 92% rename from toolkit/mozapps/update/common/updatelogging.h rename to toolkit/mozapps/update/common/updatecommon.h index f4f2c010d1ba..3055851d8dbb 100644 --- a/toolkit/mozapps/update/common/updatelogging.h +++ b/toolkit/mozapps/update/common/updatecommon.h @@ -2,8 +2,8 @@ * 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/. */ -#ifndef UPDATELOGGING_H -#define UPDATELOGGING_H +#ifndef UPDATECOMMON_H +#define UPDATECOMMON_H #include "updatedefines.h" #include @@ -35,6 +35,8 @@ protected: NS_tchar mDstFilePath[MAXPATHLEN]; }; +bool IsValidFullPath(NS_tchar* fullPath); + #define LOG_WARN(args) UpdateLog::GetPrimaryLog().WarnPrintf args #define LOG(args) UpdateLog::GetPrimaryLog().Printf args #define LogInit(PATHNAME_, FILENAME_) \ diff --git a/toolkit/mozapps/update/common/updatehelper.cpp b/toolkit/mozapps/update/common/updatehelper.cpp index 1a0d1583e2bf..937cfd23a622 100644 --- a/toolkit/mozapps/update/common/updatehelper.cpp +++ b/toolkit/mozapps/update/common/updatehelper.cpp @@ -273,7 +273,9 @@ WriteStatusFailure(LPCWSTR updateDirPath, int errorCode) // The temp file is not removed on failure since there is client code that // will remove it. WCHAR tmpUpdateStatusFilePath[MAX_PATH + 1] = { L'\0' }; - GetTempFileNameW(updateDirPath, L"svc", 0, tmpUpdateStatusFilePath); + if (GetTempFileNameW(updateDirPath, L"svc", 0, tmpUpdateStatusFilePath) == 0) { + return FALSE; + } HANDLE tmpStatusFile = CreateFileW(tmpUpdateStatusFilePath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr); diff --git a/toolkit/mozapps/update/updater/launchchild_osx.mm b/toolkit/mozapps/update/updater/launchchild_osx.mm index 97e31b918099..5a36ae6237ee 100644 --- a/toolkit/mozapps/update/updater/launchchild_osx.mm +++ b/toolkit/mozapps/update/updater/launchchild_osx.mm @@ -79,6 +79,13 @@ LaunchMacPostProcess(const char* aAppBundle) return; } + // The path must not traverse directories and it must be a relative path. + if ([exeRelPath rangeOfString:@".."].location != NSNotFound || + [exeRelPath rangeOfString:@"./"].location != NSNotFound || + [exeRelPath rangeOfString:@"/"].location == 0) { + return; + } + NSString* exeFullPath = [NSString stringWithUTF8String:aAppBundle]; exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath]; diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index f7ed1da653f8..008cb6eb382c 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -52,7 +52,7 @@ #include #include -#include "updatelogging.h" +#include "updatecommon.h" #ifdef XP_MACOSX #include "updaterfileutils_osx.h" #endif // XP_MACOSX @@ -281,7 +281,7 @@ private: //----------------------------------------------------------------------------- -static NS_tchar* gPatchDirPath; +static NS_tchar gPatchDirPath[MAXPATHLEN]; static NS_tchar gInstallDirPath[MAXPATHLEN]; static NS_tchar gWorkingDirPath[MAXPATHLEN]; static ArchiveReader gArchiveReader; @@ -1972,8 +1972,20 @@ LaunchWinPostProcess(const WCHAR *installationDir, return false; } - // Verify that exeFile doesn't contain relative paths - if (wcsstr(exefile, L"..") != nullptr) { + // The relative path must not contain directory traversals, current directory, + // or colons. + if (wcsstr(exefile, L"..") != nullptr || + wcsstr(exefile, L"./") != nullptr || + wcsstr(exefile, L".\\") != nullptr || + wcsstr(exefile, L":") != nullptr) { + return false; + } + + // The relative path must not start with a decimal point, backslash, or + // forward slash. + if (exefile[0] == L'.' || + exefile[0] == L'\\' || + exefile[0] == L'/') { return false; } @@ -1983,6 +1995,10 @@ LaunchWinPostProcess(const WCHAR *installationDir, return false; } + if (!IsValidFullPath(exefullpath)) { + return false; + } + #if !defined(TEST_UPDATER) && defined(MOZ_MAINTENANCE_SERVICE) if (sUsingService && !DoesBinaryMatchAllowedCertificates(installationDir, exefullpath)) { @@ -2089,7 +2105,9 @@ WriteStatusFile(const char* aStatus) #if defined(XP_WIN) // The temp file is not removed on failure since there is client code that // will remove it. - GetTempFileNameW(gPatchDirPath, L"sta", 0, filename); + if (GetTempFileNameW(gPatchDirPath, L"sta", 0, filename) == 0) { + return false; + } #else NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]), NS_T("%s/update.status"), gPatchDirPath); @@ -2720,9 +2738,38 @@ int NS_main(int argc, NS_tchar **argv) return 1; } + // This check is also performed in workmonitor.cpp since the maintenance + // service can be called directly. + if (!IsValidFullPath(argv[1])) { + // Since the status file is written to the patch directory and the patch + // directory is invalid don't write the status file. + fprintf(stderr, "The patch directory path is not valid for this " \ + "application (" LOG_S ")\n", argv[1]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif + return 1; + } // The directory containing the update information. - gPatchDirPath = argv[1]; + NS_tstrncpy(gPatchDirPath, argv[1], MAXPATHLEN); + // This check is also performed in workmonitor.cpp since the maintenance + // service can be called directly. + if (!IsValidFullPath(argv[2])) { + WriteStatusFile(INVALID_INSTALL_DIR_PATH_ERROR); + fprintf(stderr, "The install directory path is not valid for this " \ + "application (" LOG_S ")\n", argv[2]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif + return 1; + } // The directory we're going to update to. // We copy this string because we need to remove trailing slashes. The C++ // standard says that it's always safe to write to strings pointed to by argv @@ -2795,6 +2842,20 @@ int NS_main(int argc, NS_tchar **argv) } } + // This check is also performed in workmonitor.cpp since the maintenance + // service can be called directly. + if (!IsValidFullPath(argv[3])) { + WriteStatusFile(INVALID_WORKING_DIR_PATH_ERROR); + fprintf(stderr, "The working directory path is not valid for this " \ + "application (" LOG_S ")\n", argv[3]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif + return 1; + } // The directory we're going to update to. // We copy this string because we need to remove trailing slashes. The C++ // standard says that it's always safe to write to strings pointed to by argv @@ -2851,6 +2912,8 @@ int NS_main(int argc, NS_tchar **argv) LOG(("WORKING DIRECTORY " LOG_S, gWorkingDirPath)); #if defined(XP_WIN) + // These checks are also performed in workmonitor.cpp since the maintenance + // service can be called directly. if (_wcsnicmp(gWorkingDirPath, gInstallDirPath, MAX_PATH) != 0) { if (!sStagedUpdate && !sReplaceRequest) { WriteStatusFile(INVALID_APPLYTO_DIR_ERROR);