chromium/content/browser/site_per_process_oopsif_browsertest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/process_lock.h"
#include "content/browser/renderer_host/navigation_entry_restore_context_impl.h"
#include "content/browser/site_per_process_browsertest.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/test/render_document_feature.h"
#include "net/dns/mock_host_resolver.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/page_state/page_state_serialization.h"
#include "third_party/blink/public/common/switches.h"

namespace content {

// Test class for tests involving base url inheritance behavior.
class BaseUrlInheritanceIframeTest : public ContentBrowserTest {};  // class BaseUrlInheritanceIframeTest

// A test to ensure that a baseURI exceeding chromium's maximum length for urls
// is not inherited.
IN_PROC_BROWSER_TEST_F(BaseUrlInheritanceIframeTest,
                       InheritedBaseUrlIsLessThan2MB) {}

// A test to make sure that restoring a session history entry that was saved
// with an about:blank subframe never results in an initiator_base_url of
// an empty string. std::nullopt is expected instead of an empty GURL with
// legacy base url behavior, or the non-empty initiator base url in the
// new base url inheritance mode. This test runs in both modes.
IN_PROC_BROWSER_TEST_F(BaseUrlInheritanceIframeTest,
                       BaseURLFromSessionHistoryIsNulloptNotEmptyString) {}

// Test class to allow testing srcdoc functionality both with and without
// `kIsolateSandboxedIframes` enabled. The tests verify the correct operation of
// plumbing of both srcdoc attribute values, as well as the srcdoc frame's
// parent's base url values, to the srcdoc's frame's renderer.
class SrcdocIsolatedSandboxedIframeTest
    : public ContentBrowserTest,
      public ::testing::WithParamInterface<bool> {};  // class SrcdocIsolatedSandboxedIframeTest

// Test the scenario where a Site A mainframe contains a Site B subframe which
// in turn has a sandboxed srcdoc frame. If A tries to directly navigate
// the srcdoc to about:srcdoc, the navigation should be blocked.
IN_PROC_BROWSER_TEST_P(SrcdocIsolatedSandboxedIframeTest,
                       SrcdocNavigationForCrossOriginInitiatorIsBlocked) {}

// Out-of-process-sandboxed-iframe (OOPSIF) tests.
//
// Test classes for isolating sandboxed iframes and documents in a different
// process from the rest of their site.
// See https://crbug.com/510122.
class SitePerProcessIsolatedSandboxedIframeTest
    : public SitePerProcessBrowserTest {};

// A test class to test IsolatedSandboxedIframes with and without
// kOriginKeyedProcessesByDefault enabled.
class OriginKeyedProcessIsolatedSandboxedIframeTest
    : public SitePerProcessBrowserTestBase,
      public ::testing::WithParamInterface<bool> {};

class SitePerProcessNotIsolatedSandboxedIframeTest
    : public SitePerProcessBrowserTest {};

// A test class to allow testing isolated sandboxed iframes using the per-origin
// process model.
class SitePerProcessPerOriginIsolatedSandboxedIframeTest
    : public SitePerProcessBrowserTest {};

class SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest
    : public SitePerProcessIsolatedSandboxedIframeTest {};

// A test class to allow testing isolated sandboxed iframes using the
// per-document grouping model.
class SitePerProcessPerDocumentIsolatedSandboxedIframeTest
    : public SitePerProcessBrowserTest {};

// The following test should not crash. In this test the
// kIsolateSandboxedIframes flag is forced off, so we don't need to verify
// the process isolation details, as is done in
// SitePerProcessIsolatedSandboxedIframeTest.SrcdocCspSandboxIsIsolated below.
// https://crbug.com/1319430
IN_PROC_BROWSER_TEST_P(SitePerProcessNotIsolatedSandboxedIframeTest,
                       SrcdocSandboxFlagsCheck) {}

// Test that a sandboxed data url is loaded correctly (i.e. doesn't crash) both
// with and without kOriginKeyedProcessesByDefault enabled.
IN_PROC_BROWSER_TEST_P(OriginKeyedProcessIsolatedSandboxedIframeTest,
                       DataUrlLoadsWithoutCrashing) {}

// Test that a srcdoc iframe that receives its sandbox flags from the CSP
// attribute also gets process isolation. This test starts the same as
// SitePerProcessNotIsolatedSandboxedIframeTest.SrcdocSandboxFlagsCheck, but in
// this test the kIsolateSandboxedIframes flag is on, so we also verify that
// the process isolation has indeed occurred.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SrcdocCspSandboxIsIsolated) {}

// A test to verify that an iframe that is sandboxed using the 'csp' attribute
// instead of the 'sandbox' attribute gets process isolation when the
// kIsolatedSandboxedIframes flag is enabled.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       CspIsolatedSandbox) {}

// A test to verify that an iframe with a fully-restrictive sandbox is rendered
// in a separate process from its parent frame even if they have the same
// origin.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       IsolatedSandbox) {}

// A test to verify that postMessages sent to/from sandboxed frames get
// delivered properly.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest, PostMessage) {}

// Test that a sandboxed srcdoc iframe loads properly when its parent's url is
// different from its site_url. The child should get its own SiteInstance with a
// site_url based on the full origin of the parent's original url.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerOriginIsolatedSandboxedIframeTest,
                       SrcdocSandboxedFrameWithNonSiteParent) {}

namespace {

GURL GetFrameBaseUrl(RenderFrameHostImpl* rfhi) {}

GURL GetFrameBaseUrl(Shell* shell) {}

}  // namespace

IN_PROC_BROWSER_TEST_P(SitePerProcessPerOriginIsolatedSandboxedIframeTest,
                       SrcdocSandboxedFrameInsideAboutBlank) {}

// Similar to SrcdocSandboxedFrameWithNonSiteParent, but this time the srcdoc
// is opened from b.foo.com which is loaded in the SiteInstance that was
// created for a.foo.com, so the SiteInstance cannot be used to specify the
// origin the srcdoc should use, namely b.foo.com.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerOriginIsolatedSandboxedIframeTest,
                       SrcdocSandboxedFrameWithNonSiteParent2) {}

// Test that sandboxed iframes that are same-site with their parent but
// cross-origin from each other are put in different processes from each other,
// when the 'per-origin' isolation grouping is active for
// kIsolateSandboxedIframes. (In 'per-site' isolation mode they would be in the
// same process.)
IN_PROC_BROWSER_TEST_P(SitePerProcessPerOriginIsolatedSandboxedIframeTest,
                       CrossOriginIsolatedSandboxedIframes) {}

// Test that, while using 'per-origin' isolation grouping, navigating a
// sandboxed iframe from 'a.foo.com' to 'b.foo.com' results in the sandbox using
// two different SiteInstances.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerOriginIsolatedSandboxedIframeTest,
                       CrossOriginNavigationSwitchesSiteInstances) {}

// Test that navigating cross-origin from a non-sandboxed iframe to a CSP
// sandboxed iframe results in switching to a new SiteInstance in a different
// process.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerOriginIsolatedSandboxedIframeTest,
                       CrossOriginNavigationToCSPSwitchesSiteInstances) {}

// Check that two same-site sandboxed iframes in unrelated windows share the
// same process due to subframe process reuse.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxProcessReuse) {}

// A test to verify that when an iframe has two sibling subframes, each with a
// fully-restrictive sandbox, that each of the three gets its own process
// even though they are all same-origin.
// Note: using "sandbox = ''" in this and the following tests creates fully
// restricted sandboxes, which will include the kOrigin case we are interested
// in.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       IsolatedSandboxSiblingSubframes) {}

IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       IsolatedSandboxSrcdocSubframe) {}

// A test to make sure that about:blank in a sandboxed iframe doesn't get
// process isolation. If it did, it would be impossible for the parent to inject
// any content, and it would be stuck as empty content.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       NotIsolatedSandboxAboutBlankSubframe) {}

// Test to make sure that javascript: urls don't execute in a sandboxed iframe.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxedIframeWithJSUrl) {}

// Test to make sure that an iframe with a data:url is process isolated.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxedIframeWithDataURLIsIsolated) {}

// Verify that a navigation from a sandboxed iframe, with an origin distinct
// from its parent, to about:blank succeeds.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxedNavigationToAboutBlank) {}

// Verify that a navigation from a sandboxed iframe, with an origin distinct
// from its parent, to about:blank succeeds. This is a variation on
// SandboxedNavigationToAboutBlank in which the parent removes the sandbox flag
// after B has loaded, and before it navigates to about:blank.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxedNavigationToAboutBlank_SandboxRevokedByParent) {}

// Test to make sure that an iframe with a data:url is appropriately sandboxed.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxedIframeWithDataURL) {}

// Test to make sure that a sandboxed child iframe with a data url and a
// sandboxed parent end up in the same SiteInstance.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       SandboxedParentWithSandboxedChildWithDataURL) {}

// Test to make sure that a sandboxed iframe with a (not-explicitly) sandboxed
// subframe ends up in the same SiteInstance/process as its subframe.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       IsolatedSandboxWithNonSandboxedSubframe) {}

// A test to verify that an iframe with a fully-restrictive sandbox is rendered
// in the same process as its parent frame when the parent frame is in a
// default SiteInstance.
IN_PROC_BROWSER_TEST_P(
    SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest,
    NotIsolatedSandbox) {}

// Similar to the NotIsolatedSandbox test, but using a site that requires a
// dedicated process, and thus resulting in a separate process for the sandboxed
// iframe.
IN_PROC_BROWSER_TEST_P(
    SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest,
    IsolatedSandbox) {}

// In this test, a main frame requests sandbox isolation for a site that would
// not normally be given a dedicated process. This causes the sandbox isolation
// request to fail.
IN_PROC_BROWSER_TEST_P(
    SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest,
    CSPSandboxedMainFrame) {}

// Same as CSPSandboxedMainframe, but this time the site is isolatable on its
// own, so it gets the sandbox attribute via the CSP header.
IN_PROC_BROWSER_TEST_P(
    SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest,
    CSPSandboxedMainframeIsolated) {}

// Test to verify which IsolationContext is used when a BrowsingInstance swap is
// performed during a navigation.
// Note: this test does not work as hoped, see comment before the final
// expectation of the test.
IN_PROC_BROWSER_TEST_P(
    SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest,
    MainFrameBrowsingInstanceSwap) {}

IN_PROC_BROWSER_TEST_P(
    SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest,
    MainFrameWithSandboxedOpener) {}

// Test that sandboxed iframes that are same-site with their parent but
// same-origin to each other are put in different processes from each other,
// when the 'per-document' isolation grouping is active for
// kIsolateSandboxedIframes. (In 'per-site' and 'per-origin' isolation groupings
// they would be in the same process.)
IN_PROC_BROWSER_TEST_P(SitePerProcessPerDocumentIsolatedSandboxedIframeTest,
                       SameOriginIsolatedSandboxedIframes) {}

// This test ensures that nested srcdoc iframes get correct base urls.
IN_PROC_BROWSER_TEST_P(SitePerProcessIsolatedSandboxedIframeTest,
                       NestedSrcdocIframes) {}

// Test to verify that nested sandboxed iframes aren't put in the same
// SiteInstance.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerDocumentIsolatedSandboxedIframeTest,
                       NestedIsolatedSandboxedIframes) {}

// Verify same-document navigations in a sandboxed iframe stay in the same
// SiteInstance, and that the unique_sandbox_id changes for any
// non-same-document navigation.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerDocumentIsolatedSandboxedIframeTest,
                       SandboxedIframeNavigations) {}

// Verify that a sandboxed iframe with an about:blank subframe shares its
// SiteInstance with that subframe. Further, if the about:blank subframe
// navigates cross-site, it gets a new SiteInstance.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerDocumentIsolatedSandboxedIframeTest,
                       SandboxedAboutBlankSubframes) {}

// Test to verify that sibling srcdoc sandboxed iframes are placed in separate
// SiteInstances in the per-document grouping model.
IN_PROC_BROWSER_TEST_P(SitePerProcessPerDocumentIsolatedSandboxedIframeTest,
                       SiblingSrcdocIframesGetDifferentProcesses) {}

// Test that changes to an iframe's srcdoc attribute propagate through the
// browser and are stored/cleared on the RenderFrameHost as needed.
IN_PROC_BROWSER_TEST_P(SrcdocIsolatedSandboxedIframeTest, SrcdocIframe) {}

// Test that when a frame changes its base url by manipulating its
// base-element, and then undoes those changes, that the browser is properly
// notified.
IN_PROC_BROWSER_TEST_P(SrcdocIsolatedSandboxedIframeTest, FrameChangesBaseUrl) {}

// A test to make sure that a sandboxed srcdoc iframe correctly updates its
// base url with the <base> element, and restores the snapshotted base url from
// the parent if it removes its <base> element.
IN_PROC_BROWSER_TEST_P(SrcdocIsolatedSandboxedIframeTest,
                       SandboxedSrcdocIframeAddsRemovesBaseUrl) {}

// Test that when a sandboxed srcdoc iframe's parent changes its base url, the
// srcdoc continues to use the original base url until it reloads.
IN_PROC_BROWSER_TEST_P(SrcdocIsolatedSandboxedIframeTest,
                       SrcdocParentChangesBaseUrl) {}

// A test to verify that the base url stored in RFHI for an about:srcdoc frame
// is cleared when the frame navigates to a non-srcdoc/blank url.
IN_PROC_BROWSER_TEST_P(SrcdocIsolatedSandboxedIframeTest,
                       InheritedBaseUrlClearedOnNavigation) {}

// A test to verify the initial stages of the initiator base url plumbing work.
// The test verifies the value propagates as far as NavigationRequest and
// FrameNavigationEntry.
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, VerifyBaseUrlPlumbing) {}

// This test verifies that a renderer process doesn't crash if a srcdoc calls
// document.write on a mainframe parent.
IN_PROC_BROWSER_TEST_F(BaseUrlInheritanceIframeTest, SrcdocWritesMainFrame) {}

// A test to verify that a new about:blank mainframe inherits its base url
// from its initiator.
IN_PROC_BROWSER_TEST_F(BaseUrlInheritanceIframeTest, PopupsInheritBaseUrl) {}

IN_PROC_BROWSER_TEST_F(BaseUrlInheritanceIframeTest,
                       AboutBlankInheritsBaseUrlFromSiblingInitiator) {}

INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();

}  // namespace content