Bug 1567219 - Add a metric to collect how many users launch a process with Admin but without UAC. r=aklotz
authorToshihito Kikuchi <tkikuchi@mozilla.com>
Wed, 28 Aug 2019 02:17:49 +0000
changeset 490483 465c399713381aae67efede22e3496602d2139b5
parent 490482 38e4ea4314452422fe5fcfb8b1b557201ae9c0f8
child 490484 6d157db92bc951194c5bd528d292c84e78bbb25d
push id93883
push useraklotz@mozilla.com
push dateWed, 28 Aug 2019 19:58:31 +0000
treeherderautoland@465c39971338 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaklotz
bugs1567219
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1567219 - Add a metric to collect how many users launch a process with Admin but without UAC. r=aklotz This patch adds a new Scalar metric `os.environment.is_admin_without_uac` that indicates the process is lauched with Admin privileges when UAC is turned off. Differential Revision: https://phabricator.services.mozilla.com/D42047
browser/app/winlauncher/moz.build
toolkit/components/telemetry/Scalars.yaml
toolkit/xre/WinTokenUtils.cpp
toolkit/xre/WinTokenUtils.h
toolkit/xre/moz.build
toolkit/xre/nsAppRunner.cpp
--- a/browser/app/winlauncher/moz.build
+++ b/browser/app/winlauncher/moz.build
@@ -55,13 +55,14 @@ OS_LIBS += [
 
 TEST_DIRS += [
     'test',
 ]
 
 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]
 
 DisableStlWrapping()
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -677,16 +677,35 @@ sandbox:
       - 'firefox'
       - 'fennec'
       - 'geckoview'
     record_in_processes:
       - main
     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:
       - 1560590
     description: >
       The number of times a Picture-in-Picture window was opened, per trigger
       mechanism (e.g.: the video toggle, the context menu).
     expires: "74"
new file mode 100644
--- /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<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, adminsGroupSid, &isMember)) {
+    return LAUNCHER_ERROR_FROM_LAST();
+  }
+  return !!isMember;
+}
+
+static LauncherResult<bool> 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<bool> 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<bool> containsAdminGroup =
+      IsMemberOfAdministrators(nsAutoHandle());
+  if (containsAdminGroup.isErr()) {
+    return LAUNCHER_ERROR_FROM_RESULT(containsAdminGroup);
+  }
+
+  if (!containsAdminGroup.unwrap()) {
+    return false;
+  }
+
+  LauncherResult<bool> isUacEnabled = IsUacEnabled();
+  if (isUacEnabled.isErr()) {
+    return LAUNCHER_ERROR_FROM_RESULT(isUacEnabled);
+  }
+
+  return !isUacEnabled.unwrap();
+}
+
+}  // namespace mozilla
new file mode 100644
--- /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<bool> IsAdminWithoutUac();
+
+}  // namespace mozilla
+
+#endif  // mozilla_WinTokenUtils_h
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -45,23 +45,25 @@ if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS.mozilla += [
         'LauncherResult.h',
         'ModuleEvaluator_windows.h',
         'ModuleVersionInfo_windows.h',
         'PolicyChecks.h',
         'WinDllServices.h',
+        'WinTokenUtils.h',
     ]
     UNIFIED_SOURCES += [
         '/toolkit/mozapps/update/common/updateutils_win.cpp',
         'ModuleEvaluator_windows.cpp',
         'ModuleVersionInfo_windows.cpp',
         'nsNativeAppSupportWin.cpp',
         'WinDllServices.cpp',
+        'WinTokenUtils.cpp',
     ]
     DEFINES['PROXY_PRINTING'] = 1
     LOCAL_INCLUDES += [
         '../components/printingui',
     ]
     if CONFIG['MOZ_LAUNCHER_PROCESS']:
         EXPORTS.mozilla += [
           'LauncherRegistryInfo.h',
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -108,16 +108,17 @@
 #  include <windows.h>
 #  include <intrin.h>
 #  include <math.h>
 #  include "cairo/cairo-features.h"
 #  include "mozilla/WindowsDllBlocklist.h"
 #  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"
 #  endif
 
 #  ifndef PROCESS_DEP_ENABLE
 #    define PROCESS_DEP_ENABLE 0x1
 #  endif
@@ -4558,16 +4559,25 @@ nsresult XREMain::XRE_mainRun() {
                         sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
   nsAutoCString flagsString;
   flagsString.AppendInt(sandboxInfo.AsInteger());
 
   CrashReporter::AnnotateCrashReport(
       CrashReporter::Annotation::ContentSandboxCapabilities, flagsString);
 #endif /* MOZ_SANDBOX && XP_LINUX */
 
+#if defined(XP_WIN)
+  LauncherResult<bool> 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 */
 
   mProfileSvc->CompleteStartup();
 
   {
     rv = appStartup->Run();