diff options
19 files changed, 212 insertions, 15 deletions
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json index 4311177d..d533e4e 100644 --- a/chrome/app/policy/policy_templates.json +++ b/chrome/app/policy/policy_templates.json @@ -94,7 +94,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 84 +# For your editing convenience: highest ID currently used: 85 # # Placeholders: # The following placeholder strings are automatically substituted: @@ -234,6 +234,19 @@ 'desc': '''Disables use of the SPDY protocol in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.''', }, { + 'name': 'DisabledSchemes', + 'type': 'list', + 'supported_on': ['chrome.*:12-', 'chrome_os:0.11-'], + 'features': {'dynamic_refresh': 1}, + 'example_value': ['file', 'mailto'], + 'id': 85, + 'caption': '''Disable URL protocol schemes''', + 'desc': '''Disables the listed protocol schemes in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. + + URLs using a scheme from this list will not load and can not be navigated to.''', + 'label': '''List of disabled protocol schemes''', + }, + { 'name': 'JavascriptEnabled', 'type': 'main', 'supported_on': ['chrome.*:8-', 'chrome_os:0.11-'], diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index f45f30c..0f44325 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -63,6 +63,7 @@ #include "chrome/installer/util/google_update_constants.h" #include "content/browser/browser_child_process_host.h" #include "content/browser/browser_thread.h" +#include "content/browser/child_process_security_policy.h" #include "content/browser/plugin_service.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/resource_dispatcher_host.h" @@ -631,6 +632,8 @@ void BrowserProcessImpl::Observe(NotificationType type, if (*pref == prefs::kDefaultBrowserSettingEnabled) { if (local_state_->GetBoolean(prefs::kDefaultBrowserSettingEnabled)) ShellIntegration::SetAsDefaultBrowser(); + } else if (*pref == prefs::kDisabledSchemes) { + ApplyDisabledSchemesPolicy(); } } else { NOTREACHED(); @@ -869,6 +872,13 @@ void BrowserProcessImpl::CreateLocalState() { plugin_finder_disabled_pref_.Init(prefs::kDisablePluginFinder, local_state_.get(), NULL); plugin_finder_disabled_pref_.MoveToThread(BrowserThread::IO); + + // Initialize the preference for the disabled schemes policy, and + // load the initial policy on startup. + local_state_->RegisterListPref(prefs::kDisabledSchemes); + disabled_schemes_pref_.Init(prefs::kDisabledSchemes, local_state_.get(), + this); + ApplyDisabledSchemesPolicy(); } void BrowserProcessImpl::CreateIconManager() { @@ -951,6 +961,17 @@ bool BrowserProcessImpl::IsSafeBrowsingDetectionServiceEnabled() { #endif } +void BrowserProcessImpl::ApplyDisabledSchemesPolicy() { + std::set<std::string> schemes; + for (ListValue::const_iterator iter = (*disabled_schemes_pref_)->begin(); + iter != (*disabled_schemes_pref_)->end(); ++iter) { + std::string scheme; + if ((*iter)->GetAsString(&scheme)) + schemes.insert(scheme); + } + ChildProcessSecurityPolicy::GetInstance()->RegisterDisabledSchemes(schemes); +} + // The BrowserProcess object must outlive the file thread so we use traits // which don't do any management. DISABLE_RUNNABLE_METHOD_REFCOUNT(BrowserProcessImpl); diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 77dc71f..f0292c9 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h @@ -116,7 +116,6 @@ class BrowserProcessImpl : public BrowserProcess, bool ShouldClearLocalState(FilePath* profile_path); void CreateResourceDispatcherHost(); - void CreatePrefService(); void CreateMetricsService(); void CreateIOThread(); @@ -148,6 +147,8 @@ class BrowserProcessImpl : public BrowserProcess, bool IsSafeBrowsingDetectionServiceEnabled(); + void ApplyDisabledSchemesPolicy(); + #if defined(IPC_MESSAGE_LOG_ENABLED) void SetIPCLoggingEnabledForChildProcesses(bool enabled); #endif @@ -266,6 +267,9 @@ class BrowserProcessImpl : public BrowserProcess, // Monitors the state of the 'DisablePluginFinder' policy. BooleanPrefMember plugin_finder_disabled_pref_; + // Monitors the list of disabled schemes policy. + ListPrefMember disabled_schemes_pref_; + #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) base::RepeatingTimer<BrowserProcessImpl> autoupdate_timer_; diff --git a/chrome/browser/policy/config_dir_policy_provider_unittest.cc b/chrome/browser/policy/config_dir_policy_provider_unittest.cc index aa6354f..f6bbfc9 100644 --- a/chrome/browser/policy/config_dir_policy_provider_unittest.cc +++ b/chrome/browser/policy/config_dir_policy_provider_unittest.cc @@ -362,6 +362,9 @@ INSTANTIATE_TEST_CASE_P( key::kBookmarkBarEnabled), ValueTestParams::ForBooleanPolicy( kPolicyEditBookmarksEnabled, - key::kEditBookmarksEnabled))); + key::kEditBookmarksEnabled), + ValueTestParams::ForListPolicy( + kPolicyDisabledSchemes, + key::kDisabledSchemes))); } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc index d73ac28..cc41521 100644 --- a/chrome/browser/policy/configuration_policy_pref_store.cc +++ b/chrome/browser/policy/configuration_policy_pref_store.cc @@ -146,6 +146,8 @@ const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry prefs::kNetworkPredictionEnabled }, { Value::TYPE_BOOLEAN, kPolicyDisableSpdy, prefs::kDisableSpdy }, + { Value::TYPE_LIST, kPolicyDisabledSchemes, + prefs::kDisabledSchemes }, { Value::TYPE_BOOLEAN, kPolicySafeBrowsingEnabled, prefs::kSafeBrowsingEnabled }, { Value::TYPE_BOOLEAN, kPolicyPasswordManagerEnabled, @@ -857,6 +859,7 @@ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList() { { kPolicyDnsPrefetchingEnabled, Value::TYPE_BOOLEAN, key::kDnsPrefetchingEnabled }, { kPolicyDisableSpdy, Value::TYPE_BOOLEAN, key::kDisableSpdy }, + { kPolicyDisabledSchemes, Value::TYPE_LIST, key::kDisabledSchemes }, { kPolicySafeBrowsingEnabled, Value::TYPE_BOOLEAN, key::kSafeBrowsingEnabled }, { kPolicyMetricsReportingEnabled, Value::TYPE_BOOLEAN, diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc index ad6b451..1aea222 100644 --- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc +++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc @@ -82,7 +82,9 @@ INSTANTIATE_TEST_CASE_P( TypeAndName(kPolicyDisabledPluginsExceptions, prefs::kPluginsDisabledPluginsExceptions), TypeAndName(kPolicyEnabledPlugins, - prefs::kPluginsEnabledPlugins))); + prefs::kPluginsEnabledPlugins), + TypeAndName(kPolicyDisabledSchemes, + prefs::kDisabledSchemes))); // Test cases for string-valued policy settings. class ConfigurationPolicyPrefStoreStringTest diff --git a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc index 0a76502..2284952 100644 --- a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc +++ b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc @@ -336,6 +336,9 @@ INSTANTIATE_TEST_CASE_P( key::kEditBookmarksEnabled), PolicyTestParams::ForBooleanPolicy( kPolicyAllowFileSelectionDialogs, - key::kAllowFileSelectionDialogs))); + key::kAllowFileSelectionDialogs), + PolicyTestParams::ForListPolicy( + kPolicyDisabledSchemes, + key::kDisabledSchemes))); } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc index facff3d..865a5ca 100644 --- a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc +++ b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc @@ -494,6 +494,9 @@ INSTANTIATE_TEST_CASE_P( key::kEditBookmarksEnabled), PolicyTestParams::ForBooleanPolicy( kPolicyAllowFileSelectionDialogs, - key::kAllowFileSelectionDialogs))); + key::kAllowFileSelectionDialogs), + PolicyTestParams::ForListPolicy( + kPolicyDisabledSchemes, + key::kDisabledSchemes))); } // namespace policy diff --git a/chrome/browser/prefs/pref_member.cc b/chrome/browser/prefs/pref_member.cc index 2efeafc..90b369b 100644 --- a/chrome/browser/prefs/pref_member.cc +++ b/chrome/browser/prefs/pref_member.cc @@ -163,3 +163,27 @@ bool PrefMember<FilePath>::Internal::UpdateValueInternal(const Value& value) return base::GetValueAsFilePath(value, &value_); } +template <> +void PrefMember<ListValue*>::UpdatePref(ListValue*const& value) { + // prefs takes ownership of the value passed, so make a copy. + prefs()->SetList(pref_name().c_str(), value->DeepCopy()); +} + +template <> +bool PrefMember<ListValue*>::Internal::UpdateValueInternal(const Value& value) + const { + // Verify the type before doing the DeepCopy to avoid leaking the copy. + if (value.GetType() != Value::TYPE_LIST) + return false; + + // ListPrefMember keeps a copy of the ListValue and of its contents. + // GetAsList() assigns its |this| (the DeepCopy) to |value_|. + delete value_; + return value.DeepCopy()->GetAsList(&value_); +} + +template <> +PrefMember<ListValue*>::Internal::~Internal() { + delete value_; +} + diff --git a/chrome/browser/prefs/pref_member.h b/chrome/browser/prefs/pref_member.h index 5e58a39..5fdd91d 100644 --- a/chrome/browser/prefs/pref_member.h +++ b/chrome/browser/prefs/pref_member.h @@ -244,5 +244,6 @@ typedef PrefMember<int> IntegerPrefMember; typedef PrefMember<double> DoublePrefMember; typedef PrefMember<std::string> StringPrefMember; typedef PrefMember<FilePath> FilePathPrefMember; +typedef PrefMember<ListValue*> ListPrefMember; #endif // CHROME_BROWSER_PREFS_PREF_MEMBER_H_ diff --git a/chrome/browser/prefs/pref_member_unittest.cc b/chrome/browser/prefs/pref_member_unittest.cc index 9fca66b..b8079dd 100644 --- a/chrome/browser/prefs/pref_member_unittest.cc +++ b/chrome/browser/prefs/pref_member_unittest.cc @@ -19,12 +19,14 @@ const char kBoolPref[] = "bool"; const char kIntPref[] = "int"; const char kDoublePref[] = "double"; const char kStringPref[] = "string"; +const char kListPref[] = "list"; void RegisterTestPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(kBoolPref, false); prefs->RegisterIntegerPref(kIntPref, 0); prefs->RegisterDoublePref(kDoublePref, 0.0); prefs->RegisterStringPref(kStringPref, "default"); + prefs->RegisterListPref(kListPref); } class GetPrefValueCallback @@ -179,6 +181,42 @@ TEST(PrefMemberTest, BasicGetAndSet) { EXPECT_EQ("bar", prefs.GetString(kStringPref)); EXPECT_EQ("bar", string.GetValue()); EXPECT_EQ("bar", *string); + + // Test list + ListPrefMember list; + list.Init(kListPref, &prefs, NULL); + + // Check the defaults + const ListValue* list_value = prefs.GetList(kListPref); + ASSERT_TRUE(list_value != NULL); + EXPECT_EQ(0u, list_value->GetSize()); + EXPECT_TRUE(list_value->empty()); + ASSERT_TRUE(list.GetValue() != NULL); + EXPECT_EQ(0u, list.GetValue()->GetSize()); + EXPECT_TRUE(list.GetValue()->empty()); + ASSERT_TRUE(*list != NULL); + EXPECT_EQ(0u, (*list)->GetSize()); + EXPECT_TRUE((*list)->empty()); + + // Try changing through the member variable. + scoped_ptr<ListValue> list_value_numbers(new ListValue()); + list_value_numbers->Append(new StringValue("one")); + list_value_numbers->Append(new StringValue("two")); + list_value_numbers->Append(new StringValue("three")); + list.SetValue(list_value_numbers.get()); + EXPECT_TRUE(list_value_numbers->Equals(list.GetValue())); + EXPECT_TRUE(list_value_numbers->Equals(prefs.GetList(kListPref))); + EXPECT_TRUE(list_value_numbers->Equals(*list)); + + // Try changing back through the pref. + ListValue* list_value_ints = new ListValue(); + list_value_ints->Append(new FundamentalValue(1)); + list_value_ints->Append(new FundamentalValue(2)); + list_value_ints->Append(new FundamentalValue(3)); + prefs.SetList(kListPref, list_value_ints); // takes ownership + EXPECT_TRUE(list_value_ints->Equals(list.GetValue())); + EXPECT_TRUE(list_value_ints->Equals(prefs.GetList(kListPref))); + EXPECT_TRUE(list_value_ints->Equals(*list)); } TEST(PrefMemberTest, TwoPrefs) { diff --git a/chrome/browser/prefs/pref_service.cc b/chrome/browser/prefs/pref_service.cc index abefe07..3beff39 100644 --- a/chrome/browser/prefs/pref_service.cc +++ b/chrome/browser/prefs/pref_service.cc @@ -521,6 +521,10 @@ void PrefService::SetFilePath(const char* path, const FilePath& value) { SetUserPrefValue(path, base::CreateFilePathValue(value)); } +void PrefService::SetList(const char* path, ListValue* value) { + SetUserPrefValue(path, value); +} + void PrefService::SetInt64(const char* path, int64 value) { SetUserPrefValue(path, Value::CreateStringValue(base::Int64ToString(value))); } diff --git a/chrome/browser/prefs/pref_service.h b/chrome/browser/prefs/pref_service.h index 690b8c2..200693d 100644 --- a/chrome/browser/prefs/pref_service.h +++ b/chrome/browser/prefs/pref_service.h @@ -203,6 +203,9 @@ class PrefService : public base::NonThreadSafe { void SetDouble(const char* path, double value); void SetString(const char* path, const std::string& value); void SetFilePath(const char* path, const FilePath& value); + // SetList() takes ownership of |value|. Pass a copy of the ListValue to + // keep ownership of the original list, if necessary. + void SetList(const char* path, ListValue* value); // Int64 helper methods that actually store the given value as a string. // Note that if obtaining the named value via GetDictionary or GetList, the diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index cd65e1d..067fcab 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -246,6 +246,9 @@ const char kDnsPrefetchingHostReferralList[] = // Disables the SPDY protocol. const char kDisableSpdy[] = "spdy.disabled"; +// Disables the listed protocol schemes. +const char kDisabledSchemes[] = "protocol.disabled_schemes"; + // Boolean pref indicating whether the instant confirm dialog has been shown. const char kInstantConfirmDialogShown[] = "instant.confirm_dialog_shown"; diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index fd714ba..e00df1e 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -85,6 +85,7 @@ extern const char kDnsPrefetchingStartupList[]; extern const char kDnsHostReferralList[]; // OBSOLETE extern const char kDnsPrefetchingHostReferralList[]; extern const char kDisableSpdy[]; +extern const char kDisabledSchemes[]; extern const char kInstantConfirmDialogShown[]; extern const char kInstantEnabled[]; extern const char kInstantEnabledOnce[]; diff --git a/content/browser/child_process_security_policy.cc b/content/browser/child_process_security_policy.cc index 1f4e9ce..cda7a06 100644 --- a/content/browser/child_process_security_policy.cc +++ b/content/browser/child_process_security_policy.cc @@ -136,7 +136,7 @@ ChildProcessSecurityPolicy::ChildProcessSecurityPolicy() { RegisterWebSafeScheme(chrome::kBlobScheme); RegisterWebSafeScheme(chrome::kFileSystemScheme); - // We know about the following psuedo schemes and treat them specially. + // We know about the following pseudo schemes and treat them specially. RegisterPseudoScheme(chrome::kAboutScheme); RegisterPseudoScheme(chrome::kJavaScriptScheme); RegisterPseudoScheme(chrome::kViewSourceScheme); @@ -178,7 +178,7 @@ void ChildProcessSecurityPolicy::RegisterWebSafeScheme( const std::string& scheme) { base::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."; + DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not pseudo."; web_safe_schemes_.insert(scheme); } @@ -194,7 +194,7 @@ void ChildProcessSecurityPolicy::RegisterPseudoScheme( base::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 implies not web-safe."; pseudo_schemes_.insert(scheme); } @@ -205,6 +205,17 @@ bool ChildProcessSecurityPolicy::IsPseudoScheme(const std::string& scheme) { return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end()); } +void ChildProcessSecurityPolicy::RegisterDisabledSchemes( + const std::set<std::string>& schemes) { + base::AutoLock lock(lock_); + disabled_schemes_ = schemes; +} + +bool ChildProcessSecurityPolicy::IsDisabledScheme(const std::string& scheme) { + base::AutoLock lock(lock_); + return disabled_schemes_.find(scheme) != disabled_schemes_.end(); +} + void ChildProcessSecurityPolicy::GrantRequestURL( int child_id, const GURL& url) { @@ -334,6 +345,9 @@ bool ChildProcessSecurityPolicy::CanRequestURL( if (!url.is_valid()) return false; // Can't request invalid URLs. + if (IsDisabledScheme(url.scheme())) + return false; // The scheme is disabled by policy. + if (IsWebSafeScheme(url.scheme())) return true; // The scheme has been white-listed for every child process. diff --git a/content/browser/child_process_security_policy.h b/content/browser/child_process_security_policy.h index ec540f1..da8e924 100644 --- a/content/browser/child_process_security_policy.h +++ b/content/browser/child_process_security_policy.h @@ -20,8 +20,8 @@ class FilePath; class GURL; // The ChildProcessSecurityPolicy class is used to grant and revoke security -// capabilities for child porcesses. For example, it restricts whether a child -// process is permmitted to loaded file:// URLs based on whether the process +// capabilities for child processes. For example, it restricts whether a child +// process is permitted to load file:// URLs based on whether the process // has ever been commanded to load file:// URLs by the browser. // // ChildProcessSecurityPolicy is a singleton that may be used on any thread. @@ -53,6 +53,15 @@ class ChildProcessSecurityPolicy { // Returns true iff |scheme| has been registered as pseudo scheme. bool IsPseudoScheme(const std::string& scheme); + // Sets the list of disabled schemes. + // URLs using these schemes won't be loaded at all. The previous list of + // schemes is overwritten. An empty |schemes| disables this feature. + // Schemes listed as disabled take precedence over Web-safe schemes. + void RegisterDisabledSchemes(const std::set<std::string>& schemes); + + // Returns true iff |scheme| is listed as a disabled scheme. + bool IsDisabledScheme(const std::string& scheme); + // Upon creation, child processes should register themselves by calling this // this method exactly once. void Add(int child_id); @@ -160,6 +169,11 @@ class ChildProcessSecurityPolicy { // protected by |lock_|. SchemeSet pseudo_schemes_; + // These schemes are disabled by policy, and child processes are always + // denied permission to request them. This overrides |web_safe_schemes_|. + // This set is protected by |lock_|. + SchemeSet disabled_schemes_; + // This map holds a SecurityState for each child process. The key for the // map is the ID of the ChildProcessHost. The SecurityState objects are // owned by this object and are protected by |lock_|. References to them must diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc index e20178e..53799b7 100644 --- a/content/browser/child_process_security_policy_unittest.cc +++ b/content/browser/child_process_security_policy_unittest.cc @@ -52,9 +52,25 @@ TEST_F(ChildProcessSecurityPolicyTest, IsPseudoSchemeTest) { EXPECT_TRUE(p->IsPseudoScheme(chrome::kJavaScriptScheme)); EXPECT_TRUE(p->IsPseudoScheme(chrome::kViewSourceScheme)); - EXPECT_FALSE(p->IsPseudoScheme("registered-psuedo-scheme")); - p->RegisterPseudoScheme("registered-psuedo-scheme"); - EXPECT_TRUE(p->IsPseudoScheme("registered-psuedo-scheme")); + EXPECT_FALSE(p->IsPseudoScheme("registered-pseudo-scheme")); + p->RegisterPseudoScheme("registered-pseudo-scheme"); + EXPECT_TRUE(p->IsPseudoScheme("registered-pseudo-scheme")); +} + +TEST_F(ChildProcessSecurityPolicyTest, IsDisabledSchemeTest) { + ChildProcessSecurityPolicy* p = ChildProcessSecurityPolicy::GetInstance(); + + EXPECT_FALSE(p->IsDisabledScheme("evil-scheme")); + std::set<std::string> disabled_set; + disabled_set.insert("evil-scheme"); + p->RegisterDisabledSchemes(disabled_set); + EXPECT_TRUE(p->IsDisabledScheme("evil-scheme")); + EXPECT_FALSE(p->IsDisabledScheme("good-scheme")); + + disabled_set.clear(); + p->RegisterDisabledSchemes(disabled_set); + EXPECT_FALSE(p->IsDisabledScheme("evil-scheme")); + EXPECT_FALSE(p->IsDisabledScheme("good-scheme")); } TEST_F(ChildProcessSecurityPolicyTest, StandardSchemesTest) { @@ -161,6 +177,17 @@ TEST_F(ChildProcessSecurityPolicyTest, CanServiceCommandsTest) { p->GrantRequestURL(kRendererID, GURL("file:///etc/passwd")); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); + EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("evil-scheme:/path"))); + std::set<std::string> disabled_set; + disabled_set.insert("evil-scheme"); + p->RegisterDisabledSchemes(disabled_set); + EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("http://www.google.com"))); + EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("evil-scheme:/path"))); + disabled_set.clear(); + p->RegisterDisabledSchemes(disabled_set); + EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("http://www.google.com"))); + EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("evil-scheme:/path"))); + // We should forget our state if we repeat a renderer id. p->Remove(kRendererID); p->Add(kRendererID); diff --git a/content/browser/tab_contents/navigation_controller.cc b/content/browser/tab_contents/navigation_controller.cc index 5bdbd23..310e1cf 100644 --- a/content/browser/tab_contents/navigation_controller.cc +++ b/content/browser/tab_contents/navigation_controller.cc @@ -17,6 +17,7 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" +#include "content/browser/child_process_security_policy.h" #include "content/browser/in_process_webkit/session_storage_namespace.h" #include "content/browser/site_instance.h" #include "content/browser/tab_contents/interstitial_page.h" @@ -256,10 +257,25 @@ NavigationEntry* NavigationController::GetEntryWithPageID( } void NavigationController::LoadEntry(NavigationEntry* entry) { + // Don't navigate to URLs disabled by policy. This prevents showing the URL + // on the Omnibar when it is also going to be blocked by + // ChildProcessSecurityPolicy::CanRequestURL. + ChildProcessSecurityPolicy *policy = + ChildProcessSecurityPolicy::GetInstance(); + if (policy->IsDisabledScheme(entry->url().scheme()) || + policy->IsDisabledScheme(entry->virtual_url().scheme())) { + VLOG(1) << "URL not loaded because the scheme is blocked by policy: " + << entry->url(); + delete entry; + return; + } + // Handle non-navigational URLs that popup dialogs and such, these should not // actually navigate. - if (HandleNonNavigationAboutURL(entry->url())) + if (HandleNonNavigationAboutURL(entry->url())) { + delete entry; return; + } // When navigating to a new page, we don't know for sure if we will actually // end up leaving the current page. The new page load could for example |