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) { ...@@ -291,14 +291,29 @@ int GetIdrForPath(const std::string& path) {
} // namespace } // 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() { std::string SharedResourcesDataSource::GetSource() {
return kChromeUIResourcesHost; return source_name_;
} }
void SharedResourcesDataSource::StartDataRequest( void SharedResourcesDataSource::StartDataRequest(
......
...@@ -8,16 +8,34 @@ ...@@ -8,16 +8,34 @@
#include <string> #include <string>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/macros.h" #include "base/util/type_safety/pass_key.h"
#include "base/single_thread_task_runner.h"
#include "content/public/browser/url_data_source.h" #include "content/public/browser/url_data_source.h"
namespace content { 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 { class SharedResourcesDataSource : public URLDataSource {
public: 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. // URLDataSource implementation.
std::string GetSource() override; std::string GetSource() override;
...@@ -41,9 +59,7 @@ class SharedResourcesDataSource : public URLDataSource { ...@@ -41,9 +59,7 @@ class SharedResourcesDataSource : public URLDataSource {
bool IsPolymer2DisabledForPage(const WebContents::Getter& wc_getter); bool IsPolymer2DisabledForPage(const WebContents::Getter& wc_getter);
#endif // defined (OS_CHROMEOS) #endif // defined (OS_CHROMEOS)
~SharedResourcesDataSource() override; const std::string source_name_;
DISALLOW_COPY_AND_ASSIGN(SharedResourcesDataSource);
}; };
} // namespace content } // namespace content
......
...@@ -71,9 +71,17 @@ bool SchemeIsInSchemes(const std::string& scheme, ...@@ -71,9 +71,17 @@ bool SchemeIsInSchemes(const std::string& scheme,
} // namespace } // namespace
URLDataManagerBackend::URLDataManagerBackend() : next_request_id_(0) { URLDataManagerBackend::URLDataManagerBackend() : next_request_id_(0) {
URLDataSource* shared_source = new SharedResourcesDataSource(); // Add a shared data source for chrome://resources. For chrome:// data sources
AddDataSource(new URLDataSourceImpl(shared_source->GetSource(), // we use the host name as the source name.
base::WrapUnique(shared_source))); 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; URLDataManagerBackend::~URLDataManagerBackend() = default;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "content/browser/child_process_security_policy_impl.h" #include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_impl.h"
...@@ -36,6 +37,25 @@ ...@@ -36,6 +37,25 @@
namespace content { 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 { class WebUISecurityTest : public ContentBrowserTest {
public: public:
WebUISecurityTest() { WebUIControllerFactory::RegisterFactory(&factory_); } WebUISecurityTest() { WebUIControllerFactory::RegisterFactory(&factory_); }
...@@ -537,6 +557,46 @@ IN_PROC_BROWSER_TEST_F(WebUISecurityTest, ...@@ -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 class WebUISecurityTestWithWebUIReportOnlyTrustedTypesEnabled
: public WebUISecurityTest { : public WebUISecurityTest {
public: public:
......
...@@ -60,6 +60,7 @@ const char kChromeUINetworkErrorsListingURL[] = "chrome://network-errors/"; ...@@ -60,6 +60,7 @@ const char kChromeUINetworkErrorsListingURL[] = "chrome://network-errors/";
const char kChromeUIPpapiFlashCrashURL[] = "chrome://ppapiflashcrash/"; const char kChromeUIPpapiFlashCrashURL[] = "chrome://ppapiflashcrash/";
const char kChromeUIPpapiFlashHangURL[] = "chrome://ppapiflashhang/"; const char kChromeUIPpapiFlashHangURL[] = "chrome://ppapiflashhang/";
const char kChromeUIProcessInternalsURL[] = "chrome://process-internals"; const char kChromeUIProcessInternalsURL[] = "chrome://process-internals";
const char kChromeUIUntrustedResourcesURL[] = "chrome-untrusted://resources/";
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/"; const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/";
#endif #endif
......
...@@ -71,6 +71,7 @@ CONTENT_EXPORT extern const char kChromeUINetworkErrorURL[]; ...@@ -71,6 +71,7 @@ CONTENT_EXPORT extern const char kChromeUINetworkErrorURL[];
CONTENT_EXPORT extern const char kChromeUIPpapiFlashCrashURL[]; CONTENT_EXPORT extern const char kChromeUIPpapiFlashCrashURL[];
CONTENT_EXPORT extern const char kChromeUIPpapiFlashHangURL[]; CONTENT_EXPORT extern const char kChromeUIPpapiFlashHangURL[];
CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[]; CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[];
CONTENT_EXPORT extern const char kChromeUIUntrustedResourcesURL[];
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[]; CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[];
#endif #endif
......
...@@ -108,9 +108,14 @@ void AddUntrustedDataSource(BrowserContext* browser_context, ...@@ -108,9 +108,14 @@ void AddUntrustedDataSource(BrowserContext* browser_context,
base::BindRepeating([](const std::string& path) { return true; }), base::BindRepeating([](const std::string& path) { return true; }),
base::BindRepeating(&GetResource)); base::BindRepeating(&GetResource));
if (csp.has_value()) { if (csp.has_value()) {
if (csp->child_src.has_value()) if (csp->child_src.has_value()) {
untrusted_data_source->OverrideContentSecurityPolicyChildSrc( untrusted_data_source->OverrideContentSecurityPolicyChildSrc(
csp->child_src.value()); csp->child_src.value());
}
if (csp->script_src.has_value()) {
untrusted_data_source->OverrideContentSecurityPolicyScriptSrc(
csp->script_src.value());
}
if (csp->no_xfo) if (csp->no_xfo)
untrusted_data_source->DisableDenyXFrameOptions(); untrusted_data_source->DisableDenyXFrameOptions();
if (csp->frame_ancestors.has_value()) { if (csp->frame_ancestors.has_value()) {
......
...@@ -20,6 +20,7 @@ struct TestUntrustedDataSourceCSP { ...@@ -20,6 +20,7 @@ struct TestUntrustedDataSourceCSP {
~TestUntrustedDataSourceCSP(); ~TestUntrustedDataSourceCSP();
base::Optional<std::string> child_src = base::nullopt; base::Optional<std::string> child_src = base::nullopt;
base::Optional<std::string> script_src = base::nullopt;
bool no_xfo = false; bool no_xfo = false;
base::Optional<std::vector<std::string>> frame_ancestors = base::nullopt; 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