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