Bug 1861467 - [wpt-sync] Update web-platform-tests to eedf737ce39c512d0ca3471f988972e...
[gecko.git] / dom / ipc / ProcessIsolation.cpp
blobf0c6dd8863f9b111ba231e97feb37c87b2d52816
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et 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/. */
7 #include "mozilla/dom/ProcessIsolation.h"
9 #include "mozilla/Assertions.h"
10 #include "mozilla/dom/BrowsingContextGroup.h"
11 #include "mozilla/dom/CanonicalBrowsingContext.h"
12 #include "mozilla/dom/ContentChild.h"
13 #include "mozilla/dom/ContentParent.h"
14 #include "mozilla/dom/Element.h"
15 #include "mozilla/dom/RemoteType.h"
16 #include "mozilla/dom/WindowGlobalParent.h"
17 #include "mozilla/extensions/WebExtensionPolicy.h"
18 #include "mozilla/BasePrincipal.h"
19 #include "mozilla/ClearOnShutdown.h"
20 #include "mozilla/ContentPrincipal.h"
21 #include "mozilla/ExtensionPolicyService.h"
22 #include "mozilla/Logging.h"
23 #include "mozilla/NullPrincipal.h"
24 #include "mozilla/PermissionManager.h"
25 #include "mozilla/Preferences.h"
26 #include "mozilla/RefPtr.h"
27 #include "mozilla/StaticPrefs_browser.h"
28 #include "mozilla/StaticPrefs_fission.h"
29 #include "mozilla/StaticPtr.h"
30 #include "nsAboutProtocolUtils.h"
31 #include "nsDocShell.h"
32 #include "nsError.h"
33 #include "nsIChromeRegistry.h"
34 #include "nsIHttpChannel.h"
35 #include "nsIHttpChannelInternal.h"
36 #include "nsIProtocolHandler.h"
37 #include "nsIXULRuntime.h"
38 #include "nsNetUtil.h"
39 #include "nsServiceManagerUtils.h"
40 #include "nsSHistory.h"
41 #include "nsURLHelper.h"
43 namespace mozilla::dom {
45 mozilla::LazyLogModule gProcessIsolationLog{"ProcessIsolation"};
47 namespace {
49 // Strategy used to determine whether or not a particular site should load into
50 // a webIsolated content process. The particular strategy chosen is controlled
51 // by the `fission.webContentIsolationStrategy` pref, which must hold one of the
52 // following values.
53 enum class WebContentIsolationStrategy : uint32_t {
54 // All web content is loaded into a shared `web` content process. This is
55 // similar to the non-Fission behaviour, however remote subframes may still
56 // be used for sites with special isolation behaviour, such as extension or
57 // mozillaweb content processes.
58 IsolateNothing = 0,
59 // Web content is always isolated into its own `webIsolated` content process
60 // based on site-origin, and will only load in a shared `web` content process
61 // if site-origin could not be determined.
62 IsolateEverything = 1,
63 // Only isolates web content loaded by sites which are considered "high
64 // value". A site is considered "high value" if it has been granted a
65 // `highValue*` permission by the permission manager, which is done in
66 // response to certain actions.
67 IsolateHighValue = 2,
70 /**
71 * Helper class for caching the result of splitting prefs which are represented
72 * as a comma-separated list of strings.
74 struct CommaSeparatedPref {
75 public:
76 explicit constexpr CommaSeparatedPref(nsLiteralCString aPrefName)
77 : mPrefName(aPrefName) {}
79 void OnChange() {
80 if (mValues) {
81 mValues->Clear();
82 nsAutoCString prefValue;
83 if (NS_SUCCEEDED(Preferences::GetCString(mPrefName.get(), prefValue))) {
84 for (const auto& value :
85 nsCCharSeparatedTokenizer(prefValue, ',').ToRange()) {
86 mValues->EmplaceBack(value);
92 const nsTArray<nsCString>& Get() {
93 if (!mValues) {
94 mValues = new nsTArray<nsCString>;
95 Preferences::RegisterCallbackAndCall(
96 [](const char*, void* aData) {
97 static_cast<CommaSeparatedPref*>(aData)->OnChange();
99 mPrefName, this);
100 RunOnShutdown([this] {
101 delete this->mValues;
102 this->mValues = nullptr;
105 return *mValues;
108 auto begin() { return Get().cbegin(); }
109 auto end() { return Get().cend(); }
111 private:
112 nsLiteralCString mPrefName;
113 nsTArray<nsCString>* MOZ_OWNING_REF mValues = nullptr;
116 CommaSeparatedPref sSeparatedMozillaDomains{
117 "browser.tabs.remote.separatedMozillaDomains"_ns};
120 * Certain URIs have special isolation behaviour, and need to be loaded within
121 * specific process types.
123 enum class IsolationBehavior {
124 // This URI loads web content and should be treated as a content load, being
125 // isolated based on the response principal if enabled.
126 WebContent,
127 // Forcibly load in a process with the "web" remote type. This will ignore the
128 // response principal completely.
129 // This is generally reserved for internal documents which are loaded in
130 // content, but not in the privilegedabout content process.
131 ForceWebRemoteType,
132 // Load this URI in the privileged about content process.
133 PrivilegedAbout,
134 // Load this URI in the extension process.
135 Extension,
136 // Load this URI in the file content process.
137 File,
138 // Load this URI in the priviliged mozilla content process.
139 PrivilegedMozilla,
140 // Load this URI explicitly in the parent process.
141 Parent,
142 // Load this URI wherever the browsing context is currently loaded. This is
143 // generally used for error pages.
144 Anywhere,
145 // May only be returned for subframes. Inherits the remote type of the parent
146 // document which is embedding this document.
147 Inherit,
148 // Special case for the `about:reader` URI which should be loaded in the same
149 // process which would be used for the "url" query parameter.
150 AboutReader,
151 // There was a fatal error, and the load should be aborted.
152 Error,
156 * Returns a static string with the name of the given isolation behaviour. For
157 * use in logging code.
159 static const char* IsolationBehaviorName(IsolationBehavior aBehavior) {
160 switch (aBehavior) {
161 case IsolationBehavior::WebContent:
162 return "WebContent";
163 case IsolationBehavior::ForceWebRemoteType:
164 return "ForceWebRemoteType";
165 case IsolationBehavior::PrivilegedAbout:
166 return "PrivilegedAbout";
167 case IsolationBehavior::Extension:
168 return "Extension";
169 case IsolationBehavior::File:
170 return "File";
171 case IsolationBehavior::PrivilegedMozilla:
172 return "PrivilegedMozilla";
173 case IsolationBehavior::Parent:
174 return "Parent";
175 case IsolationBehavior::Anywhere:
176 return "Anywhere";
177 case IsolationBehavior::Inherit:
178 return "Inherit";
179 case IsolationBehavior::AboutReader:
180 return "AboutReader";
181 case IsolationBehavior::Error:
182 return "Error";
183 default:
184 return "Unknown";
189 * Returns a static string with the name of the given worker kind. For use in
190 * logging code.
192 static const char* WorkerKindName(WorkerKind aWorkerKind) {
193 switch (aWorkerKind) {
194 case WorkerKindDedicated:
195 return "Dedicated";
196 case WorkerKindShared:
197 return "Shared";
198 case WorkerKindService:
199 return "Service";
200 default:
201 return "Unknown";
206 * Check if a given URI has specialized process isolation behaviour, such as
207 * needing to be loaded within a specific type of content process.
209 * When handling a navigation, this method will be called twice: first with the
210 * channel's creation URI, and then it will be called with a result principal's
211 * URI.
213 static IsolationBehavior IsolationBehaviorForURI(nsIURI* aURI, bool aIsSubframe,
214 bool aForChannelCreationURI) {
215 nsAutoCString scheme;
216 MOZ_ALWAYS_SUCCEEDS(aURI->GetScheme(scheme));
218 if (scheme == "chrome"_ns) {
219 // `chrome://` URIs are always loaded in the parent process, unless they
220 // have opted in to loading in a content process. This is currently only
221 // done in tests.
223 // FIXME: These flags should be removed from `chrome` URIs at some point.
224 nsCOMPtr<nsIXULChromeRegistry> chromeReg =
225 do_GetService("@mozilla.org/chrome/chrome-registry;1");
226 bool mustLoadRemotely = false;
227 if (NS_SUCCEEDED(chromeReg->MustLoadURLRemotely(aURI, &mustLoadRemotely)) &&
228 mustLoadRemotely) {
229 return IsolationBehavior::ForceWebRemoteType;
231 bool canLoadRemotely = false;
232 if (NS_SUCCEEDED(chromeReg->CanLoadURLRemotely(aURI, &canLoadRemotely)) &&
233 canLoadRemotely) {
234 return IsolationBehavior::Anywhere;
236 return IsolationBehavior::Parent;
239 if (scheme == "about"_ns) {
240 nsAutoCString path;
241 MOZ_ALWAYS_SUCCEEDS(NS_GetAboutModuleName(aURI, path));
243 // The `about:blank` and `about:srcdoc` pages are loaded by normal web
244 // content, and should be allocated processes based on their simple content
245 // principals.
246 if (path == "blank"_ns || path == "srcdoc"_ns) {
247 MOZ_ASSERT(NS_IsContentAccessibleAboutURI(aURI));
248 return IsolationBehavior::WebContent;
251 MOZ_ASSERT(!NS_IsContentAccessibleAboutURI(aURI));
252 // If we're loading an `about:reader` URI, perform isolation based on the
253 // principal of the URI being loaded.
254 if (path == "reader"_ns && aForChannelCreationURI) {
255 return IsolationBehavior::AboutReader;
258 // Otherwise, we're going to be loading an about: page. Consult the module.
259 nsCOMPtr<nsIAboutModule> aboutModule;
260 if (NS_FAILED(NS_GetAboutModule(aURI, getter_AddRefs(aboutModule))) ||
261 !aboutModule) {
262 // If we don't know of an about: module for this load, it's going to end
263 // up being a network error. Allow the load to finish as normal.
264 return IsolationBehavior::WebContent;
267 // NOTE: about modules can be implemented in JS, so this may run script, and
268 // therefore can spuriously fail.
269 uint32_t flags = 0;
270 if (NS_FAILED(aboutModule->GetURIFlags(aURI, &flags))) {
271 NS_WARNING(
272 "nsIAboutModule::GetURIFlags unexpectedly failed. Abort the load");
273 return IsolationBehavior::Error;
276 if (flags & nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
277 return IsolationBehavior::Extension;
280 if (flags & nsIAboutModule::URI_MUST_LOAD_IN_CHILD) {
281 if (flags & nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS) {
282 return IsolationBehavior::PrivilegedAbout;
284 return IsolationBehavior::ForceWebRemoteType;
287 if (flags & nsIAboutModule::URI_CAN_LOAD_IN_CHILD) {
288 return IsolationBehavior::Anywhere;
291 return IsolationBehavior::Parent;
294 // If the test-only `dataUriInDefaultWebProcess` pref is enabled, dump all
295 // `data:` URIs in a "web" content process, rather than loading them in
296 // content processes based on their precursor origins.
297 if (StaticPrefs::browser_tabs_remote_dataUriInDefaultWebProcess() &&
298 scheme == "data"_ns) {
299 return IsolationBehavior::ForceWebRemoteType;
302 // Make sure to unwrap nested URIs before we early return for channel creation
303 // URI. The checks past this point are intended to operate on the principal,
304 // which has it's origin constructed from the innermost URI.
305 nsCOMPtr<nsIURI> inner;
306 if (nsCOMPtr<nsINestedURI> nested = do_QueryInterface(aURI);
307 nested && NS_SUCCEEDED(nested->GetInnerURI(getter_AddRefs(inner)))) {
308 return IsolationBehaviorForURI(inner, aIsSubframe, aForChannelCreationURI);
311 // If we're doing the initial check based on the channel creation URI, stop
312 // here as we want to only perform the following checks on the true channel
313 // result principal.
314 if (aForChannelCreationURI) {
315 return IsolationBehavior::WebContent;
318 // Protocols used by Thunderbird to display email messages.
319 if (scheme == "imap"_ns || scheme == "mailbox"_ns || scheme == "news"_ns ||
320 scheme == "nntp"_ns || scheme == "snews"_ns) {
321 return IsolationBehavior::Parent;
324 // There is more handling for extension content processes in the caller, but
325 // they should load in an extension content process unless we're loading a
326 // subframe.
327 if (scheme == "moz-extension"_ns) {
328 if (aIsSubframe) {
329 // As a temporary measure, extension iframes must be loaded within the
330 // same process as their parent document.
331 return IsolationBehavior::Inherit;
333 return IsolationBehavior::Extension;
336 if (scheme == "file"_ns) {
337 return IsolationBehavior::File;
340 // Check if the URI is listed as a privileged mozilla content process.
341 if (scheme == "https"_ns &&
342 StaticPrefs::
343 browser_tabs_remote_separatePrivilegedMozillaWebContentProcess()) {
344 nsAutoCString host;
345 if (NS_SUCCEEDED(aURI->GetAsciiHost(host))) {
346 for (const auto& separatedDomain : sSeparatedMozillaDomains) {
347 // If the domain exactly matches our host, or our host ends with "." +
348 // separatedDomain, we consider it matching.
349 if (separatedDomain == host ||
350 (separatedDomain.Length() < host.Length() &&
351 host.CharAt(host.Length() - separatedDomain.Length() - 1) == '.' &&
352 StringEndsWith(host, separatedDomain))) {
353 return IsolationBehavior::PrivilegedMozilla;
359 nsCOMPtr<nsIScriptSecurityManager> secMan =
360 nsContentUtils::GetSecurityManager();
361 bool inFileURIAllowList = false;
362 if (NS_SUCCEEDED(secMan->InFileURIAllowlist(aURI, &inFileURIAllowList)) &&
363 inFileURIAllowList) {
364 return IsolationBehavior::File;
367 return IsolationBehavior::WebContent;
371 * Helper method for logging the origin of a principal as a string.
373 static nsAutoCString OriginString(nsIPrincipal* aPrincipal) {
374 nsAutoCString origin;
375 aPrincipal->GetOrigin(origin);
376 return origin;
380 * Trim the OriginAttributes from aPrincipal, and use it to create a
381 * OriginSuffix string appropriate to use within a remoteType string.
383 static nsAutoCString OriginSuffixForRemoteType(nsIPrincipal* aPrincipal) {
384 nsAutoCString originSuffix;
385 OriginAttributes attrs = aPrincipal->OriginAttributesRef();
386 attrs.StripAttributes(OriginAttributes::STRIP_FIRST_PARTY_DOMAIN |
387 OriginAttributes::STRIP_PARITION_KEY);
388 attrs.CreateSuffix(originSuffix);
389 return originSuffix;
393 * Given an about:reader URI, extract the "url" query parameter, and use it to
394 * construct a principal which should be used for process selection.
396 static already_AddRefed<BasePrincipal> GetAboutReaderURLPrincipal(
397 nsIURI* aURI, const OriginAttributes& aAttrs) {
398 #ifdef DEBUG
399 MOZ_ASSERT(aURI->SchemeIs("about"));
400 nsAutoCString path;
401 MOZ_ALWAYS_SUCCEEDS(NS_GetAboutModuleName(aURI, path));
402 MOZ_ASSERT(path == "reader"_ns);
403 #endif
405 nsAutoCString query;
406 MOZ_ALWAYS_SUCCEEDS(aURI->GetQuery(query));
408 // Extract the "url" parameter from the `about:reader`'s query parameters,
409 // and recover a content principal from it.
410 nsAutoString readerSpec;
411 if (URLParams::Extract(query, u"url"_ns, readerSpec)) {
412 nsCOMPtr<nsIURI> readerUri;
413 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(readerUri), readerSpec))) {
414 return BasePrincipal::CreateContentPrincipal(readerUri, aAttrs);
417 return nullptr;
421 * Returns `true` if loads for this site should be isolated on a per-site basis.
422 * If `aTopBC` is nullptr, this is being called to check if a shared or service
423 * worker should be isolated.
425 static bool ShouldIsolateSite(nsIPrincipal* aPrincipal,
426 bool aUseRemoteSubframes) {
427 // If Fission is disabled, we never want to isolate. We check the toplevel BC
428 // if it's available, or the global pref if checking for shared or service
429 // workers.
430 if (!aUseRemoteSubframes) {
431 return false;
434 // non-content principals currently can't have webIsolated remote types
435 // assigned to them, so should not be isolated.
436 if (!aPrincipal->GetIsContentPrincipal()) {
437 return false;
440 switch (WebContentIsolationStrategy(
441 StaticPrefs::fission_webContentIsolationStrategy())) {
442 case WebContentIsolationStrategy::IsolateNothing:
443 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
444 ("Not isolating '%s' as isolation is disabled",
445 OriginString(aPrincipal).get()));
446 return false;
447 case WebContentIsolationStrategy::IsolateEverything:
448 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
449 ("Isolating '%s' as isolation is enabled for all sites",
450 OriginString(aPrincipal).get()));
451 return true;
452 case WebContentIsolationStrategy::IsolateHighValue: {
453 RefPtr<PermissionManager> perms = PermissionManager::GetInstance();
454 if (NS_WARN_IF(!perms)) {
455 // If we somehow have no permission manager, fall back to the safest
456 // option, and try to isolate.
457 MOZ_ASSERT_UNREACHABLE("Permission manager is missing");
458 return true;
461 static constexpr nsLiteralCString kHighValuePermissions[] = {
462 mozilla::dom::kHighValueCOOPPermission,
463 mozilla::dom::kHighValueHasSavedLoginPermission,
464 mozilla::dom::kHighValueIsLoggedInPermission,
467 for (const auto& type : kHighValuePermissions) {
468 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
469 if (NS_SUCCEEDED(perms->TestPermissionFromPrincipal(aPrincipal, type,
470 &permission)) &&
471 permission == nsIPermissionManager::ALLOW_ACTION) {
472 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
473 ("Isolating '%s' due to high-value permission '%s'",
474 OriginString(aPrincipal).get(), type.get()));
475 return true;
478 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
479 ("Not isolating '%s' as it is not high-value",
480 OriginString(aPrincipal).get()));
481 return false;
483 default:
484 // An invalid pref value was used. Fall back to the safest option and
485 // isolate everything.
486 NS_WARNING("Invalid pref value for fission.webContentIsolationStrategy");
487 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
488 ("Isolating '%s' due to unknown strategy pref value",
489 OriginString(aPrincipal).get()));
490 return true;
494 static Result<nsCString, nsresult> SpecialBehaviorRemoteType(
495 IsolationBehavior aBehavior, const nsACString& aCurrentRemoteType,
496 WindowGlobalParent* aParentWindow) {
497 switch (aBehavior) {
498 case IsolationBehavior::ForceWebRemoteType:
499 return {WEB_REMOTE_TYPE};
500 case IsolationBehavior::PrivilegedAbout:
501 // The privileged about: content process cannot be disabled, as it
502 // causes various actors to break.
503 return {PRIVILEGEDABOUT_REMOTE_TYPE};
504 case IsolationBehavior::Extension:
505 if (ExtensionPolicyService::GetSingleton().UseRemoteExtensions()) {
506 return {EXTENSION_REMOTE_TYPE};
508 return {NOT_REMOTE_TYPE};
509 case IsolationBehavior::File:
510 if (StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
511 return {FILE_REMOTE_TYPE};
513 return {WEB_REMOTE_TYPE};
514 case IsolationBehavior::PrivilegedMozilla:
515 return {PRIVILEGEDMOZILLA_REMOTE_TYPE};
516 case IsolationBehavior::Parent:
517 return {NOT_REMOTE_TYPE};
518 case IsolationBehavior::Anywhere:
519 return {nsCString(aCurrentRemoteType)};
520 case IsolationBehavior::Inherit:
521 MOZ_DIAGNOSTIC_ASSERT(aParentWindow);
522 return {nsCString(aParentWindow->GetRemoteType())};
524 case IsolationBehavior::Error:
525 return Err(NS_ERROR_UNEXPECTED);
527 default:
528 MOZ_ASSERT_UNREACHABLE();
529 return Err(NS_ERROR_UNEXPECTED);
533 enum class WebProcessType {
534 Web,
535 WebIsolated,
536 WebCoopCoep,
539 } // namespace
541 Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
542 CanonicalBrowsingContext* aTopBC, WindowGlobalParent* aParentWindow,
543 nsIURI* aChannelCreationURI, nsIChannel* aChannel,
544 const nsACString& aCurrentRemoteType, bool aHasCOOPMismatch,
545 bool aForNewTab, uint32_t aLoadStateLoadType,
546 const Maybe<uint64_t>& aChannelId,
547 const Maybe<nsCString>& aRemoteTypeOverride) {
548 // Get the final principal, used to select which process to load into.
549 nsCOMPtr<nsIPrincipal> resultPrincipal;
550 nsresult rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
551 aChannel, getter_AddRefs(resultPrincipal));
552 if (NS_FAILED(rv)) {
553 MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
554 ("failed to get channel result principal"));
555 return Err(rv);
558 MOZ_LOG(
559 gProcessIsolationLog, LogLevel::Verbose,
560 ("IsolationOptionsForNavigation principal:%s, uri:%s, parentUri:%s",
561 OriginString(resultPrincipal).get(),
562 aChannelCreationURI->GetSpecOrDefault().get(),
563 aParentWindow ? aParentWindow->GetDocumentURI()->GetSpecOrDefault().get()
564 : ""));
566 // If we're loading a null principal, we can't easily make a process
567 // selection decision off ot it. Instead, we'll use our null principal's
568 // precursor principal to make process selection decisions.
569 bool isNullPrincipalPrecursor = false;
570 nsCOMPtr<nsIPrincipal> resultOrPrecursor(resultPrincipal);
571 if (nsCOMPtr<nsIPrincipal> precursor =
572 resultOrPrecursor->GetPrecursorPrincipal()) {
573 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
574 ("using null principal precursor origin %s",
575 OriginString(precursor).get()));
576 resultOrPrecursor = precursor;
577 isNullPrincipalPrecursor = true;
580 NavigationIsolationOptions options;
581 options.mReplaceBrowsingContext = aHasCOOPMismatch;
583 // Check if this load has an explicit remote type override. This is used to
584 // perform an about:blank load within a specific content process.
585 if (aRemoteTypeOverride) {
586 MOZ_DIAGNOSTIC_ASSERT(
587 NS_IsAboutBlank(aChannelCreationURI),
588 "Should only have aRemoteTypeOverride for about:blank URIs");
589 if (NS_WARN_IF(!resultPrincipal->GetIsNullPrincipal())) {
590 MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
591 ("invalid remote type override on non-null principal"));
592 return Err(NS_ERROR_DOM_SECURITY_ERR);
595 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
596 ("using remote type override (%s) for load",
597 aRemoteTypeOverride->get()));
598 options.mRemoteType = *aRemoteTypeOverride;
599 return options;
602 // First, check for any special cases which should be handled using the
603 // channel creation URI, and handle them.
604 auto behavior = IsolationBehaviorForURI(aChannelCreationURI, aParentWindow,
605 /* aForChannelCreationURI */ true);
606 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
607 ("Channel Creation Isolation Behavior: %s",
608 IsolationBehaviorName(behavior)));
610 // In the about:reader special case, we want to fetch the relevant information
611 // from the URI, an then treat it as a normal web content load.
612 if (behavior == IsolationBehavior::AboutReader) {
613 if (RefPtr<BasePrincipal> readerURIPrincipal = GetAboutReaderURLPrincipal(
614 aChannelCreationURI, resultOrPrecursor->OriginAttributesRef())) {
615 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
616 ("using about:reader's url origin %s",
617 OriginString(readerURIPrincipal).get()));
618 resultOrPrecursor = readerURIPrincipal;
620 behavior = IsolationBehavior::WebContent;
621 // If loading an about:reader page in a BrowsingContext which shares a
622 // BrowsingContextGroup with other toplevel documents, replace the
623 // BrowsingContext to destroy any references.
625 // With SHIP we can apply this to all about:reader loads, but otherwise
626 // do it at least where there are opener/group relationships.
627 if (mozilla::SessionHistoryInParent() ||
628 aTopBC->Group()->Toplevels().Length() > 1) {
629 options.mReplaceBrowsingContext = true;
633 // If we're running in a test which is requesting that system-triggered
634 // about:blank documents load within the current process, override the
635 // behaviour for loads which meet the requirements.
636 if (StaticPrefs::browser_tabs_remote_systemTriggeredAboutBlankAnywhere() &&
637 NS_IsAboutBlank(aChannelCreationURI)) {
638 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
639 if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
640 resultOrPrecursor->GetIsNullPrincipal()) {
641 MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
642 ("Forcing system-principal triggered about:blank load to "
643 "complete in the current process"));
644 behavior = IsolationBehavior::Anywhere;
648 #ifdef MOZ_WIDGET_ANDROID
649 // If we're loading an error page on android, it must complete within the same
650 // process as the errored page load would complete in due to code expecting
651 // that behavior. See bug 1673763.
652 if (aLoadStateLoadType == LOAD_ERROR_PAGE) {
653 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
654 ("Forcing error page load to complete in the current process"));
655 behavior = IsolationBehavior::Anywhere;
657 #endif
659 // If we're loading for a specific extension, we'll need to perform a
660 // BCG-switching load to get our toplevel extension window in the correct
661 // BrowsingContextGroup.
662 if (auto* addonPolicy =
663 BasePrincipal::Cast(resultOrPrecursor)->AddonPolicy()) {
664 if (aParentWindow) {
665 // As a temporary measure, extension iframes must be loaded within the
666 // same process as their parent document.
667 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
668 ("Loading extension subframe in same process as parent"));
669 behavior = IsolationBehavior::Inherit;
670 } else {
671 MOZ_LOG(
672 gProcessIsolationLog, LogLevel::Verbose,
673 ("Found extension frame with addon policy. Will use group id %" PRIx64
674 " (currentId: %" PRIx64 ")",
675 addonPolicy->GetBrowsingContextGroupId(), aTopBC->Group()->Id()));
676 behavior = IsolationBehavior::Extension;
677 if (aTopBC->Group()->Id() != addonPolicy->GetBrowsingContextGroupId()) {
678 options.mReplaceBrowsingContext = true;
679 options.mSpecificGroupId = addonPolicy->GetBrowsingContextGroupId();
684 // Do a second run of `GetIsolationBehavior`, this time using the
685 // principal's URI to handle additional special cases such as the file and
686 // privilegedmozilla content process.
687 if (behavior == IsolationBehavior::WebContent) {
688 if (resultOrPrecursor->IsSystemPrincipal()) {
689 // We're loading something with a system principal which isn't caught in
690 // one of our other edge-cases. If the load started in the parent process,
691 // and it's safe for it to end in the parent process, we should finish the
692 // load there.
693 bool isUIResource = false;
694 if (aCurrentRemoteType.IsEmpty() &&
695 (aChannelCreationURI->SchemeIs("about") ||
696 (NS_SUCCEEDED(NS_URIChainHasFlags(
697 aChannelCreationURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
698 &isUIResource)) &&
699 isUIResource))) {
700 behavior = IsolationBehavior::Parent;
701 } else {
702 // In general, we don't want to load documents with a system principal
703 // in a content process, however we need to in some cases, such as when
704 // loading blob: URLs created by system code. We can force the load to
705 // finish in a content process instead.
706 behavior = IsolationBehavior::ForceWebRemoteType;
708 } else if (nsCOMPtr<nsIURI> principalURI = resultOrPrecursor->GetURI()) {
709 behavior = IsolationBehaviorForURI(principalURI, aParentWindow,
710 /* aForChannelCreationURI */ false);
714 // If we're currently loaded in the extension process, and are going to switch
715 // to some other remote type, make sure we leave the extension's BCG which we
716 // may have entered earlier to separate extension and non-extension BCGs from
717 // each-other.
718 if (!aParentWindow && aCurrentRemoteType == EXTENSION_REMOTE_TYPE &&
719 behavior != IsolationBehavior::Extension &&
720 behavior != IsolationBehavior::Anywhere) {
721 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
722 ("Forcing BC replacement to leave extension BrowsingContextGroup "
723 "%" PRIx64 " on navigation",
724 aTopBC->Group()->Id()));
725 options.mReplaceBrowsingContext = true;
728 // We don't want to load documents with sandboxed null principals, like
729 // `data:` URIs, in the parent process, even if they were created by a
730 // document which would otherwise be loaded in the parent process.
731 if (behavior == IsolationBehavior::Parent && isNullPrincipalPrecursor) {
732 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
733 ("Ensuring sandboxed null-principal load doesn't occur in the "
734 "parent process"));
735 behavior = IsolationBehavior::ForceWebRemoteType;
738 MOZ_LOG(
739 gProcessIsolationLog, LogLevel::Debug,
740 ("Using IsolationBehavior %s for %s (original uri %s)",
741 IsolationBehaviorName(behavior), OriginString(resultOrPrecursor).get(),
742 aChannelCreationURI->GetSpecOrDefault().get()));
744 // Check if we can put the previous document into the BFCache.
745 if (mozilla::BFCacheInParent() && nsSHistory::GetMaxTotalViewers() > 0 &&
746 !aForNewTab && !aParentWindow && !aTopBC->HadOriginalOpener() &&
747 behavior != IsolationBehavior::Parent &&
748 (ExtensionPolicyService::GetSingleton().UseRemoteExtensions() ||
749 behavior != IsolationBehavior::Extension) &&
750 !aCurrentRemoteType.IsEmpty() &&
751 aTopBC->GetHasLoadedNonInitialDocument() &&
752 (aLoadStateLoadType == LOAD_NORMAL ||
753 aLoadStateLoadType == LOAD_HISTORY || aLoadStateLoadType == LOAD_LINK ||
754 aLoadStateLoadType == LOAD_STOP_CONTENT ||
755 aLoadStateLoadType == LOAD_STOP_CONTENT_AND_REPLACE) &&
756 (!aTopBC->GetActiveSessionHistoryEntry() ||
757 aTopBC->GetActiveSessionHistoryEntry()->GetSaveLayoutStateFlag())) {
758 if (nsCOMPtr<nsIURI> uri = aTopBC->GetCurrentURI()) {
759 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
760 ("current uri: %s", uri->GetSpecOrDefault().get()));
762 options.mTryUseBFCache =
763 aTopBC->AllowedInBFCache(aChannelId, aChannelCreationURI);
764 if (options.mTryUseBFCache) {
765 options.mReplaceBrowsingContext = true;
766 options.mActiveSessionHistoryEntry =
767 aTopBC->GetActiveSessionHistoryEntry();
771 // If the load has any special remote type handling, do so at this point.
772 if (behavior != IsolationBehavior::WebContent) {
773 MOZ_TRY_VAR(
774 options.mRemoteType,
775 SpecialBehaviorRemoteType(behavior, aCurrentRemoteType, aParentWindow));
777 if (options.mRemoteType != aCurrentRemoteType &&
778 (options.mRemoteType.IsEmpty() || aCurrentRemoteType.IsEmpty())) {
779 options.mReplaceBrowsingContext = true;
782 MOZ_LOG(
783 gProcessIsolationLog, LogLevel::Debug,
784 ("Selecting specific remote type (%s) due to a special case isolation "
785 "behavior %s",
786 options.mRemoteType.get(), IsolationBehaviorName(behavior)));
787 return options;
790 // At this point we're definitely not going to be loading in the parent
791 // process anymore, so we're definitely going to be replacing BrowsingContext
792 // if we're in the parent process.
793 if (aCurrentRemoteType.IsEmpty()) {
794 MOZ_ASSERT(!aParentWindow);
795 options.mReplaceBrowsingContext = true;
798 nsAutoCString siteOriginNoSuffix;
799 MOZ_TRY(resultOrPrecursor->GetSiteOriginNoSuffix(siteOriginNoSuffix));
801 // Check if we've already loaded a document with the given principal in some
802 // content process. We want to finish the load in the same process in that
803 // case.
805 // The exception to that is with extension loads and the system principal,
806 // where we may have multiple documents with the same principal in different
807 // processes. Those have been handled above, and will not be reaching here.
809 // If we're doing a replace load or opening a new tab, we won't be staying in
810 // the same BrowsingContextGroup, so ignore this step.
811 if (!options.mReplaceBrowsingContext && !aForNewTab) {
812 // Helper for efficiently determining if a given origin is same-site. This
813 // will attempt to do a fast equality check, and will only fall back to
814 // computing the site-origin for content principals.
815 auto principalIsSameSite = [&](nsIPrincipal* aDocumentPrincipal) -> bool {
816 // If we're working with a null principal with a precursor, compare
817 // precursors, as `resultOrPrecursor` has already been stripped to its
818 // precursor.
819 nsCOMPtr<nsIPrincipal> documentPrincipal(aDocumentPrincipal);
820 if (nsCOMPtr<nsIPrincipal> precursor =
821 documentPrincipal->GetPrecursorPrincipal()) {
822 documentPrincipal = precursor;
825 // First, attempt to use `Equals` to compare principals, and if that
826 // fails compare siteOrigins. Only compare siteOrigin for content
827 // principals, as non-content principals will never have siteOrigin !=
828 // origin.
829 nsAutoCString documentSiteOrigin;
830 return resultOrPrecursor->Equals(documentPrincipal) ||
831 (documentPrincipal->GetIsContentPrincipal() &&
832 resultOrPrecursor->GetIsContentPrincipal() &&
833 NS_SUCCEEDED(documentPrincipal->GetSiteOriginNoSuffix(
834 documentSiteOrigin)) &&
835 documentSiteOrigin == siteOriginNoSuffix);
838 // XXX: Consider also checking in-flight process switches to see if any have
839 // matching principals?
840 AutoTArray<RefPtr<BrowsingContext>, 8> contexts;
841 aTopBC->Group()->GetToplevels(contexts);
842 while (!contexts.IsEmpty()) {
843 auto bc = contexts.PopLastElement();
844 for (const auto& wc : bc->GetWindowContexts()) {
845 WindowGlobalParent* wgp = wc->Canonical();
847 // Check if this WindowGlobalParent has the given resultPrincipal, and
848 // if it does, we need to load in that process.
849 if (!wgp->GetRemoteType().IsEmpty() &&
850 principalIsSameSite(wgp->DocumentPrincipal())) {
851 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
852 ("Found existing frame with matching principal "
853 "(remoteType:(%s), origin:%s)",
854 PromiseFlatCString(wgp->GetRemoteType()).get(),
855 OriginString(wgp->DocumentPrincipal()).get()));
856 options.mRemoteType = wgp->GetRemoteType();
857 return options;
860 // Also enumerate over this WindowContexts' subframes.
861 contexts.AppendElements(wc->Children());
866 nsAutoCString originSuffix = OriginSuffixForRemoteType(resultOrPrecursor);
868 WebProcessType webProcessType = WebProcessType::Web;
869 if (ShouldIsolateSite(resultOrPrecursor, aTopBC->UseRemoteSubframes())) {
870 webProcessType = WebProcessType::WebIsolated;
873 // Check if we should be loading in a webCOOP+COEP remote type due to our COOP
874 // status.
875 nsILoadInfo::CrossOriginOpenerPolicy coop =
876 nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
877 if (aParentWindow) {
878 coop = aTopBC->GetOpenerPolicy();
879 } else if (nsCOMPtr<nsIHttpChannelInternal> httpChannel =
880 do_QueryInterface(aChannel)) {
881 MOZ_ALWAYS_SUCCEEDS(httpChannel->GetCrossOriginOpenerPolicy(&coop));
883 if (coop ==
884 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP) {
885 webProcessType = WebProcessType::WebCoopCoep;
887 // If we're changing BrowsingContext, and are going to end up within a
888 // webCOOP+COEP group, ensure we use a cross-origin isolated BCG ID.
889 if (options.mReplaceBrowsingContext) {
890 MOZ_ASSERT(!options.mSpecificGroupId,
891 "overriding previously-specified BCG ID");
892 options.mSpecificGroupId = BrowsingContextGroup::CreateId(
893 /* aPotentiallyCrossOriginIsolated */ true);
897 switch (webProcessType) {
898 case WebProcessType::Web:
899 options.mRemoteType = WEB_REMOTE_TYPE;
900 break;
901 case WebProcessType::WebIsolated:
902 options.mRemoteType =
903 FISSION_WEB_REMOTE_TYPE "="_ns + siteOriginNoSuffix + originSuffix;
904 break;
905 case WebProcessType::WebCoopCoep:
906 options.mRemoteType =
907 WITH_COOP_COEP_REMOTE_TYPE "="_ns + siteOriginNoSuffix + originSuffix;
908 break;
910 return options;
913 Result<WorkerIsolationOptions, nsresult> IsolationOptionsForWorker(
914 nsIPrincipal* aPrincipal, WorkerKind aWorkerKind,
915 const nsACString& aCurrentRemoteType, bool aUseRemoteSubframes) {
916 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
917 ("IsolationOptionsForWorker principal:%s, kind:%s, current:%s",
918 OriginString(aPrincipal).get(), WorkerKindName(aWorkerKind),
919 PromiseFlatCString(aCurrentRemoteType).get()));
921 MOZ_ASSERT(NS_IsMainThread());
922 MOZ_RELEASE_ASSERT(
923 aWorkerKind == WorkerKindService || aWorkerKind == WorkerKindShared,
924 "Unexpected remote worker kind");
926 if (aWorkerKind == WorkerKindService &&
927 !aPrincipal->GetIsContentPrincipal()) {
928 MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
929 ("Rejecting service worker with non-content principal"));
930 return Err(NS_ERROR_UNEXPECTED);
933 if (aPrincipal->GetIsExpandedPrincipal()) {
934 MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
935 ("Rejecting remote worker with expanded principal"));
936 return Err(NS_ERROR_UNEXPECTED);
939 // In some cases, such as for null principals without precursors, we will want
940 // to load a shared worker in a process based on the current process. This is
941 // not done for service workers - process selection for those should function
942 // the same in all processes.
944 // We only allow the current remote type to be used if it is not a COOP+COEP
945 // remote type, in order to avoid loading a shared worker in one of these
946 // processes. Currently process selection for workers occurs before response
947 // headers are available, so we will never select to load a shared worker in a
948 // COOP+COEP content process.
949 nsCString preferredRemoteType = DEFAULT_REMOTE_TYPE;
950 if (aWorkerKind == WorkerKind::WorkerKindShared &&
951 !StringBeginsWith(aCurrentRemoteType,
952 WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
953 preferredRemoteType = aCurrentRemoteType;
956 WorkerIsolationOptions options;
958 // If we're loading a null principal, we can't easily make a process
959 // selection decision off ot it. Instead, we'll use our null principal's
960 // precursor principal to make process selection decisions.
961 bool isNullPrincipalPrecursor = false;
962 nsCOMPtr<nsIPrincipal> resultOrPrecursor(aPrincipal);
963 if (nsCOMPtr<nsIPrincipal> precursor =
964 resultOrPrecursor->GetPrecursorPrincipal()) {
965 MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
966 ("using null principal precursor origin %s",
967 OriginString(precursor).get()));
968 resultOrPrecursor = precursor;
969 isNullPrincipalPrecursor = true;
972 IsolationBehavior behavior = IsolationBehavior::WebContent;
973 if (resultOrPrecursor->GetIsContentPrincipal()) {
974 nsCOMPtr<nsIURI> uri = resultOrPrecursor->GetURI();
975 behavior = IsolationBehaviorForURI(uri, /* aIsSubframe */ false,
976 /* aForChannelCreationURI */ false);
977 } else if (resultOrPrecursor->IsSystemPrincipal()) {
978 MOZ_ASSERT(aWorkerKind == WorkerKindShared);
980 // Allow system principal shared workers to load within either the
981 // parent process or privilegedabout process, depending on the
982 // responsible process.
983 if (preferredRemoteType == NOT_REMOTE_TYPE) {
984 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
985 ("Loading system principal shared worker in parent process"));
986 behavior = IsolationBehavior::Parent;
987 } else if (preferredRemoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
988 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
989 ("Loading system principal shared worker in privilegedabout "
990 "process"));
991 behavior = IsolationBehavior::PrivilegedAbout;
992 } else {
993 MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
994 ("Cannot load system-principal shared worker in "
995 "non-privilegedabout content process"));
996 return Err(NS_ERROR_UNEXPECTED);
998 } else {
999 MOZ_ASSERT(resultOrPrecursor->GetIsNullPrincipal());
1000 MOZ_ASSERT(aWorkerKind == WorkerKindShared);
1002 if (preferredRemoteType == NOT_REMOTE_TYPE) {
1003 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
1004 ("Ensuring precursorless null principal shared worker loads in a "
1005 "content process"));
1006 behavior = IsolationBehavior::ForceWebRemoteType;
1007 } else {
1008 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
1009 ("Loading precursorless null principal shared worker within "
1010 "current remotetype: (%s)",
1011 preferredRemoteType.get()));
1012 behavior = IsolationBehavior::Anywhere;
1016 if (behavior == IsolationBehavior::Parent && isNullPrincipalPrecursor) {
1017 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
1018 ("Ensuring sandboxed null-principal shared worker doesn't load in "
1019 "the parent process"));
1020 behavior = IsolationBehavior::ForceWebRemoteType;
1023 if (behavior != IsolationBehavior::WebContent) {
1024 MOZ_TRY_VAR(
1025 options.mRemoteType,
1026 SpecialBehaviorRemoteType(behavior, preferredRemoteType, nullptr));
1028 MOZ_LOG(
1029 gProcessIsolationLog, LogLevel::Debug,
1030 ("Selecting specific %s worker remote type (%s) due to a special case "
1031 "isolation behavior %s",
1032 WorkerKindName(aWorkerKind), options.mRemoteType.get(),
1033 IsolationBehaviorName(behavior)));
1034 return options;
1037 // If we should be isolating this site, we can determine the correct fission
1038 // remote type from the principal's site-origin.
1039 if (ShouldIsolateSite(resultOrPrecursor, aUseRemoteSubframes)) {
1040 nsAutoCString siteOriginNoSuffix;
1041 MOZ_TRY(resultOrPrecursor->GetSiteOriginNoSuffix(siteOriginNoSuffix));
1042 nsAutoCString originSuffix = OriginSuffixForRemoteType(resultOrPrecursor);
1044 nsCString prefix = aWorkerKind == WorkerKindService
1045 ? SERVICEWORKER_REMOTE_TYPE
1046 : FISSION_WEB_REMOTE_TYPE;
1047 options.mRemoteType = prefix + "="_ns + siteOriginNoSuffix + originSuffix;
1049 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
1050 ("Isolating web content %s worker in remote type (%s)",
1051 WorkerKindName(aWorkerKind), options.mRemoteType.get()));
1052 } else {
1053 options.mRemoteType = WEB_REMOTE_TYPE;
1055 MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
1056 ("Loading web content %s worker in shared web remote type",
1057 WorkerKindName(aWorkerKind)));
1059 return options;
1062 void AddHighValuePermission(nsIPrincipal* aResultPrincipal,
1063 const nsACString& aPermissionType) {
1064 RefPtr<PermissionManager> perms = PermissionManager::GetInstance();
1065 if (NS_WARN_IF(!perms)) {
1066 return;
1069 // We can't act on non-content principals, so if the load was sandboxed, try
1070 // to use the unsandboxed precursor principal to add the highValue permission.
1071 nsCOMPtr<nsIPrincipal> resultOrPrecursor(aResultPrincipal);
1072 if (!aResultPrincipal->GetIsContentPrincipal()) {
1073 resultOrPrecursor = aResultPrincipal->GetPrecursorPrincipal();
1074 if (!resultOrPrecursor) {
1075 return;
1079 // Use the site-origin principal as we want to add the permission for the
1080 // entire site, rather than a specific subdomain, as process isolation acts on
1081 // a site granularity.
1082 nsAutoCString siteOrigin;
1083 if (NS_FAILED(resultOrPrecursor->GetSiteOrigin(siteOrigin))) {
1084 return;
1087 nsCOMPtr<nsIPrincipal> sitePrincipal =
1088 BasePrincipal::CreateContentPrincipal(siteOrigin);
1089 if (!sitePrincipal || !sitePrincipal->GetIsContentPrincipal()) {
1090 return;
1093 MOZ_LOG(dom::gProcessIsolationLog, LogLevel::Verbose,
1094 ("Adding %s Permission for site '%s'", aPermissionType.BeginReading(),
1095 siteOrigin.get()));
1097 uint32_t expiration = 0;
1098 if (aPermissionType.Equals(mozilla::dom::kHighValueCOOPPermission)) {
1099 expiration = StaticPrefs::fission_highValue_coop_expiration();
1100 } else if (aPermissionType.Equals(
1101 mozilla::dom::kHighValueHasSavedLoginPermission) ||
1102 aPermissionType.Equals(
1103 mozilla::dom::kHighValueIsLoggedInPermission)) {
1104 expiration = StaticPrefs::fission_highValue_login_expiration();
1105 } else {
1106 MOZ_ASSERT_UNREACHABLE("Unknown permission type");
1109 // XXX: Would be nice if we could use `TimeStamp` here, but there's
1110 // unfortunately no convenient way to recover a time in milliseconds since the
1111 // unix epoch from `TimeStamp`.
1112 int64_t expirationTime =
1113 (PR_Now() / PR_USEC_PER_MSEC) + (int64_t(expiration) * PR_MSEC_PER_SEC);
1114 Unused << perms->AddFromPrincipal(
1115 sitePrincipal, aPermissionType, nsIPermissionManager::ALLOW_ACTION,
1116 nsIPermissionManager::EXPIRE_TIME, expirationTime);
1119 void AddHighValuePermission(const nsACString& aOrigin,
1120 const nsACString& aPermissionType) {
1121 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
1122 nsCOMPtr<nsIPrincipal> principal;
1123 nsresult rv =
1124 ssm->CreateContentPrincipalFromOrigin(aOrigin, getter_AddRefs(principal));
1125 if (NS_WARN_IF(NS_FAILED(rv))) {
1126 return;
1129 AddHighValuePermission(principal, aPermissionType);
1132 bool IsIsolateHighValueSiteEnabled() {
1133 return mozilla::FissionAutostart() &&
1134 WebContentIsolationStrategy(
1135 StaticPrefs::fission_webContentIsolationStrategy()) ==
1136 WebContentIsolationStrategy::IsolateHighValue;
1139 } // namespace mozilla::dom