script: Fix check for document root when targeting CSP events (#37474)

The check was incorrect, where it was never matching and always
discarding the element. Instead, we should check the owner document,
which is the shadow-including root of the node.

Part of #4577

---------

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
Tim van der Lippe 2025-06-15 16:54:41 +02:00 committed by GitHub
parent 576c7445b8
commit f2d0be1b9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 15 additions and 34 deletions

View file

@ -121,7 +121,7 @@ use crate::dom::htmlscriptelement::{ScriptId, SourceCode};
use crate::dom::imagebitmap::ImageBitmap; use crate::dom::imagebitmap::ImageBitmap;
use crate::dom::messageevent::MessageEvent; use crate::dom::messageevent::MessageEvent;
use crate::dom::messageport::MessagePort; use crate::dom::messageport::MessagePort;
use crate::dom::node::Node; use crate::dom::node::{Node, NodeTraits};
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope; use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::performance::Performance; use crate::dom::performance::Performance;
use crate::dom::performanceobserver::VALID_ENTRY_TYPES; use crate::dom::performanceobserver::VALID_ENTRY_TYPES;
@ -2934,7 +2934,11 @@ impl GlobalScope {
is_js_evaluation_allowed == CheckResult::Allowed is_js_evaluation_allowed == CheckResult::Allowed
} }
pub(crate) fn should_navigation_request_be_blocked(&self, load_data: &LoadData) -> bool { pub(crate) fn should_navigation_request_be_blocked(
&self,
load_data: &LoadData,
element: Option<&Element>,
) -> bool {
let Some(csp_list) = self.get_csp_list() else { let Some(csp_list) = self.get_csp_list() else {
return false; return false;
}; };
@ -2956,7 +2960,7 @@ impl GlobalScope {
let (result, violations) = let (result, violations) =
csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other); csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other);
self.report_csp_violations(violations, None); self.report_csp_violations(violations, element);
result == CheckResult::Blocked result == CheckResult::Blocked
} }
@ -3627,11 +3631,10 @@ impl GlobalScope {
// Step 3.1: If target is not null, and global is a Window, // Step 3.1: If target is not null, and global is a Window,
// and targets shadow-including root is not globals associated Document, set target to null. // and targets shadow-including root is not globals associated Document, set target to null.
if let Some(window) = self.downcast::<Window>() { if let Some(window) = self.downcast::<Window>() {
if !window // If a node is connected, its owner document is always the shadow-including root.
.Document() // If it isn't connected, then it also doesn't have a corresponding document, hence
.upcast::<Node>() // it can't be this document.
.is_shadow_including_inclusive_ancestor_of(event_target.upcast()) if event_target.upcast::<Node>().owner_document() != window.Document() {
{
return None; return None;
} }
} }

View file

@ -168,7 +168,7 @@ impl HTMLIFrameElement {
if let Some(window_proxy) = window_proxy { if let Some(window_proxy) = window_proxy {
if document if document
.global() .global()
.should_navigation_request_be_blocked(&load_data) .should_navigation_request_be_blocked(&load_data, Some(self.upcast()))
{ {
return; return;
} }

View file

@ -627,7 +627,7 @@ impl ScriptThread {
if let Some(window) = trusted_global.root().downcast::<Window>() { if let Some(window) = trusted_global.root().downcast::<Window>() {
// Step 5: If the result of should navigation request of type be blocked by // Step 5: If the result of should navigation request of type be blocked by
// Content Security Policy? given request and cspNavigationType is "Blocked", then return. [CSP] // Content Security Policy? given request and cspNavigationType is "Blocked", then return. [CSP]
if trusted_global.root().should_navigation_request_be_blocked(&load_data) { if trusted_global.root().should_navigation_request_be_blocked(&load_data, None) {
return; return;
} }
if ScriptThread::check_load_origin(&load_data.load_origin, &window.get_url().origin()) { if ScriptThread::check_load_origin(&load_data.load_origin, &window.get_url().origin()) {

View file

@ -59,7 +59,7 @@ impl CSPViolationReportTask {
&self.global.root(), &self.global.root(),
Atom::from("securitypolicyviolation"), Atom::from("securitypolicyviolation"),
EventBubbles::Bubbles, EventBubbles::Bubbles,
EventCancelable::Cancelable, EventCancelable::NotCancelable,
EventComposed::Composed, EventComposed::Composed,
&self.violation_report.clone().convert(), &self.violation_report.clone().convert(),
can_gc, can_gc,

View file

@ -1,7 +0,0 @@
[script-sample-no-opt-in.html]
expected: TIMEOUT
[JavaScript URLs in iframes should not have a sample.]
expected: TIMEOUT
[Inline event handlers should not have a sample.]
expected: TIMEOUT

View file

@ -1,7 +1,3 @@
[script-sample.html] [script-sample.html]
expected: TIMEOUT
[JavaScript URLs in iframes should have a sample.] [JavaScript URLs in iframes should have a sample.]
expected: TIMEOUT expected: FAIL
[Inline event handlers should have a sample.]
expected: TIMEOUT

View file

@ -1,4 +0,0 @@
[style-sample-no-opt-in.html]
expected: TIMEOUT
[Inline style attributes should not have a sample.]
expected: TIMEOUT

View file

@ -1,4 +0,0 @@
[style-sample.html]
expected: TIMEOUT
[Inline style attributes should have a sample.]
expected: TIMEOUT

View file

@ -8,6 +8,3 @@
[Correct targeting inside shadow tree (inline handler).] [Correct targeting inside shadow tree (inline handler).]
expected: TIMEOUT expected: TIMEOUT
[Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.]
expected: TIMEOUT