diff --git a/browser/app/winlauncher/moz.build b/browser/app/winlauncher/moz.build index f50cc8f1302c..be2be08e32a5 100644 --- a/browser/app/winlauncher/moz.build +++ b/browser/app/winlauncher/moz.build @@ -60,6 +60,7 @@ TEST_DIRS += [ if CONFIG['MOZ_LAUNCHER_PROCESS']: UNIFIED_SOURCES += [ '/toolkit/xre/LauncherRegistryInfo.cpp', + '/toolkit/xre/WinTokenUtils.cpp', ] for var in ('MOZ_APP_BASENAME', 'MOZ_APP_VENDOR'): DEFINES[var] = '"%s"' % CONFIG[var] diff --git a/toolkit/components/telemetry/Scalars.yaml b/toolkit/components/telemetry/Scalars.yaml index 4530dd594c6e..aae2012b4118 100644 --- a/toolkit/components/telemetry/Scalars.yaml +++ b/toolkit/components/telemetry/Scalars.yaml @@ -682,6 +682,25 @@ sandbox: operating_systems: - "windows" +os.environment: + is_admin_without_uac: + bug_numbers: + - 1567219 + description: > + Indicates that the process is lauched with Admin privileges but without + UAC. + expires: never + kind: boolean + notification_emails: + - tkikuchi@mozilla.com + release_channel_collection: opt-out + products: + - 'firefox' + record_in_processes: + - main + operating_systems: + - "windows" + pictureinpicture: opened_method: bug_numbers: diff --git a/toolkit/xre/WinTokenUtils.cpp b/toolkit/xre/WinTokenUtils.cpp new file mode 100644 index 000000000000..ed45e0c8fac8 --- /dev/null +++ b/toolkit/xre/WinTokenUtils.cpp @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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 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, adminsGroupSid, &isMember)) { + return LAUNCHER_ERROR_FROM_LAST(); + } + return !!isMember; +} + +static LauncherResult IsUacEnabled() { + DWORD len = sizeof(DWORD); + DWORD value; + LSTATUS status = RegGetValueW( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", + L"EnableLUA", RRF_RT_DWORD, nullptr, &value, &len); + if (status != ERROR_SUCCESS) { + return LAUNCHER_ERROR_FROM_WIN32(status); + } + + // UAC is disabled only when EnableLUA is 0. + return (value != 0); +} + +namespace mozilla { + +LauncherResult IsAdminWithoutUac() { + // 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 Administratos SID or not + // instead. + LauncherResult containsAdminGroup = + IsMemberOfAdministrators(nsAutoHandle()); + if (containsAdminGroup.isErr()) { + return LAUNCHER_ERROR_FROM_RESULT(containsAdminGroup); + } + + if (!containsAdminGroup.unwrap()) { + return false; + } + + LauncherResult isUacEnabled = IsUacEnabled(); + if (isUacEnabled.isErr()) { + return LAUNCHER_ERROR_FROM_RESULT(isUacEnabled); + } + + return !isUacEnabled.unwrap(); +} + +} // namespace mozilla diff --git a/toolkit/xre/WinTokenUtils.h b/toolkit/xre/WinTokenUtils.h new file mode 100644 index 000000000000..f582bd0696b2 --- /dev/null +++ b/toolkit/xre/WinTokenUtils.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_WinTokenUtils_h +#define mozilla_WinTokenUtils_h + +#include "mozilla/LauncherResult.h" + +namespace mozilla { + +LauncherResult IsAdminWithoutUac(); + +} // namespace mozilla + +#endif // mozilla_WinTokenUtils_h diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index 57ae50a68c0d..f53f7b38f4c0 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -50,6 +50,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'ModuleVersionInfo_windows.h', 'PolicyChecks.h', 'WinDllServices.h', + 'WinTokenUtils.h', ] UNIFIED_SOURCES += [ '/toolkit/mozapps/update/common/updateutils_win.cpp', @@ -57,6 +58,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'ModuleVersionInfo_windows.cpp', 'nsNativeAppSupportWin.cpp', 'WinDllServices.cpp', + 'WinTokenUtils.cpp', ] DEFINES['PROXY_PRINTING'] = 1 LOCAL_INCLUDES += [ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index d7883d9f70a0..80b926d71367 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -113,6 +113,7 @@ # include "mozilla/WinHeaderOnlyUtils.h" # include "mozilla/mscom/ProcessRuntime.h" # include "mozilla/widget/AudioSession.h" +# include "WinTokenUtils.h" # if defined(MOZ_LAUNCHER_PROCESS) # include "mozilla/LauncherRegistryInfo.h" @@ -4563,6 +4564,15 @@ nsresult XREMain::XRE_mainRun() { CrashReporter::Annotation::ContentSandboxCapabilities, flagsString); #endif /* MOZ_SANDBOX && XP_LINUX */ +#if defined(XP_WIN) + LauncherResult isAdminWithoutUac = IsAdminWithoutUac(); + if (isAdminWithoutUac.isOk()) { + Telemetry::ScalarSet( + Telemetry::ScalarID::OS_ENVIRONMENT_IS_ADMIN_WITHOUT_UAC, + isAdminWithoutUac.unwrap()); + } +#endif /* XP_WIN */ + #if defined(MOZ_SANDBOX) AddSandboxAnnotations(); #endif /* MOZ_SANDBOX */