Commit 1e9e4fd3 authored by Tommy Steimel's avatar Tommy Steimel Committed by Commit Bot

Add chrome-untrusted://resources endpoint

This CL adds a second SharedResourcesDataSource to
URLDataManagerBackend that is used to host the resources at
chrome-untrusted://resources. This allows chrome-untrusted:// frames to
access shared resources.

Design doc:
https://docs.google.com/document/d/1vM-giNmjhKBLGQHu5wMeMHk8VaqOhDWjVa9pYAKVZKY/edit?usp=sharing

Bug: 1082937
Change-Id: I808f6c3d602c6fead880cf2362963dea6646ad21
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2202673Reviewed-by: default avatarNasko Oskov <nasko@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771198}
parent 37999459
......@@ -291,14 +291,29 @@ int GetIdrForPath(const std::string& path) {
} // namespace
SharedResourcesDataSource::SharedResourcesDataSource() {
// static
std::unique_ptr<SharedResourcesDataSource>
SharedResourcesDataSource::CreateForChromeScheme() {
return std::make_unique<SharedResourcesDataSource>(PassKey(),
kChromeUIResourcesHost);
}
SharedResourcesDataSource::~SharedResourcesDataSource() {
// static
std::unique_ptr<SharedResourcesDataSource>
SharedResourcesDataSource::CreateForChromeUntrustedScheme() {
return std::make_unique<SharedResourcesDataSource>(
PassKey(), kChromeUIUntrustedResourcesURL);
}
SharedResourcesDataSource::SharedResourcesDataSource(
PassKey,
const std::string& source_name)
: source_name_(source_name) {}
SharedResourcesDataSource::~SharedResourcesDataSource() = default;
std::string SharedResourcesDataSource::GetSource() {
return kChromeUIResourcesHost;
return source_name_;
}
void SharedResourcesDataSource::StartDataRequest(
......
......@@ -8,16 +8,34 @@
#include <string>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/util/type_safety/pass_key.h"
#include "content/public/browser/url_data_source.h"
namespace content {
// A DataSource for chrome://resources/ URLs.
// A DataSource for chrome://resources/ and chrome-untrusted://resources/ URLs.
// TODO(https://crbug.com/866236): chrome-untrusted://resources/ is not
// currently fully functional, as some resources have absolute
// chrome://resources URLs. If you need access to chrome-untrusted://resources/
// resources that are not currently functional, it is up to you to get them
// working.
class SharedResourcesDataSource : public URLDataSource {
public:
SharedResourcesDataSource();
using PassKey = util::PassKey<SharedResourcesDataSource>;
// Creates a SharedResourcesDataSource instance for chrome://resources.
static std::unique_ptr<SharedResourcesDataSource> CreateForChromeScheme();
// Creates a SharedResourcesDataSource instance for
// chrome-untrusted://resources.
static std::unique_ptr<SharedResourcesDataSource>
CreateForChromeUntrustedScheme();
explicit SharedResourcesDataSource(PassKey, const std::string& source_name);
SharedResourcesDataSource(const SharedResourcesDataSource&) = delete;
SharedResourcesDataSource& operator=(const SharedResourcesDataSource&) =
delete;
~SharedResourcesDataSource() override;
// URLDataSource implementation.
std::string GetSource() override;
......@@ -41,9 +59,7 @@ class SharedResourcesDataSource : public URLDataSource {
bool IsPolymer2DisabledForPage(const WebContents::Getter& wc_getter);
#endif // defined (OS_CHROMEOS)
~SharedResourcesDataSource() override;
DISALLOW_COPY_AND_ASSIGN(SharedResourcesDataSource);
const std::string source_name_;
};
} // namespace content
......
......@@ -71,9 +71,17 @@ bool SchemeIsInSchemes(const std::string& scheme,
} // namespace
URLDataManagerBackend::URLDataManagerBackend() : next_request_id_(0) {
URLDataSource* shared_source = new SharedResourcesDataSource();
AddDataSource(new URLDataSourceImpl(shared_source->GetSource(),
base::WrapUnique(shared_source)));
// Add a shared data source for chrome://resources. For chrome:// data sources
// we use the host name as the source name.
AddDataSource(new URLDataSourceImpl(
kChromeUIResourcesHost,
SharedResourcesDataSource::CreateForChromeScheme()));
// Add a shared data source for chrome-untrusted://resources. For
// chrome-untrusted:// data sources we use the full origin as the source name.
AddDataSource(new URLDataSourceImpl(
kChromeUIUntrustedResourcesURL,
SharedResourcesDataSource::CreateForChromeUntrustedScheme()));
}
URLDataManagerBackend::~URLDataManagerBackend() = default;
......
......@@ -10,6 +10,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/web_contents/web_contents_impl.h"
......@@ -36,6 +37,25 @@
namespace content {
namespace {
// Loads a given module script. The promise resolves to true if the script loads
// successfully, and false otherwise.
const char kAddScriptModuleScript[] =
"new Promise((resolve, reject) => {\n"
" const script = document.createElement('script');\n"
" script.src = $1;\n"
" script.type = 'module';\n"
" script.onload = () => resolve(true);\n"
" script.onerror = () => resolve(false);\n"
" document.body.appendChild(script);\n"
"});\n";
// Path to an existing chrome-untrusted://resources script.
const char kSharedResourcesModuleJsPath[] = "resources/js/assert.m.js";
} // namespace
class WebUISecurityTest : public ContentBrowserTest {
public:
WebUISecurityTest() { WebUIControllerFactory::RegisterFactory(&factory_); }
......@@ -537,6 +557,46 @@ IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
}
}
#if defined(OS_ANDROID)
// TODO(https://crbug.com/1085196): This sometimes fails on Android bots.
#define MAYBE_ChromeUntrustedFramesCanUseChromeUntrustedResources \
DISABLED_ChromeUntrustedFramesCanUseChromeUntrustedResources
#else
#define MAYBE_ChromeUntrustedFramesCanUseChromeUntrustedResources \
ChromeUntrustedFramesCanUseChromeUntrustedResources
#endif // defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(
WebUISecurityTest,
MAYBE_ChromeUntrustedFramesCanUseChromeUntrustedResources) {
// Add a DataSource whose CSP allows chrome-untrusted://resources scripts.
TestUntrustedDataSourceCSP csp;
csp.script_src = "chrome-untrusted://resources";
AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
"test-host", csp);
GURL main_frame_url(GetChromeUntrustedUIURL("test-host/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_frame_url));
// A chrome-untrusted://resources resources should load successfully.
GURL script_url = GetChromeUntrustedUIURL(kSharedResourcesModuleJsPath);
EXPECT_TRUE(EvalJs(shell(), JsReplace(kAddScriptModuleScript, script_url),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */)
.ExtractBool());
}
// Verify that websites cannot access chrome-untrusted://resources scripts.
IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
DisallowChromeUntrustedResourcesFromWebFrame) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL main_frame_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_frame_url));
// A chrome-untrusted://resources resources should fail to load.
GURL script_url = GetChromeUntrustedUIURL(kSharedResourcesModuleJsPath);
EXPECT_FALSE(EvalJs(shell(), JsReplace(kAddScriptModuleScript, script_url),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */)
.ExtractBool());
}
class WebUISecurityTestWithWebUIReportOnlyTrustedTypesEnabled
: public WebUISecurityTest {
public:
......
......@@ -60,6 +60,7 @@ const char kChromeUINetworkErrorsListingURL[] = "chrome://network-errors/";
const char kChromeUIPpapiFlashCrashURL[] = "chrome://ppapiflashcrash/";
const char kChromeUIPpapiFlashHangURL[] = "chrome://ppapiflashhang/";
const char kChromeUIProcessInternalsURL[] = "chrome://process-internals";
const char kChromeUIUntrustedResourcesURL[] = "chrome-untrusted://resources/";
#if defined(OS_ANDROID)
const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/";
#endif
......
......@@ -71,6 +71,7 @@ CONTENT_EXPORT extern const char kChromeUINetworkErrorURL[];
CONTENT_EXPORT extern const char kChromeUIPpapiFlashCrashURL[];
CONTENT_EXPORT extern const char kChromeUIPpapiFlashHangURL[];
CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[];
CONTENT_EXPORT extern const char kChromeUIUntrustedResourcesURL[];
#if defined(OS_ANDROID)
CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[];
#endif
......
......@@ -108,9 +108,14 @@ void AddUntrustedDataSource(BrowserContext* browser_context,
base::BindRepeating([](const std::string& path) { return true; }),
base::BindRepeating(&GetResource));
if (csp.has_value()) {
if (csp->child_src.has_value())
if (csp->child_src.has_value()) {
untrusted_data_source->OverrideContentSecurityPolicyChildSrc(
csp->child_src.value());
}
if (csp->script_src.has_value()) {
untrusted_data_source->OverrideContentSecurityPolicyScriptSrc(
csp->script_src.value());
}
if (csp->no_xfo)
untrusted_data_source->DisableDenyXFrameOptions();
if (csp->frame_ancestors.has_value()) {
......
......@@ -20,6 +20,7 @@ struct TestUntrustedDataSourceCSP {
~TestUntrustedDataSourceCSP();
base::Optional<std::string> child_src = base::nullopt;
base::Optional<std::string> script_src = base::nullopt;
bool no_xfo = false;
base::Optional<std::vector<std::string>> frame_ancestors = base::nullopt;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment