| Index: chrome/renderer/extensions/resource_request_policy.cc
|
| diff --git a/chrome/renderer/extensions/resource_request_policy.cc b/chrome/renderer/extensions/resource_request_policy.cc
|
| index 0519a63fe5363c77ad5c83e97caa4cfbc6fca418..681d86c9dd382df8172f16e68f3f7a5f4f3b6427 100644
|
| --- a/chrome/renderer/extensions/resource_request_policy.cc
|
| +++ b/chrome/renderer/extensions/resource_request_policy.cc
|
| @@ -30,6 +30,30 @@ namespace extensions {
|
|
|
| ResourceRequestPolicy::ResourceRequestPolicy(Dispatcher* dispatcher)
|
| : dispatcher_(dispatcher) {}
|
| +ResourceRequestPolicy::~ResourceRequestPolicy() = default;
|
| +
|
| +void ResourceRequestPolicy::OnExtensionLoaded(const Extension& extension) {
|
| + if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) ||
|
| + // Extensions below manifest version 2 had all resources accessible by
|
| + // default.
|
| + // TODO(devlin): Two things - first, we might not have any v1 extensions
|
| + // anymore; second, this should maybe be included in
|
| + // HasWebAccessibleResources().
|
| + extension.manifest_version() < 2 ||
|
| + WebviewInfo::HasWebviewAccessibleResources(
|
| + extension, dispatcher_->webview_partition_id()) ||
|
| + // Hosted app icons are accessible.
|
| + // TODO(devlin): Should we incorporate this into
|
| + // WebAccessibleResourcesInfo?
|
| + (extension.is_hosted_app() && !IconsInfo::GetIcons(&extension).empty())) {
|
| + web_accessible_ids_.insert(extension.id());
|
| + }
|
| +}
|
| +
|
| +void ResourceRequestPolicy::OnExtensionUnloaded(
|
| + const ExtensionId& extension_id) {
|
| + web_accessible_ids_.erase(extension_id);
|
| +}
|
|
|
| // This method does a security check whether chrome-extension:// URLs can be
|
| // requested by the renderer. Since this is in an untrusted process, the browser
|
| @@ -42,14 +66,70 @@ bool ResourceRequestPolicy::CanRequestResource(
|
| ui::PageTransition transition_type) {
|
| CHECK(resource_url.SchemeIs(kExtensionScheme));
|
|
|
| + GURL frame_url = frame->GetDocument().Url();
|
| +
|
| + // The page_origin may be GURL("null") for unique origins like data URLs,
|
| + // but this is ok for the checks below. We only care if it matches the
|
| + // current extension or has a devtools scheme.
|
| + GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL();
|
| +
|
| + GURL extension_origin = resource_url.GetOrigin();
|
| +
|
| + // We always allow loads in the following cases, regardless of web accessible
|
| + // resources:
|
| +
|
| + // Empty urls (needed for some edge cases when we have empty urls).
|
| + if (frame_url.is_empty())
|
| + return true;
|
| +
|
| + // Extensions requesting their own resources (frame_url check is for images,
|
| + // page_url check is for iframes).
|
| + // TODO(devlin): We should be checking the ancestor chain, not just the
|
| + // top-level frame. Additionally, we should be checking the security origin
|
| + // of the frame, to account for about:blank subframes being scripted by an
|
| + // extension parent (though we'll still need the frame origin check for
|
| + // sandboxed frames).
|
| + if (frame_url.GetOrigin() == extension_origin ||
|
| + page_origin == extension_origin) {
|
| + return true;
|
| + }
|
| +
|
| + if (!ui::PageTransitionIsWebTriggerable(transition_type))
|
| + return true;
|
| +
|
| + // Unreachable web page error page (to allow showing the icon of the
|
| + // unreachable app on this page).
|
| + if (frame_url == content::kUnreachableWebDataURL)
|
| + return true;
|
| +
|
| + bool is_dev_tools = page_origin.SchemeIs(content::kChromeDevToolsScheme);
|
| + // Note: we check |web_accessible_ids_| (rather than first looking up the
|
| + // extension in the registry and checking that) to be more resistant against
|
| + // timing attacks. This way, determining access for an extension that isn't
|
| + // installed takes the same amount of time as determining access for an
|
| + // extension with no web accessible resources. We aren't worried about any
|
| + // extensions with web accessible resources, since those are inherently
|
| + // identifiable.
|
| + if (!is_dev_tools && !web_accessible_ids_.count(extension_origin.host()))
|
| + return false;
|
| +
|
| const Extension* extension =
|
| RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url);
|
| - if (!extension) {
|
| + if (is_dev_tools) {
|
| // Allow the load in the case of a non-existent extension. We'll just get a
|
| // 404 from the browser process.
|
| - return true;
|
| + // TODO(devlin): Can this happen? Does devtools potentially make requests
|
| + // to non-existent extensions?
|
| + if (!extension)
|
| + return true;
|
| + // Devtools (chrome-extension:// URLs are loaded into frames of devtools to
|
| + // support the devtools extension APIs).
|
| + if (!chrome_manifest_urls::GetDevToolsPage(extension).is_empty())
|
| + return true;
|
| }
|
|
|
| + DCHECK(extension);
|
| +
|
| // Disallow loading of packaged resources for hosted apps. We don't allow
|
| // hybrid hosted/packaged apps. The one exception is access to icons, since
|
| // some extensions want to be able to do things like create their own
|
| @@ -72,43 +152,15 @@ bool ResourceRequestPolicy::CanRequestResource(
|
| !WebviewInfo::IsResourceWebviewAccessible(
|
| extension, dispatcher_->webview_partition_id(),
|
| resource_url.path())) {
|
| - GURL frame_url = frame->GetDocument().Url();
|
| -
|
| - // The page_origin may be GURL("null") for unique origins like data URLs,
|
| - // but this is ok for the checks below. We only care if it matches the
|
| - // current extension or has a devtools scheme.
|
| - GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL();
|
| -
|
| - // Exceptions are:
|
| - // - empty origin (needed for some edge cases when we have empty origins)
|
| - bool is_empty_origin = frame_url.is_empty();
|
| - // - extensions requesting their own resources (frame_url check is for
|
| - // images, page_url check is for iframes)
|
| - bool is_own_resource = frame_url.GetOrigin() == extension->url() ||
|
| - page_origin == extension->url();
|
| - // - devtools (chrome-extension:// URLs are loaded into frames of devtools
|
| - // to support the devtools extension APIs)
|
| - bool is_dev_tools =
|
| - page_origin.SchemeIs(content::kChromeDevToolsScheme) &&
|
| - !chrome_manifest_urls::GetDevToolsPage(extension).is_empty();
|
| - bool transition_allowed =
|
| - !ui::PageTransitionIsWebTriggerable(transition_type);
|
| - // - unreachable web page error page (to allow showing the icon of the
|
| - // unreachable app on this page)
|
| - bool is_error_page = frame_url == content::kUnreachableWebDataURL;
|
| -
|
| - if (!is_empty_origin && !is_own_resource &&
|
| - !is_dev_tools && !transition_allowed && !is_error_page) {
|
| - std::string message = base::StringPrintf(
|
| - "Denying load of %s. Resources must be listed in the "
|
| - "web_accessible_resources manifest key in order to be loaded by "
|
| - "pages outside the extension.",
|
| - resource_url.spec().c_str());
|
| - frame->AddMessageToConsole(
|
| - blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError,
|
| - blink::WebString::FromUTF8(message)));
|
| - return false;
|
| - }
|
| + std::string message = base::StringPrintf(
|
| + "Denying load of %s. Resources must be listed in the "
|
| + "web_accessible_resources manifest key in order to be loaded by "
|
| + "pages outside the extension.",
|
| + resource_url.spec().c_str());
|
| + frame->AddMessageToConsole(
|
| + blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError,
|
| + blink::WebString::FromUTF8(message)));
|
| + return false;
|
| }
|
|
|
| return true;
|
|
|