Backed out changeset c22053f7eb41 (bug 1917536) for causing bug 1923376.

This commit is contained in:
Ryan VanderMeulen 2024-10-11 17:46:54 -04:00
parent d0c13bb2a9
commit a753e3b7b0
4 changed files with 81 additions and 101 deletions

View File

@ -36,7 +36,6 @@ if CONFIG["MOZ_VERIFY_MAR_SIGNATURE"]:
if CONFIG["OS_ARCH"] == "WINNT":
have_progressui = 1
srcs += [
"/toolkit/xre/WinTokenUtils.cpp",
"loaddlls.cpp",
"progressui_win.cpp",
]

View File

@ -55,7 +55,6 @@
#ifdef XP_WIN
# include "mozilla/Maybe.h"
# include "mozilla/WinHeaderOnlyUtils.h"
# include "mozilla/WinTokenUtils.h"
# include <climits>
#endif // XP_WIN
@ -131,14 +130,14 @@ BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath,
// Closes the handle if valid and if the updater is elevated returns with the
// return code specified. This prevents multiple launches of the callback
// application by preventing the elevated process from launching the callback.
# define EXIT_WHEN_ELEVATED(handle, retCode) \
{ \
if (handle != INVALID_HANDLE_VALUE) { \
CloseHandle(handle); \
} \
if (gIsElevated) { \
return retCode; \
} \
# define EXIT_WHEN_ELEVATED(path, handle, retCode) \
{ \
if (handle != INVALID_HANDLE_VALUE) { \
CloseHandle(handle); \
} \
if (NS_tremove(path) && errno != ENOENT) { \
return retCode; \
} \
}
#endif
@ -2882,6 +2881,7 @@ int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv,
int callbackIndex
#ifdef XP_WIN
,
const WCHAR* elevatedLockFilePath,
HANDLE updateLockFileHandle
#elif XP_MACOSX
,
@ -2940,7 +2940,7 @@ int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv,
LOG(("Not launching Windows post update process because !gSucceeded"));
}
EXIT_WHEN_ELEVATED(updateLockFileHandle, 0);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
#elif XP_MACOSX
if (!gIsElevated) {
if (gSucceeded) {
@ -3123,31 +3123,18 @@ int NS_main(int argc, NS_tchar** argv) {
gPatchDirPath[MAXPATHLEN - 1] = NS_T('\0');
#ifdef XP_WIN
auto isAdmin = mozilla::UserHasAdminPrivileges();
if (isAdmin.isErr()) {
fprintf(stderr,
"Failed to query if the current process has admin privileges.\n");
return 1;
}
auto isLocalSystem = mozilla::UserIsLocalSystem();
if (isLocalSystem.isErr()) {
fprintf(
stderr,
"Failed to query if the current process has LocalSystem privileges.\n");
return 1;
}
NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')};
NS_tsnprintf(elevatedLockFilePath,
sizeof(elevatedLockFilePath) / sizeof(elevatedLockFilePath[0]),
NS_T("%s\\update_elevated.lock"), gPatchDirPath);
gUseSecureOutputPath =
sUsingService || (NS_tremove(elevatedLockFilePath) && errno != ENOENT);
// While is it technically redundant to check LocalSystem in addition to Admin
// given the former contains privileges of the latter, we have opt to verify
// both. A few reasons for this decision include the off chance that the
// Windows security model changes in the future and weird system setups where
// someone has modified the group lists in surprising ways.
//
// We use this to detect if we were launched from the Maintenance Service
// under LocalSystem or UAC under the user's account, and therefore can
// proceed with an install to `Program Files` or `Program Files(x86)`.
gIsElevated = isAdmin.unwrap() || isLocalSystem.unwrap();
gUseSecureOutputPath = sUsingService || gIsElevated;
// Even if a file has no sharing access, you can still get its attributes
// If we are running elevated, this file will exist, having been opened by
// the unelevated updater that started this one.
gIsElevated =
GetFileAttributesW(elevatedLockFilePath) != INVALID_FILE_ATTRIBUTES;
#elif defined(XP_MACOSX)
// This is only ever true on macOS and Windows. We don't currently have a
// way of elevating on other platforms.
@ -3600,9 +3587,26 @@ int NS_main(int argc, NS_tchar** argv) {
(noServiceFallback || forceServiceFallback))) {
LOG(("Can't open lock file - seems like we need elevation"));
HANDLE elevatedFileHandle;
if (NS_tremove(elevatedLockFilePath) && errno != ENOENT) {
LOG(("Unable to create elevated lock file! Exiting"));
output_finish();
return 1;
}
elevatedFileHandle = CreateFileW(
elevatedLockFilePath, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
if (elevatedFileHandle == INVALID_HANDLE_VALUE) {
LOG(("Unable to create elevated lock file! Exiting"));
output_finish();
return 1;
}
auto cmdLine = mozilla::MakeCommandLine(argc - 1, argv + 1);
if (!cmdLine) {
LOG(("Failed to make command line! Exiting"));
CloseHandle(elevatedFileHandle);
output_finish();
return 1;
}
@ -3842,6 +3846,17 @@ int NS_main(int argc, NS_tchar** argv) {
// And we don't have a good way of accepting the prompt in
// automation.
sinfo.lpVerb = L"open";
// This handle is what lets the updater that we spawn below know
// that it's the elevated updater. We are going to close it so that
// it doesn't know that and will run un-elevated. Doing this make
// this makes for an imperfect test of the service fallback
// functionality because it changes how the (usually) elevated
// updater runs. One of the effects of this is that the secure
// output files will not be used. So that functionality won't really
// be covered by testing. But we can't really have the updater run
// elevated, because that would require a UAC, which we have no way
// to deal with in automation.
CloseHandle(elevatedFileHandle);
// We need to let go of the update lock to let the un-elevated
// updater we are about to spawn update.
if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
@ -3912,6 +3927,8 @@ int NS_main(int argc, NS_tchar** argv) {
}
}
CloseHandle(elevatedFileHandle);
if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
CloseHandle(updateLockFileHandle);
}
@ -3999,7 +4016,7 @@ int NS_main(int argc, NS_tchar** argv) {
WriteStatusFile(WRITE_ERROR_APPLY_DIR_PATH);
LOG(("NS_main: unable to find apply to dir: " LOG_S, gWorkingDirPath));
output_finish();
EXIT_WHEN_ELEVATED(updateLockFileHandle, 1);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
if (argc > callbackIndex) {
LaunchCallbackApp(argv[5], argc - callbackIndex, argv + callbackIndex,
sUsingService);
@ -4053,7 +4070,7 @@ int NS_main(int argc, NS_tchar** argv) {
WriteStatusFile(WRITE_ERROR_CALLBACK_PATH);
LOG(("NS_main: unable to find callback file: " LOG_S, targetPath));
output_finish();
EXIT_WHEN_ELEVATED(updateLockFileHandle, 1);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
if (argc > callbackIndex) {
LaunchCallbackApp(argv[5], argc - callbackIndex, argv + callbackIndex,
sUsingService);
@ -4102,7 +4119,7 @@ int NS_main(int argc, NS_tchar** argv) {
// Don't attempt to launch the callback when the callback path is
// longer than expected.
EXIT_WHEN_ELEVATED(updateLockFileHandle, 1);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
return 1;
}
@ -4119,7 +4136,7 @@ int NS_main(int argc, NS_tchar** argv) {
" into place at " LOG_S,
argv[callbackIndex], gCallbackBackupPath));
output_finish();
EXIT_WHEN_ELEVATED(updateLockFileHandle, 1);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
LaunchCallbackApp(argv[callbackIndex], argc - callbackIndex,
argv + callbackIndex, sUsingService);
return 1;
@ -4194,7 +4211,7 @@ int NS_main(int argc, NS_tchar** argv) {
gCallbackBackupPath));
}
output_finish();
EXIT_WHEN_ELEVATED(updateLockFileHandle, 1);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
LaunchCallbackApp(argv[5], argc - callbackIndex,
argv + callbackIndex, sUsingService);
return 1;
@ -4305,6 +4322,7 @@ int NS_main(int argc, NS_tchar** argv) {
int retVal = LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex
#ifdef XP_WIN
,
elevatedLockFilePath,
updateLockFileHandle
#elif XP_MACOSX
,

View File

@ -5,21 +5,23 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "WinTokenUtils.h"
#include "nsWindowsHelpers.h"
using namespace mozilla;
// If |aToken| is nullptr, CheckTokenMembership uses the calling thread's
// primary token to check membership for.
static LauncherResult<bool> IsMemberOfSidType(
const nsAutoHandle& aToken, const WELL_KNOWN_SID_TYPE aWellKnownSid) {
BYTE sid[SECURITY_MAX_SID_SIZE];
DWORD sidSize = sizeof(sid);
if (!CreateWellKnownSid(aWellKnownSid, nullptr, sid, &sidSize)) {
static LauncherResult<bool> IsMemberOfAdministrators(
const nsAutoHandle& aToken) {
BYTE adminsGroupSid[SECURITY_MAX_SID_SIZE];
DWORD adminsGroupSidSize = sizeof(adminsGroupSid);
if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, nullptr, adminsGroupSid,
&adminsGroupSidSize)) {
return LAUNCHER_ERROR_FROM_LAST();
}
BOOL isMember;
if (!CheckTokenMembership(aToken, sid, &isMember)) {
if (!CheckTokenMembership(aToken, adminsGroupSid, &isMember)) {
return LAUNCHER_ERROR_FROM_LAST();
}
return !!isMember;
@ -43,33 +45,28 @@ static LauncherResult<bool> IsUacEnabled() {
namespace mozilla {
LauncherResult<bool> IsAdminWithoutUac() {
// To check whether the process was launched with Administrator privileges or
// not, we cannot simply check the integrity level of the current process
// To check whether the process was launched with Administrator priviledges
// or not, we cannot simply check the integrity level of the current process
// because the launcher process spawns the browser process with the medium
// integrity level even though the launcher process is high integrity level.
// We check whether the thread's token contains Administrators SID or not
// We check whether the thread's token contains Administratos SID or not
// instead.
return UserHasAdminPrivileges().andThen(
[](bool containsAdminGroup) -> LauncherResult<bool> {
if (!containsAdminGroup) {
// We don't have Administrator privileges, no need to check if UAC is
// enabled.
return false;
}
LauncherResult<bool> containsAdminGroup =
IsMemberOfAdministrators(nsAutoHandle());
if (containsAdminGroup.isErr()) {
return containsAdminGroup.propagateErr();
}
// We have Administrator privileges, now check if we have them while UAC
// is disabled.
return IsUacEnabled().map(
[](bool isUacEnabled) { return !isUacEnabled; });
});
}
if (!containsAdminGroup.unwrap()) {
return false;
}
LauncherResult<bool> UserHasAdminPrivileges() {
return IsMemberOfSidType(nsAutoHandle(), WinBuiltinAdministratorsSid);
}
LauncherResult<bool> isUacEnabled = IsUacEnabled();
if (isUacEnabled.isErr()) {
return isUacEnabled.propagateErr();
}
LauncherResult<bool> UserIsLocalSystem() {
return IsMemberOfSidType(nsAutoHandle(), WinLocalSystemSid);
return !isUacEnabled.unwrap();
}
} // namespace mozilla

View File

@ -11,42 +11,8 @@
namespace mozilla {
/**
* Windows UAC can be disabled via the registry. This checks if the user has
* Administrator privileges and UAC has been disabled.
*
* @return `Ok(true)` when the current process has Administrator privileges
* *and* UAC has been disabled, otherwise `Ok(false)` or
* `Err(WindowsError)`.
*/
LauncherResult<bool> IsAdminWithoutUac();
/**
* Checks if the current process has Administrator privileges.
*
* @return `Ok(true)` when the current process has Administrator privileges,
* otherwise `Ok(false)` or `Err(WindowsError)`.
*
*/
LauncherResult<bool> UserHasAdminPrivileges();
/**
* Checks if the current process user is LocalSystem.
*
* LocalSystem (or just SYSTEM in Task Manager) is a high privileged account
* similar to Administrator. Unlike Administrator which runs under a User
* context, LocalSystem runs under a System context and has some privileges
* beyond that of Administrator. We use LocalSystem for privileges necessary for
* our updater.
*
* Note that LocalSystem is not equivalent to the lower privileged LocalSerivce
* account.
*
* @return `Ok(true)` when the current process user is LocalSystem, otherwise
* `Ok(false)` or `Err(WindowsError)`.
*/
LauncherResult<bool> UserIsLocalSystem();
} // namespace mozilla
#endif // mozilla_WinTokenUtils_h