summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-10-14 11:58:26 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-10-14 11:52:44 +0000
commitd627df149baae2da731ed8f0eeca6b91778d485c (patch)
tree86998c53502c6212516021779e85e6e63852fc26
parent00d9e1e3be09a80f9c03302f86b77a9d849a822f (diff)
downloadqtwebengine-chromium-d627df149baae2da731ed8f0eeca6b91778d485c.tar.gz
[Backport] CVE-2019-5875
Pass renderer initiated flag for navigations triggered by cross-origin download If a navigation is triggered by a cross-origin download initiated by renderer, the navigation should carry the renderer initiated flag. BUG=979443 (cherry picked from commit 6d7c9ec2923a71d3f9acb7fdd019a5e56f44c09b) Change-Id: I0716193768a5473f70e909b7efbb5fc74933d89e Reviewed-by: Xing Liu <xingliu@chromium.org> Commit-Queue: Min Qin <qinmin@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#690869} Reviewed-by: Min Qin <qinmin@chromium.org> Cr-Commit-Position: refs/branch-heads/3865@{#714} Cr-Branched-From: 0cdcc6158160790658d1f033d3db873603250124-refs/heads/master@{#681094} Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
-rw-r--r--chromium/components/download/internal/common/download_create_info.cc3
-rw-r--r--chromium/components/download/internal/common/resource_downloader.cc3
-rw-r--r--chromium/components/download/internal/common/resource_downloader.h3
-rw-r--r--chromium/components/download/public/common/download_create_info.h3
-rw-r--r--chromium/content/browser/download/download_browsertest.cc78
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc1
6 files changed, 90 insertions, 1 deletions
diff --git a/chromium/components/download/internal/common/download_create_info.cc b/chromium/components/download/internal/common/download_create_info.cc
index ebc8df19a11..1cd8bd169b0 100644
--- a/chromium/components/download/internal/common/download_create_info.cc
+++ b/chromium/components/download/internal/common/download_create_info.cc
@@ -31,7 +31,8 @@ DownloadCreateInfo::DownloadCreateInfo(
accept_range(false),
connection_info(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
method("GET"),
- ukm_source_id(ukm::kInvalidSourceId) {}
+ ukm_source_id(ukm::kInvalidSourceId),
+ is_content_initiated(false) {}
DownloadCreateInfo::DownloadCreateInfo()
: DownloadCreateInfo(base::Time(), base::WrapUnique(new DownloadSaveInfo)) {
diff --git a/chromium/components/download/internal/common/resource_downloader.cc b/chromium/components/download/internal/common/resource_downloader.cc
index 751474fd56f..25158cae55d 100644
--- a/chromium/components/download/internal/common/resource_downloader.cc
+++ b/chromium/components/download/internal/common/resource_downloader.cc
@@ -129,6 +129,7 @@ ResourceDownloader::ResourceDownloader(
delegate_task_runner_(task_runner),
url_loader_factory_getter_(std::move(url_loader_factory_getter)),
url_security_policy_(url_security_policy),
+ is_content_initiated_(false),
weak_ptr_factory_(this) {}
ResourceDownloader::~ResourceDownloader() = default;
@@ -139,6 +140,7 @@ void ResourceDownloader::Start(
callback_ = download_url_parameters->callback();
upload_callback_ = download_url_parameters->upload_callback();
guid_ = download_url_parameters->guid();
+ is_content_initiated_ = download_url_parameters->content_initiated();
// Set up the URLLoaderClient.
url_loader_client_ = std::make_unique<DownloadResponseHandler>(
@@ -214,6 +216,7 @@ void ResourceDownloader::OnResponseStarted(
download_create_info->render_process_id = render_process_id_;
download_create_info->render_frame_id = render_frame_id_;
download_create_info->has_user_gesture = resource_request_->has_user_gesture;
+ download_create_info->is_content_initiated = is_content_initiated_;
delegate_task_runner_->PostTask(
FROM_HERE,
diff --git a/chromium/components/download/internal/common/resource_downloader.h b/chromium/components/download/internal/common/resource_downloader.h
index 63664cfbe8f..0e2477411ba 100644
--- a/chromium/components/download/internal/common/resource_downloader.h
+++ b/chromium/components/download/internal/common/resource_downloader.h
@@ -154,6 +154,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
// Used to check if the URL is safe to request.
URLSecurityPolicy url_security_policy_;
+ // Whether download is initated by the content on the page.
+ bool is_content_initiated_;
+
base::WeakPtrFactory<ResourceDownloader> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ResourceDownloader);
diff --git a/chromium/components/download/public/common/download_create_info.h b/chromium/components/download/public/common/download_create_info.h
index 7c82695416b..ec793ca4218 100644
--- a/chromium/components/download/public/common/download_create_info.h
+++ b/chromium/components/download/public/common/download_create_info.h
@@ -166,6 +166,9 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadCreateInfo {
// Source of the download, used in metrics.
DownloadSource download_source = DownloadSource::UNKNOWN;
+ // Whether download is initated by the content on the page.
+ bool is_content_initiated;
+
private:
DISALLOW_COPY_AND_ASSIGN(DownloadCreateInfo);
};
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index 6cdb9cd8d52..ed9e9c1de83 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -620,6 +620,38 @@ class ErrorStreamCountingObserver : download::DownloadItem::Observer {
base::Closure completion_closure_;
};
+// Class to wait for a WebContents to kick off a specified number of
+// navigations.
+class NavigationStartObserver : public WebContentsObserver {
+ public:
+ explicit NavigationStartObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+ ~NavigationStartObserver() override {}
+
+ void WaitForFinished(int navigation_count) {
+ if (start_count_ >= navigation_count)
+ return;
+ navigation_count_ = navigation_count;
+ base::RunLoop run_loop;
+ completion_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ private:
+ // WebContentsObserver implementations.
+ void DidStartNavigation(NavigationHandle* navigation_handle) override {
+ start_count_++;
+ if (start_count_ >= navigation_count_ && !completion_closure_.is_null()) {
+ std::move(completion_closure_).Run();
+ }
+ }
+
+ int navigation_count_ = 0;
+ int start_count_ = 0;
+ base::Closure completion_closure_;
+ DISALLOW_COPY_AND_ASSIGN(NavigationStartObserver);
+};
+
bool IsDownloadInState(download::DownloadItem::DownloadState state,
download::DownloadItem* item) {
return item->GetState() == state;
@@ -3146,8 +3178,54 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
std::vector<download::DownloadItem*> downloads;
DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
ASSERT_EQ(0u, downloads.size());
+ ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
+ ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
+}
+
+// Tests that if a renderer initiated download triggers cross origin in the
+// redirect chain, the visible URL of the current tab shouldn't change.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+ DownloadAttributeSameOriginRedirectNavigationTimeOut) {
+ net::EmbeddedTestServer origin_one;
+ net::EmbeddedTestServer origin_two;
+ ASSERT_TRUE(origin_one.InitializeAndListen());
+ ASSERT_TRUE(origin_two.InitializeAndListen());
+ // The download-attribute.html page contains an anchor element whose href is
+ // set to the value of the query parameter (specified as |target| in the URL
+ // below). The suggested filename for the anchor is 'suggested-filename'. When
+ // the page is loaded, a script simulates a click on the anchor, triggering a
+ // download of the target URL.
+ //
+ // We construct two test servers; origin_one and origin_two. Once started, the
+ // server URLs will differ by the port number. Therefore they will be in
+ // different origins.
+ GURL download_url = origin_one.GetURL("/ping");
+ GURL referrer_url = origin_one.GetURL(
+ std::string("/download-attribute.html?target=") + download_url.spec());
+ origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
+
+ // <origin_one>/download-attribute.html initiates a download of
+ // <origin_one>/ping, which redirects to <origin_two>/download. The latter
+ // will time out.
+ origin_one.RegisterRequestHandler(
+ CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
+
+ origin_one.StartAcceptingConnections();
+
+ NavigationStartObserver obs(shell()->web_contents());
+ NavigationController::LoadURLParams params(referrer_url);
+ params.transition_type = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+ shell()->web_contents()->GetController().LoadURLWithParams(params);
+ shell()->web_contents()->Focus();
+
+ // Waiting for 2 navigation to happen, one for the original request, one for
+ // the redirect.
+ obs.WaitForFinished(2);
+ EXPECT_EQ(referrer_url, shell()->web_contents()->GetVisibleURL());
ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
+ origin_two.StartAcceptingConnections();
ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
}
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index a68e0c52394..771bcf5ac57 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -532,6 +532,7 @@ bool DownloadManagerImpl::InterceptDownload(
params.frame_tree_node_id =
RenderFrameHost::GetFrameTreeNodeIdForRoutingId(
info.render_process_id, info.render_frame_id);
+ params.is_renderer_initiated = info.is_content_initiated;
web_contents->GetController().LoadURLWithParams(params);
}
if (info.request_handle)