tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sandboxBroker.cpp (83402B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #define MOZ_USE_LAUNCHER_ERROR
      8 
      9 #include "sandboxBroker.h"
     10 
     11 #include <aclapi.h>
     12 #include <sddl.h>
     13 #include <shlobj.h>
     14 #include <string>
     15 
     16 #include "base/win/windows_version.h"
     17 #include "base/win/sid.h"
     18 #include "ConfigHelpers.h"
     19 #include "GfxDriverInfo.h"
     20 #include "mozilla/Assertions.h"
     21 #include "mozilla/ClearOnShutdown.h"
     22 #include "mozilla/Components.h"
     23 #include "mozilla/ImportDir.h"
     24 #include "mozilla/Logging.h"
     25 #include "mozilla/NSPRLogModulesParser.h"
     26 #include "mozilla/Omnijar.h"
     27 #include "mozilla/Preferences.h"
     28 #include "mozilla/SandboxSettings.h"
     29 #include "mozilla/SHA1.h"
     30 #include "mozilla/StaticPrefs_network.h"
     31 #include "mozilla/StaticPrefs_security.h"
     32 #include "mozilla/StaticPrefs_widget.h"
     33 #include "mozilla/StaticPtr.h"
     34 #include "mozilla/UniquePtr.h"
     35 #include "mozilla/glean/SecuritySandboxMetrics.h"
     36 #include "mozilla/WinDllServices.h"
     37 #include "mozilla/WindowsVersion.h"
     38 #include "mozilla/ipc/LaunchError.h"
     39 #include "nsAppDirectoryServiceDefs.h"
     40 #include "nsCOMPtr.h"
     41 #include "nsDirectoryServiceDefs.h"
     42 #include "nsIFile.h"
     43 #include "nsIGfxInfo.h"
     44 #include "nsIProperties.h"
     45 #include "nsIXULRuntime.h"
     46 #include "nsServiceManagerUtils.h"
     47 #include "nsString.h"
     48 #include "nsTArray.h"
     49 #include "nsTHashtable.h"
     50 #include "sandbox/win/src/app_container.h"
     51 #include "sandbox/win/src/sandbox.h"
     52 #include "sandbox/win/src/security_level.h"
     53 #include "WinUtils.h"
     54 
     55 #define SANDBOX_SUCCEED_OR_CRASH(x)                                   \
     56  do {                                                                \
     57    sandbox::ResultCode result = (x);                                 \
     58    MOZ_RELEASE_ASSERT(result == sandbox::SBOX_ALL_OK, #x " failed"); \
     59  } while (0)
     60 
     61 namespace mozilla {
     62 
     63 constexpr wchar_t kLpacFirefoxInstallFiles[] = L"lpacFirefoxInstallFiles";
     64 
     65 sandbox::BrokerServices* sBrokerService = nullptr;
     66 
     67 // This is set to true in Initialize when our exe file name has a drive type of
     68 // DRIVE_REMOTE, so that we can tailor the sandbox policy as some settings break
     69 // fundamental things when running from a network drive. We default to false in
     70 // case those checks fail as that gives us the strongest policy.
     71 bool SandboxBroker::sRunningFromNetworkDrive = false;
     72 
     73 // Cached special directories used for adding policy rules.
     74 static StaticAutoPtr<nsString> sBinDir;
     75 static StaticAutoPtr<nsString> sProfileDir;
     76 static StaticAutoPtr<nsString> sWindowsProfileDir;
     77 static StaticAutoPtr<nsString> sLocalAppDataDir;
     78 static StaticAutoPtr<nsString> sRoamingAppDataDir;
     79 static StaticAutoPtr<nsString> sSystemFontsDir;
     80 static StaticAutoPtr<nsString> sWindowsSystemDir;
     81 static StaticAutoPtr<nsString> sLocalAppDataLowDir;
     82 static StaticAutoPtr<nsString> sLocalAppDataLowParentDir;
     83 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
     84 static StaticAutoPtr<nsString> sUserExtensionsDir;
     85 #endif
     86 
     87 LazyLogModule sSandboxBrokerLog("SandboxBroker");
     88 
     89 #define LOG_E(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Error, (__VA_ARGS__))
     90 #define LOG_W(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Warning, (__VA_ARGS__))
     91 #define LOG_D(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Debug, (__VA_ARGS__))
     92 
     93 // Used to store whether we have accumulated an error combination for this
     94 // session.
     95 static StaticAutoPtr<nsTHashtable<nsCStringHashKey>> sLaunchErrors;
     96 
     97 // This helper function is our version of SandboxWin::AddWin32kLockdownConfig
     98 // of Chromium, making sure the MITIGATION_WIN32K_DISABLE flag is set before
     99 // adding the SUBSYS_WIN32K_LOCKDOWN rule which is required by
    100 // PolicyBase::AddRuleInternal.
    101 static sandbox::ResultCode AddWin32kLockdownConfig(
    102    sandbox::TargetConfig* aConfig) {
    103  sandbox::MitigationFlags flags = aConfig->GetProcessMitigations();
    104  MOZ_ASSERT(flags,
    105             "Mitigations should be set before AddWin32kLockdownConfig.");
    106  MOZ_ASSERT(!(flags & sandbox::MITIGATION_WIN32K_DISABLE),
    107             "Check not enabling twice.  Should not happen.");
    108 
    109  flags |= sandbox::MITIGATION_WIN32K_DISABLE;
    110  sandbox::ResultCode result = aConfig->SetProcessMitigations(flags);
    111  if (result != sandbox::SBOX_ALL_OK) {
    112    return result;
    113  }
    114 
    115  result = aConfig->SetFakeGdiInit();
    116  if (result != sandbox::SBOX_ALL_OK) {
    117    return result;
    118  }
    119 
    120  return result;
    121 }
    122 
    123 static void CacheAndStandardizeDir(const nsAString& aDir,
    124                                   StaticAutoPtr<nsString>& aCacheVar) {
    125  MOZ_ASSERT(!aCacheVar);
    126  aCacheVar = new nsString(aDir);
    127 
    128  // Convert network share path to format for sandbox policy.
    129  if (Substring(*aCacheVar, 0, 2).Equals(u"\\\\"_ns)) {
    130    aCacheVar->InsertLiteral(u"??\\UNC", 1);
    131  }
    132 }
    133 
    134 /* static */
    135 void SandboxBroker::Initialize(sandbox::BrokerServices* aBrokerServices,
    136                               const nsAString& aBinDir) {
    137  sBrokerService = aBrokerServices;
    138 
    139  sRunningFromNetworkDrive = widget::WinUtils::RunningFromANetworkDrive();
    140 
    141  if (!aBinDir.IsEmpty()) {
    142    CacheAndStandardizeDir(aBinDir, sBinDir);
    143  }
    144 
    145  // Clear statics on shutdown.
    146  RunOnShutdown([] {
    147    sLaunchErrors = nullptr;
    148    sBinDir = nullptr;
    149    sProfileDir = nullptr;
    150    sWindowsProfileDir = nullptr;
    151    sLocalAppDataDir = nullptr;
    152    sRoamingAppDataDir = nullptr;
    153    sSystemFontsDir = nullptr;
    154    sWindowsSystemDir = nullptr;
    155    sLocalAppDataLowDir = nullptr;
    156    sLocalAppDataLowParentDir = nullptr;
    157 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
    158    sUserExtensionsDir = nullptr;
    159 #endif
    160  });
    161 }
    162 
    163 static void CacheDirectoryServiceDir(nsIProperties* aDirSvc,
    164                                     const char* aDirKey,
    165                                     StaticAutoPtr<nsString>& aCacheVar) {
    166  nsCOMPtr<nsIFile> dirToCache;
    167  nsresult rv =
    168      aDirSvc->Get(aDirKey, NS_GET_IID(nsIFile), getter_AddRefs(dirToCache));
    169  if (NS_FAILED(rv)) {
    170    // This can only be an NS_WARNING, because it can fail for xpcshell tests.
    171    NS_WARNING("Failed to get directory to cache.");
    172    LOG_E("Failed to get directory to cache, key: %s.", aDirKey);
    173    return;
    174  }
    175 
    176  nsAutoString dirPath;
    177  MOZ_ALWAYS_SUCCEEDS(dirToCache->GetPath(dirPath));
    178  CacheAndStandardizeDir(dirPath, aCacheVar);
    179 }
    180 
    181 template <typename TC>
    182 static void AddCachedDirRule(TC* aConfig, sandbox::FileSemantics aAccess,
    183                             const StaticAutoPtr<nsString>& aBaseDir,
    184                             const nsLiteralString& aRelativePath = u""_ns) {
    185  if (!aBaseDir) {
    186    // This can only be an NS_WARNING, because it can null for xpcshell tests.
    187    NS_WARNING("Tried to add rule with null base dir.");
    188    LOG_E("Tried to add rule with null base dir. Relative path: %S, Access: %d",
    189          static_cast<const wchar_t*>(aRelativePath.get()), aAccess);
    190    return;
    191  }
    192 
    193  nsAutoString rulePath(*aBaseDir);
    194  rulePath.Append(aRelativePath);
    195 
    196  sandbox::ResultCode result =
    197      aConfig->AllowFileAccess(aAccess, rulePath.get());
    198  if (sandbox::SBOX_ALL_OK != result) {
    199    NS_ERROR("Failed to add file policy rule.");
    200    LOG_E("Failed (ResultCode %d) to add %d access to: %S", result, aAccess,
    201          rulePath.getW());
    202  }
    203 }
    204 
    205 static void EnsureWindowsDirCached(
    206    GUID aFolderID, StaticAutoPtr<nsString>& aCacheVar, const char* aErrMsg,
    207    StaticAutoPtr<nsString>* aParentCacheVar = nullptr) {
    208  if (aCacheVar) {
    209    return;
    210  }
    211 
    212  UniquePtr<wchar_t, mozilla::CoTaskMemFreeDeleter> dirPath;
    213  if (FAILED(::SHGetKnownFolderPath(aFolderID, 0, nullptr,
    214                                    getter_Transfers(dirPath)))) {
    215    NS_ERROR(aErrMsg);
    216    LOG_E("%s", aErrMsg);
    217    return;
    218  }
    219 
    220  nsDependentString dirString(dirPath.get());
    221  CacheAndStandardizeDir(dirString, aCacheVar);
    222  if (aParentCacheVar) {
    223    nsCOMPtr<nsIFile> dirFile;
    224    nsCOMPtr<nsIFile> parentDir;
    225    if (NS_FAILED(NS_NewLocalFile(dirString, getter_AddRefs(dirFile))) ||
    226        NS_FAILED(dirFile->GetParent(getter_AddRefs(parentDir)))) {
    227      NS_WARNING("Failed to get parent directory to cache.");
    228      LOG_E("%s parent", aErrMsg);
    229      return;
    230    }
    231 
    232    nsString parentPath;
    233    MOZ_ALWAYS_SUCCEEDS(parentDir->GetPath(parentPath));
    234    CacheAndStandardizeDir(parentPath, *aParentCacheVar);
    235  }
    236 }
    237 
    238 template <typename TC>
    239 static void AddCachedWindowsDirRule(
    240    TC* aConfig, sandbox::FileSemantics aAccess, GUID aFolderID,
    241    const nsLiteralString& aRelativePath = u""_ns) {
    242  if (aFolderID == FOLDERID_Fonts) {
    243    EnsureWindowsDirCached(FOLDERID_Fonts, sSystemFontsDir,
    244                           "Failed to get Windows Fonts folder");
    245    AddCachedDirRule(aConfig, aAccess, sSystemFontsDir, aRelativePath);
    246    return;
    247  }
    248  if (aFolderID == FOLDERID_System) {
    249    EnsureWindowsDirCached(FOLDERID_System, sWindowsSystemDir,
    250                           "Failed to get Windows System folder");
    251    AddCachedDirRule(aConfig, aAccess, sWindowsSystemDir, aRelativePath);
    252    return;
    253  }
    254  if (aFolderID == FOLDERID_LocalAppData) {
    255    EnsureWindowsDirCached(FOLDERID_LocalAppData, sLocalAppDataDir,
    256                           "Failed to get Windows LocalAppData folder");
    257    AddCachedDirRule(aConfig, aAccess, sLocalAppDataDir, aRelativePath);
    258    return;
    259  }
    260  if (aFolderID == FOLDERID_LocalAppDataLow) {
    261    // For LocalAppDataLow we also require the parent dir.
    262    EnsureWindowsDirCached(FOLDERID_LocalAppDataLow, sLocalAppDataLowDir,
    263                           "Failed to get Windows LocalAppDataLow folder",
    264                           &sLocalAppDataLowParentDir);
    265    AddCachedDirRule(aConfig, aAccess, sLocalAppDataLowDir, aRelativePath);
    266    return;
    267  }
    268  if (aFolderID == FOLDERID_RoamingAppData) {
    269    EnsureWindowsDirCached(FOLDERID_RoamingAppData, sRoamingAppDataDir,
    270                           "Failed to get Windows RoamingAppData folder");
    271    AddCachedDirRule(aConfig, aAccess, sRoamingAppDataDir, aRelativePath);
    272    return;
    273  }
    274  if (aFolderID == FOLDERID_Profile) {
    275    EnsureWindowsDirCached(FOLDERID_Profile, sWindowsProfileDir,
    276                           "Failed to get Windows Profile folder");
    277    AddCachedDirRule(aConfig, aAccess, sWindowsProfileDir, aRelativePath);
    278    return;
    279  }
    280 
    281  MOZ_CRASH("Unhandled FOLDERID guid.");
    282 }
    283 
    284 /* static */
    285 void SandboxBroker::GeckoDependentInitialize() {
    286  MOZ_ASSERT(NS_IsMainThread());
    287 
    288  // Cache directory paths for use in policy rules, because the directory
    289  // service must be called on the main thread.
    290  nsresult rv;
    291  nsCOMPtr<nsIProperties> dirSvc =
    292      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
    293  if (NS_FAILED(rv)) {
    294    MOZ_ASSERT(false,
    295               "Failed to get directory service, cannot cache directories "
    296               "for rules.");
    297    LOG_E(
    298        "Failed to get directory service, cannot cache directories for "
    299        "rules.");
    300    return;
    301  }
    302 
    303  CacheDirectoryServiceDir(dirSvc, NS_APP_USER_PROFILE_50_DIR, sProfileDir);
    304 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
    305  CacheDirectoryServiceDir(dirSvc, XRE_USER_SYS_EXTENSION_DIR,
    306                           sUserExtensionsDir);
    307 #endif
    308 }
    309 
    310 SandboxBroker::SandboxBroker() {
    311  if (sBrokerService) {
    312    mPolicy = sBrokerService->CreatePolicy();
    313    if (sRunningFromNetworkDrive) {
    314      mPolicy->GetConfig()->SetDoNotUseRestrictingSIDs();
    315    }
    316  }
    317 }
    318 
    319 #define WSTRING(STRING) L"" STRING
    320 
    321 static void AddMozLogRulesToConfig(sandbox::TargetConfig* aConfig,
    322                                   const base::EnvironmentMap& aEnvironment) {
    323  auto it = aEnvironment.find(ENVIRONMENT_LITERAL("MOZ_LOG_FILE"));
    324  if (it == aEnvironment.end()) {
    325    it = aEnvironment.find(ENVIRONMENT_LITERAL("NSPR_LOG_FILE"));
    326  }
    327  if (it == aEnvironment.end()) {
    328    return;
    329  }
    330 
    331  char const* logFileModules = getenv("MOZ_LOG");
    332  if (!logFileModules) {
    333    return;
    334  }
    335 
    336  // MOZ_LOG files have a standard file extension appended.
    337  std::wstring logFileName(it->second);
    338  logFileName.append(WSTRING(MOZ_LOG_FILE_EXTENSION));
    339 
    340  // Allow for rotation number if rotate is on in the MOZ_LOG settings.
    341  bool rotate = false;
    342  NSPRLogModulesParser(
    343      logFileModules,
    344      [&rotate](const char* aName, LogLevel aLevel, int32_t aValue) {
    345        if (strcmp(aName, "rotate") == 0) {
    346          // Less or eq zero means to turn rotate off.
    347          rotate = aValue > 0;
    348        }
    349      });
    350  if (rotate) {
    351    logFileName.append(L".?");
    352  }
    353 
    354  // Allow for %PID token in the filename. We don't allow it in the dir path, if
    355  // specified, because we have to use a wildcard as we don't know the PID yet.
    356  auto pidPos = logFileName.find(WSTRING(MOZ_LOG_PID_TOKEN));
    357  auto lastSlash = logFileName.find_last_of(L"/\\");
    358  if (pidPos != std::wstring::npos &&
    359      (lastSlash == std::wstring::npos || lastSlash < pidPos)) {
    360    logFileName.replace(pidPos, strlen(MOZ_LOG_PID_TOKEN), L"*");
    361  }
    362 
    363  auto result = aConfig->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
    364                                         logFileName.c_str());
    365  if (result != sandbox::SBOX_ALL_OK) {
    366    NS_WARNING("Failed to add rule for MOZ_LOG files.");
    367    LOG_W("Failed (ResultCode %d) to add rule for MOZ_LOG files", result);
    368  }
    369 }
    370 
    371 static void AddDeveloperRepoDirToConfig(sandbox::TargetConfig* aConfig) {
    372  const wchar_t* developer_repo_dir =
    373      _wgetenv(WSTRING("MOZ_DEVELOPER_REPO_DIR"));
    374  if (!developer_repo_dir) {
    375    return;
    376  }
    377 
    378  std::wstring repoPath(developer_repo_dir);
    379  std::replace(repoPath.begin(), repoPath.end(), '/', '\\');
    380  repoPath.append(WSTRING("\\*"));
    381 
    382  auto result = aConfig->AllowFileAccess(sandbox::FileSemantics::kAllowReadonly,
    383                                         repoPath.c_str());
    384  if (result != sandbox::SBOX_ALL_OK) {
    385    NS_ERROR("Failed to add rule for developer repo dir.");
    386    LOG_E("Failed (ResultCode %d) to add read access to developer repo dir",
    387          result);
    388  }
    389 
    390  // The following is required if the process is using a USER_RESTRICTED or
    391  // lower access token level.
    392  result = aConfig->AllowFileAccess(sandbox::FileSemantics::kAllowReadonly,
    393                                    L"\\??\\MountPointManager");
    394  if (result != sandbox::SBOX_ALL_OK) {
    395    NS_ERROR("Failed to add rule for MountPointManager.");
    396    LOG_E("Failed (ResultCode %d) to add read access to MountPointManager",
    397          result);
    398  }
    399 }
    400 
    401 #if defined(MOZ_PROFILE_GENERATE)
    402 // It should only be allowed on instrumented builds, never on production
    403 // builds.
    404 static void AddLLVMProfilePathDirectoryToPolicy(
    405    sandbox::TargetConfig* aConfig) {
    406  std::wstring parentPath;
    407  if (GetLlvmProfileDir(parentPath)) {
    408    (void)aConfig->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
    409                                   parentPath.c_str());
    410  }
    411 }
    412 #endif
    413 
    414 #undef WSTRING
    415 
    416 static void EnsureAppLockerAccess(sandbox::TargetConfig* aConfig) {
    417  if (aConfig->GetLockdownTokenLevel() < sandbox::USER_LIMITED) {
    418    // The following rules are to allow DLLs to be loaded when the token level
    419    // blocks access to AppLocker. If the sandbox does not allow access to the
    420    // DLL or the AppLocker rules specifically block it, then it will not load.
    421    auto result = aConfig->AllowFileAccess(
    422        sandbox::FileSemantics::kAllowReadonly, L"\\Device\\SrpDevice");
    423    if (sandbox::SBOX_ALL_OK != result) {
    424      NS_ERROR("Failed to add rule for SrpDevice.");
    425      LOG_E("Failed (ResultCode %d) to add read access to SrpDevice", result);
    426    }
    427    result = aConfig->AllowRegistryRead(
    428        L"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Srp\\GP\\");
    429    if (sandbox::SBOX_ALL_OK != result) {
    430      NS_ERROR("Failed to add rule for Srp\\GP.");
    431      LOG_E("Failed (ResultCode %d) to add read access to Srp\\GP", result);
    432    }
    433    // On certain Windows versions there is a double slash before GP.
    434    result = aConfig->AllowRegistryRead(
    435        L"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Srp\\\\GP\\");
    436    if (sandbox::SBOX_ALL_OK != result) {
    437      NS_ERROR("Failed to add rule for Srp\\\\GP.");
    438      LOG_E("Failed (ResultCode %d) to add read access to Srp\\\\GP", result);
    439    }
    440  }
    441 }
    442 
    443 Result<Ok, mozilla::ipc::LaunchError> SandboxBroker::LaunchApp(
    444    const wchar_t* aPath, const wchar_t* aArguments,
    445    base::EnvironmentMap& aEnvironment, GeckoProcessType aProcessType,
    446    const bool aEnableLogging, const IMAGE_THUNK_DATA* aCachedNtdllThunk,
    447    void** aProcessHandle) {
    448  if (!sBrokerService) {
    449    return Err(mozilla::ipc::LaunchError("SB::LA::sBrokerService"));
    450  }
    451 
    452  if (!mPolicy) {
    453    return Err(mozilla::ipc::LaunchError("SB::LA::mPolicy"));
    454  }
    455 
    456  // Set stdout and stderr, to allow inheritance for logging.
    457  mPolicy->SetStdoutHandle(::GetStdHandle(STD_OUTPUT_HANDLE));
    458  mPolicy->SetStderrHandle(::GetStdHandle(STD_ERROR_HANDLE));
    459 
    460  auto* config = mPolicy->GetConfig();
    461 
    462  // If we're running from a network drive then we can't block loading from
    463  // remote locations. Strangely using MITIGATION_IMAGE_LOAD_NO_LOW_LABEL in
    464  // this situation also means the process fails to start (bug 1423296).
    465  if (sRunningFromNetworkDrive) {
    466    sandbox::MitigationFlags mitigations = config->GetProcessMitigations();
    467    mitigations &= ~(sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
    468                     sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL);
    469    MOZ_RELEASE_ASSERT(
    470        config->SetProcessMitigations(mitigations) == sandbox::SBOX_ALL_OK,
    471        "Setting the reduced set of flags should always succeed");
    472  }
    473 
    474  sandbox::MitigationFlags delayedMitigations =
    475      config->GetDelayedProcessMitigations();
    476 
    477  // Only prefer loading from the system directory as a delayed mitigation, and
    478  // always enable this delayed mitigation. This means that:
    479  //  - if the launcher or browser process chose to apply the mitigation, child
    480  //    processes will have it enabled at startup automatically anyway;
    481  //  - even if the launcher or browser process chose not to apply the
    482  //    mitigation, at least sandboxed child processes will run with the
    483  //    mitigation once the sandbox starts (by this time, they will already
    484  //    have loaded the Visual C++ runtime DLLs, so these are no longer a
    485  //    concern; also, although some sandboxed child processes can start new
    486  //    processes, they never start new *Firefox* processes).
    487  // Refer to EnablePreferLoadFromSystem32IfCompatible for more details.
    488  MOZ_ASSERT(!(config->GetProcessMitigations() &
    489               sandbox::MITIGATION_IMAGE_LOAD_PREFER_SYS32));
    490  delayedMitigations |= sandbox::MITIGATION_IMAGE_LOAD_PREFER_SYS32;
    491 
    492  // Bug 1936749: MpDetours.dll injection is incompatible with ACG.
    493  constexpr sandbox::MitigationFlags kDynamicCodeFlags =
    494      sandbox::MITIGATION_DYNAMIC_CODE_DISABLE |
    495      sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT;
    496  if ((delayedMitigations & kDynamicCodeFlags) &&
    497      ::GetModuleHandleW(L"MpDetours.dll")) {
    498    delayedMitigations &= ~kDynamicCodeFlags;
    499  }
    500 
    501  SANDBOX_SUCCEED_OR_CRASH(
    502      config->SetDelayedProcessMitigations(delayedMitigations));
    503 
    504  EnsureAppLockerAccess(config);
    505 
    506  // If logging enabled, set up the policy.
    507  if (aEnableLogging) {
    508    ApplyLoggingConfig();
    509  }
    510 
    511 #if defined(DEBUG)
    512  // Allow write access to TEMP directory in debug builds for logging purposes.
    513  // The path from GetTempPathW can have a length up to MAX_PATH + 1, including
    514  // the null, so we need MAX_PATH + 2, so we can add an * to the end.
    515  wchar_t tempPath[MAX_PATH + 2];
    516  uint32_t pathLen = ::GetTempPathW(MAX_PATH + 1, tempPath);
    517  if (pathLen > 0) {
    518    // GetTempPath path ends with \ and returns the length without the null.
    519    tempPath[pathLen] = L'*';
    520    tempPath[pathLen + 1] = L'\0';
    521    auto result =
    522        config->AllowFileAccess(sandbox::FileSemantics::kAllowAny, tempPath);
    523    if (result != sandbox::SBOX_ALL_OK) {
    524      NS_WARNING("Failed to add rule for TEMP debug logging.");
    525      LOG_W("Failed (ResultCode %d) to add rule for TEMP debug logging",
    526            result);
    527    }
    528  }
    529 #endif
    530 
    531  // Enable the child process to write log files when setup
    532  AddMozLogRulesToConfig(config, aEnvironment);
    533 
    534 #if defined(MOZ_PROFILE_GENERATE)
    535  AddLLVMProfilePathDirectoryToPolicy(config);
    536 #endif
    537 
    538  if (!mozilla::IsPackagedBuild()) {
    539    AddDeveloperRepoDirToConfig(config);
    540  }
    541 
    542  // Create the sandboxed process
    543  PROCESS_INFORMATION targetInfo = {0};
    544  sandbox::ResultCode result;
    545  DWORD last_error = ERROR_SUCCESS;
    546  result =
    547      sBrokerService->SpawnTarget(aPath, aArguments, aEnvironment,
    548                                  std::move(mPolicy), &last_error, &targetInfo);
    549  if (sandbox::SBOX_ALL_OK != result) {
    550    nsAutoCString key;
    551    key.AppendASCII(XRE_GeckoProcessTypeToString(aProcessType));
    552    key.AppendLiteral("/0x");
    553    key.AppendInt(static_cast<uint32_t>(last_error), 16);
    554 
    555    // Only accumulate for each combination once per session.
    556    if (!sLaunchErrors) {
    557      sLaunchErrors = new nsTHashtable<nsCStringHashKey>();
    558    }
    559    if (!sLaunchErrors->Contains(key)) {
    560      glean::sandbox::failed_launch_keyed.Get(key).AccumulateSingleSample(
    561          result);
    562      sLaunchErrors->PutEntry(key);
    563    }
    564 
    565    LOG_E("Failed (ResultCode %d) to SpawnTarget with last_error=%lu", result,
    566          last_error);
    567 
    568    return Err(mozilla::ipc::LaunchError::FromWin32Error("SB::LA::SpawnTarget",
    569                                                         last_error));
    570  }
    571 
    572 #ifdef MOZ_THUNDERBIRD
    573  // In Thunderbird, mInitDllBlocklistOOP is null, so InitDllBlocklistOOP would
    574  // hit MOZ_RELEASE_ASSERT.
    575  constexpr bool isThunderbird = true;
    576 #else
    577  constexpr bool isThunderbird = false;
    578 #endif
    579 
    580  if (!isThunderbird &&
    581      XRE_GetChildProcBinPathType(aProcessType) == BinPathType::Self) {
    582    RefPtr<DllServices> dllSvc(DllServices::Get());
    583    LauncherVoidResultWithLineInfo blocklistInitOk =
    584        dllSvc->InitDllBlocklistOOP(aPath, targetInfo.hProcess,
    585                                    aCachedNtdllThunk, aProcessType);
    586    if (blocklistInitOk.isErr()) {
    587      dllSvc->HandleLauncherError(blocklistInitOk.unwrapErr(),
    588                                  XRE_GeckoProcessTypeToString(aProcessType));
    589      LOG_E("InitDllBlocklistOOP failed at %s:%d with HRESULT 0x%08lX",
    590            blocklistInitOk.unwrapErr().mFile,
    591            blocklistInitOk.unwrapErr().mLine,
    592            blocklistInitOk.unwrapErr().mError.AsHResult());
    593      TerminateProcess(targetInfo.hProcess, 1);
    594      CloseHandle(targetInfo.hThread);
    595      CloseHandle(targetInfo.hProcess);
    596      return Err(mozilla::ipc::LaunchError(
    597          "InitDllBlocklistOOP",
    598          blocklistInitOk.unwrapErr().mError.AsHResult()));
    599    }
    600  } else {
    601    // Load the child executable as a datafile so that we can examine its
    602    // headers without doing a full load with dependencies and such.
    603    nsModuleHandle moduleHandle(
    604        ::LoadLibraryExW(aPath, nullptr, LOAD_LIBRARY_AS_DATAFILE));
    605    if (moduleHandle) {
    606      nt::CrossExecTransferManager transferMgr(targetInfo.hProcess,
    607                                               moduleHandle);
    608      if (!!transferMgr) {
    609        LauncherVoidResult importsRestored =
    610            RestoreImportDirectory(aPath, transferMgr);
    611        if (importsRestored.isErr()) {
    612          RefPtr<DllServices> dllSvc(DllServices::Get());
    613          dllSvc->HandleLauncherError(
    614              importsRestored.unwrapErr(),
    615              XRE_GeckoProcessTypeToString(aProcessType));
    616          LOG_E("Failed to restore import directory with HRESULT 0x%08lX",
    617                importsRestored.unwrapErr().mError.AsHResult());
    618          TerminateProcess(targetInfo.hProcess, 1);
    619          CloseHandle(targetInfo.hThread);
    620          CloseHandle(targetInfo.hProcess);
    621          return Err(mozilla::ipc::LaunchError(
    622              "RestoreImportDirectory",
    623              importsRestored.unwrapErr().mError.AsHResult()));
    624        }
    625      }
    626    }
    627  }
    628 
    629  // The sandboxed process is started in a suspended state, resume it now that
    630  // we've set things up.
    631  ResumeThread(targetInfo.hThread);
    632  CloseHandle(targetInfo.hThread);
    633 
    634  // Return the process handle to the caller
    635  *aProcessHandle = targetInfo.hProcess;
    636 
    637  return Ok();
    638 }
    639 
    640 // This function caches and returns an array of NT paths of the executable's
    641 // dependent modules.
    642 // If this returns Nothing(), it means the retrieval of the modules failed
    643 // (e.g. when the launcher process is disabled), so the process should not
    644 // enable pre-spawn CIG.
    645 static const Maybe<Vector<const wchar_t*>>& GetPrespawnCigExceptionModules() {
    646  // The shared section contains a list of dependent modules as a
    647  // null-delimited string.  We convert it to a string vector and
    648  // cache it to avoid converting the same data every time.
    649  static Maybe<Vector<const wchar_t*>> sDependentModules =
    650      []() -> Maybe<Vector<const wchar_t*>> {
    651    RefPtr<DllServices> dllSvc(DllServices::Get());
    652    auto sharedSection = dllSvc->GetSharedSection();
    653    if (!sharedSection) {
    654      return Nothing();
    655    }
    656 
    657    return sharedSection->GetDependentModules();
    658  }();
    659 
    660  return sDependentModules;
    661 }
    662 
    663 static sandbox::ResultCode AllowProxyLoadFromBinDir(
    664    sandbox::TargetConfig* aConfig) {
    665  // Allow modules in the directory containing the executable such as
    666  // mozglue.dll, nss3.dll, etc.
    667  nsAutoString rulePath(*sBinDir);
    668  rulePath.Append(u"\\*"_ns);
    669  return aConfig->AllowExtraDlls(rulePath.get());
    670 }
    671 
    672 static sandbox::ResultCode AddCigToConfig(
    673    sandbox::TargetConfig* aConfig, bool aAlwaysProxyBinDirLoading = false) {
    674  if (StaticPrefs::security_sandbox_cig_prespawn_enabled()) {
    675    const Maybe<Vector<const wchar_t*>>& exceptionModules =
    676        GetPrespawnCigExceptionModules();
    677    if (exceptionModules.isSome()) {
    678      sandbox::MitigationFlags mitigations = aConfig->GetProcessMitigations();
    679      MOZ_ASSERT(mitigations,
    680                 "Mitigations should be set before AddCigToPolicy.");
    681      MOZ_ASSERT(!(mitigations & sandbox::MITIGATION_FORCE_MS_SIGNED_BINS),
    682                 "AddCigToPolicy should not be called twice.");
    683 
    684      mitigations |= sandbox::MITIGATION_FORCE_MS_SIGNED_BINS;
    685      sandbox::ResultCode result = aConfig->SetProcessMitigations(mitigations);
    686      if (result != sandbox::SBOX_ALL_OK) {
    687        return result;
    688      }
    689 
    690      result = AllowProxyLoadFromBinDir(aConfig);
    691      if (result != sandbox::SBOX_ALL_OK) {
    692        return result;
    693      }
    694 
    695      for (const wchar_t* path : exceptionModules.ref()) {
    696        result = aConfig->AllowExtraDlls(path);
    697        if (result != sandbox::SBOX_ALL_OK) {
    698          return result;
    699        }
    700      }
    701 
    702      return sandbox::SBOX_ALL_OK;
    703    }
    704  }
    705 
    706  sandbox::MitigationFlags delayedMitigations =
    707      aConfig->GetDelayedProcessMitigations();
    708  MOZ_ASSERT(delayedMitigations,
    709             "Delayed mitigations should be set before AddCigToPolicy.");
    710  MOZ_ASSERT(!(delayedMitigations & sandbox::MITIGATION_FORCE_MS_SIGNED_BINS),
    711             "AddCigToPolicy should not be called twice.");
    712 
    713  delayedMitigations |= sandbox::MITIGATION_FORCE_MS_SIGNED_BINS;
    714  sandbox::ResultCode result =
    715      aConfig->SetDelayedProcessMitigations(delayedMitigations);
    716  if (result != sandbox::SBOX_ALL_OK) {
    717    return result;
    718  }
    719 
    720  if (aAlwaysProxyBinDirLoading) {
    721    result = AllowProxyLoadFromBinDir(aConfig);
    722  }
    723  return result;
    724 }
    725 
    726 // Returns the most strict dynamic code mitigation flag that is compatible with
    727 // system libraries MSAudDecMFT.dll and msmpeg2vdec.dll. This depends on the
    728 // Windows version and the architecture. See bug 1783223 comment 27.
    729 //
    730 // Use the result with SetDelayedProcessMitigations. Using non-delayed ACG
    731 // results in incompatibility with third-party antivirus software, the Windows
    732 // internal Shim Engine mechanism, parts of our own DLL blocklist code, and
    733 // AddressSanitizer initialization code. See bug 1783223.
    734 static sandbox::MitigationFlags DynamicCodeFlagForSystemMediaLibraries() {
    735  static auto dynamicCodeFlag = []() {
    736 #ifdef _M_X64
    737    if (IsWin10CreatorsUpdateOrLater()) {
    738      return sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
    739    }
    740 #endif  // _M_X64
    741 
    742    if (IsWin10AnniversaryUpdateOrLater()) {
    743      return sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT;
    744    }
    745 
    746    return sandbox::MitigationFlags{};
    747  }();
    748  return dynamicCodeFlag;
    749 }
    750 
    751 static auto GetProcessUserSidString() {
    752  std::unique_ptr<wchar_t, LocalFreeDeleter> userSidString;
    753  std::unique_ptr<HANDLE, CloseHandleDeleter> tokenHandle;
    754  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY,
    755                          getter_Transfers(tokenHandle))) {
    756    return userSidString;
    757  }
    758 
    759  BYTE tokenUserBuffer[sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE];
    760  DWORD len = sizeof(tokenUserBuffer);
    761  if (!::GetTokenInformation(tokenHandle.get(), TokenUser, &tokenUserBuffer,
    762                             len, &len)) {
    763    return userSidString;
    764  }
    765 
    766  auto* tokenUser = reinterpret_cast<TOKEN_USER*>(tokenUserBuffer);
    767  if (!::ConvertSidToStringSidW(tokenUser->User.Sid,
    768                                getter_Transfers(userSidString))) {
    769    userSidString.reset();
    770  }
    771 
    772  return userSidString;
    773 }
    774 
    775 // Process fails to start in LPAC with ASan build
    776 #if !defined(MOZ_ASAN)
    777 static void HexEncode(const Span<const uint8_t>& aBytes, nsACString& aEncoded) {
    778  static const char kHexChars[] = "0123456789abcdef";
    779 
    780  // Each input byte creates two output hex characters.
    781  char* encodedPtr;
    782  aEncoded.GetMutableData(&encodedPtr, aBytes.size() * 2);
    783 
    784  for (auto byte : aBytes) {
    785    *(encodedPtr++) = kHexChars[byte >> 4];
    786    *(encodedPtr++) = kHexChars[byte & 0xf];
    787  }
    788 }
    789 
    790 // This is left as a void because we might fail to set the permission for some
    791 // reason and yet the LPAC permission is already granted. So returning success
    792 // or failure isn't really that useful.
    793 /* static */
    794 void SandboxBroker::EnsureLpacPermsissionsOnDir(const nsString& aDir) {
    795  // For MSIX packages we get access through the packageContents capability and
    796  // we probably won't have access to add the permission either way.
    797  if (widget::WinUtils::HasPackageIdentity()) {
    798    return;
    799  }
    800 
    801  BYTE sidBytes[SECURITY_MAX_SID_SIZE];
    802  PSID lpacFirefoxInstallFilesSid = static_cast<PSID>(sidBytes);
    803  if (!sBrokerService->DeriveCapabilitySidFromName(kLpacFirefoxInstallFiles,
    804                                                   lpacFirefoxInstallFilesSid,
    805                                                   sizeof(sidBytes))) {
    806    LOG_E("Failed to derive Firefox install files capability SID.");
    807    return;
    808  }
    809 
    810  HANDLE hDir = ::CreateFileW(aDir.get(), WRITE_DAC | READ_CONTROL, 0, NULL,
    811                              OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
    812  if (hDir == INVALID_HANDLE_VALUE) {
    813    LOG_W("Unable to get directory handle for %s",
    814          NS_ConvertUTF16toUTF8(aDir).get());
    815    return;
    816  }
    817 
    818  UniquePtr<HANDLE, CloseHandleDeleter> autoHandleCloser(hDir);
    819  PACL pBinDirAcl = nullptr;
    820  PSECURITY_DESCRIPTOR pSD = nullptr;
    821  DWORD result =
    822      ::GetSecurityInfo(hDir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
    823                        nullptr, nullptr, &pBinDirAcl, nullptr, &pSD);
    824  if (result != ERROR_SUCCESS) {
    825    LOG_E("Failed to get DACL for %s", NS_ConvertUTF16toUTF8(aDir).get());
    826    return;
    827  }
    828 
    829  UniquePtr<VOID, LocalFreeDeleter> autoFreeSecDesc(pSD);
    830  if (!pBinDirAcl) {
    831    LOG_E("DACL was null for %s", NS_ConvertUTF16toUTF8(aDir).get());
    832    return;
    833  }
    834 
    835  for (DWORD i = 0; i < pBinDirAcl->AceCount; ++i) {
    836    VOID* pAce = nullptr;
    837    if (!::GetAce(pBinDirAcl, i, &pAce) ||
    838        static_cast<PACE_HEADER>(pAce)->AceType != ACCESS_ALLOWED_ACE_TYPE) {
    839      continue;
    840    }
    841 
    842    auto* pAllowedAce = static_cast<ACCESS_ALLOWED_ACE*>(pAce);
    843    if ((pAllowedAce->Mask & (GENERIC_READ | GENERIC_EXECUTE)) !=
    844        (GENERIC_READ | GENERIC_EXECUTE)) {
    845      continue;
    846    }
    847 
    848    PSID aceSID = reinterpret_cast<PSID>(&(pAllowedAce->SidStart));
    849    if (::EqualSid(aceSID, lpacFirefoxInstallFilesSid)) {
    850      LOG_D("Firefox install files permission found on %s",
    851            NS_ConvertUTF16toUTF8(aDir).get());
    852      return;
    853    }
    854  }
    855 
    856  EXPLICIT_ACCESS_W newAccess = {0};
    857  newAccess.grfAccessMode = GRANT_ACCESS;
    858  newAccess.grfAccessPermissions = GENERIC_READ | GENERIC_EXECUTE;
    859  newAccess.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
    860  ::BuildTrusteeWithSidW(&newAccess.Trustee, lpacFirefoxInstallFilesSid);
    861  PACL newDacl = nullptr;
    862  if (ERROR_SUCCESS !=
    863      ::SetEntriesInAclW(1, &newAccess, pBinDirAcl, &newDacl)) {
    864    LOG_E("Failed to create new DACL with Firefox install files SID.");
    865    return;
    866  }
    867 
    868  UniquePtr<ACL, LocalFreeDeleter> autoFreeAcl(newDacl);
    869  if (ERROR_SUCCESS != ::SetSecurityInfo(hDir, SE_FILE_OBJECT,
    870                                         DACL_SECURITY_INFORMATION, nullptr,
    871                                         nullptr, newDacl, nullptr)) {
    872    LOG_E("Failed to set new DACL on %s", NS_ConvertUTF16toUTF8(aDir).get());
    873  }
    874 
    875  LOG_D("Firefox install files permission granted on %s",
    876        NS_ConvertUTF16toUTF8(aDir).get());
    877 }
    878 
    879 static bool IsLowPrivilegedAppContainerSupported() {
    880  // Chromium doesn't support adding an LPAC before this version due to
    881  // incompatibility with some process mitigations.
    882  return IsWin10Sep2018UpdateOrLater();
    883 }
    884 
    885 // AddAndConfigureAppContainerProfile deliberately fails if it is called on an
    886 // unsupported version. This is because for some process types the LPAC is
    887 // required to provide a sufficiently strong sandbox. Processes where the use of
    888 // an LPAC is an optional extra should use IsLowPrivilegedAppContainerSupported
    889 // to check support first.
    890 static sandbox::ResultCode AddAndConfigureAppContainerProfile(
    891    sandbox::TargetConfig* aConfig, const nsAString& aPackagePrefix,
    892    const nsTArray<base::win::WellKnownCapability>& aWellKnownCapabilites,
    893    const nsTArray<const wchar_t*>& aNamedCapabilites) {
    894  // CreateAppContainerProfile requires that the profile name is at most 64
    895  // characters but 50 on WCOS systems. The size of sha1 is a constant 40,
    896  // so validate that the base names are sufficiently short that the total
    897  // length is valid on all systems.
    898  MOZ_ASSERT(aPackagePrefix.Length() <= 10U,
    899             "AppContainer Package prefix too long.");
    900 
    901  if (!IsLowPrivilegedAppContainerSupported()) {
    902    return sandbox::SBOX_ERROR_UNSUPPORTED;
    903  }
    904 
    905  static nsAutoString uniquePackageStr = []() {
    906    // userenv.dll may not have been loaded and some of the chromium sandbox
    907    // AppContainer code assumes that it is. Done here to load once.
    908    ::LoadLibraryW(L"userenv.dll");
    909 
    910    // Done during the package string initialization so we only do it once.
    911    SandboxBroker::EnsureLpacPermsissionsOnDir(*sBinDir.get());
    912 
    913    // This mirrors Edge's use of the exe path for the SHA1 hash to give a
    914    // machine unique name per install.
    915    nsAutoString ret;
    916    char exePathBuf[MAX_PATH];
    917    DWORD pathSize = ::GetModuleFileNameA(nullptr, exePathBuf, MAX_PATH);
    918    if (!pathSize) {
    919      return ret;
    920    }
    921 
    922    SHA1Sum sha1Sum;
    923    SHA1Sum::Hash sha1Hash;
    924    sha1Sum.update(exePathBuf, pathSize);
    925    sha1Sum.finish(sha1Hash);
    926 
    927    nsAutoCString hexEncoded;
    928    HexEncode(sha1Hash, hexEncoded);
    929    ret = NS_ConvertUTF8toUTF16(hexEncoded);
    930    return ret;
    931  }();
    932 
    933  if (uniquePackageStr.IsEmpty()) {
    934    return sandbox::SBOX_ERROR_CREATE_APPCONTAINER;
    935  }
    936 
    937  // The bool parameter is called create_profile, but in fact it tries to create
    938  // and then opens if it already exists. So always passing true is fine.
    939  bool createOrOpenProfile = true;
    940  nsAutoString packageName = aPackagePrefix + uniquePackageStr;
    941  sandbox::ResultCode result =
    942      aConfig->AddAppContainerProfile(packageName.get(), createOrOpenProfile);
    943  if (result != sandbox::SBOX_ALL_OK) {
    944    return result;
    945  }
    946 
    947  // This looks odd, but unfortunately holding a scoped_refptr and
    948  // dereferencing has DCHECKs that cause a linking problem.
    949  sandbox::AppContainer* appContainer = aConfig->GetAppContainer().get();
    950  appContainer->SetEnableLowPrivilegeAppContainer(true);
    951 
    952  for (auto wkCap : aWellKnownCapabilites) {
    953    appContainer->AddCapability(wkCap);
    954  }
    955 
    956  for (auto namedCap : aNamedCapabilites) {
    957    appContainer->AddCapability(namedCap);
    958  }
    959 
    960  return sandbox::SBOX_ALL_OK;
    961 }
    962 #endif
    963 
    964 void AddShaderCachesToPolicy(sandboxing::SizeTrackingConfig* aConfig,
    965                             int32_t aSandboxLevel) {
    966  // The GPU process needs to write to a shader cache for performance reasons
    967  if (sProfileDir) {
    968    // Currently the GPU process creates the shader-cache directory if it
    969    // doesn't exist, so we have to give FILES_ALLOW_ANY access.
    970    // FILES_ALLOW_DIR_ANY has been seen to fail on an existing profile although
    971    // the root cause hasn't been found. FILES_ALLOW_DIR_ANY has also been
    972    // removed from the sandbox code upstream.
    973    // It is possible that we might be able to use FILES_ALLOW_READONLY for the
    974    // dir if it is already created, bug 1966157 has been filed to track.
    975    AddCachedDirRule(aConfig, sandbox::FileSemantics::kAllowAny, sProfileDir,
    976                     u"\\shader-cache"_ns);
    977 
    978    AddCachedDirRule(aConfig, sandbox::FileSemantics::kAllowAny, sProfileDir,
    979                     u"\\shader-cache\\*"_ns);
    980  }
    981 
    982  // Add GPU specific shader cache rules.
    983  const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
    984  MOZ_ASSERT(gfxInfo);
    985  nsAutoString vendorID;
    986  if (NS_FAILED(gfxInfo->GetAdapterVendorID(vendorID))) {
    987    NS_WARNING("Failed to get GPU Vendor ID.");
    988    return;
    989  }
    990 
    991  if (aSandboxLevel >= 2 && vendorID == widget::GfxDriverInfo::GetDeviceVendor(
    992                                            widget::DeviceVendor::Intel)) {
    993    // Add rules to allow Intel's shader cache.
    994    AddCachedWindowsDirRule(aConfig, sandbox::FileSemantics::kAllowAny,
    995                            FOLDERID_LocalAppDataLow,
    996                            u"\\Intel\\ShaderCache\\*"_ns);
    997    AddCachedWindowsDirRule(aConfig, sandbox::FileSemantics::kAllowQuery,
    998                            FOLDERID_LocalAppDataLow,
    999                            u"\\Intel\\ShaderCache"_ns);
   1000    AddCachedWindowsDirRule(aConfig, sandbox::FileSemantics::kAllowQuery,
   1001                            FOLDERID_LocalAppDataLow, u"\\Intel"_ns);
   1002    AddCachedWindowsDirRule(aConfig, sandbox::FileSemantics::kAllowQuery,
   1003                            FOLDERID_LocalAppDataLow);
   1004 
   1005    // The parent of LocalAppDataLow is cached by AddCachedWindowsDirRule.
   1006    if (sLocalAppDataLowParentDir) {
   1007      AddCachedDirRule(aConfig, sandbox::FileSemantics::kAllowQuery,
   1008                       sLocalAppDataLowParentDir);
   1009    }
   1010  }
   1011 }
   1012 
   1013 void SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
   1014                                                      bool aIsFileProcess) {
   1015  MOZ_RELEASE_ASSERT(mPolicy, "mPolicy must be set before this call.");
   1016 
   1017  sandbox::JobLevel jobLevel;
   1018  sandbox::TokenLevel accessTokenLevel;
   1019  sandbox::IntegrityLevel initialIntegrityLevel;
   1020  sandbox::IntegrityLevel delayedIntegrityLevel;
   1021 
   1022  auto* config = mPolicy->GetConfig();
   1023 
   1024  // The setting of these levels is pretty arbitrary, but they are a useful (if
   1025  // crude) tool while we are tightening the policy. Gaps are left to try and
   1026  // avoid changing their meaning.
   1027  MOZ_RELEASE_ASSERT(aSandboxLevel >= 1,
   1028                     "Should not be called with aSandboxLevel < 1");
   1029  if (aSandboxLevel >= 20) {
   1030    jobLevel = sandbox::JobLevel::kLockdown;
   1031    accessTokenLevel = sandbox::USER_LOCKDOWN;
   1032    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1033    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED;
   1034  } else if (aSandboxLevel >= 9) {
   1035    jobLevel = sandbox::JobLevel::kLockdown;
   1036    accessTokenLevel = sandbox::USER_LOCKDOWN_WITH_TRAVERSE;
   1037    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1038    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED;
   1039  } else if (aSandboxLevel >= 8) {
   1040    jobLevel = sandbox::JobLevel::kLockdown;
   1041    accessTokenLevel = sandbox::USER_RESTRICTED;
   1042    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1043    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED;
   1044  } else if (aSandboxLevel >= 7) {
   1045    jobLevel = sandbox::JobLevel::kLockdown;
   1046    accessTokenLevel = sandbox::USER_LIMITED;
   1047    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1048    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED;
   1049  } else if (aSandboxLevel >= 4) {
   1050    jobLevel = sandbox::JobLevel::kLockdown;
   1051    accessTokenLevel = sandbox::USER_LIMITED;
   1052    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1053    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1054  } else if (aSandboxLevel >= 3) {
   1055    jobLevel = sandbox::JobLevel::kLockdown;
   1056    accessTokenLevel = sandbox::USER_LIMITED;
   1057    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1058    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1059  } else if (aSandboxLevel == 2) {
   1060    jobLevel = sandbox::JobLevel::kInteractive;
   1061    accessTokenLevel = sandbox::USER_INTERACTIVE;
   1062    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1063    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1064  } else {
   1065    MOZ_ASSERT(aSandboxLevel == 1);
   1066 
   1067    jobLevel = sandbox::JobLevel::kUnprotected;
   1068    accessTokenLevel = sandbox::USER_RESTRICTED_NON_ADMIN;
   1069    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1070    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1071  }
   1072 
   1073  // If the process will handle file: URLs, don't allow settings that
   1074  // block reads.
   1075  if (aIsFileProcess) {
   1076    if (accessTokenLevel < sandbox::USER_RESTRICTED_NON_ADMIN) {
   1077      accessTokenLevel = sandbox::USER_RESTRICTED_NON_ADMIN;
   1078    }
   1079    if (delayedIntegrityLevel > sandbox::INTEGRITY_LEVEL_LOW) {
   1080      delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1081    }
   1082  }
   1083 
   1084 #if defined(DEBUG)
   1085  // This is required for a MOZ_ASSERT check in WindowsMessageLoop.cpp
   1086  // WinEventHook, see bug 1366694 for details.
   1087  DWORD uiExceptions = JOB_OBJECT_UILIMIT_HANDLES;
   1088 #else
   1089  DWORD uiExceptions = 0;
   1090 #endif
   1091  sandbox::ResultCode result = config->SetJobLevel(jobLevel, uiExceptions);
   1092  MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1093                     "Setting job level failed, have you set memory limit when "
   1094                     "jobLevel == JOB_NONE?");
   1095 
   1096  result = config->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
   1097                                 accessTokenLevel);
   1098  MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1099                     "Lockdown level cannot be USER_UNPROTECTED or USER_LAST "
   1100                     "if initial level was USER_RESTRICTED_SAME_ACCESS");
   1101 
   1102  result = config->SetIntegrityLevel(initialIntegrityLevel);
   1103  MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1104                     "SetIntegrityLevel should never fail, what happened?");
   1105  config->SetDelayedIntegrityLevel(delayedIntegrityLevel);
   1106 
   1107  if (aSandboxLevel > 5) {
   1108    config->SetLockdownDefaultDacl();
   1109    config->AddRestrictingRandomSid();
   1110  }
   1111 
   1112  if (aSandboxLevel > 4) {
   1113    config->SetDesktop(sandbox::Desktop::kAlternateWinstation);
   1114  }
   1115 
   1116  if (StaticPrefs::security_sandbox_content_close_ksecdd_handle()) {
   1117    result = config->AddKernelObjectToClose(L"File", L"\\Device\\KsecDD");
   1118    MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1119                       "AddKernelObjectToClose should never fail.");
   1120  }
   1121 
   1122  sandbox::MitigationFlags mitigations =
   1123      sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
   1124      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_DEP_NO_ATL_THUNK |
   1125      sandbox::MITIGATION_DEP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
   1126      sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED |
   1127      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
   1128      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL;
   1129 
   1130 #if defined(_M_ARM64)
   1131  // Disable CFG on older versions of ARM64 Windows to avoid a crash in COM.
   1132  if (!IsWin10Sep2018UpdateOrLater()) {
   1133    mitigations |= sandbox::MITIGATION_CONTROL_FLOW_GUARD_DISABLE;
   1134  }
   1135 #endif
   1136 
   1137  if (StaticPrefs::security_sandbox_content_shadow_stack_enabled()) {
   1138    mitigations |= sandbox::MITIGATION_CET_COMPAT_MODE;
   1139  }
   1140 
   1141  result = config->SetProcessMitigations(mitigations);
   1142  MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1143                     "Invalid flags for SetProcessMitigations.");
   1144 
   1145  nsIXULRuntime::ContentWin32kLockdownState win32kLockdownState =
   1146      GetContentWin32kLockdownState();
   1147 
   1148  LOG_W("Win32k Lockdown State: '%s'",
   1149        ContentWin32kLockdownStateToString(win32kLockdownState));
   1150 
   1151  if (GetContentWin32kLockdownEnabled()) {
   1152    result = AddWin32kLockdownConfig(config);
   1153    MOZ_RELEASE_ASSERT(result == sandbox::SBOX_ALL_OK,
   1154                       "Failed to add the win32k lockdown config");
   1155  }
   1156 
   1157  mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1158                sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1159 
   1160  result = config->SetDelayedProcessMitigations(mitigations);
   1161  MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1162                     "Invalid flags for SetDelayedProcessMitigations.");
   1163 
   1164  // We still have edge cases where the child at low integrity can't read some
   1165  // files, so add a rule to allow read access to everything when required.
   1166  if (aSandboxLevel == 1 || aIsFileProcess) {
   1167    result =
   1168        config->AllowFileAccess(sandbox::FileSemantics::kAllowReadonly, L"*");
   1169    MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1170                       "With these static arguments AddRule should never fail, "
   1171                       "what happened?");
   1172  } else {
   1173    // Add rule to allow access to user specific fonts.
   1174    AddCachedWindowsDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1175                            FOLDERID_LocalAppData,
   1176                            u"\\Microsoft\\Windows\\Fonts\\*"_ns);
   1177 
   1178    // Add rule to allow read access to installation directory.
   1179    AddCachedDirRule(config, sandbox::FileSemantics::kAllowReadonly, sBinDir,
   1180                     u"\\*"_ns);
   1181 
   1182    // Add rule to allow read access to the chrome directory within profile.
   1183    AddCachedDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1184                     sProfileDir, u"\\chrome\\*"_ns);
   1185 
   1186    // Add rule to allow read access to the extensions directory within profile.
   1187    AddCachedDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1188                     sProfileDir, u"\\extensions\\*"_ns);
   1189 
   1190 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
   1191    // Add rule to allow read access to the per-user extensions directory.
   1192    AddCachedDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1193                     sUserExtensionsDir, u"\\*"_ns);
   1194 #endif
   1195  }
   1196 
   1197  if (StaticPrefs::security_sandbox_chrome_pipe_rule_enabled()) {
   1198    // Add the policy for the client side of a pipe. It is just a file
   1199    // in the \pipe\ namespace. We restrict it to pipes that start with
   1200    // "chrome." so the sandboxed process cannot connect to system services.
   1201    result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1202                                     L"\\??\\pipe\\chrome.*");
   1203    MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
   1204                       "With these static arguments AddRule should never fail, "
   1205                       "what happened?");
   1206  }
   1207 
   1208  // Add the policy for the client side of the crash server pipe.
   1209  result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1210                                   L"\\??\\pipe\\gecko-crash-server-pipe.*");
   1211  MOZ_RELEASE_ASSERT(
   1212      sandbox::SBOX_ALL_OK == result,
   1213      "With these static arguments AddRule should never fail, what happened?");
   1214 
   1215  // Allow content processes to use complex line breaking brokering.
   1216  result = config->AllowLineBreaking();
   1217  MOZ_RELEASE_ASSERT(
   1218      sandbox::SBOX_ALL_OK == result,
   1219      "With these static arguments AddRule should never fail, what happened?");
   1220 
   1221  if (aSandboxLevel >= 8) {
   1222    // Content process still needs to be able to read fonts.
   1223    AddCachedWindowsDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1224                            FOLDERID_Fonts);
   1225    AddCachedWindowsDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1226                            FOLDERID_Fonts, u"\\*"_ns);
   1227 
   1228    // Add access to Windows system binary dir to allow DLLs that are not
   1229    // required in all content processes to load later.
   1230    AddCachedWindowsDirRule(config, sandbox::FileSemantics::kAllowReadonly,
   1231                            FOLDERID_System, u"\\*"_ns);
   1232 
   1233    // USER_RESTRCITED will also block access to the KnownDlls list, so we force
   1234    // that path to fall-back to the normal loading path.
   1235    config->SetForceKnownDllLoadingFallback();
   1236 
   1237    // We should be able to remove access to these media registry keys below
   1238    // once encoding has moved out of the content process (bug 1972552).
   1239 
   1240    // Read access for MF Media Source Activate and subkeys/values.
   1241    result = config->AllowRegistryRead(
   1242        L"HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID"
   1243        L"\\{e79167d7-1b85-4d78-b603-798e0e1a4c67}*");
   1244    if (sandbox::SBOX_ALL_OK != result) {
   1245      NS_ERROR("Failed to add rule for MFStartup CLSID.");
   1246      LOG_E("Failed (ResultCode %d) to add rule for MFStartup CLSID.", result);
   1247    }
   1248 
   1249    // Read access for other Media Foundation Classes.
   1250    result = config->AllowRegistryRead(
   1251        L"HKEY_LOCAL_MACHINE\\Software\\Classes\\MediaFoundation\\*");
   1252    if (sandbox::SBOX_ALL_OK != result) {
   1253      NS_ERROR("Failed to add rule for MFStartup CLSID.");
   1254      LOG_E("Failed (ResultCode %d) to add rule for MFStartup CLSID.", result);
   1255    }
   1256 
   1257    // Read access for MF H264 Encoder and subkeys/values.
   1258    result = config->AllowRegistryRead(
   1259        L"HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID"
   1260        L"\\{6CA50344-051A-4DED-9779-A43305165E35}*");
   1261    if (sandbox::SBOX_ALL_OK != result) {
   1262      NS_ERROR("Failed to add rule for MF H264 Encoder CLSID.");
   1263      LOG_E("Failed (ResultCode %d) to add rule for MF H264 Encoder CLSID.",
   1264            result);
   1265    }
   1266 
   1267 #if !defined(_WIN64)
   1268    BOOL isWow64Process;
   1269    if (::IsWow64Process(::GetCurrentProcess(), &isWow64Process) &&
   1270        isWow64Process) {
   1271      // Read access for other Media Foundation Classes for WOW64.
   1272      result = config->AllowRegistryRead(
   1273          L"HKEY_LOCAL_MACHINE\\"
   1274          L"Software\\Classes\\WOW6432Node\\MediaFoundation\\*");
   1275      if (sandbox::SBOX_ALL_OK != result) {
   1276        NS_ERROR("Failed to add rule for MFStartup CLSID.");
   1277        LOG_E("Failed (ResultCode %d) to add rule for MFStartup CLSID.",
   1278              result);
   1279      }
   1280 
   1281      // Read access for MF H264 Encoder and subkeys/values for WOW64.
   1282      result = config->AllowRegistryRead(
   1283          L"HKEY_LOCAL_MACHINE\\Software\\Classes\\WOW6432Node\\CLSID"
   1284          L"\\{6CA50344-051A-4DED-9779-A43305165E35}*");
   1285      if (sandbox::SBOX_ALL_OK != result) {
   1286        NS_ERROR("Failed to add rule for MF H264 Encoder CLSID.");
   1287        LOG_E("Failed (ResultCode %d) to add rule for MF H264 Encoder CLSID.",
   1288              result);
   1289      }
   1290    }
   1291 #endif
   1292  }
   1293 
   1294  if (aSandboxLevel >= 9) {
   1295    // Before reading the media registry keys (specified for aSandboxLevel >= 8)
   1296    // the user's Classes key is read. We lose access to this at
   1297    // USER_LOCKDOWN_WITH_TRAVERSE because we no longer have the Restricted SID.
   1298    // We should be able to remove this once encoding has moved out of the
   1299    // content process (bug 1972552).
   1300    auto userSidString = GetProcessUserSidString();
   1301    if (userSidString) {
   1302      std::wstring userClassKeyName(L"HKEY_USERS\\");
   1303      userClassKeyName += userSidString.get();
   1304      userClassKeyName += L"_Classes";
   1305      result = config->AllowRegistryRead(userClassKeyName.c_str());
   1306      if (sandbox::SBOX_ALL_OK != result) {
   1307        NS_ERROR("Failed to add rule for user's Classes.");
   1308        LOG_E("Failed (ResultCode %d) to add rule for user's Classes.", result);
   1309      }
   1310    } else {
   1311      NS_ERROR("Failed to get user's SID.");
   1312      LOG_E("Failed to get user's SID. %lx", ::GetLastError());
   1313    }
   1314  }
   1315 }
   1316 
   1317 void SandboxBroker::SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) {
   1318  MOZ_RELEASE_ASSERT(mPolicy, "mPolicy must be set before this call.");
   1319  MOZ_RELEASE_ASSERT(aSandboxLevel >= 1);
   1320 
   1321  sandbox::TokenLevel initialTokenLevel = sandbox::USER_RESTRICTED_SAME_ACCESS;
   1322  sandbox::TokenLevel lockdownTokenLevel =
   1323      (aSandboxLevel >= 2) ? sandbox::USER_LIMITED
   1324                           : sandbox::USER_RESTRICTED_NON_ADMIN;
   1325 
   1326  sandbox::IntegrityLevel initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1327  sandbox::IntegrityLevel delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   1328 
   1329  sandbox::JobLevel jobLevel = sandbox::JobLevel::kLimitedUser;
   1330 
   1331  uint32_t uiExceptions =
   1332      JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_DESKTOP |
   1333      JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
   1334 
   1335  sandbox::MitigationFlags initialMitigations =
   1336      sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
   1337      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_DEP_NO_ATL_THUNK |
   1338      sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED |
   1339      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
   1340      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL | sandbox::MITIGATION_DEP;
   1341 
   1342  if (StaticPrefs::security_sandbox_gpu_shadow_stack_enabled()) {
   1343    initialMitigations |= sandbox::MITIGATION_CET_COMPAT_MODE;
   1344  }
   1345 
   1346  sandbox::MitigationFlags delayedMitigations =
   1347      sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1348      sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1349 
   1350  auto* config = mPolicy->GetConfig();
   1351 
   1352  SANDBOX_SUCCEED_OR_CRASH(config->SetJobLevel(jobLevel, uiExceptions));
   1353  SANDBOX_SUCCEED_OR_CRASH(
   1354      config->SetTokenLevel(initialTokenLevel, lockdownTokenLevel));
   1355  SANDBOX_SUCCEED_OR_CRASH(config->SetIntegrityLevel(initialIntegrityLevel));
   1356  config->SetDelayedIntegrityLevel(delayedIntegrityLevel);
   1357  SANDBOX_SUCCEED_OR_CRASH(config->SetProcessMitigations(initialMitigations));
   1358  SANDBOX_SUCCEED_OR_CRASH(
   1359      config->SetDelayedProcessMitigations(delayedMitigations));
   1360 
   1361  config->SetLockdownDefaultDacl();
   1362  config->AddRestrictingRandomSid();
   1363 
   1364  // Policy wrapper to keep track of available rule space. The full policy has
   1365  // 14 pages, so 12 allows two pages for generic process rules and to allow for
   1366  // padding that occurs in LowLevelPolicy::Done. See bug 2009140.
   1367  sandboxing::SizeTrackingConfig trackingConfig(config, 12);
   1368 
   1369  if (StaticPrefs::security_sandbox_chrome_pipe_rule_enabled()) {
   1370    // Add the policy for the client side of a pipe. It is just a file
   1371    // in the \pipe\ namespace. We restrict it to pipes that start with
   1372    // "chrome." so the sandboxed process cannot connect to system services.
   1373    SANDBOX_SUCCEED_OR_CRASH(trackingConfig.AllowFileAccess(
   1374        sandbox::FileSemantics::kAllowAny, L"\\??\\pipe\\chrome.*"));
   1375  }
   1376 
   1377  // Add the policy for the client side of the crash server pipe.
   1378  SANDBOX_SUCCEED_OR_CRASH(
   1379      trackingConfig.AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1380                                     L"\\??\\pipe\\gecko-crash-server-pipe.*"));
   1381 
   1382  // Add rule to allow read access to installation directory.
   1383  AddCachedDirRule(&trackingConfig, sandbox::FileSemantics::kAllowReadonly,
   1384                   sBinDir, u"\\*"_ns);
   1385 
   1386  AddShaderCachesToPolicy(&trackingConfig, aSandboxLevel);
   1387 
   1388  if (aSandboxLevel >= 2) {
   1389    // We don't want to add a rule directly here but use the same retrieval and
   1390    // caching mechanism to get the Windows user's dirs.
   1391    EnsureWindowsDirCached(FOLDERID_Profile, sWindowsProfileDir,
   1392                           "Failed to get Windows Profile folder");
   1393    EnsureWindowsDirCached(FOLDERID_LocalAppData, sLocalAppDataDir,
   1394                           "Failed to get Windows LocalAppData folder");
   1395    EnsureWindowsDirCached(FOLDERID_RoamingAppData, sRoamingAppDataDir,
   1396                           "Failed to get Windows RoamingAppData folder");
   1397    if (sWindowsProfileDir && sLocalAppDataDir && sRoamingAppDataDir) {
   1398      sandboxing::UserFontConfigHelper configHelper(
   1399          LR"(Software\Microsoft\Windows NT\CurrentVersion\Fonts)",
   1400          *sWindowsProfileDir, *sLocalAppDataDir, *sRoamingAppDataDir);
   1401      configHelper.AddRules(trackingConfig);
   1402    }
   1403  }
   1404 }
   1405 
   1406 #define SANDBOX_ENSURE_SUCCESS(result, message)          \
   1407  do {                                                   \
   1408    MOZ_ASSERT(sandbox::SBOX_ALL_OK == result, message); \
   1409    if (sandbox::SBOX_ALL_OK != result) return false;    \
   1410  } while (0)
   1411 
   1412 bool SandboxBroker::SetSecurityLevelForRDDProcess() {
   1413  if (!mPolicy) {
   1414    return false;
   1415  }
   1416 
   1417  auto* config = mPolicy->GetConfig();
   1418 
   1419  auto result =
   1420      config->SetJobLevel(sandbox::JobLevel::kLockdown, 0 /* ui_exceptions */);
   1421  SANDBOX_ENSURE_SUCCESS(
   1422      result,
   1423      "SetJobLevel should never fail with these arguments, what happened?");
   1424 
   1425  result = config->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
   1426                                 sandbox::USER_LIMITED);
   1427  SANDBOX_ENSURE_SUCCESS(
   1428      result,
   1429      "SetTokenLevel should never fail with these arguments, what happened?");
   1430 
   1431  config->SetDesktop(sandbox::Desktop::kAlternateWinstation);
   1432 
   1433  result = config->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   1434  SANDBOX_ENSURE_SUCCESS(result,
   1435                         "SetIntegrityLevel should never fail with these "
   1436                         "arguments, what happened?");
   1437 
   1438  config->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   1439 
   1440  config->SetLockdownDefaultDacl();
   1441  config->AddRestrictingRandomSid();
   1442 
   1443  sandbox::MitigationFlags mitigations =
   1444      sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
   1445      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
   1446      sandbox::MITIGATION_DEP_NO_ATL_THUNK | sandbox::MITIGATION_DEP |
   1447      sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
   1448      sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED |
   1449      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
   1450      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL;
   1451 
   1452  if (StaticPrefs::security_sandbox_rdd_shadow_stack_enabled()) {
   1453    mitigations |= sandbox::MITIGATION_CET_COMPAT_MODE;
   1454  }
   1455 
   1456  result = config->SetProcessMitigations(mitigations);
   1457  SANDBOX_ENSURE_SUCCESS(result, "Invalid flags for SetProcessMitigations.");
   1458 
   1459  mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1460                sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1461 
   1462  if (StaticPrefs::security_sandbox_rdd_acg_enabled()) {
   1463    // The RDD process depends on msmpeg2vdec.dll.
   1464    mitigations |= DynamicCodeFlagForSystemMediaLibraries();
   1465  }
   1466 
   1467  result = config->SetDelayedProcessMitigations(mitigations);
   1468  SANDBOX_ENSURE_SUCCESS(result,
   1469                         "Invalid flags for SetDelayedProcessMitigations.");
   1470 
   1471  result = AddCigToConfig(config);
   1472  SANDBOX_ENSURE_SUCCESS(result, "Failed to initialize signed policy rules.");
   1473 
   1474  if (StaticPrefs::security_sandbox_chrome_pipe_rule_enabled()) {
   1475    // Add the policy for the client side of a pipe. It is just a file
   1476    // in the \pipe\ namespace. We restrict it to pipes that start with
   1477    // "chrome." so the sandboxed process cannot connect to system services.
   1478    result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1479                                     L"\\??\\pipe\\chrome.*");
   1480    SANDBOX_ENSURE_SUCCESS(result,
   1481                           "With these static arguments AddRule should never "
   1482                           "fail, what happened?");
   1483  }
   1484 
   1485  // Add the policy for the client side of the crash server pipe.
   1486  result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1487                                   L"\\??\\pipe\\gecko-crash-server-pipe.*");
   1488  SANDBOX_ENSURE_SUCCESS(
   1489      result,
   1490      "With these static arguments AddRule should never fail, what happened?");
   1491 
   1492  return true;
   1493 }
   1494 
   1495 bool SandboxBroker::SetSecurityLevelForSocketProcess() {
   1496  if (!mPolicy) {
   1497    return false;
   1498  }
   1499 
   1500  auto* config = mPolicy->GetConfig();
   1501 
   1502  auto result =
   1503      config->SetJobLevel(sandbox::JobLevel::kLockdown, 0 /* ui_exceptions */);
   1504  SANDBOX_ENSURE_SUCCESS(
   1505      result,
   1506      "SetJobLevel should never fail with these arguments, what happened?");
   1507 
   1508  result = config->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
   1509                                 sandbox::USER_LIMITED);
   1510  SANDBOX_ENSURE_SUCCESS(
   1511      result,
   1512      "SetTokenLevel should never fail with these arguments, what happened?");
   1513 
   1514  config->SetDesktop(sandbox::Desktop::kAlternateWinstation);
   1515 
   1516  result = config->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   1517  SANDBOX_ENSURE_SUCCESS(result,
   1518                         "SetIntegrityLevel should never fail with these "
   1519                         "arguments, what happened?");
   1520 
   1521  config->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
   1522 
   1523  config->SetLockdownDefaultDacl();
   1524  config->AddRestrictingRandomSid();
   1525 
   1526  sandbox::MitigationFlags mitigations =
   1527      sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
   1528      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
   1529      sandbox::MITIGATION_DEP_NO_ATL_THUNK | sandbox::MITIGATION_DEP |
   1530      sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
   1531      sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED |
   1532      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
   1533      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL;
   1534 
   1535  if (StaticPrefs::security_sandbox_socket_shadow_stack_enabled()) {
   1536    mitigations |= sandbox::MITIGATION_CET_COMPAT_MODE;
   1537  }
   1538 
   1539  result = config->SetProcessMitigations(mitigations);
   1540  SANDBOX_ENSURE_SUCCESS(result, "Invalid flags for SetProcessMitigations.");
   1541 
   1542  if (StaticPrefs::security_sandbox_socket_win32k_disable()) {
   1543    result = AddWin32kLockdownConfig(config);
   1544    SANDBOX_ENSURE_SUCCESS(result, "Failed to add the win32k lockdown config");
   1545  }
   1546 
   1547  mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1548                sandbox::MITIGATION_DLL_SEARCH_ORDER |
   1549                sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
   1550 
   1551  result = config->SetDelayedProcessMitigations(mitigations);
   1552  SANDBOX_ENSURE_SUCCESS(result,
   1553                         "Invalid flags for SetDelayedProcessMitigations.");
   1554 
   1555  result = AddCigToConfig(config);
   1556  SANDBOX_ENSURE_SUCCESS(result, "Failed to initialize signed policy rules.");
   1557 
   1558  if (StaticPrefs::security_sandbox_chrome_pipe_rule_enabled()) {
   1559    // Add the policy for the client side of a pipe. It is just a file
   1560    // in the \pipe\ namespace. We restrict it to pipes that start with
   1561    // "chrome." so the sandboxed process cannot connect to system services.
   1562    result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1563                                     L"\\??\\pipe\\chrome.*");
   1564    SANDBOX_ENSURE_SUCCESS(result,
   1565                           "With these static arguments AddRule should never "
   1566                           "fail, what happened?");
   1567  }
   1568 
   1569  // Add the policy for the client side of the crash server pipe.
   1570  result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1571                                   L"\\??\\pipe\\gecko-crash-server-pipe.*");
   1572  SANDBOX_ENSURE_SUCCESS(
   1573      result,
   1574      "With these static arguments AddRule should never fail, what happened?");
   1575 
   1576  return true;
   1577 }
   1578 
   1579 // A strict base sandbox for utility sandboxes to adapt.
   1580 struct UtilitySandboxProps {
   1581  sandbox::JobLevel mJobLevel = sandbox::JobLevel::kLockdown;
   1582 
   1583  sandbox::TokenLevel mInitialTokenLevel = sandbox::USER_RESTRICTED_SAME_ACCESS;
   1584  sandbox::TokenLevel mDelayedTokenLevel = sandbox::USER_LOCKDOWN;
   1585 
   1586  sandbox::IntegrityLevel mInitialIntegrityLevel =  // before lockdown
   1587      sandbox::INTEGRITY_LEVEL_LOW;
   1588  sandbox::IntegrityLevel mDelayedIntegrityLevel =  // after lockdown
   1589      sandbox::INTEGRITY_LEVEL_UNTRUSTED;
   1590 
   1591  sandbox::Desktop mDesktop = sandbox::Desktop::kAlternateWinstation;
   1592  bool mLockdownDefaultDacl = true;
   1593  bool mAddRestrictingRandomSid = true;
   1594  bool mUseWin32kLockdown = true;
   1595  bool mUseCig = true;
   1596 
   1597  sandbox::MitigationFlags mInitialMitigations =
   1598      sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
   1599      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
   1600      sandbox::MITIGATION_DEP_NO_ATL_THUNK | sandbox::MITIGATION_DEP |
   1601      sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
   1602      sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED |
   1603      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
   1604      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL |
   1605      sandbox::MITIGATION_CET_COMPAT_MODE;
   1606 
   1607  sandbox::MitigationFlags mExcludedInitialMitigations = 0;
   1608 
   1609  sandbox::MitigationFlags mDelayedMitigations =
   1610      sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1611      sandbox::MITIGATION_DLL_SEARCH_ORDER |
   1612      sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
   1613 
   1614  // Low Privileged Application Container settings;
   1615  nsString mPackagePrefix;
   1616  nsTArray<base::win::WellKnownCapability> mWellKnownCapabilites;
   1617  nsTArray<const wchar_t*> mNamedCapabilites;
   1618 };
   1619 
   1620 struct GenericUtilitySandboxProps : public UtilitySandboxProps {};
   1621 
   1622 struct UtilityAudioDecodingWmfSandboxProps : public UtilitySandboxProps {
   1623  UtilityAudioDecodingWmfSandboxProps() {
   1624    mDelayedTokenLevel = sandbox::USER_LIMITED;
   1625    mDelayedMitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1626                          sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1627 #ifdef MOZ_WMF
   1628    if (StaticPrefs::security_sandbox_utility_wmf_acg_enabled()) {
   1629      mDelayedMitigations |= DynamicCodeFlagForSystemMediaLibraries();
   1630    }
   1631 #else
   1632    mDelayedMitigations |= sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
   1633 #endif  // MOZ_WMF
   1634  }
   1635 };
   1636 
   1637 #ifdef MOZ_WMF_MEDIA_ENGINE
   1638 struct UtilityMfMediaEngineCdmSandboxProps : public UtilitySandboxProps {
   1639  UtilityMfMediaEngineCdmSandboxProps() {
   1640    mJobLevel = sandbox::JobLevel::kInteractive;
   1641    mInitialTokenLevel = sandbox::USER_UNPROTECTED;
   1642    mDelayedTokenLevel = sandbox::USER_UNPROTECTED;
   1643    mDesktop = sandbox::Desktop::kDefault;
   1644    mLockdownDefaultDacl = false;
   1645    mAddRestrictingRandomSid = false;
   1646    mUseCig = false;
   1647 
   1648    // When we have an LPAC we can't set an integrity level and the process will
   1649    // default to low integrity anyway. Without an LPAC using low integrity
   1650    // causes problems with the CDMs.
   1651    mInitialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LAST;
   1652    mDelayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LAST;
   1653 
   1654    if (StaticPrefs::security_sandbox_utility_wmf_cdm_lpac_enabled()) {
   1655      mPackagePrefix = u"fx.sb.cdm"_ns;
   1656      mWellKnownCapabilites = {
   1657          base::win::WellKnownCapability::kPrivateNetworkClientServer,
   1658          base::win::WellKnownCapability::kInternetClient,
   1659      };
   1660      mNamedCapabilites = {
   1661          L"lpacCom",
   1662          L"lpacIdentityServices",
   1663          L"lpacMedia",
   1664          L"lpacPnPNotifications",
   1665          L"lpacServicesManagement",
   1666          L"lpacSessionManagement",
   1667          L"lpacAppExperience",
   1668          L"lpacInstrumentation",
   1669          L"lpacCryptoServices",
   1670          L"lpacEnterprisePolicyChangeNotifications",
   1671          L"mediaFoundationCdmFiles",
   1672          L"lpacMediaFoundationCdmData",
   1673          L"registryRead",
   1674          kLpacFirefoxInstallFiles,
   1675          L"lpacDeviceAccess",
   1676      };
   1677 
   1678      // For MSIX packages we need access to the package contents.
   1679      if (widget::WinUtils::HasPackageIdentity()) {
   1680        mNamedCapabilites.AppendElement(L"packageContents");
   1681      }
   1682    }
   1683    mUseWin32kLockdown = false;
   1684    mDelayedMitigations = sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1685  }
   1686 };
   1687 #endif
   1688 
   1689 struct WindowsUtilitySandboxProps : public UtilitySandboxProps {
   1690  WindowsUtilitySandboxProps() {
   1691    mJobLevel = sandbox::JobLevel::kInteractive;
   1692    mDelayedTokenLevel = sandbox::USER_RESTRICTED_SAME_ACCESS;
   1693    mDesktop = sandbox::Desktop::kDefault;
   1694    mInitialIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM;
   1695    mDelayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM;
   1696    mUseWin32kLockdown = false;
   1697    mUseCig = false;
   1698    mExcludedInitialMitigations =
   1699        sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED;
   1700    mDelayedMitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1701                          sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1702  }
   1703 };
   1704 
   1705 static const char* WellKnownCapabilityNames[] = {
   1706    "InternetClient",
   1707    "InternetClientServer",
   1708    "PrivateNetworkClientServer",
   1709    "PicturesLibrary",
   1710    "VideosLibrary",
   1711    "MusicLibrary",
   1712    "DocumentsLibrary",
   1713    "EnterpriseAuthentication",
   1714    "SharedUserCertificates",
   1715    "RemovableStorage",
   1716    "Appointments",
   1717    "Contacts",
   1718 };
   1719 
   1720 void LogUtilitySandboxProps(const UtilitySandboxProps& us) {
   1721  if (!static_cast<LogModule*>(sSandboxBrokerLog)->ShouldLog(LogLevel::Debug)) {
   1722    return;
   1723  }
   1724 
   1725  nsAutoCString logMsg;
   1726  logMsg.AppendPrintf("Building sandbox for utility process:\n");
   1727  logMsg.AppendPrintf("\tJob Level: %d\n", static_cast<int>(us.mJobLevel));
   1728  logMsg.AppendPrintf("\tInitial Token Level: %d\n",
   1729                      static_cast<int>(us.mInitialTokenLevel));
   1730  logMsg.AppendPrintf("\tDelayed Token Level: %d\n",
   1731                      static_cast<int>(us.mDelayedTokenLevel));
   1732  logMsg.AppendPrintf("\tInitial Integrity Level: %d\n",
   1733                      static_cast<int>(us.mInitialIntegrityLevel));
   1734  logMsg.AppendPrintf("\tDelayed Integrity Level: %d\n",
   1735                      static_cast<int>(us.mDelayedIntegrityLevel));
   1736  logMsg.AppendPrintf("\tDesktop: %d\n", static_cast<int>(us.mDesktop));
   1737  logMsg.AppendPrintf("\tLockdown Default Dacl: %s\n",
   1738                      us.mLockdownDefaultDacl ? "yes" : "no");
   1739  logMsg.AppendPrintf("\tAdd Random Restricting SID: %s\n",
   1740                      us.mAddRestrictingRandomSid ? "yes" : "no");
   1741  logMsg.AppendPrintf("\tUse Win32k Lockdown: %s\n",
   1742                      us.mUseWin32kLockdown ? "yes" : "no");
   1743  logMsg.AppendPrintf("\tUse CIG: %s\n", us.mUseCig ? "yes" : "no");
   1744  logMsg.AppendPrintf("\tInitial mitigations: %016llx\n",
   1745                      static_cast<uint64_t>(us.mInitialMitigations &
   1746                                            ~us.mExcludedInitialMitigations));
   1747  logMsg.AppendPrintf("\tDelayed mitigations: %016llx\n",
   1748                      static_cast<uint64_t>(us.mDelayedMitigations));
   1749  if (us.mPackagePrefix.IsEmpty()) {
   1750    logMsg.AppendPrintf("\tNo Low Privileged Application Container\n");
   1751  } else {
   1752    logMsg.AppendPrintf("\tLow Privileged Application Container Settings:\n");
   1753    logMsg.AppendPrintf("\t\tPackage Name Prefix: %S\n",
   1754                        static_cast<wchar_t*>(us.mPackagePrefix.get()));
   1755    logMsg.AppendPrintf("\t\tWell Known Capabilities:\n");
   1756    for (auto wkCap : us.mWellKnownCapabilites) {
   1757      logMsg.AppendPrintf("\t\t\t%s\n",
   1758                          WellKnownCapabilityNames[static_cast<int>(wkCap)]);
   1759    }
   1760    logMsg.AppendPrintf("\t\tNamed Capabilities:\n");
   1761    for (auto namedCap : us.mNamedCapabilites) {
   1762      logMsg.AppendPrintf("\t\t\t%S\n", namedCap);
   1763    }
   1764  }
   1765 
   1766  LOG_D("%s", logMsg.get());
   1767 }
   1768 
   1769 bool BuildUtilitySandbox(sandbox::TargetConfig* config,
   1770                         const UtilitySandboxProps& us) {
   1771  LogUtilitySandboxProps(us);
   1772 
   1773  auto result = config->SetJobLevel(us.mJobLevel, 0 /* ui_exceptions */);
   1774  SANDBOX_ENSURE_SUCCESS(
   1775      result,
   1776      "SetJobLevel should never fail with these arguments, what happened?");
   1777 
   1778  result = config->SetTokenLevel(us.mInitialTokenLevel, us.mDelayedTokenLevel);
   1779  SANDBOX_ENSURE_SUCCESS(
   1780      result,
   1781      "SetTokenLevel should never fail with these arguments, what happened?");
   1782 
   1783  if (us.mInitialIntegrityLevel != sandbox::INTEGRITY_LEVEL_LAST) {
   1784    result = config->SetIntegrityLevel(us.mInitialIntegrityLevel);
   1785    SANDBOX_ENSURE_SUCCESS(result,
   1786                           "SetIntegrityLevel should never fail with these "
   1787                           "arguments, what happened?");
   1788  }
   1789 
   1790  if (us.mDelayedIntegrityLevel != sandbox::INTEGRITY_LEVEL_LAST) {
   1791    config->SetDelayedIntegrityLevel(us.mDelayedIntegrityLevel);
   1792  }
   1793 
   1794  config->SetDesktop(us.mDesktop);
   1795 
   1796  if (us.mLockdownDefaultDacl) {
   1797    config->SetLockdownDefaultDacl();
   1798  }
   1799  if (us.mAddRestrictingRandomSid) {
   1800    config->AddRestrictingRandomSid();
   1801  }
   1802 
   1803  result = config->SetProcessMitigations(us.mInitialMitigations &
   1804                                         ~us.mExcludedInitialMitigations);
   1805  SANDBOX_ENSURE_SUCCESS(result, "Invalid flags for SetProcessMitigations.");
   1806 
   1807  result = config->SetDelayedProcessMitigations(us.mDelayedMitigations);
   1808  SANDBOX_ENSURE_SUCCESS(result,
   1809                         "Invalid flags for SetDelayedProcessMitigations.");
   1810 
   1811  // Win32k lockdown might not work on earlier versions
   1812  // Bug 1719212, 1769992
   1813  if (us.mUseWin32kLockdown && IsWin10FallCreatorsUpdateOrLater()) {
   1814    result = AddWin32kLockdownConfig(config);
   1815    SANDBOX_ENSURE_SUCCESS(result, "Failed to add the win32k lockdown config");
   1816  }
   1817 
   1818  if (us.mUseCig) {
   1819    bool alwaysProxyBinDirLoading = mozilla::HasPackageIdentity();
   1820    result = AddCigToConfig(config, alwaysProxyBinDirLoading);
   1821    SANDBOX_ENSURE_SUCCESS(result, "Failed to initialize signed policy rules.");
   1822  }
   1823 
   1824  // Process fails to start in LPAC with ASan build
   1825 #if !defined(MOZ_ASAN)
   1826  if (!us.mPackagePrefix.IsEmpty()) {
   1827    MOZ_ASSERT(us.mInitialIntegrityLevel == sandbox::INTEGRITY_LEVEL_LAST,
   1828               "Initial integrity level cannot be specified if using an LPAC.");
   1829 
   1830    result = AddAndConfigureAppContainerProfile(config, us.mPackagePrefix,
   1831                                                us.mWellKnownCapabilites,
   1832                                                us.mNamedCapabilites);
   1833    SANDBOX_ENSURE_SUCCESS(result, "Failed to configure AppContainer profile.");
   1834  }
   1835 #endif
   1836 
   1837  if (StaticPrefs::security_sandbox_chrome_pipe_rule_enabled()) {
   1838    // Add the policy for the client side of a pipe. It is just a file
   1839    // in the \pipe\ namespace. We restrict it to pipes that start with
   1840    // "chrome." so the sandboxed process cannot connect to system services.
   1841    result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1842                                     L"\\??\\pipe\\chrome.*");
   1843    SANDBOX_ENSURE_SUCCESS(result,
   1844                           "With these static arguments AddRule should never "
   1845                           "fail, what happened?");
   1846  }
   1847 
   1848  // Add the policy for the client side of the crash server pipe.
   1849  result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1850                                   L"\\??\\pipe\\gecko-crash-server-pipe.*");
   1851  SANDBOX_ENSURE_SUCCESS(
   1852      result,
   1853      "With these static arguments AddRule should never fail, what happened?");
   1854 
   1855  return true;
   1856 }
   1857 
   1858 bool SandboxBroker::SetSecurityLevelForUtilityProcess(
   1859    mozilla::ipc::SandboxingKind aSandbox) {
   1860  if (!mPolicy) {
   1861    return false;
   1862  }
   1863 
   1864  auto* config = mPolicy->GetConfig();
   1865 
   1866  switch (aSandbox) {
   1867    case mozilla::ipc::SandboxingKind::GENERIC_UTILITY:
   1868      return BuildUtilitySandbox(config, GenericUtilitySandboxProps());
   1869    case mozilla::ipc::SandboxingKind::UTILITY_AUDIO_DECODING_WMF:
   1870      return BuildUtilitySandbox(config, UtilityAudioDecodingWmfSandboxProps());
   1871 #ifdef MOZ_WMF_MEDIA_ENGINE
   1872    case mozilla::ipc::SandboxingKind::MF_MEDIA_ENGINE_CDM:
   1873      return BuildUtilitySandbox(config, UtilityMfMediaEngineCdmSandboxProps());
   1874 #endif
   1875    case mozilla::ipc::SandboxingKind::WINDOWS_UTILS:
   1876      return BuildUtilitySandbox(config, WindowsUtilitySandboxProps());
   1877    case mozilla::ipc::SandboxingKind::WINDOWS_FILE_DIALOG:
   1878      // This process type is not sandboxed. (See commentary in
   1879      // `ipc::IsUtilitySandboxEnabled()`.)
   1880      MOZ_ASSERT_UNREACHABLE("No sandboxing for this process type");
   1881      return false;
   1882    default:
   1883      MOZ_ASSERT_UNREACHABLE("Unknown sandboxing value");
   1884      return false;
   1885  }
   1886 }
   1887 
   1888 bool SandboxBroker::SetSecurityLevelForGMPlugin(
   1889    GMPSandboxKind aGMPSandboxKind) {
   1890  if (!mPolicy) {
   1891    return false;
   1892  }
   1893 
   1894  auto* config = mPolicy->GetConfig();
   1895 
   1896  auto result =
   1897      config->SetJobLevel(sandbox::JobLevel::kLockdown, 0 /* ui_exceptions */);
   1898  SANDBOX_ENSURE_SUCCESS(
   1899      result,
   1900      "SetJobLevel should never fail with these arguments, what happened?");
   1901 
   1902  // The Widevine CDM on Windows can only load at USER_RESTRICTED
   1903  auto level = (aGMPSandboxKind == Widevine) ? sandbox::USER_RESTRICTED
   1904                                             : sandbox::USER_LOCKDOWN;
   1905  result = config->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, level);
   1906  SANDBOX_ENSURE_SUCCESS(
   1907      result,
   1908      "SetTokenLevel should never fail with these arguments, what happened?");
   1909 
   1910  config->SetDesktop(sandbox::Desktop::kAlternateWinstation);
   1911 
   1912  result = config->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   1913  MOZ_ASSERT(sandbox::SBOX_ALL_OK == result,
   1914             "SetIntegrityLevel should never fail with these arguments, what "
   1915             "happened?");
   1916 
   1917  config->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
   1918 
   1919  config->SetLockdownDefaultDacl();
   1920  config->AddRestrictingRandomSid();
   1921 
   1922  sandbox::MitigationFlags mitigations =
   1923      sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
   1924      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
   1925      sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
   1926      sandbox::MITIGATION_KTM_COMPONENT | sandbox::MITIGATION_FSCTL_DISABLED |
   1927      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
   1928      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL |
   1929      sandbox::MITIGATION_DEP_NO_ATL_THUNK | sandbox::MITIGATION_DEP;
   1930 
   1931  if (StaticPrefs::security_sandbox_gmp_shadow_stack_enabled()) {
   1932    mitigations |= sandbox::MITIGATION_CET_COMPAT_MODE;
   1933  }
   1934 
   1935  result = config->SetProcessMitigations(mitigations);
   1936  SANDBOX_ENSURE_SUCCESS(result, "Invalid flags for SetProcessMitigations.");
   1937 
   1938  // win32k is currently not disabled for clearkey due to WMF decoding or
   1939  // widevine due to intermittent test failures, where the GMP process fails
   1940  // very early. See bug 1449348.
   1941  // The sandbox doesn't provide Output Protection Manager API brokering
   1942  // anymore, so we can't use this for the Fake plugin that is used to partially
   1943  // test it. This brokering was only used in the tests anyway.
   1944  if (StaticPrefs::security_sandbox_gmp_win32k_disable() &&
   1945      aGMPSandboxKind != Widevine && aGMPSandboxKind != Clearkey &&
   1946      aGMPSandboxKind != Fake) {
   1947    result = AddWin32kLockdownConfig(config);
   1948    SANDBOX_ENSURE_SUCCESS(result, "Failed to add the win32k lockdown policy");
   1949  }
   1950 
   1951  mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
   1952                sandbox::MITIGATION_DLL_SEARCH_ORDER;
   1953  if (StaticPrefs::security_sandbox_gmp_acg_enabled()) {
   1954    auto acgMitigation = sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
   1955    if (aGMPSandboxKind == Widevine) {
   1956      // We can't guarantee that widevine won't use dynamic code.
   1957      acgMitigation = 0;
   1958    } else if (aGMPSandboxKind == Clearkey) {
   1959      // Clearkey uses system decoding libraries.
   1960      acgMitigation = DynamicCodeFlagForSystemMediaLibraries();
   1961    }
   1962    mitigations |= acgMitigation;
   1963  }
   1964 
   1965  result = config->SetDelayedProcessMitigations(mitigations);
   1966  SANDBOX_ENSURE_SUCCESS(result,
   1967                         "Invalid flags for SetDelayedProcessMitigations.");
   1968 
   1969  if (StaticPrefs::security_sandbox_chrome_pipe_rule_enabled()) {
   1970    // Add the policy for the client side of a pipe. It is just a file
   1971    // in the \pipe\ namespace. We restrict it to pipes that start with
   1972    // "chrome." so the sandboxed process cannot connect to system services.
   1973    result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1974                                     L"\\??\\pipe\\chrome.*");
   1975    SANDBOX_ENSURE_SUCCESS(result,
   1976                           "With these static arguments AddRule should never "
   1977                           "fail, what happened?");
   1978  }
   1979 
   1980  // Add the policy for the client side of the crash server pipe.
   1981  result = config->AllowFileAccess(sandbox::FileSemantics::kAllowAny,
   1982                                   L"\\??\\pipe\\gecko-crash-server-pipe.*");
   1983  SANDBOX_ENSURE_SUCCESS(
   1984      result,
   1985      "With these static arguments AddRule should never fail, what happened?");
   1986 
   1987  // The following rules were added because, during analysis of an EME
   1988  // plugin during development, these registry keys were accessed when
   1989  // loading the plugin. Commenting out these policy exceptions caused
   1990  // plugin loading to fail, so they are necessary for proper functioning
   1991  // of at least one EME plugin.
   1992  result = config->AllowRegistryRead(L"HKEY_CURRENT_USER");
   1993  SANDBOX_ENSURE_SUCCESS(
   1994      result,
   1995      "With these static arguments AddRule should never fail, what happened?");
   1996 
   1997  result =
   1998      config->AllowRegistryRead(L"HKEY_CURRENT_USER\\Control Panel\\Desktop");
   1999  SANDBOX_ENSURE_SUCCESS(
   2000      result,
   2001      "With these static arguments AddRule should never fail, what happened?");
   2002 
   2003  result = config->AllowRegistryRead(
   2004      L"HKEY_CURRENT_USER\\Control Panel\\Desktop\\LanguageConfiguration");
   2005  SANDBOX_ENSURE_SUCCESS(
   2006      result,
   2007      "With these static arguments AddRule should never fail, what happened?");
   2008 
   2009  result = config->AllowRegistryRead(
   2010      L"HKEY_LOCAL_MACHINE"
   2011      L"\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SideBySide");
   2012  SANDBOX_ENSURE_SUCCESS(
   2013      result,
   2014      "With these static arguments AddRule should never fail, what happened?");
   2015 
   2016  // The following rules were added because, during analysis of an EME
   2017  // plugin during development, these registry keys were accessed when
   2018  // loading the plugin. Commenting out these policy exceptions did not
   2019  // cause anything to break during initial testing, but might cause
   2020  // unforeseen issues down the road.
   2021  result = config->AllowRegistryRead(
   2022      L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\MUI\\Settings");
   2023  SANDBOX_ENSURE_SUCCESS(
   2024      result,
   2025      "With these static arguments AddRule should never fail, what happened?");
   2026 
   2027  result = config->AllowRegistryRead(
   2028      L"HKEY_CURRENT_USER"
   2029      L"\\Software\\Policies\\Microsoft\\Control Panel\\Desktop");
   2030  SANDBOX_ENSURE_SUCCESS(
   2031      result,
   2032      "With these static arguments AddRule should never fail, what happened?");
   2033 
   2034  result = config->AllowRegistryRead(
   2035      L"HKEY_CURRENT_USER\\Control Panel\\Desktop\\PreferredUILanguages");
   2036  SANDBOX_ENSURE_SUCCESS(
   2037      result,
   2038      "With these static arguments AddRule should never fail, what happened?");
   2039 
   2040  result = config->AllowRegistryRead(
   2041      L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion"
   2042      L"\\SideBySide\\PreferExternalManifest");
   2043  SANDBOX_ENSURE_SUCCESS(
   2044      result,
   2045      "with these static arguments addrule should never fail, what happened?");
   2046 
   2047  return true;
   2048 }
   2049 #undef SANDBOX_ENSURE_SUCCESS
   2050 
   2051 bool SandboxBroker::AllowReadFile(wchar_t const* file) {
   2052  if (!mPolicy) {
   2053    return false;
   2054  }
   2055 
   2056  auto result = mPolicy->GetConfig()->AllowFileAccess(
   2057      sandbox::FileSemantics::kAllowReadonly, file);
   2058  if (sandbox::SBOX_ALL_OK != result) {
   2059    LOG_E("Failed (ResultCode %d) to add read access to: %S", result, file);
   2060    return false;
   2061  }
   2062 
   2063  return true;
   2064 }
   2065 
   2066 void SandboxBroker::AddHandleToShare(HANDLE aHandle) {
   2067  mPolicy->AddHandleToShare(aHandle);
   2068 }
   2069 
   2070 bool SandboxBroker::IsWin32kLockedDown() {
   2071  return mPolicy->GetConfig()->GetProcessMitigations() &
   2072         sandbox::MITIGATION_WIN32K_DISABLE;
   2073 }
   2074 
   2075 void SandboxBroker::ApplyLoggingConfig() {
   2076  MOZ_ASSERT(mPolicy);
   2077 
   2078  auto* config = mPolicy->GetConfig();
   2079 
   2080  // Add dummy rules, so that we can log in the interception code.
   2081  // We already have a file interception set up for the client side of pipes.
   2082  // Also, passing just "dummy" for file system policy causes win_utils.cc
   2083  // IsReparsePoint() to loop.
   2084  (void)config->AllowNamedPipes(L"dummy");
   2085  (void)config->AllowRegistryRead(L"HKEY_CURRENT_USER\\dummy");
   2086 }
   2087 
   2088 SandboxBroker::~SandboxBroker() = default;
   2089 
   2090 }  // namespace mozilla