mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 06:43:32 +00:00
Backed out changeset c22053f7eb41 (bug 1917536) for causing bug 1923376.
This commit is contained in:
parent
d0c13bb2a9
commit
a753e3b7b0
@ -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",
|
||||
]
|
||||
|
@ -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,12 +130,12 @@ 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) \
|
||||
# define EXIT_WHEN_ELEVATED(path, handle, retCode) \
|
||||
{ \
|
||||
if (handle != INVALID_HANDLE_VALUE) { \
|
||||
CloseHandle(handle); \
|
||||
} \
|
||||
if (gIsElevated) { \
|
||||
if (NS_tremove(path) && errno != ENOENT) { \
|
||||
return retCode; \
|
||||
} \
|
||||
}
|
||||
@ -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
|
||||
,
|
||||
|
@ -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.
|
||||
LauncherResult<bool> containsAdminGroup =
|
||||
IsMemberOfAdministrators(nsAutoHandle());
|
||||
if (containsAdminGroup.isErr()) {
|
||||
return containsAdminGroup.propagateErr();
|
||||
}
|
||||
|
||||
if (!containsAdminGroup.unwrap()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have Administrator privileges, now check if we have them while UAC
|
||||
// is disabled.
|
||||
return IsUacEnabled().map(
|
||||
[](bool isUacEnabled) { return !isUacEnabled; });
|
||||
});
|
||||
LauncherResult<bool> isUacEnabled = IsUacEnabled();
|
||||
if (isUacEnabled.isErr()) {
|
||||
return isUacEnabled.propagateErr();
|
||||
}
|
||||
|
||||
LauncherResult<bool> UserHasAdminPrivileges() {
|
||||
return IsMemberOfSidType(nsAutoHandle(), WinBuiltinAdministratorsSid);
|
||||
}
|
||||
|
||||
LauncherResult<bool> UserIsLocalSystem() {
|
||||
return IsMemberOfSidType(nsAutoHandle(), WinLocalSystemSid);
|
||||
return !isUacEnabled.unwrap();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user