/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gtest/gtest.h" #include "mozilla/BasePrincipal.h" #include "mozilla/dom/ProcessIsolation.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/ExpandedPrincipal.h" #include "mozilla/ExtensionPolicyService.h" #include "mozilla/gtest/MozAssertions.h" #include "mozilla/gtest/MozHelpers.h" #include "mozilla/NullPrincipal.h" #include "mozilla/SystemPrincipal.h" #include "mozilla/StaticPrefs_browser.h" using namespace mozilla; using namespace mozilla::dom; static nsCOMPtr MakeTestPrincipal(const char* aURI) { nsCOMPtr uri; MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), aURI)); return BasePrincipal::CreateContentPrincipal(uri, {}); } namespace { struct RemoteTypes { nsCString mIsolated; nsCString mUnisolated; }; struct WorkerExpectation { nsCOMPtr mPrincipal; WorkerKind mWorkerKind = WorkerKindShared; Result mExpected = Err(NS_ERROR_FAILURE); nsCString mCurrentRemoteType = "fakeRemoteType"_ns; void Check(bool aUseRemoteSubframes) { nsAutoCString origin; ASSERT_NS_SUCCEEDED(mPrincipal->GetOrigin(origin)); nsPrintfCString describe( "origin: %s, workerKind: %s, currentRemoteType: %s, " "useRemoteSubframes: %d", origin.get(), mWorkerKind == WorkerKindShared ? "shared" : "service", mCurrentRemoteType.get(), aUseRemoteSubframes); auto result = IsolationOptionsForWorker( mPrincipal, mWorkerKind, mCurrentRemoteType, aUseRemoteSubframes); ASSERT_EQ(result.isOk(), mExpected.isOk()) << "Unexpected status (expected " << (mExpected.isOk() ? "ok" : "err") << ") for " << describe; if (mExpected.isOk()) { const nsCString& expected = aUseRemoteSubframes ? mExpected.inspect().mIsolated : mExpected.inspect().mUnisolated; ASSERT_EQ(result.inspect().mRemoteType, expected) << "Unexpected remote type (expected " << expected << ") for " << describe; } } }; } // namespace static nsCString WebIsolatedRemoteType(nsIPrincipal* aPrincipal) { nsAutoCString origin; MOZ_ALWAYS_SUCCEEDS(aPrincipal->GetSiteOrigin(origin)); return FISSION_WEB_REMOTE_TYPE + "="_ns + origin; } static nsCString CoopCoepRemoteType(nsIPrincipal* aPrincipal) { nsAutoCString origin; MOZ_ALWAYS_SUCCEEDS(aPrincipal->GetSiteOrigin(origin)); return WITH_COOP_COEP_REMOTE_TYPE + "="_ns + origin; } static nsCString ServiceWorkerIsolatedRemoteType(nsIPrincipal* aPrincipal) { nsAutoCString origin; MOZ_ALWAYS_SUCCEEDS(aPrincipal->GetSiteOrigin(origin)); return SERVICEWORKER_REMOTE_TYPE + "="_ns + origin; } TEST(ProcessIsolationTest, WorkerOptions) { // Forcibly enable the privileged mozilla content process for the duration of // the test. MOZ_ALWAYS_SUCCEEDS(Preferences::SetCString( "browser.tabs.remote.separatedMozillaDomains", "addons.mozilla.org")); MOZ_ALWAYS_SUCCEEDS(Preferences::SetBool( "browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", true)); auto cleanup = MakeScopeExit([&] { MOZ_ALWAYS_SUCCEEDS( Preferences::ClearUser("browser.tabs.remote.separatedMozillaDomains")); MOZ_ALWAYS_SUCCEEDS(Preferences::ClearUser( "browser.tabs.remote.separatePrivilegedMozillaWebContentProcess")); }); nsCOMPtr systemPrincipal = SystemPrincipal::Get(); nsCOMPtr nullPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); nsCOMPtr secureComPrincipal = MakeTestPrincipal("https://example.com"); nsCOMPtr secureOrgPrincipal = MakeTestPrincipal("https://example.org"); nsCOMPtr insecureOrgPrincipal = MakeTestPrincipal("http://example.org"); nsCOMPtr filePrincipal = MakeTestPrincipal("file:///path/to/dir"); nsCOMPtr extensionPrincipal = MakeTestPrincipal("moz-extension://fake-uuid"); nsCOMPtr privilegedMozillaPrincipal = MakeTestPrincipal("https://addons.mozilla.org"); nsCOMPtr expandedPrincipal = ExpandedPrincipal::Create( nsTArray{secureComPrincipal, extensionPrincipal}, {}); nsCOMPtr nullSecureComPrecursorPrincipal = NullPrincipal::CreateWithInheritedAttributes(secureComPrincipal); nsCString extensionRemoteType = ExtensionPolicyService::GetSingleton().UseRemoteExtensions() ? EXTENSION_REMOTE_TYPE : NOT_REMOTE_TYPE; nsCString fileRemoteType = StaticPrefs::browser_tabs_remote_separateFileUriProcess() ? FILE_REMOTE_TYPE : WEB_REMOTE_TYPE; WorkerExpectation expectations[] = { // Neither service not shared workers can have expanded principals {.mPrincipal = expandedPrincipal, .mWorkerKind = WorkerKindService, .mExpected = Err(NS_ERROR_UNEXPECTED)}, {.mPrincipal = expandedPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = Err(NS_ERROR_UNEXPECTED)}, // Service workers cannot have system or null principals {.mPrincipal = systemPrincipal, .mWorkerKind = WorkerKindService, .mExpected = Err(NS_ERROR_UNEXPECTED)}, {.mPrincipal = nullPrincipal, .mWorkerKind = WorkerKindService, .mExpected = Err(NS_ERROR_UNEXPECTED)}, {.mPrincipal = nullSecureComPrecursorPrincipal, .mWorkerKind = WorkerKindService, .mExpected = Err(NS_ERROR_UNEXPECTED)}, // Service workers with various content principals {.mPrincipal = secureComPrincipal, .mWorkerKind = WorkerKindService, .mExpected = RemoteTypes{ServiceWorkerIsolatedRemoteType(secureComPrincipal), WEB_REMOTE_TYPE}}, {.mPrincipal = secureOrgPrincipal, .mWorkerKind = WorkerKindService, .mExpected = RemoteTypes{ServiceWorkerIsolatedRemoteType(secureOrgPrincipal), WEB_REMOTE_TYPE}}, {.mPrincipal = extensionPrincipal, .mWorkerKind = WorkerKindService, .mExpected = RemoteTypes{extensionRemoteType, extensionRemoteType}}, {.mPrincipal = privilegedMozillaPrincipal, .mWorkerKind = WorkerKindService, .mExpected = RemoteTypes{PRIVILEGEDMOZILLA_REMOTE_TYPE, PRIVILEGEDMOZILLA_REMOTE_TYPE}}, // Shared Worker loaded from within a webCOOP+COEP remote type process, // should load elsewhere. {.mPrincipal = secureComPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{WebIsolatedRemoteType(secureComPrincipal), WEB_REMOTE_TYPE}, .mCurrentRemoteType = CoopCoepRemoteType(secureComPrincipal)}, // Even precursorless null principal should load elsewhere. {.mPrincipal = nullPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{WEB_REMOTE_TYPE, WEB_REMOTE_TYPE}, .mCurrentRemoteType = CoopCoepRemoteType(secureComPrincipal)}, // System principal shared workers can only load in the parent process or // the privilegedabout remote type. {.mPrincipal = systemPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{NOT_REMOTE_TYPE, NOT_REMOTE_TYPE}, .mCurrentRemoteType = NOT_REMOTE_TYPE}, {.mPrincipal = systemPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{PRIVILEGEDABOUT_REMOTE_TYPE, PRIVILEGEDABOUT_REMOTE_TYPE}, .mCurrentRemoteType = PRIVILEGEDABOUT_REMOTE_TYPE}, {.mPrincipal = systemPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = Err(NS_ERROR_UNEXPECTED)}, {.mPrincipal = systemPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = Err(NS_ERROR_UNEXPECTED)}, // Content principals should load in the appropriate remote types, // ignoring the current remote type. {.mPrincipal = secureComPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{WebIsolatedRemoteType(secureComPrincipal), WEB_REMOTE_TYPE}}, {.mPrincipal = secureOrgPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{WebIsolatedRemoteType(secureOrgPrincipal), WEB_REMOTE_TYPE}}, {.mPrincipal = insecureOrgPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{WebIsolatedRemoteType(insecureOrgPrincipal), WEB_REMOTE_TYPE}}, {.mPrincipal = filePrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{fileRemoteType, fileRemoteType}}, {.mPrincipal = extensionPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{extensionRemoteType, extensionRemoteType}}, {.mPrincipal = privilegedMozillaPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{PRIVILEGEDMOZILLA_REMOTE_TYPE, PRIVILEGEDMOZILLA_REMOTE_TYPE}}, {.mPrincipal = nullSecureComPrecursorPrincipal, .mWorkerKind = WorkerKindShared, .mExpected = RemoteTypes{WebIsolatedRemoteType(secureComPrincipal), WEB_REMOTE_TYPE}}, }; for (auto& expectation : expectations) { expectation.Check(true); expectation.Check(false); } }