diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-23 21:31:06 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-23 21:31:06 +0000 |
commit | af7eb3fb5d0666d37b5c754c2976cc1276b66323 (patch) | |
tree | 4623bf0e86a9e20a5c94090b43094da34b26871c /chrome/renderer | |
parent | 943ca53d131a04f71e18fd140780b39304492ec1 (diff) | |
download | chromium_src-af7eb3fb5d0666d37b5c754c2976cc1276b66323.zip chromium_src-af7eb3fb5d0666d37b5c754c2976cc1276b66323.tar.gz chromium_src-af7eb3fb5d0666d37b5c754c2976cc1276b66323.tar.bz2 |
Trying to reland r59889, this time as a multi-stage patch.
Fix regression introduced by
http://src.chromium.org/viewvc/chrome?view=rev&revision=57788
Add a delegate interface so that chromium have more fine-grained control over
whether a V8 extension is injected into a script context. This is the
chromium-side change of webkit bug
https://bugs.webkit.org/show_bug.cgi?id=45721
BUG=37290
TEST=covered by unit tests
Review URL: http://codereview.chromium.org/3464005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60350 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/extensions/event_bindings.cc | 24 | ||||
-rw-r--r-- | chrome/renderer/render_thread.cc | 110 | ||||
-rw-r--r-- | chrome/renderer/render_thread.h | 21 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 17 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 3 |
5 files changed, 100 insertions, 75 deletions
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 54edbb4..6f3b7e3 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -262,18 +262,11 @@ void EventBindings::HandleContextCreated(WebFrame* frame, bool content_script) { GURL url = ds->request().url(); std::string extension_id = ExtensionRendererInfo::GetIdByURL(url); - // Note: because process isolation doesn't work correcly with redirects, - // it is possible that a page that IS in an extension process won't have - // bindings setup for it, so we must also check IsExtensionProcess, otherwise - // we'll attempt to invoke a JS function that doesn't exist. - // Fixing crbug.com/53610 should fix this as well. - RenderThread* current_thread = RenderThread::current(); - if ((!current_thread || - !current_thread->IsExtensionProcess() || - !ExtensionRendererInfo::ExtensionBindingsAllowed(url)) && + if (!ExtensionRendererInfo::ExtensionBindingsAllowed(url) && !content_script) { - // This context is a regular non-extension web page. Ignore it. We only - // care about content scripts and extension frames. + // This context is a regular non-extension web page or an unprivileged + // chrome app. Ignore it. We only care about content scripts and extension + // frames. // (Unless we're in unit tests, in which case we don't care what the URL // is). DCHECK(frame_context.IsEmpty() || frame_context == context); @@ -305,9 +298,12 @@ void EventBindings::HandleContextCreated(WebFrame* frame, bool content_script) { new ContextInfo(persistent_context, extension_id, parent_frame, render_view))); - v8::Handle<v8::Value> argv[1]; - argv[0] = v8::String::New(extension_id.c_str()); - CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv); + // Content scripts get initialized in user_script_slave.cc. + if (!content_script) { + v8::Handle<v8::Value> argv[1]; + argv[0] = v8::String::New(extension_id.c_str()); + CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv); + } } // static diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 2729d14..6fdecc5 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -849,80 +849,40 @@ void RenderThread::EnsureWebKitInitialized() { #if defined(OS_WIN) // We don't yet support Gears on non-Windows, so don't tell pages that we do. - WebScriptController::registerExtension(extensions_v8::GearsExtension::Get()); + RegisterExtension(extensions_v8::GearsExtension::Get(), false); #endif - WebScriptController::registerExtension( - extensions_v8::LoadTimesExtension::Get()); - WebScriptController::registerExtension( - extensions_v8::ChromeAppExtension::Get()); - WebScriptController::registerExtension( - extensions_v8::ExternalExtension::Get()); + RegisterExtension(extensions_v8::LoadTimesExtension::Get(), false); + RegisterExtension(extensions_v8::ChromeAppExtension::Get(), false); + RegisterExtension(extensions_v8::ExternalExtension::Get(), false); v8::Extension* search_extension = extensions_v8::SearchExtension::Get(); // search_extension is null if not enabled. if (search_extension) - WebScriptController::registerExtension(search_extension); - - // TODO(rafaelw). Note that extension-related v8 extensions are being - // bound currently based on is_extension_process_. This means that - // non-extension renderers that slip into an extension process (for example, - // an extension page opening an iframe) will be extension bindings setup. - // This should be relatively rare, and the offending page won't be able to - // make extension API requests because it'll be denied on both sides of - // the renderer by a permission check. However, this is still fairly lame - // and we should consider implementing a V8Proxy delegate that calls out - // to the render thread and makes a decision as to whether to bind these - // extensions based on the frame's url. - // See: crbug.com/53610. - - if (is_extension_process_) - WebScriptController::registerExtension(ExtensionProcessBindings::Get()); - - WebScriptController::registerExtension( - BaseJsV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS); - if (is_extension_process_) - WebScriptController::registerExtension(BaseJsV8Extension::Get()); - - WebScriptController::registerExtension( - JsonSchemaJsV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS); - if (is_extension_process_) - WebScriptController::registerExtension(JsonSchemaJsV8Extension::Get()); - - WebScriptController::registerExtension( - EventBindings::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS); - if (is_extension_process_) - WebScriptController::registerExtension(EventBindings::Get()); - - WebScriptController::registerExtension( - RendererExtensionBindings::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS); - if (is_extension_process_) - WebScriptController::registerExtension(RendererExtensionBindings::Get()); - - WebScriptController::registerExtension( - ExtensionApiTestV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS); - if (is_extension_process_) - WebScriptController::registerExtension( - ExtensionApiTestV8Extension::Get()); - - web_database_observer_impl_.reset(new WebDatabaseObserverImpl(this)); - WebKit::WebDatabase::setObserver(web_database_observer_impl_.get()); + RegisterExtension(search_extension, false); const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kEnableBenchmarking)) { - WebScriptController::registerExtension( - extensions_v8::BenchmarkingExtension::Get()); - } + if (command_line.HasSwitch(switches::kEnableBenchmarking)) + RegisterExtension(extensions_v8::BenchmarkingExtension::Get(), false); if (command_line.HasSwitch(switches::kPlaybackMode) || command_line.HasSwitch(switches::kRecordMode) || command_line.HasSwitch(switches::kNoJsRandomness)) { - WebScriptController::registerExtension( - extensions_v8::PlaybackExtension::Get()); + RegisterExtension(extensions_v8::PlaybackExtension::Get(), false); } - if (command_line.HasSwitch(switches::kDomAutomationController)) { - WebScriptController::registerExtension(DomAutomationV8Extension::Get()); - } + if (command_line.HasSwitch(switches::kDomAutomationController)) + RegisterExtension(DomAutomationV8Extension::Get(), false); + + // Add v8 extensions related to chrome extensions. + RegisterExtension(ExtensionProcessBindings::Get(), true); + RegisterExtension(BaseJsV8Extension::Get(), true); + RegisterExtension(JsonSchemaJsV8Extension::Get(), true); + RegisterExtension(EventBindings::Get(), true); + RegisterExtension(RendererExtensionBindings::Get(), true); + RegisterExtension(ExtensionApiTestV8Extension::Get(), true); + + web_database_observer_impl_.reset(new WebDatabaseObserverImpl(this)); + WebKit::WebDatabase::setObserver(web_database_observer_impl_.get()); WebRuntimeFeatures::enableMediaPlayer( RenderProcess::current()->HasInitializedMediaLibrary()); @@ -1119,3 +1079,31 @@ RenderThread::GetFileThreadMessageLoopProxy() { } return file_thread_->message_loop_proxy(); } + +bool RenderThread::AllowScriptExtension(const std::string& v8_extension_name, + const GURL& url, + int extension_group) { + // If we don't know about it, it was added by WebCore, so we should allow it. + if (v8_extensions_.find(v8_extension_name) == v8_extensions_.end()) + return true; + + // If the V8 extension is not restricted, allow it to run anywhere. + bool restrict_to_extensions = v8_extensions_[v8_extension_name]; + if (!restrict_to_extensions) + return true; + + // Extension-only bindings should be restricted to content scripts and + // extension-blessed URLs. + if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS || + ExtensionRendererInfo::ExtensionBindingsAllowed(url)) { + return true; + } + + return false; +} + +void RenderThread::RegisterExtension(v8::Extension* extension, + bool restrict_to_extensions) { + WebScriptController::registerExtension(extension); + v8_extensions_[extension->name()] = restrict_to_extensions; +} diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 6b28214..4572b49 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -6,6 +6,7 @@ #define CHROME_RENDERER_RENDER_THREAD_H_ #pragma once +#include <map> #include <string> #include <vector> @@ -60,6 +61,10 @@ namespace WebKit { class WebStorageEventDispatcher; } +namespace v8 { +class Extension; +} + // The RenderThreadBase is the minimal interface that a RenderView/Widget // expects from a render thread. The interface basically abstracts a way to send // and receive messages. @@ -231,6 +236,13 @@ class RenderThread : public RenderThreadBase, // on the renderer's main thread. scoped_refptr<base::MessageLoopProxy> GetFileThreadMessageLoopProxy(); + // This function is called for every registered V8 extension each time a new + // script context is created. Returns true if the given V8 extension is + // allowed to run on the given URL and extension group. + bool AllowScriptExtension(const std::string& v8_extension_name, + const GURL& url, + int extension_group); + private: virtual void OnControlMessageReceived(const IPC::Message& msg); @@ -311,6 +323,10 @@ class RenderThread : public RenderThreadBase, // Schedule a call to IdleHandler with the given initial delay. void ScheduleIdleHandler(double initial_delay_s); + // Registers the given V8 extension with WebKit, and also tracks what pages + // it is allowed to run on. + void RegisterExtension(v8::Extension* extension, bool restrict_to_extensions); + // These objects live solely on the render thread. scoped_ptr<ScopedRunnableMethodFactory<RenderThread> > task_factory_; scoped_ptr<VisitedLinkSlave> visited_link_slave_; @@ -371,6 +387,11 @@ class RenderThread : public RenderThreadBase, // A lazily initiated thread on which file operations are run. scoped_ptr<base::Thread> file_thread_; + // Map of registered v8 extensions. The key is the extension name. The value + // is true if the extension should be restricted to extension-related + // contexts. + std::map<std::string, bool> v8_extensions_; + DISALLOW_COPY_AND_ASSIGN(RenderThread); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index ae155e8..8dceb39 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -3408,6 +3408,23 @@ void RenderView::didCreateIsolatedScriptContext(WebFrame* frame) { EventBindings::HandleContextCreated(frame, true); } +bool RenderView::allowScriptExtension(WebFrame* frame, + const WebString& extension_name, + int extension_group) { + // NULL in unit tests. + if (!RenderThread::current()) + return true; + + // Note: we prefer the provisional URL here instead of the document URL + // because we might be currently loading an URL into a blank page. + // See http://code.google.com/p/chromium/issues/detail?id=10924 + WebDataSource* ds = frame->provisionalDataSource(); + if (!ds) + ds = frame->dataSource(); + return RenderThread::current()->AllowScriptExtension( + extension_name.utf8(), ds->request().url(), extension_group); +} + void RenderView::logCrossFramePropertyAccess(WebFrame* frame, WebFrame* target, bool cross_origin, diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 01f9655..bf43b2e 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -553,6 +553,9 @@ class RenderView : public RenderWidget, virtual void didCreateScriptContext(WebKit::WebFrame* frame); virtual void didDestroyScriptContext(WebKit::WebFrame* frame); virtual void didCreateIsolatedScriptContext(WebKit::WebFrame* frame); + virtual bool allowScriptExtension(WebKit::WebFrame*, + const WebKit::WebString& extension_name, + int extensionGroup); virtual void logCrossFramePropertyAccess( WebKit::WebFrame* frame, WebKit::WebFrame* target, |