diff options
author | Sohom <dattasohom1@gmail.com> | 2023-01-20 15:20:52 +0000 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2023-04-03 15:23:54 +0000 |
commit | 10ed81d38083ad3061ef163dd2c3b089c385590f (patch) | |
tree | e6afc6c186f70512d850bfa5513461cd5de836cf | |
parent | 0487d1dcb21e3c931cb5b1185b6419740570ab25 (diff) | |
download | qtwebengine-chromium-10ed81d38083ad3061ef163dd2c3b089c385590f.tar.gz |
[Backport] CVE-2023-1232: Insufficient policy enforcement in Resource Timing
Manual backport of patch originally reviewed on
https://chromium-review.googlesource.com/c/chromium/src/+/3976688:
Report ResourceTiming entries for 204/205 status codes even when not navigating
Bug: 1346924
Change-Id: I368885b3dfaa5647795f08213d410861114c1dfa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3976688
Reviewed-by: Emily Stark <estark@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Commit-Queue: Sohom Datta <dattasohom1@gmail.com>
Cr-Commit-Position: refs/heads/main@{#1095047}
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/468202
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
18 files changed, 368 insertions, 142 deletions
diff --git a/chromium/content/browser/BUILD.gn b/chromium/content/browser/BUILD.gn index 3cd5feb4203..2e42331adbb 100644 --- a/chromium/content/browser/BUILD.gn +++ b/chromium/content/browser/BUILD.gn @@ -1208,6 +1208,8 @@ jumbo_source_set("browser") { "loader/prefetch_url_loader.h", "loader/prefetch_url_loader_service.cc", "loader/prefetch_url_loader_service.h", + "loader/resource_timing_utils.cc", + "loader/resource_timing_utils.h", "loader/shared_cors_origin_access_list_impl.cc", "loader/shared_cors_origin_access_list_impl.h", "loader/single_request_url_loader_factory.cc", diff --git a/chromium/content/browser/loader/object_navigation_fallback_body_loader.cc b/chromium/content/browser/loader/object_navigation_fallback_body_loader.cc index 7389d290e54..cbaf2723d4d 100644 --- a/chromium/content/browser/loader/object_navigation_fallback_body_loader.cc +++ b/chromium/content/browser/loader/object_navigation_fallback_body_loader.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/containers/contains.h" +#include "content/browser/loader/resource_timing_utils.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/render_frame_host_impl.h" @@ -32,145 +33,6 @@ namespace content { namespace { -// This logic is duplicated from Performance::PassesTimingAllowCheck. Ensure -// that any changes are synced between both copies. -bool PassesTimingAllowCheck( - const network::mojom::URLResponseHead& response_head, - const GURL& url, - const GURL& next_url, - const url::Origin& parent_origin, - bool& response_tainting_not_basic, - bool& tainted_origin_flag) { - const url::Origin response_origin = url::Origin::Create(url); - const bool is_same_origin = response_origin.IsSameOriginWith(parent_origin); - // Still same-origin and resource tainting is "basic": just return true. - if (!response_tainting_not_basic && is_same_origin) { - return true; - } - - // Otherwise, a cross-origin response is currently (or has previously) been - // handled, so resource tainting is no longer "basic". - response_tainting_not_basic = true; - - const network::mojom::TimingAllowOriginPtr& tao = - response_head.parsed_headers->timing_allow_origin; - if (!tao) { - return false; - } - - if (tao->which() == network::mojom::TimingAllowOrigin::Tag::kAll) - return true; - - // TODO(https://crbug.com/1128402): For now, this bookkeeping only exists to - // stay in sync with the Blink code. - bool is_next_resource_same_origin = true; - if (url != next_url) { - is_next_resource_same_origin = - response_origin.IsSameOriginWith(url::Origin::Create(next_url)); - } - - if (!is_same_origin && !is_next_resource_same_origin) { - tainted_origin_flag = true; - } - - return base::Contains(tao->get_serialized_origins(), - parent_origin.Serialize()); -} - -// This logic is duplicated from Performance::AllowsTimingRedirect(). Ensure -// that any changes are synced between both copies. -// -// TODO(https://crbug.com/1201767): There is a *third* implementation of the TAO -// check in CorsURLLoader, but it exactly implements the TAO check as defined in -// the Fetch standard. Unfortunately, the definition in the standard always -// allows timing details for navigations: the response tainting is always -// considered "basic" for navigations, which means that timing details will -// always be allowed, even for cross-origin frames. Oops. -bool AllowTimingDetailsForParent( - const url::Origin& parent_origin, - const blink::mojom::CommonNavigationParams& common_params, - const blink::mojom::CommitNavigationParams& commit_params, - const network::mojom::URLResponseHead& response_head) { - bool response_tainting_not_basic = false; - bool tainted_origin_flag = false; - - DCHECK_EQ(commit_params.redirect_infos.size(), - commit_params.redirect_response.size()); - for (size_t i = 0; i < commit_params.redirect_infos.size(); ++i) { - const GURL& next_response_url = - i + 1 < commit_params.redirect_infos.size() - ? commit_params.redirect_infos[i + 1].new_url - : common_params.url; - if (!PassesTimingAllowCheck( - *commit_params.redirect_response[i], - commit_params.redirect_infos[i].new_url, next_response_url, - parent_origin, response_tainting_not_basic, tainted_origin_flag)) { - return false; - } - } - - return PassesTimingAllowCheck( - response_head, common_params.url, common_params.url, parent_origin, - response_tainting_not_basic, tainted_origin_flag); -} - -// This logic is duplicated from Performance::GenerateResourceTiming(). Ensure -// that any changes are synced between both copies. -blink::mojom::ResourceTimingInfoPtr GenerateResourceTiming( - const url::Origin& parent_origin, - const blink::mojom::CommonNavigationParams& common_params, - const blink::mojom::CommitNavigationParams& commit_params, - const network::mojom::URLResponseHead& response_head) { - // TODO(dcheng): There should be a Blink helper for populating the timing info - // that's exposed in //third_party/blink/common. This would allow a lot of the - // boilerplate to be shared. - - auto timing_info = blink::mojom::ResourceTimingInfo::New(); - const GURL& initial_url = !commit_params.original_url.is_empty() - ? commit_params.original_url - : common_params.url; - timing_info->name = initial_url.spec(); - timing_info->start_time = common_params.navigation_start; - timing_info->alpn_negotiated_protocol = - response_head.alpn_negotiated_protocol; - timing_info->connection_info = net::HttpResponseInfo::ConnectionInfoToString( - response_head.connection_info); - - // If there's no received headers end time, don't set load timing. This is the - // case for non-HTTP requests, requests that don't go over the wire, and - // certain error cases. - // TODO(dcheng): Is it actually possible to hit this path if - // `response_head.headers` is populated? - if (!response_head.load_timing.receive_headers_end.is_null()) { - timing_info->timing = response_head.load_timing; - } - // `response_end` will be populated after loading the body. - timing_info->context_type = blink::mojom::RequestContextType::OBJECT; - - timing_info->allow_timing_details = AllowTimingDetailsForParent( - parent_origin, common_params, commit_params, response_head); - - DCHECK_EQ(commit_params.redirect_infos.size(), - commit_params.redirect_response.size()); - - if (!commit_params.redirect_infos.empty()) { - timing_info->allow_redirect_details = timing_info->allow_timing_details; - timing_info->last_redirect_end_time = - commit_params.redirect_response.back()->load_timing.receive_headers_end; - } else { - timing_info->allow_redirect_details = false; - timing_info->last_redirect_end_time = base::TimeTicks(); - } - // The final value for `encoded_body_size` and `decoded_body_size` will be - // populated after loading the body. - timing_info->did_reuse_connection = response_head.load_timing.socket_reused; - // Use url::Origin to handle cases like blob:https://. - timing_info->is_secure_transport = base::Contains( - url::GetSecureSchemes(), url::Origin::Create(common_params.url).scheme()); - timing_info->allow_negative_values = false; - return timing_info; -} - std::string ExtractServerTimingValueIfNeeded( const network::mojom::URLResponseHead& response_head) { std::string value; @@ -205,9 +67,11 @@ void ObjectNavigationFallbackBodyLoader::CreateAndStart( // It's safe to snapshot the parent origin in the calculation here; if the // parent frame navigates, `render_frame_host_` will be deleted, which // triggers deletion of `this`, cancelling all remaining work. - blink::mojom::ResourceTimingInfoPtr timing_info = GenerateResourceTiming( - render_frame_host->GetParent()->GetLastCommittedOrigin(), common_params, - commit_params, response_head); + blink::mojom::ResourceTimingInfoPtr timing_info = + GenerateResourceTimingForNavigation( + render_frame_host->GetParent()->GetLastCommittedOrigin(), + common_params, commit_params, response_head, + blink::mojom::RequestContextType::OBJECT); std::string server_timing_value = ExtractServerTimingValueIfNeeded(response_head); diff --git a/chromium/content/browser/loader/resource_timing_utils.cc b/chromium/content/browser/loader/resource_timing_utils.cc new file mode 100644 index 00000000000..f6ffc3fee68 --- /dev/null +++ b/chromium/content/browser/loader/resource_timing_utils.cc @@ -0,0 +1,103 @@ +// Copyright 2023 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/loader/resource_timing_utils.h" + +#include <string> +#include <utility> + +#include "base/containers/contains.h" +#include "net/http/http_response_info.h" +#include "third_party/blink/public/mojom/navigation/navigation_params.mojom.h" +#include "third_party/blink/public/mojom/timing/resource_timing.mojom.h" +#include "url/gurl.h" +#include "url/url_util.h" + +namespace { + +// Implements the TimingAllowOrigin check +// This logic is duplicated from Performance::AllowsTimingRedirect(). Ensure +// that any changes are synced between both copies. +bool IsCrossOriginResponseOrHasCrossOriginRedirects( + const url::Origin& parent_origin, + const blink::mojom::CommonNavigationParams& common_params, + const blink::mojom::CommitNavigationParams& commit_params) { + DCHECK_EQ(commit_params.redirect_infos.size(), + commit_params.redirect_response.size()); + for (const auto& info : commit_params.redirect_infos) { + if (!parent_origin.IsSameOriginWith(info.new_url)) { + return true; + } + } + + return !parent_origin.IsSameOriginWith(common_params.url); +} + +} // namespace + +namespace content { + +// This logic is duplicated from Performance::GenerateResourceTiming(). Ensure +// that any changes are synced between both copies. +blink::mojom::ResourceTimingInfoPtr GenerateResourceTimingForNavigation( + const url::Origin& parent_origin, + const blink::mojom::CommonNavigationParams& common_params, + const blink::mojom::CommitNavigationParams& commit_params, + const network::mojom::URLResponseHead& response_head, + blink::mojom::RequestContextType context_type) { + // TODO(dcheng): There should be a Blink helper for populating the timing info + // that's exposed in //chromium/third_party/blink/common. This would allow a lot of the + // boilerplate to be shared. + + auto timing_info = blink::mojom::ResourceTimingInfo::New(); + const GURL& initial_url = !commit_params.original_url.is_empty() + ? commit_params.original_url + : common_params.url; + timing_info->name = initial_url.spec(); + timing_info->start_time = common_params.navigation_start; + timing_info->alpn_negotiated_protocol = + response_head.alpn_negotiated_protocol; + timing_info->connection_info = net::HttpResponseInfo::ConnectionInfoToString( + response_head.connection_info); + + // If there's no received headers end time, don't set load timing. This is the + // case for non-HTTP requests, requests that don't go over the wire, and + // certain error cases. + // TODO(dcheng): Is it actually possible to hit this path if + // `response_head.headers` is populated? + if (!response_head.load_timing.receive_headers_end.is_null()) { + timing_info->timing = response_head.load_timing; + } + // `response_end` will be populated after loading the body. + timing_info->context_type = context_type; + timing_info->allow_timing_details = response_head.timing_allow_passed; + + // Only expose the response code when the response tainting is "basic" - + // same-origin requests throughout the redirect chain + if (!IsCrossOriginResponseOrHasCrossOriginRedirects( + parent_origin, common_params, commit_params)) { + timing_info->response_status = commit_params.http_response_code; + } + + DCHECK_EQ(commit_params.redirect_infos.size(), + commit_params.redirect_response.size()); + + if (!commit_params.redirect_infos.empty()) { + timing_info->allow_redirect_details = timing_info->allow_timing_details; + timing_info->last_redirect_end_time = + commit_params.redirect_response.back()->load_timing.receive_headers_end; + } else { + timing_info->allow_redirect_details = false; + timing_info->last_redirect_end_time = base::TimeTicks(); + } + // The final value for `encoded_body_size` and `decoded_body_size` will be + // populated after loading the body. + timing_info->did_reuse_connection = response_head.load_timing.socket_reused; + // Use url::Origin to handle cases like blob:https://. + timing_info->is_secure_transport = base::Contains( + url::GetSecureSchemes(), url::Origin::Create(common_params.url).scheme()); + timing_info->allow_negative_values = false; + return timing_info; +} +} // namespace content
\ No newline at end of file diff --git a/chromium/content/browser/loader/resource_timing_utils.h b/chromium/content/browser/loader/resource_timing_utils.h new file mode 100644 index 00000000000..5fd32d4be51 --- /dev/null +++ b/chromium/content/browser/loader/resource_timing_utils.h @@ -0,0 +1,25 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_LOADER_RESOURCE_TIMING_UTILS_H_ +#define CONTENT_BROWSER_LOADER_RESOURCE_TIMING_UTILS_H_ + +#include "services/network/public/mojom/url_response_head.mojom-forward.h" +#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-forward.h" +#include "third_party/blink/public/mojom/navigation/navigation_params.mojom-forward.h" +#include "third_party/blink/public/mojom/timing/resource_timing.mojom-forward.h" +#include "url/origin.h" + +namespace content { + +blink::mojom::ResourceTimingInfoPtr GenerateResourceTimingForNavigation( + const url::Origin& parent_origin, + const blink::mojom::CommonNavigationParams& common_params, + const blink::mojom::CommitNavigationParams& commit_params, + const network::mojom::URLResponseHead& response_head, + blink::mojom::RequestContextType context_type); + +} // namespace content + +#endif diff --git a/chromium/content/browser/renderer_host/navigation_request.cc b/chromium/content/browser/renderer_host/navigation_request.cc index c46ed4d91ed..b20250eb0f1 100644 --- a/chromium/content/browser/renderer_host/navigation_request.cc +++ b/chromium/content/browser/renderer_host/navigation_request.cc @@ -23,6 +23,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" +#include "base/notreached.h" #include "base/rand_util.h" #include "base/state_transitions.h" #include "base/strings/strcat.h" @@ -47,6 +48,7 @@ #include "content/browser/loader/navigation_early_hints_manager.h" #include "content/browser/loader/navigation_url_loader.h" #include "content/browser/loader/object_navigation_fallback_body_loader.h" +#include "content/browser/loader/resource_timing_utils.h" #include "content/browser/navigation_or_document_handle.h" #include "content/browser/network/cross_origin_embedder_policy_reporter.h" #include "content/browser/network/cross_origin_opener_policy_reporter.h" @@ -168,6 +170,7 @@ #include "third_party/blink/public/mojom/navigation/prefetched_signed_exchange_info.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_provider.mojom.h" #include "third_party/blink/public/mojom/storage_key/ancestor_chain_bit.mojom.h" +#include "third_party/blink/public/mojom/timing/resource_timing.mojom-forward.h" #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h" #include "third_party/blink/public/platform/resource_request_blocked_reason.h" #include "ui/compositor/compositor_lock.h" @@ -4548,6 +4551,42 @@ network::mojom::WebSandboxFlags NavigationRequest::SandboxFlagsToCommit() { return policy_container_builder_->FinalPolicies().sandbox_flags; } +void NavigationRequest::MaybeAddResourceTimingEntryForCancelledNavigation() { + if (!base::FeatureList::IsEnabled( + features::kResourceTimingForCancelledNavigationInFrame)) { + return; + } + + RenderFrameHostImpl* parent_rfh = GetParentFrame(); + + // Do not add ResourceTiming entries if the navigated URL does not have a + // parent. + if (!parent_rfh) { + return; + } + + // Some navigation are cancelled even before requesting and receiving a + // response. Those cases are not supported and the ResourceTiming is not + // reported to the parent. + if (!response_head_) { + return; + } + + if (initiator_document_.AsRenderFrameHostIfValid() != parent_rfh) { + return; + } + + blink::mojom::ResourceTimingInfoPtr timing_info = + GenerateResourceTimingForNavigation( + parent_rfh->GetLastCommittedOrigin(), *common_params_, + *commit_params_, *response_head_, request_context_type()); + timing_info->response_end = base::TimeTicks::Now(); + parent_rfh->GetAssociatedLocalFrame() + ->AddResourceTimingEntryFromNonNavigatedFrame( + std::move(timing_info), + frame_tree_node()->frame_owner_element_type()); +} + void NavigationRequest::OnRedirectChecksComplete( NavigationThrottle::ThrottleCheckResult result) { DCHECK(result.action() != NavigationThrottle::DEFER); @@ -4792,6 +4831,7 @@ void NavigationRequest::OnWillProcessResponseChecksComplete( if (result.action() == NavigationThrottle::CANCEL_AND_IGNORE || result.action() == NavigationThrottle::CANCEL || !response_should_be_rendered_) { + MaybeAddResourceTimingEntryForCancelledNavigation(); // Reset the RenderFrameHost that had been computed for the commit of the // navigation. render_frame_host_ = nullptr; diff --git a/chromium/content/browser/renderer_host/navigation_request.h b/chromium/content/browser/renderer_host/navigation_request.h index dcdf1c2c4c6..3554b505726 100644 --- a/chromium/content/browser/renderer_host/navigation_request.h +++ b/chromium/content/browser/renderer_host/navigation_request.h @@ -525,6 +525,14 @@ class CONTENT_EXPORT NavigationRequest // new process. void ResetStateForSiteInstanceChange(); + // If a navigation has been cancelled, and was initiated by the parent + // document, report it with the appropriate ResourceTiming entry information. + // + // The ResourceTiming entry may not be sent if the current frame + // does not have a parent, or if the navigation was cancelled before + // a request was made. + void MaybeAddResourceTimingEntryForCancelledNavigation(); + // Lazily initializes and returns the mojo::NavigationClient interface used // for commit. mojom::NavigationClient* GetCommitNavigationClient(); diff --git a/chromium/content/public/common/content_features.cc b/chromium/content/public/common/content_features.cc index 759d4f529f4..ca4dc1203c3 100644 --- a/chromium/content/public/common/content_features.cc +++ b/chromium/content/public/common/content_features.cc @@ -98,6 +98,12 @@ BASE_FEATURE(kBackForwardCache, "BackForwardCache", base::FEATURE_ENABLED_BY_DEFAULT); +// Enables reporting ResourceTiming entries for document, who initiated a +// cancelled navigation in one of their <iframe>. +BASE_FEATURE(kResourceTimingForCancelledNavigationInFrame, + "ResourceTimingForCancelledNavigationInFrame", + base::FEATURE_ENABLED_BY_DEFAULT); + // Allows pages that created a MediaSession service to stay eligible for the // back/forward cache. BASE_FEATURE(kBackForwardCacheMediaSessionService, diff --git a/chromium/content/public/common/content_features.h b/chromium/content/public/common/content_features.h index a773f61f367..be3ab65b232 100644 --- a/chromium/content/public/common/content_features.h +++ b/chromium/content/public/common/content_features.h @@ -31,6 +31,8 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kAvoidUnnecessaryBeforeUnloadCheckPostTask); CONTENT_EXPORT BASE_DECLARE_FEATURE(kAvoidUnnecessaryBeforeUnloadCheckSync); CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackgroundFetch); CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackForwardCache); +CONTENT_EXPORT BASE_DECLARE_FEATURE( + kResourceTimingForCancelledNavigationInFrame); CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackForwardCacheMemoryControls); CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackForwardCacheMediaSessionService); CONTENT_EXPORT BASE_DECLARE_FEATURE(kBlockInsecurePrivateNetworkRequests); diff --git a/chromium/third_party/blink/common/BUILD.gn b/chromium/third_party/blink/common/BUILD.gn index 272639aa093..096ac8b993f 100644 --- a/chromium/third_party/blink/common/BUILD.gn +++ b/chromium/third_party/blink/common/BUILD.gn @@ -136,6 +136,7 @@ jumbo_source_set("common") { "fetch/fetch_api_request_body_mojom_traits.cc", "frame/frame_ad_evidence.cc", "frame/frame_ad_evidence_mojom_traits.cc", + "frame/frame_owner_element_type_mojom_traits.cc", "frame/frame_policy.cc", "frame/frame_policy_mojom_traits.cc", "frame/frame_visual_properties.cc", diff --git a/chromium/third_party/blink/common/frame/frame_owner_element_type_mojom_traits.cc b/chromium/third_party/blink/common/frame/frame_owner_element_type_mojom_traits.cc new file mode 100644 index 00000000000..7650dd3ad1e --- /dev/null +++ b/chromium/third_party/blink/common/frame/frame_owner_element_type_mojom_traits.cc @@ -0,0 +1,65 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/public/common/frame/frame_owner_element_type_mojom_traits.h" +#include "base/notreached.h" +#include "third_party/blink/public/common/frame/frame_owner_element_type.h" +#include "third_party/blink/public/mojom/frame/frame.mojom-shared.h" + +namespace mojo { + +blink::mojom::FrameOwnerElementType EnumTraits< + blink::mojom::FrameOwnerElementType, + blink::FrameOwnerElementType>::ToMojom(blink::FrameOwnerElementType input) { + switch (input) { + case blink::FrameOwnerElementType::kIframe: + return blink::mojom::FrameOwnerElementType::kIframe; + case blink::FrameOwnerElementType::kObject: + return blink::mojom::FrameOwnerElementType::kObject; + case blink::FrameOwnerElementType::kEmbed: + return blink::mojom::FrameOwnerElementType::kEmbed; + case blink::FrameOwnerElementType::kFrame: + return blink::mojom::FrameOwnerElementType::kFrame; + case blink::FrameOwnerElementType::kPortal: + return blink::mojom::FrameOwnerElementType::kPortal; + case blink::FrameOwnerElementType::kFencedframe: + return blink::mojom::FrameOwnerElementType::kFencedframe; + case blink::FrameOwnerElementType::kNone: + return blink::mojom::FrameOwnerElementType::kNone; + } + NOTREACHED(); + return blink::mojom::FrameOwnerElementType::kFrame; +} + +bool EnumTraits<blink::mojom::FrameOwnerElementType, + blink::FrameOwnerElementType>:: + FromMojom(blink::mojom::FrameOwnerElementType input, + blink::FrameOwnerElementType* output) { + switch (input) { + case blink::mojom::FrameOwnerElementType::kIframe: + *output = blink::FrameOwnerElementType::kIframe; + return true; + case blink::mojom::FrameOwnerElementType::kObject: + *output = blink::FrameOwnerElementType::kObject; + return true; + case blink::mojom::FrameOwnerElementType::kEmbed: + *output = blink::FrameOwnerElementType::kEmbed; + return true; + case blink::mojom::FrameOwnerElementType::kFrame: + *output = blink::FrameOwnerElementType::kFrame; + return true; + case blink::mojom::FrameOwnerElementType::kPortal: + *output = blink::FrameOwnerElementType::kPortal; + return true; + case blink::mojom::FrameOwnerElementType::kFencedframe: + *output = blink::FrameOwnerElementType::kFencedframe; + return true; + case blink::mojom::FrameOwnerElementType::kNone: + *output = blink::FrameOwnerElementType::kFrame; + return false; + } + *output = blink::FrameOwnerElementType::kFrame; + return false; +} +} // namespace mojo diff --git a/chromium/third_party/blink/public/common/BUILD.gn b/chromium/third_party/blink/public/common/BUILD.gn index a1ec4a5129a..2495af4966d 100644 --- a/chromium/third_party/blink/public/common/BUILD.gn +++ b/chromium/third_party/blink/public/common/BUILD.gn @@ -139,6 +139,7 @@ source_set("headers") { "frame/fenced_frame_sandbox_flags.h", "frame/frame_ad_evidence.h", "frame/frame_owner_element_type.h", + "frame/frame_owner_element_type_mojom_traits.h", "frame/frame_policy.h", "frame/frame_visual_properties.h", "frame/from_ad_state.h", diff --git a/chromium/third_party/blink/public/common/frame/frame_owner_element_type_mojom_traits.h b/chromium/third_party/blink/public/common/frame/frame_owner_element_type_mojom_traits.h new file mode 100644 index 00000000000..bfc786ea42c --- /dev/null +++ b/chromium/third_party/blink/public/common/frame/frame_owner_element_type_mojom_traits.h @@ -0,0 +1,22 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_OWNER_ELEMENT_TYPE_MOJOM_TRAITS_H_ +#define THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_OWNER_ELEMENT_TYPE_MOJOM_TRAITS_H_ + +#include "third_party/blink/public/common/common_export.h" +#include "third_party/blink/public/common/frame/frame_owner_element_type.h" +#include "third_party/blink/public/mojom/frame/frame.mojom-shared.h" + +namespace mojo { +template <> +struct BLINK_COMMON_EXPORT EnumTraits<blink::mojom::FrameOwnerElementType, + blink::FrameOwnerElementType> { + static blink::mojom::FrameOwnerElementType ToMojom( + blink::FrameOwnerElementType input); + static bool FromMojom(blink::mojom::FrameOwnerElementType input, + blink::FrameOwnerElementType* output); +}; +} // namespace mojo +#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_OWNER_ELEMENT_TYPE_MOJOM_TRAITS_H_ diff --git a/chromium/third_party/blink/public/mojom/BUILD.gn b/chromium/third_party/blink/public/mojom/BUILD.gn index 64d971565ed..8086871fdbd 100644 --- a/chromium/third_party/blink/public/mojom/BUILD.gn +++ b/chromium/third_party/blink/public/mojom/BUILD.gn @@ -503,6 +503,15 @@ mojom("mojom_platform") { { types = [ { + mojom = "blink.mojom.FrameOwnerElementType" + cpp = "::blink::FrameOwnerElementType" + }, + ] + traits_headers = [ "//third_party/blink/public/common/frame/frame_owner_element_type_mojom_traits.h" ] + }, + { + types = [ + { mojom = "blink.mojom.SHA256HashValue" cpp = "::net::SHA256HashValue" }, diff --git a/chromium/third_party/blink/public/mojom/frame/frame.mojom b/chromium/third_party/blink/public/mojom/frame/frame.mojom index fdf74376972..b691331179e 100644 --- a/chromium/third_party/blink/public/mojom/frame/frame.mojom +++ b/chromium/third_party/blink/public/mojom/frame/frame.mojom @@ -146,6 +146,16 @@ enum TraverseCancelledReason { kSandboxViolation, }; +enum FrameOwnerElementType { + kNone, + kIframe, + kObject, + kEmbed, + kFrame, + kPortal, + kFencedframe +}; + // The maximum number of characters of the document's title that we're willing // to accept in the browser process. const uint16 kMaxTitleChars = 4096; // 4 * 1024; @@ -618,6 +628,22 @@ interface LocalFrame { => (mojo_base.mojom.String16 content, uint32 start_offset, uint32 end_offset); + // Report ResourceTiming information about cancelled navigation in iframe + // initiated from this document. This is required to prevent revealing + // information about the status codes to the parent frame. (See crbug.com/1346924) + // + // Example of cancelled navigations: + // - 204 - No Content + // - 205 - Reset Content + // - Extension blocking navigation (e.g. Ad blocker) + // - etc + // + // |parent_frame_element_type| is used on the blink side to determine the + // 'initiator_type' of the entry. + AddResourceTimingEntryFromNonNavigatedFrame( + ResourceTimingInfo timing, + blink.mojom.FrameOwnerElementType parent_frame_element_type); + // Creates an intervention report in the frame with contents |id| and // |message|, returns once the report has been queued. |id| identifies the // intervention that occurred. |message| is a human-readable string that diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.cc b/chromium/third_party/blink/renderer/core/frame/local_frame.cc index f5b84b6821f..d6dca121c99 100644 --- a/chromium/third_party/blink/renderer/core/frame/local_frame.cc +++ b/chromium/third_party/blink/renderer/core/frame/local_frame.cc @@ -179,6 +179,7 @@ #include "third_party/blink/renderer/core/script/classic_script.h" #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h" #include "third_party/blink/renderer/core/svg/svg_document_extensions.h" +#include "third_party/blink/renderer/core/timing/dom_window_performance.h" #include "third_party/blink/renderer/platform/back_forward_cache_utils.h" #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h" #include "third_party/blink/renderer/platform/bindings/source_location.h" @@ -229,6 +230,28 @@ namespace blink { namespace { +const AtomicString& ConvertElementTypeToInitiatorType( + blink::FrameOwnerElementType frame_owner_elem_type) { + switch (frame_owner_elem_type) { + case blink::FrameOwnerElementType::kFrame: + return blink::html_names::kFrameTag.LocalName(); + case blink::FrameOwnerElementType::kIframe: + return blink::html_names::kIFrameTag.LocalName(); + case blink::FrameOwnerElementType::kObject: + return blink::html_names::kObjectTag.LocalName(); + case blink::FrameOwnerElementType::kFencedframe: + return blink::html_names::kFencedframeTag.LocalName(); + case blink::FrameOwnerElementType::kEmbed: + return blink::html_names::kEmbedTag.LocalName(); + case blink::FrameOwnerElementType::kPortal: + return blink::html_names::kPortalTag.LocalName(); + case blink::FrameOwnerElementType::kNone: + NOTREACHED(); + } + NOTREACHED(); + return blink::html_names::kFrameTag.LocalName(); +} + // Maintain a global (statically-allocated) hash map indexed by the the result // of hashing the |frame_token| passed on creation of a LocalFrame object. using LocalFramesByTokenMap = HeapHashMap<uint64_t, WeakMember<LocalFrame>>; @@ -667,6 +690,16 @@ ClipPathPaintImageGenerator* LocalFrame::GetClipPathPaintImageGenerator() { return local_root.clip_path_paint_image_generator_.Get(); } +void LocalFrame::AddResourceTimingEntryFromNonNavigatedFrame( + mojom::blink::ResourceTimingInfoPtr timing, + blink::FrameOwnerElementType initiator_type) { + auto* local_dom_window = DomWindow(); + DOMWindowPerformance::performance(*local_dom_window) + ->AddResourceTiming(std::move(timing), + ConvertElementTypeToInitiatorType(initiator_type), + local_dom_window); +} + const SecurityContext* LocalFrame::GetSecurityContext() const { return DomWindow() ? &DomWindow()->GetSecurityContext() : nullptr; } diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.h b/chromium/third_party/blink/renderer/core/frame/local_frame.h index fcb29bcadaa..fe739c6f015 100644 --- a/chromium/third_party/blink/renderer/core/frame/local_frame.h +++ b/chromium/third_party/blink/renderer/core/frame/local_frame.h @@ -41,6 +41,7 @@ #include "services/device/public/mojom/device_posture_provider.mojom-blink-forward.h" #include "services/network/public/mojom/fetch_api.mojom-blink-forward.h" #include "third_party/blink/public/common/frame/frame_ad_evidence.h" +#include "third_party/blink/public/common/frame/frame_owner_element_type.h" #include "third_party/blink/public/common/frame/transient_allow_fullscreen.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/public/mojom/back_forward_cache_not_restored_reasons.mojom-blink.h" @@ -281,6 +282,10 @@ class CORE_EXPORT LocalFrame final BoxShadowPaintImageGenerator* GetBoxShadowPaintImageGenerator(); ClipPathPaintImageGenerator* GetClipPathPaintImageGenerator(); + void AddResourceTimingEntryFromNonNavigatedFrame( + mojom::blink::ResourceTimingInfoPtr timing, + blink::FrameOwnerElementType initiator_type); + // A local root is the root of a connected subtree that contains only // LocalFrames. The local root is responsible for coordinating input, layout, // et cetera for that subtree of frames. diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc index bf8890f93a3..463a5b2c2b2 100644 --- a/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc +++ b/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc @@ -16,11 +16,13 @@ #include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/public/common/chrome_debug_urls.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/frame/frame_owner_element_type.h" #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h" #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h" #include "third_party/blink/public/mojom/frame/media_player_action.mojom-blink.h" #include "third_party/blink/public/mojom/opengraph/metadata.mojom-blink.h" #include "third_party/blink/public/platform/interface_registry.h" +#include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink-forward.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/web/web_frame_serializer.h" #include "third_party/blink/public/web/web_local_frame.h" @@ -67,6 +69,7 @@ #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/paint/paint_timing.h" #include "third_party/blink/renderer/core/script/classic_script.h" +#include "third_party/blink/renderer/core/timing/dom_window_performance.h" #include "third_party/blink/renderer/platform/mhtml/serialized_resource.h" #include "third_party/blink/renderer/platform/widget/frame_widget.h" @@ -753,6 +756,13 @@ void LocalFrameMojoHandler::RenderFallbackContentWithResourceTiming( server_timing_value); } +void LocalFrameMojoHandler::AddResourceTimingEntryFromNonNavigatedFrame( + mojom::blink::ResourceTimingInfoPtr timing, + blink::FrameOwnerElementType parent_frame_owner_element_type) { + frame_->AddResourceTimingEntryFromNonNavigatedFrame( + std::move(timing), parent_frame_owner_element_type); +} + void LocalFrameMojoHandler::BeforeUnload(bool is_reload, BeforeUnloadCallback callback) { base::TimeTicks before_unload_start_time = base::TimeTicks::Now(); diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h b/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h index 64ce6036d3f..50306685ebe 100644 --- a/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h +++ b/chromium/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h @@ -12,6 +12,7 @@ #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h" #include "third_party/blink/public/mojom/media/fullscreen_video_element.mojom-blink.h" #include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h" +#include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink-forward.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h" @@ -119,6 +120,9 @@ class LocalFrameMojoHandler void RenderFallbackContentWithResourceTiming( mojom::blink::ResourceTimingInfoPtr timing, const String& server_timing_values) final; + void AddResourceTimingEntryFromNonNavigatedFrame( + mojom::blink::ResourceTimingInfoPtr timing, + blink::FrameOwnerElementType parent_frame_owner_element_type) final; void BeforeUnload(bool is_reload, BeforeUnloadCallback callback) final; void MediaPlayerActionAt( const gfx::Point& window_point, |