Browse Source

chore: cherry-pick 2ef09109c0ec from chromium (#36592)

Co-authored-by: electron-patch-conflict-fixer[bot] <83340002+electron-patch-conflict-fixer[bot]@users.noreply.github.com>
Pedro Pontes 2 years ago
parent
commit
5cfaf82036
2 changed files with 365 additions and 0 deletions
  1. 1 0
      patches/chromium/.patches
  2. 364 0
      patches/chromium/cherry-pick-2ef09109c0ec.patch

+ 1 - 0
patches/chromium/.patches

@@ -143,4 +143,5 @@ cherry-pick-ac4785387fff.patch
 cherry-pick-81cb17c24788.patch
 cherry-pick-1894458e04a2.patch
 cherry-pick-6b4af5d82083.patch
+cherry-pick-2ef09109c0ec.patch
 cherry-pick-f98adc846aad.patch

+ 364 - 0
patches/chromium/cherry-pick-2ef09109c0ec.patch

@@ -0,0 +1,364 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jun Kokatsu <[email protected]>
+Date: Thu, 22 Sep 2022 22:16:55 +0000
+Subject: Unify security check for Javascript URL navigation
+
+This change unifies CSP and Trusted Types check for Javascript URL
+navigations.
+
+Bug: 1365082
+Change-Id: I46aea31a918c6397ea71fd5ab345bc9dc19d91c2
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3905476
+Auto-Submit: Jun Kokatsu <[email protected]>
+Commit-Queue: Jun Kokatsu <[email protected]>
+Reviewed-by: Nate Chapin <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1050416}
+
+diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
+index 5ad3d687829db7ed64424b0f593e3aab7951e37e..da289bc7ffc4416ad817b0f344bc24cc0f084582 100644
+--- a/third_party/blink/renderer/bindings/core/v8/script_controller.cc
++++ b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
+@@ -164,34 +164,9 @@ void ScriptController::ExecuteJavaScriptURL(
+     const DOMWrapperWorld* world_for_csp) {
+   DCHECK(url.ProtocolIsJavaScript());
+ 
+-  const int kJavascriptSchemeLength = sizeof("javascript:") - 1;
+-  String script_source = DecodeURLEscapeSequences(
+-      url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
+-
+   if (!window_->GetFrame())
+     return;
+ 
+-  auto* policy = window_->GetContentSecurityPolicyForWorld(world_for_csp);
+-  if (csp_disposition == network::mojom::CSPDisposition::CHECK &&
+-      !policy->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
+-                           nullptr, script_source, String() /* nonce */,
+-                           window_->Url(), EventHandlerPosition().line_)) {
+-    return;
+-  }
+-
+-  // TODO(crbug.com/896041): Investigate how trusted type checks can be
+-  // implemented for isolated worlds.
+-  const bool should_bypass_trusted_type_check =
+-      csp_disposition == network::mojom::CSPDisposition::DO_NOT_CHECK ||
+-      ContentSecurityPolicy::ShouldBypassMainWorldDeprecated(world_for_csp);
+-  script_source = script_source.Substring(kJavascriptSchemeLength);
+-  if (!should_bypass_trusted_type_check) {
+-    script_source = TrustedTypesCheckForJavascriptURLinNavigation(
+-        script_source, window_.Get());
+-    if (script_source.IsEmpty())
+-      return;
+-  }
+-
+   bool had_navigation_before =
+       window_->GetFrame()->Loader().HasProvisionalNavigation();
+ 
+@@ -199,6 +174,9 @@ void ScriptController::ExecuteJavaScriptURL(
+   // Step 6. "Let baseURL be settings's API base URL." [spec text]
+   const KURL base_url = window_->BaseURL();
+ 
++  String script_source = window_->CheckAndGetJavascriptUrl(
++      world_for_csp, url, nullptr /* element */, csp_disposition);
++
+   // Step 7. "Let script be the result of creating a classic script given
+   // scriptSource, settings, baseURL, and the default classic script fetch
+   // options." [spec text]
+diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
+index 2f0615ee1454946d6f46f6626ce9b860a0e04fee..3eab00e4410e749aecdf600097cb68df22dcf072 100644
+--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
++++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
+@@ -415,6 +415,39 @@ bool LocalDOMWindow::CanExecuteScripts(
+   return script_enabled;
+ }
+ 
++String LocalDOMWindow::CheckAndGetJavascriptUrl(
++    const DOMWrapperWorld* world,
++    const KURL& url,
++    Element* element,
++    network::mojom::CSPDisposition csp_disposition) {
++  const int kJavascriptSchemeLength = sizeof("javascript:") - 1;
++  String decoded_url = DecodeURLEscapeSequences(
++      url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
++  String script_source = decoded_url.Substring(kJavascriptSchemeLength);
++
++  if (csp_disposition == network::mojom::CSPDisposition::DO_NOT_CHECK)
++    return script_source;
++
++  // Check the CSP of the caller (the "source browsing context") if required,
++  // as per https://html.spec.whatwg.org/C/#javascript-protocol.
++  if (!GetContentSecurityPolicyForWorld(world)->AllowInline(
++          ContentSecurityPolicy::InlineType::kNavigation, element, decoded_url,
++          String() /* nonce */, Url(), OrdinalNumber::First()))
++    return String();
++
++  // TODO(crbug.com/896041): Investigate how trusted type checks can be
++  // implemented for isolated worlds.
++  if (ContentSecurityPolicy::ShouldBypassMainWorldDeprecated(world))
++    return script_source;
++
++  // https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-pre-navigation-check
++  // 4.9.1.1. require-trusted-types-for Pre-Navigation check
++  script_source =
++      TrustedTypesCheckForJavascriptURLinNavigation(script_source, this);
++
++  return script_source;
++}
++
+ void LocalDOMWindow::ExceptionThrown(ErrorEvent* event) {
+   MainThreadDebugger::Instance()->ExceptionThrown(this, event);
+ }
+diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
+index dcc065abe83948ca3d906f676365226dd82c732d..da06213cfbe2bd156509cd1ff67d600d528c34b0 100644
+--- a/third_party/blink/renderer/core/frame/local_dom_window.h
++++ b/third_party/blink/renderer/core/frame/local_dom_window.h
+@@ -31,6 +31,7 @@
+ 
+ #include "services/metrics/public/cpp/ukm_recorder.h"
+ #include "services/metrics/public/cpp/ukm_source_id.h"
++#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
+ #include "third_party/blink/public/common/frame/fullscreen_request_token.h"
+ #include "third_party/blink/public/common/frame/payment_request_token.h"
+ #include "third_party/blink/public/common/metrics/post_message_counter.h"
+@@ -211,6 +212,16 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
+       mojom::blink::PermissionsPolicyFeature feature,
+       UseCounterImpl::PermissionsPolicyUsageType type);
+ 
++  // Checks if navigation to Javascript URL is allowed. This check should run
++  // before any action is taken (e.g. creating new window) for all
++  // same-origin navigations.
++  String CheckAndGetJavascriptUrl(
++      const DOMWrapperWorld* world,
++      const KURL& url,
++      Element* element,
++      network::mojom::CSPDisposition csp_disposition =
++          network::mojom::CSPDisposition::CHECK);
++
+   Document* InstallNewDocument(const DocumentInit&);
+ 
+   // EventTarget overrides:
+diff --git a/third_party/blink/renderer/core/frame/location.cc b/third_party/blink/renderer/core/frame/location.cc
+index a1aeede568cfe33267d87fa68f096d20a83d50f9..92740842827d470d63da34dd90bdb937321c1a83 100644
+--- a/third_party/blink/renderer/core/frame/location.cc
++++ b/third_party/blink/renderer/core/frame/location.cc
+@@ -270,23 +270,6 @@ void Location::SetLocation(const String& url,
+     return;
+   }
+ 
+-  // Check the source browsing context's CSP to fulfill the CSP check
+-  // requirement of https://html.spec.whatwg.org/C/#navigate for javascript
+-  // URLs. Although the spec states we should perform this check on task
+-  // execution, there are concerns about the correctness of that statement,
+-  // see http://github.com/whatwg/html/issues/2591.
+-  if (completed_url.ProtocolIsJavaScript()) {
+-    String script_source = DecodeURLEscapeSequences(
+-        completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
+-    if (!incumbent_window->GetContentSecurityPolicyForCurrentWorld()
+-             ->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
+-                           nullptr /* element */, script_source,
+-                           String() /* nonce */, incumbent_window->Url(),
+-                           OrdinalNumber::First())) {
+-      return;
+-    }
+-  }
+-
+   V8DOMActivityLogger* activity_logger =
+       V8DOMActivityLogger::CurrentActivityLoggerIfIsolatedWorld();
+   if (activity_logger) {
+diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
+index e2398389b2064f0d804977ea9f5233cf34da5dae..49601b48571fbaebda29b6c2848a65275e4fd861 100644
+--- a/third_party/blink/renderer/core/loader/frame_loader.cc
++++ b/third_party/blink/renderer/core/loader/frame_loader.cc
+@@ -547,19 +547,12 @@ bool FrameLoader::AllowRequestForThisFrame(const FrameLoadRequest& request) {
+ 
+   const KURL& url = request.GetResourceRequest().Url();
+   if (url.ProtocolIsJavaScript()) {
+-    // Check the CSP of the caller (the "source browsing context") if required,
+-    // as per https://html.spec.whatwg.org/C/#javascript-protocol.
+-    bool javascript_url_is_allowed =
+-        request.GetOriginWindow()
+-            ->GetContentSecurityPolicyForWorld(request.JavascriptWorld().get())
+-            ->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
+-                          frame_->DeprecatedLocalOwner(), url.GetString(),
+-                          String() /* nonce */,
+-                          request.GetOriginWindow()->Url(),
+-                          OrdinalNumber::First());
+-
+-    if (!javascript_url_is_allowed)
++    if (request.GetOriginWindow()
++            ->CheckAndGetJavascriptUrl(request.JavascriptWorld().get(), url,
++                                       frame_->DeprecatedLocalOwner())
++            .IsEmpty()) {
+       return false;
++    }
+ 
+     if (frame_->Owner() && ((frame_->Owner()->GetFramePolicy().sandbox_flags &
+                              network::mojom::blink::WebSandboxFlags::kOrigin) !=
+diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc
+index c526aab02f300a32404253537df6ff6c506664f8..36796587c96a51bc90f460def64358ec9788c72e 100644
+--- a/third_party/blink/renderer/core/page/create_window.cc
++++ b/third_party/blink/renderer/core/page/create_window.cc
+@@ -294,15 +294,11 @@ Frame* CreateNewWindow(LocalFrame& opener_frame,
+   request.SetFrameType(mojom::RequestContextFrameType::kAuxiliary);
+ 
+   const KURL& url = request.GetResourceRequest().Url();
+-  auto* csp_for_world = opener_window.GetContentSecurityPolicyForCurrentWorld();
+-  if (url.ProtocolIsJavaScript() && csp_for_world) {
+-    String script_source = DecodeURLEscapeSequences(
+-        url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
+-
+-    if (!csp_for_world->AllowInline(
+-            ContentSecurityPolicy::InlineType::kNavigation,
+-            nullptr /* element */, script_source, String() /* nonce */,
+-            opener_window.Url(), OrdinalNumber::First())) {
++  if (url.ProtocolIsJavaScript()) {
++    if (opener_window
++            .CheckAndGetJavascriptUrl(request.JavascriptWorld().get(), url,
++                                      nullptr /* element */)
++            .IsEmpty()) {
+       return nullptr;
+     }
+   }
+diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html
+new file mode 100644
+index 0000000000000000000000000000000000000000..25cf073e79fa48f4311c3729f0b39d9be2a64e7c
+--- /dev/null
++++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html
+@@ -0,0 +1,6 @@
++<!DOCTYPE html>
++<head>
++</head>
++<body>
++</body>
++</html>
+diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html
+index d00d0538753a74411feeec42d5682082031c09d4..5f7856fabb7bb16085ffaffffbf6d7553179e8f3 100644
+--- a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html
++++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html
+@@ -5,7 +5,8 @@
+ <p>Support page for trusted-types-navigation-report-only.*.html tests.</p>
+ <a id="anchor" href="#">link</a>
+ <script>
+-  if (location.search == "?defaultpolicy") {
++  const params = new URLSearchParams(location.search);
++  if (!!params.get("defaultpolicy")) {
+     trustedTypes.createPolicy("default", {
+         createScript: s => s.replace("continue", "defaultpolicywashere"),
+     });
+@@ -36,9 +37,17 @@
+   // won't disturb delivery of that event to the opener.
+   const anchor = document.getElementById("anchor");
+   anchor.href = target;
++
++  if (!!params.get("frame")) {
++    const frame = document.createElement("iframe");
++    frame.src = "frame-without-trusted-types.html";
++    frames.name = "frame";
++    document.body.appendChild(frame);
++    anchor.target = "frame";
++  }
++
+   if (!location.hash) {
+     document.addEventListener("DOMContentLoaded", _ => anchor.click());
+   }
+ </script>
+ </body>
+-
+diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html
+index cd41f3968e7c74f84a7541506053808073ce541d..5e02e6d4bf5aff9fa4f0b4b897a35726ed24168b 100644
+--- a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html
++++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html
+@@ -5,7 +5,8 @@
+ <p>Support page for trusted-types-navigation.*.html tests.</p>
+ <a id="anchor" href="#">link</a>
+ <script>
+-  if (location.search == "?defaultpolicy") {
++  const params = new URLSearchParams(location.search);
++  if (!!params.get("defaultpolicy")) {
+     trustedTypes.createPolicy("default", {
+         createScript: s => s.replace("continue", "defaultpolicywashere"),
+     });
+@@ -35,8 +36,16 @@
+ 
+   const anchor = document.getElementById("anchor");
+   anchor.href = target;
++
++  if (!!params.get("frame")) {
++    const frame = document.createElement("iframe");
++    frame.src = "frame-without-trusted-types.html";
++    frames.name = "frame";
++    document.body.appendChild(frame);
++    anchor.target = "frame";
++  }
++
+   if (!location.hash)
+     document.addEventListener("DOMContentLoaded", _ => anchor.click());
+ </script>
+ </body>
+-
+diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html
+index 4e784611dd64ecf2f9995403b1d4e5a19f8b4548..2113711902ae787cb3ad5d0e44eaed0fc2e99b87 100644
+--- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html
++++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html
+@@ -38,10 +38,10 @@
+   }, "Navigate a window with javascript:-urls in enforcing mode.");
+ 
+   promise_test(t => {
+-    openWindow(t, "support/navigation-support.html?defaultpolicy");
++    openWindow(t, "support/navigation-support.html?defaultpolicy=1");
+     return Promise.all([
+-      expectLoadedAsMessage("navigation-support.html?defaultpolicy"),
+-      expectLoadedAsMessage("navigation-support.html?defaultpolicy&defaultpolicywashere"),
++      expectLoadedAsMessage("navigation-support.html?defaultpolicy=1"),
++      expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&defaultpolicywashere"),
+     ]);
+   }, "Navigate a window with javascript:-urls w/ default policy in enforcing mode.");
+ 
+@@ -55,12 +55,46 @@
+   }, "Navigate a window with javascript:-urls in report-only mode.");
+ 
+   promise_test(t => {
+-    const page = "navigation-report-only-support.html?defaultpolicy";
++    const page = "navigation-report-only-support.html?defaultpolicy=1";
+     openWindow(t, `support/${page}`);
+     return Promise.all([
+       expectLoadedAsMessage(page),
+-      expectLoadedAsMessage("navigation-support.html?defaultpolicy#defaultpolicywashere"),
++      expectLoadedAsMessage("navigation-support.html?defaultpolicy=1#defaultpolicywashere"),
+     ]);
+   }, "Navigate a window with javascript:-urls w/ default policy in report-only mode.");
++
++  promise_test(t => {
++    openWindow(t, "support/navigation-support.html?frame=1");
++    return Promise.all([
++      expectLoadedAsMessage("navigation-support.html?frame=1"),
++      expectViolationAsMessage("Location href"),
++    ]);
++  }, "Navigate a frame with javascript:-urls in enforcing mode.");
++
++  promise_test(t => {
++    openWindow(t, "support/navigation-support.html?defaultpolicy=1&frame=1");
++    return Promise.all([
++      expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1"),
++      expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1&defaultpolicywashere"),
++    ]);
++  }, "Navigate a frame with javascript:-urls w/ default policy in enforcing mode.");
++
++  promise_test(t => {
++    const page = "navigation-report-only-support.html?frame=1"
++    openWindow(t, `support/${page}`);
++    return Promise.all([
++      expectLoadedAsMessage(page),
++      expectLoadedAsMessage("navigation-support.html?frame=1#continue"),
++    ]);
++  }, "Navigate a frame with javascript:-urls in report-only mode.");
++
++  promise_test(t => {
++    const page = "navigation-report-only-support.html?defaultpolicy=1&frame=1";
++    openWindow(t, `support/${page}`);
++    return Promise.all([
++      expectLoadedAsMessage(page),
++      expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1#defaultpolicywashere"),
++    ]);
++  }, "Navigate a frame with javascript:-urls w/ default policy in report-only mode.");
+ </script>
+ </body>