summaryrefslogtreecommitdiffstats
path: root/chrome/browser/renderer_host
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-15 21:09:56 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-15 21:09:56 +0000
commit07578ba5d0ee4653a6c22899c4991b4d20163388 (patch)
tree4bb9cf3620bbf97597dee958614449c26a818fcf /chrome/browser/renderer_host
parentd906d5217d397250c6569ce93f9d1af80a407d0c (diff)
downloadchromium_src-07578ba5d0ee4653a6c22899c4991b4d20163388.zip
chromium_src-07578ba5d0ee4653a6c22899c4991b4d20163388.tar.gz
chromium_src-07578ba5d0ee4653a6c22899c4991b4d20163388.tar.bz2
revert r16181 as it broke linux
TBR=jam Review URL: http://codereview.chromium.org/115418 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16183 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host')
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc6
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc32
-rw-r--r--chrome/browser/renderer_host/renderer_security_policy.cc292
-rw-r--r--chrome/browser/renderer_host/renderer_security_policy.h127
-rw-r--r--chrome/browser/renderer_host/renderer_security_policy_unittest.cc268
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc8
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc8
7 files changed, 714 insertions, 27 deletions
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index e1c9bd9..6ae9d1b 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -27,7 +27,6 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/history/history.h"
@@ -36,6 +35,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_helper.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/visitedlink_master.h"
@@ -155,7 +155,7 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
BrowserRenderProcessHost::~BrowserRenderProcessHost() {
if (pid() >= 0) {
WebCacheManager::GetInstance()->Remove(pid());
- ChildProcessSecurityPolicy::GetInstance()->Remove(pid());
+ RendererSecurityPolicy::GetInstance()->Remove(pid());
}
// We may have some unsent messages at this point, but that's OK.
@@ -342,7 +342,7 @@ bool BrowserRenderProcessHost::Init() {
resource_message_filter->Init(pid());
WebCacheManager::GetInstance()->Add(pid());
- ChildProcessSecurityPolicy::GetInstance()->Add(pid());
+ RendererSecurityPolicy::GetInstance()->Add(pid());
// Now that the process is created, set its backgrounding accordingly.
SetBackgrounded(backgrounded_);
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index 11f8754..5fee2fb 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -14,13 +14,13 @@
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/cross_site_request_manager.h"
#include "chrome/browser/debugger/debugger_wrapper.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -48,7 +48,7 @@ using WebKit::WebInputEvent;
namespace {
-void FilterURL(ChildProcessSecurityPolicy* policy, int renderer_id, GURL* url) {
+void FilterURL(RendererSecurityPolicy* policy, int renderer_id, GURL* url) {
if (!url->is_valid())
return; // We don't need to block invalid URLs.
@@ -140,7 +140,7 @@ bool RenderViewHost::CreateRenderView() {
DCHECK(process()->profile());
if (enabled_bindings_ & BindingsPolicy::DOM_UI) {
- ChildProcessSecurityPolicy::GetInstance()->GrantDOMUIBindings(
+ RendererSecurityPolicy::GetInstance()->GrantDOMUIBindings(
process()->pid());
}
@@ -196,7 +196,7 @@ void RenderViewHost::NavigateToEntry(const NavigationEntry& entry,
ViewMsg_Navigate_Params params;
MakeNavigateParams(entry, is_reload, &params);
- ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL(
+ RendererSecurityPolicy::GetInstance()->GrantRequestURL(
process()->pid(), params.url);
DoNavigate(entry.url(), new ViewMsg_Navigate(routing_id(), params));
@@ -209,7 +209,7 @@ void RenderViewHost::NavigateToURL(const GURL& url) {
params.transition = PageTransition::LINK;
params.reload = false;
- ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL(
+ RendererSecurityPolicy::GetInstance()->GrantRequestURL(
process()->pid(), params.url);
DoNavigate(url, new ViewMsg_Navigate(routing_id(), params));
@@ -396,7 +396,7 @@ void RenderViewHost::DragTargetDragEnter(
const gfx::Point& client_pt,
const gfx::Point& screen_pt) {
// Grant the renderer the ability to load the drop_data.
- ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance();
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
policy->GrantRequestURL(process()->pid(), drop_data.url);
for (std::vector<string16>::const_iterator iter(drop_data.filenames.begin());
iter != drop_data.filenames.end(); ++iter) {
@@ -568,7 +568,7 @@ void RenderViewHost::InspectElementAt(int x, int y) {
DevToolsManager* manager = g_browser_process->devtools_manager();
manager->InspectElement(this, x, y);
} else {
- ChildProcessSecurityPolicy::GetInstance()->
+ RendererSecurityPolicy::GetInstance()->
GrantInspectElement(process()->pid());
Send(new ViewMsg_InspectElement(routing_id(), x, y));
}
@@ -580,7 +580,7 @@ void RenderViewHost::ShowJavaScriptConsole() {
DevToolsManager* manager = g_browser_process->devtools_manager();
manager->OpenDevToolsWindow(this);
} else {
- ChildProcessSecurityPolicy::GetInstance()->
+ RendererSecurityPolicy::GetInstance()->
GrantInspectElement(process()->pid());
Send(new ViewMsg_ShowJavaScriptConsole(routing_id()));
}
@@ -668,7 +668,7 @@ void RenderViewHost::InstallMissingPlugin() {
}
void RenderViewHost::FileSelected(const FilePath& path) {
- ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(process()->pid(),
+ RendererSecurityPolicy::GetInstance()->GrantUploadFile(process()->pid(),
path);
std::vector<FilePath> files;
files.push_back(path);
@@ -679,7 +679,7 @@ void RenderViewHost::MultiFilesSelected(
const std::vector<FilePath>& files) {
for (std::vector<FilePath>::const_iterator file = files.begin();
file != files.end(); ++file) {
- ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(
+ RendererSecurityPolicy::GetInstance()->GrantUploadFile(
process()->pid(), *file);
}
Send(new ViewMsg_RunFileChooserResponse(routing_id(), files));
@@ -906,7 +906,7 @@ void RenderViewHost::OnMsgNavigate(const IPC::Message& msg) {
return;
const int renderer_id = process()->pid();
- ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance();
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
// Without this check, an evil renderer can trick the browser into creating
// a navigation entry for a banned URL. If the user clicks the back button
// followed by the forward button (or clicks reload, or round-trips through
@@ -1002,7 +1002,7 @@ void RenderViewHost::OnMsgDidLoadResourceFromMemoryCache(
void RenderViewHost::OnMsgDidStartProvisionalLoadForFrame(bool is_main_frame,
const GURL& url) {
GURL validated_url(url);
- FilterURL(ChildProcessSecurityPolicy::GetInstance(),
+ FilterURL(RendererSecurityPolicy::GetInstance(),
process()->pid(), &validated_url);
delegate_->DidStartProvisionalLoadForFrame(this, is_main_frame,
@@ -1015,7 +1015,7 @@ void RenderViewHost::OnMsgDidFailProvisionalLoadWithError(
const GURL& url,
bool showing_repost_interstitial) {
GURL validated_url(url);
- FilterURL(ChildProcessSecurityPolicy::GetInstance(),
+ FilterURL(RendererSecurityPolicy::GetInstance(),
process()->pid(), &validated_url);
delegate_->DidFailProvisionalLoadWithError(this, is_main_frame,
@@ -1062,7 +1062,7 @@ void RenderViewHost::OnMsgContextMenu(const ContextMenuParams& params) {
// directly, don't show them in the context menu.
ContextMenuParams validated_params(params);
const int renderer_id = process()->pid();
- ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance();
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
// We don't validate |unfiltered_link_url| so that this field can be used
// when users want to copy the original link URL.
@@ -1078,7 +1078,7 @@ void RenderViewHost::OnMsgOpenURL(const GURL& url,
const GURL& referrer,
WindowOpenDisposition disposition) {
GURL validated_url(url);
- FilterURL(ChildProcessSecurityPolicy::GetInstance(),
+ FilterURL(RendererSecurityPolicy::GetInstance(),
process()->pid(), &validated_url);
delegate_->RequestOpenURL(validated_url, referrer, disposition);
@@ -1098,7 +1098,7 @@ void RenderViewHost::OnMsgDomOperationResponse(
void RenderViewHost::OnMsgDOMUISend(
const std::string& message, const std::string& content) {
- if (!ChildProcessSecurityPolicy::GetInstance()->
+ if (!RendererSecurityPolicy::GetInstance()->
HasDOMUIBindings(process()->pid())) {
NOTREACHED() << "Blocked unauthorized use of DOMUIBindings.";
return;
diff --git a/chrome/browser/renderer_host/renderer_security_policy.cc b/chrome/browser/renderer_host/renderer_security_policy.cc
new file mode 100644
index 0000000..dd988ff
--- /dev/null
+++ b/chrome/browser/renderer_host/renderer_security_policy.cc
@@ -0,0 +1,292 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "base/string_util.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request.h"
+
+// The SecurityState class is used to maintain per-renderer security state
+// information.
+class RendererSecurityPolicy::SecurityState {
+ public:
+ SecurityState() : has_dom_ui_bindings_(false) { }
+ ~SecurityState() {
+ scheme_policy_.clear();
+ }
+
+ // Grant permission to request URLs with the specified scheme.
+ void GrantScheme(const std::string& scheme) {
+ scheme_policy_[scheme] = true;
+ }
+
+ // Revoke permission to request URLs with the specified scheme.
+ void RevokeScheme(const std::string& scheme) {
+ scheme_policy_[scheme] = false;
+ }
+
+ // Grant permission to upload the specified file to the web.
+ void GrantUploadFile(const FilePath& file) {
+ uploadable_files_.insert(file);
+ }
+
+ void GrantDOMUIBindings() {
+ has_dom_ui_bindings_ = true;
+ }
+
+ // Determine whether permission has been granted to request url.
+ // Schemes that have not been granted default to being denied.
+ bool CanRequestURL(const GURL& url) {
+ SchemeMap::const_iterator judgment(scheme_policy_.find(url.scheme()));
+
+ if (judgment == scheme_policy_.end())
+ return false; // Unmentioned schemes are disallowed.
+
+ return judgment->second;
+ }
+
+ // Determine whether permission has been granted to upload file.
+ // Files that have not been granted default to being denied.
+ bool CanUploadFile(const FilePath& file) {
+ return uploadable_files_.find(file) != uploadable_files_.end();
+ }
+
+ bool has_dom_ui_bindings() const { return has_dom_ui_bindings_; }
+
+ private:
+ typedef std::map<std::string, bool> SchemeMap;
+ typedef std::set<FilePath> FileSet;
+
+ // Maps URL schemes to whether permission has been granted or revoked:
+ // |true| means the scheme has been granted.
+ // |false| means the scheme has been revoked.
+ // If a scheme is not present in the map, then it has never been granted
+ // or revoked.
+ SchemeMap scheme_policy_;
+
+ // The set of files the renderer is permited to upload to the web.
+ FileSet uploadable_files_;
+
+ bool has_dom_ui_bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(SecurityState);
+};
+
+RendererSecurityPolicy::RendererSecurityPolicy() {
+ // We know about these schemes and believe them to be safe.
+ RegisterWebSafeScheme(chrome::kHttpScheme);
+ RegisterWebSafeScheme(chrome::kHttpsScheme);
+ RegisterWebSafeScheme(chrome::kFtpScheme);
+ RegisterWebSafeScheme(chrome::kDataScheme);
+ RegisterWebSafeScheme("feed");
+ RegisterWebSafeScheme("chrome-extension");
+
+ // We know about the following psuedo schemes and treat them specially.
+ RegisterPseudoScheme(chrome::kAboutScheme);
+ RegisterPseudoScheme(chrome::kJavaScriptScheme);
+ RegisterPseudoScheme(chrome::kViewSourceScheme);
+}
+
+RendererSecurityPolicy::~RendererSecurityPolicy() {
+ web_safe_schemes_.clear();
+ pseudo_schemes_.clear();
+ STLDeleteContainerPairSecondPointers(security_state_.begin(),
+ security_state_.end());
+ security_state_.clear();
+}
+
+// static
+RendererSecurityPolicy* RendererSecurityPolicy::GetInstance() {
+ return Singleton<RendererSecurityPolicy>::get();
+}
+
+void RendererSecurityPolicy::Add(int renderer_id) {
+ AutoLock lock(lock_);
+ if (security_state_.count(renderer_id) != 0) {
+ NOTREACHED() << "Add renderers at most once.";
+ return;
+ }
+
+ security_state_[renderer_id] = new SecurityState();
+}
+
+void RendererSecurityPolicy::Remove(int renderer_id) {
+ AutoLock lock(lock_);
+ if (security_state_.count(renderer_id) != 1) {
+ NOTREACHED() << "Remove renderers at most once.";
+ return;
+ }
+
+ delete security_state_[renderer_id];
+ security_state_.erase(renderer_id);
+}
+
+void RendererSecurityPolicy::RegisterWebSafeScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+ DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once.";
+ DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not psuedo.";
+
+ web_safe_schemes_.insert(scheme);
+}
+
+bool RendererSecurityPolicy::IsWebSafeScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+
+ return (web_safe_schemes_.find(scheme) != web_safe_schemes_.end());
+}
+
+void RendererSecurityPolicy::RegisterPseudoScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+ DCHECK(pseudo_schemes_.count(scheme) == 0) << "Add schemes at most once.";
+ DCHECK(web_safe_schemes_.count(scheme) == 0) <<
+ "Psuedo implies not web-safe.";
+
+ pseudo_schemes_.insert(scheme);
+}
+
+bool RendererSecurityPolicy::IsPseudoScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+
+ return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end());
+}
+
+void RendererSecurityPolicy::GrantRequestURL(int renderer_id, const GURL& url) {
+
+ if (!url.is_valid())
+ return; // Can't grant the capability to request invalid URLs.
+
+ if (IsWebSafeScheme(url.scheme()))
+ return; // The scheme has already been white-listed for every renderer.
+
+ if (IsPseudoScheme(url.scheme())) {
+ // The view-source scheme is a special case of a pseudo URL that eventually
+ // results in requesting its embedded URL.
+ if (url.SchemeIs(chrome::kViewSourceScheme)) {
+ // URLs with the view-source scheme typically look like:
+ // view-source:http://www.google.com/a
+ // In order to request these URLs, the renderer needs to be able to
+ // request the embedded URL.
+ GrantRequestURL(renderer_id, GURL(url.path()));
+ }
+
+ return; // Can't grant the capability to request pseudo schemes.
+ }
+
+ {
+ AutoLock lock(lock_);
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ // If the renderer has been commanded to request a scheme, then we grant
+ // it the capability to request URLs of that scheme.
+ state->second->GrantScheme(url.scheme());
+ }
+}
+
+void RendererSecurityPolicy::GrantUploadFile(int renderer_id,
+ const FilePath& file) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ state->second->GrantUploadFile(file);
+}
+
+void RendererSecurityPolicy::GrantInspectElement(int renderer_id) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ // The inspector is served from a chrome: URL. In order to run the
+ // inspector, the renderer needs to be able to load chrome: URLs.
+ state->second->GrantScheme(chrome::kChromeUIScheme);
+}
+
+void RendererSecurityPolicy::GrantDOMUIBindings(int renderer_id) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ state->second->GrantDOMUIBindings();
+
+ // DOM UI bindings need the ability to request chrome: URLs.
+ state->second->GrantScheme(chrome::kChromeUIScheme);
+
+ // DOM UI pages can contain links to file:// URLs.
+ state->second->GrantScheme(chrome::kFileScheme);
+}
+
+bool RendererSecurityPolicy::CanRequestURL(int renderer_id, const GURL& url) {
+ if (!url.is_valid())
+ return false; // Can't request invalid URLs.
+
+ if (IsWebSafeScheme(url.scheme()))
+ return true; // The scheme has been white-listed for every renderer.
+
+ if (IsPseudoScheme(url.scheme())) {
+ // There are a number of special cases for pseudo schemes.
+
+ if (url.SchemeIs(chrome::kViewSourceScheme)) {
+ // A view-source URL is allowed if the renderer is permitted to request
+ // the embedded URL.
+ return CanRequestURL(renderer_id, GURL(url.path()));
+ }
+
+ if (LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL))
+ return true; // Every renderer can request <about:blank>.
+
+ // URLs like <about:memory> and <about:crash> shouldn't be requestable by
+ // any renderer. Also, this case covers <javascript:...>, which should be
+ // handled internally by the renderer and not kicked up to the browser.
+ return false;
+ }
+
+ if (!URLRequest::IsHandledURL(url))
+ return true; // This URL request is destined for ShellExecute.
+
+ {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return false;
+
+ // Otherwise, we consult the renderer's security state to see if it is
+ // allowed to request the URL.
+ return state->second->CanRequestURL(url);
+ }
+}
+
+bool RendererSecurityPolicy::CanUploadFile(int renderer_id,
+ const FilePath& file) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return false;
+
+ return state->second->CanUploadFile(file);
+}
+
+bool RendererSecurityPolicy::HasDOMUIBindings(int renderer_id) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return false;
+
+ return state->second->has_dom_ui_bindings();
+}
diff --git a/chrome/browser/renderer_host/renderer_security_policy.h b/chrome/browser/renderer_host/renderer_security_policy.h
new file mode 100644
index 0000000..41cf04e
--- /dev/null
+++ b/chrome/browser/renderer_host/renderer_security_policy.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDERER_SECURITY_POLICY_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDERER_SECURITY_POLICY_H_
+
+#include <string>
+#include <map>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/lock.h"
+#include "base/singleton.h"
+
+class FilePath;
+class GURL;
+
+// The RendererSecurityPolicy class is used to grant and revoke security
+// capabilities for renderers. For example, it restricts whether a renderer
+// is permmitted to loaded file:// URLs based on whether the renderer has ever
+// been commanded to load file:// URLs by the browser.
+//
+// RendererSecurityPolicy is a singleton that may be used on any thread.
+//
+class RendererSecurityPolicy {
+ public:
+ // Object can only be created through GetInstance() so the constructor is
+ // private.
+ ~RendererSecurityPolicy();
+
+ // There is one global RendererSecurityPolicy object for the entire browser
+ // processes. The object returned by this method may be accessed on any
+ // thread.
+ static RendererSecurityPolicy* GetInstance();
+
+ // Web-safe schemes can be requested by any renderer. Once a web-safe scheme
+ // has been registered, any renderer processes can request URLs with that
+ // scheme. There is no mechanism for revoking web-safe schemes.
+ void RegisterWebSafeScheme(const std::string& scheme);
+
+ // Returns true iff |scheme| has been registered as a web-safe scheme.
+ bool IsWebSafeScheme(const std::string& scheme);
+
+ // Pseudo schemes are treated differently than other schemes because they
+ // cannot be requested like normal URLs. There is no mechanism for revoking
+ // pseudo schemes.
+ void RegisterPseudoScheme(const std::string& scheme);
+
+ // Returns true iff |scheme| has been registered as pseudo scheme.
+ bool IsPseudoScheme(const std::string& scheme);
+
+ // Upon creation, render processes should register themselves by calling this
+ // this method exactly once.
+ void Add(int renderer_id);
+
+ // Upon destruction, render processess should unregister themselves by caling
+ // this method exactly once.
+ void Remove(int renderer_id);
+
+ // Whenever the browser processes commands the renderer to request a URL, it
+ // should call this method to grant the renderer process the capability to
+ // request the URL.
+ void GrantRequestURL(int renderer_id, const GURL& url);
+
+ // Whenever the user picks a file from a <input type="file"> element, the
+ // browser should call this function to grant the renderer the capability to
+ // upload the file to the web.
+ void GrantUploadFile(int renderer_id, const FilePath& file);
+
+ // Whenever the browser processes commands the renderer to run web inspector,
+ // it should call this method to grant the renderer process the capability to
+ // run the inspector.
+ void GrantInspectElement(int renderer_id);
+
+ // Grant this renderer the ability to use DOM UI Bindings.
+ void GrantDOMUIBindings(int renderer_id);
+
+ // Before servicing a renderer's request for a URL, the browser should call
+ // this method to determine whether the renderer has the capability to
+ // request the URL.
+ bool CanRequestURL(int renderer_id, const GURL& url);
+
+ // Before servicing a renderer's request to upload a file to the web, the
+ // browser should call this method to determine whether the renderer has the
+ // capability to upload the requested file.
+ bool CanUploadFile(int renderer_id, const FilePath& file);
+
+ // Returns true of the specified renderer_id has been granted DOMUIBindings.
+ // The browser should check this property before assuming the renderer is
+ // allowed to use DOMUIBindings.
+ bool HasDOMUIBindings(int renderer_id);
+
+ private:
+ class SecurityState;
+
+ typedef std::set<std::string> SchemeSet;
+ typedef std::map<int, SecurityState*> SecurityStateMap;
+
+ // Obtain an instance of RendererSecurityPolicy via GetInstance().
+ RendererSecurityPolicy();
+ friend struct DefaultSingletonTraits<RendererSecurityPolicy>;
+
+ // You must acquire this lock before reading or writing any members of this
+ // class. You must not block while holding this lock.
+ Lock lock_;
+
+ // These schemes are white-listed for all renderers. This set is protected
+ // by |lock_|.
+ SchemeSet web_safe_schemes_;
+
+ // These schemes do not actually represent retrievable URLs. For example,
+ // the the URLs in the "about" scheme are aliases to other URLs. This set is
+ // protected by |lock_|.
+ SchemeSet pseudo_schemes_;
+
+ // This map holds a SecurityState for each renderer process. The key for the
+ // map is the ID of the RenderProcessHost. The SecurityState objects are
+ // owned by this object and are protected by |lock_|. References to them must
+ // not escape this class.
+ SecurityStateMap security_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererSecurityPolicy);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDERER_SECURITY_POLICY_H_
diff --git a/chrome/browser/renderer_host/renderer_security_policy_unittest.cc b/chrome/browser/renderer_host/renderer_security_policy_unittest.cc
new file mode 100644
index 0000000..2144229
--- /dev/null
+++ b/chrome/browser/renderer_host/renderer_security_policy_unittest.cc
@@ -0,0 +1,268 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
+#include "chrome/common/url_constants.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_job.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class RendererSecurityPolicyTest : public testing::Test {
+protected:
+ // testing::Test
+ virtual void SetUp() {
+ // In the real world, "chrome:" is a handled scheme.
+ URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme,
+ &URLRequestTestJob::Factory);
+ }
+ virtual void TearDown() {
+ URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme, NULL);
+ }
+};
+
+static int kRendererID = 42;
+
+TEST_F(RendererSecurityPolicyTest, IsWebSafeSchemeTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ EXPECT_TRUE(p->IsWebSafeScheme("http"));
+ EXPECT_TRUE(p->IsWebSafeScheme("https"));
+ EXPECT_TRUE(p->IsWebSafeScheme("ftp"));
+ EXPECT_TRUE(p->IsWebSafeScheme("data"));
+ EXPECT_TRUE(p->IsWebSafeScheme("feed"));
+ EXPECT_TRUE(p->IsWebSafeScheme("chrome-extension"));
+
+ EXPECT_FALSE(p->IsWebSafeScheme("registered-web-safe-scheme"));
+ p->RegisterWebSafeScheme("registered-web-safe-scheme");
+ EXPECT_TRUE(p->IsWebSafeScheme("registered-web-safe-scheme"));
+}
+
+TEST_F(RendererSecurityPolicyTest, IsPseudoSchemeTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ EXPECT_TRUE(p->IsPseudoScheme("about"));
+ EXPECT_TRUE(p->IsPseudoScheme("javascript"));
+ EXPECT_TRUE(p->IsPseudoScheme("view-source"));
+
+ EXPECT_FALSE(p->IsPseudoScheme("registered-psuedo-scheme"));
+ p->RegisterPseudoScheme("registered-psuedo-scheme");
+ EXPECT_TRUE(p->IsPseudoScheme("registered-psuedo-scheme"));
+}
+
+TEST_F(RendererSecurityPolicyTest, StandardSchemesTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ // Safe
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("http://www.google.com/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("https://www.paypal.com/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("ftp://ftp.gnu.org/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("data:text/html,<b>Hi</b>")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID,
+ GURL("view-source:http://www.google.com/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("chrome-extension://xy/z")));
+
+ // Dangerous
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("file:///etc/passwd")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("view-cache:http://www.google.com/")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("chrome://foo/bar")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, AboutTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("about:blank")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("about:BlAnK")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("aBouT:BlAnK")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("aBouT:blank")));
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:memory")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:cache")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:hang")));
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("aBoUt:memory")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:CrASh")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("abOuT:cAChe")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:memory"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:memory")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:crash"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:cache"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:cache")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:hang"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:hang")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, JavaScriptTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("javascript:alert('xss')")));
+ p->GrantRequestURL(kRendererID, GURL("javascript:alert('xss')"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("javascript:alert('xss')")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, RegisterWebSafeSchemeTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ // Currently, "asdf" is destined for ShellExecute, so it is allowed.
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ // Once we register a ProtocolFactory for "asdf", we default to deny.
+ URLRequest::RegisterProtocolFactory("asdf", &URLRequestTestJob::Factory);
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ // We can allow new schemes by adding them to the whitelist.
+ p->RegisterWebSafeScheme("asdf");
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ // Cleanup.
+ URLRequest::RegisterProtocolFactory("asdf", NULL);
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanServiceCommandsTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+ p->GrantRequestURL(kRendererID, GURL("file:///etc/passwd"));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+
+ // We should forget our state if we repeat a renderer id.
+ p->Remove(kRendererID);
+ p->Add(kRendererID);
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, ViewSource) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ // View source is determined by the embedded scheme.
+ EXPECT_TRUE(p->CanRequestURL(kRendererID,
+ GURL("view-source:http://www.google.com/")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("view-source:file:///etc/passwd")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+
+ p->GrantRequestURL(kRendererID, GURL("view-source:file:///etc/passwd"));
+ // View source needs to be able to request the embedded scheme.
+ EXPECT_TRUE(p->CanRequestURL(kRendererID,
+ GURL("view-source:file:///etc/passwd")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanUploadFiles) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ FilePath(FILE_PATH_LITERAL("/etc/passwd"))));
+ p->GrantUploadFile(kRendererID, FilePath(FILE_PATH_LITERAL("/etc/passwd")));
+ EXPECT_TRUE(p->CanUploadFile(kRendererID,
+ FilePath(FILE_PATH_LITERAL("/etc/passwd"))));
+ EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ FilePath(FILE_PATH_LITERAL("/etc/shadow"))));
+
+ p->Remove(kRendererID);
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ FilePath(FILE_PATH_LITERAL("/etc/passwd"))));
+ EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ FilePath(FILE_PATH_LITERAL("/etc/shadow"))));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanServiceInspectElement) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ GURL url("chrome://inspector/inspector.html");
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
+ p->GrantInspectElement(kRendererID);
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanServiceDOMUIBindings) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ GURL url("chrome://thumb/http://www.google.com/");
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->HasDOMUIBindings(kRendererID));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
+ p->GrantDOMUIBindings(kRendererID);
+ EXPECT_TRUE(p->HasDOMUIBindings(kRendererID));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, RemoveRace) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ GURL url("file:///etc/passwd");
+ FilePath file(FILE_PATH_LITERAL("/etc/passwd"));
+
+ p->Add(kRendererID);
+
+ p->GrantRequestURL(kRendererID, url);
+ p->GrantUploadFile(kRendererID, file);
+ p->GrantDOMUIBindings(kRendererID);
+
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
+ EXPECT_TRUE(p->CanUploadFile(kRendererID, file));
+ EXPECT_TRUE(p->HasDOMUIBindings(kRendererID));
+
+ p->Remove(kRendererID);
+
+ // Renderers are added and removed on the UI thread, but the policy can be
+ // queried on the IO thread. The RendererSecurityPolicy needs to be prepared
+ // to answer policy questions about renderers who no longer exist.
+
+ // In this case, we default to secure behavior.
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
+ EXPECT_FALSE(p->CanUploadFile(kRendererID, file));
+ EXPECT_FALSE(p->HasDOMUIBindings(kRendererID));
+}
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index e091819..3f0075b 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -13,7 +13,6 @@
#include "base/stl_util-inl.h"
#include "base/time.h"
#include "chrome/browser/cert_store.h"
-#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/cross_site_request_manager.h"
#include "chrome/browser/download/download_file.h"
#include "chrome/browser/download/download_manager.h"
@@ -28,6 +27,7 @@
#include "chrome/browser/renderer_host/download_resource_handler.h"
#include "chrome/browser/renderer_host/media_resource_handler.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
#include "chrome/browser/renderer_host/resource_request_details.h"
#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
#include "chrome/browser/renderer_host/save_file_resource_handler.h"
@@ -109,7 +109,7 @@ bool ShouldServiceRequest(ChildProcessInfo::ProcessType process_type,
if (process_type != ChildProcessInfo::RENDER_PROCESS)
return true;
- ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance();
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
// Check if the renderer is permitted to request the requested URL.
if (!policy->CanRequestURL(process_id, request_data.url)) {
@@ -484,7 +484,7 @@ void ResourceDispatcherHost::BeginDownload(const GURL& url,
return;
// Check if the renderer is permitted to request the requested URL.
- if (!ChildProcessSecurityPolicy::GetInstance()->
+ if (!RendererSecurityPolicy::GetInstance()->
CanRequestURL(process_id, url)) {
LOG(INFO) << "Denied unauthorized download request for " <<
url.possibly_invalid_spec();
@@ -821,7 +821,7 @@ void ResourceDispatcherHost::OnReceivedRedirect(URLRequest* request,
DCHECK(request->status().is_success());
if (info->process_type == ChildProcessInfo::RENDER_PROCESS &&
- !ChildProcessSecurityPolicy::GetInstance()->
+ !RendererSecurityPolicy::GetInstance()->
CanRequestURL(info->process_id, new_url)) {
LOG(INFO) << "Denied unauthorized request for " <<
new_url.possibly_invalid_spec();
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
index 6278d3e..1e2b458 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -7,7 +7,7 @@
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/process_util.h"
-#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/render_messages.h"
@@ -112,13 +112,13 @@ class ResourceDispatcherHostTest : public testing::Test,
protected:
// testing::Test
virtual void SetUp() {
- ChildProcessSecurityPolicy::GetInstance()->Add(0);
+ RendererSecurityPolicy::GetInstance()->Add(0);
URLRequest::RegisterProtocolFactory("test", &URLRequestTestJob::Factory);
EnsureTestSchemeIsAllowed();
}
virtual void TearDown() {
URLRequest::RegisterProtocolFactory("test", NULL);
- ChildProcessSecurityPolicy::GetInstance()->Remove(0);
+ RendererSecurityPolicy::GetInstance()->Remove(0);
// The plugin lib is automatically loaded during these test
// and we want a clean environment for other tests.
@@ -143,7 +143,7 @@ class ResourceDispatcherHostTest : public testing::Test,
static bool have_white_listed_test_scheme = false;
if (!have_white_listed_test_scheme) {
- ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme("test");
+ RendererSecurityPolicy::GetInstance()->RegisterWebSafeScheme("test");
have_white_listed_test_scheme = true;
}
}