Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(694)

Side by Side Diff: chrome/browser/extensions/extensions_service.cc

Issue 4687005: Track permissions granted to extensions in prefs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: incorporate feedback Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extensions_service.h" 5 #include "chrome/browser/extensions/extensions_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 622
623 // TODO(erikkay) this should probably be deferred as well. 623 // TODO(erikkay) this should probably be deferred as well.
624 GarbageCollectExtensions(); 624 GarbageCollectExtensions();
625 } 625 }
626 626
627 void ExtensionsService::InstallExtension(const FilePath& extension_path) { 627 void ExtensionsService::InstallExtension(const FilePath& extension_path) {
628 scoped_refptr<CrxInstaller> installer( 628 scoped_refptr<CrxInstaller> installer(
629 new CrxInstaller(install_directory_, 629 new CrxInstaller(install_directory_,
630 this, // frontend 630 this, // frontend
631 NULL)); // no client (silent install) 631 NULL)); // no client (silent install)
632 installer->set_allow_privilege_increase(true); 632 installer->set_allow_privilege_increase(false);
633 installer->InstallCrx(extension_path); 633 installer->InstallCrx(extension_path);
634 } 634 }
635 635
636 namespace { 636 namespace {
637 // TODO(akalin): Put this somewhere where both crx_installer.cc and 637 // TODO(akalin): Put this somewhere where both crx_installer.cc and
638 // this file can use it. 638 // this file can use it.
639 void DeleteFileHelper(const FilePath& path, bool recursive) { 639 void DeleteFileHelper(const FilePath& path, bool recursive) {
640 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 640 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
641 file_util::Delete(path, recursive); 641 file_util::Delete(path, recursive);
642 } 642 }
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
920 extension); 920 extension);
921 extensions_.erase(iter); 921 extensions_.erase(iter);
922 922
923 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_, 923 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
924 extension->GetChromeURLOverrides()); 924 extension->GetChromeURLOverrides());
925 925
926 NotifyExtensionUnloaded(extension); 926 NotifyExtensionUnloaded(extension);
927 UpdateActiveExtensionsInCrashReporter(); 927 UpdateActiveExtensionsInCrashReporter();
928 } 928 }
929 929
930 void ExtensionsService::GrantPermissions(const Extension* extension) {
931 CHECK(extension);
932 ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions();
933 extension_prefs_->AddGrantedPermissions(extension->id(),
934 extension->api_permissions(),
935 effective_hosts);
936 }
937
938 void ExtensionsService::GrantPermissionsAndEnableExtension(
939 const Extension* extension) {
940 CHECK(extension);
941 GrantPermissions(extension);
942 extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
943 EnableExtension(extension->id());
944 }
945
930 void ExtensionsService::LoadExtension(const FilePath& extension_path) { 946 void ExtensionsService::LoadExtension(const FilePath& extension_path) {
931 BrowserThread::PostTask( 947 BrowserThread::PostTask(
932 BrowserThread::FILE, FROM_HERE, 948 BrowserThread::FILE, FROM_HERE,
933 NewRunnableMethod( 949 NewRunnableMethod(
934 backend_.get(), 950 backend_.get(),
935 &ExtensionsServiceBackend::LoadSingleExtension, 951 &ExtensionsServiceBackend::LoadSingleExtension,
936 extension_path, scoped_refptr<ExtensionsService>(this))); 952 extension_path, scoped_refptr<ExtensionsService>(this)));
937 } 953 }
938 954
939 void ExtensionsService::LoadComponentExtensions() { 955 void ExtensionsService::LoadComponentExtensions() {
(...skipping 12 matching lines...) Expand all
952 it->root_directory, 968 it->root_directory,
953 Extension::COMPONENT, 969 Extension::COMPONENT,
954 *static_cast<DictionaryValue*>(manifest.get()), 970 *static_cast<DictionaryValue*>(manifest.get()),
955 true, // require key 971 true, // require key
956 &error)); 972 &error));
957 if (!extension.get()) { 973 if (!extension.get()) {
958 NOTREACHED() << error; 974 NOTREACHED() << error;
959 return; 975 return;
960 } 976 }
961 977
962 OnExtensionLoaded(extension, false); // Don't allow privilege increase. 978 OnExtensionLoaded(extension, true);
963 } 979 }
964 } 980 }
965 981
966 void ExtensionsService::LoadAllExtensions() { 982 void ExtensionsService::LoadAllExtensions() {
967 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 983 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
968 984
969 base::TimeTicks start_time = base::TimeTicks::Now(); 985 base::TimeTicks start_time = base::TimeTicks::Now();
970 986
971 // Load any component extensions. 987 // Load any component extensions.
972 LoadComponentExtensions(); 988 LoadComponentExtensions();
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1097 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count); 1113 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
1098 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count); 1114 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
1099 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count); 1115 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
1100 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count); 1116 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
1101 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count); 1117 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
1102 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count); 1118 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
1103 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction", 1119 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
1104 browser_action_count); 1120 browser_action_count);
1105 } 1121 }
1106 1122
1107
1108 void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, 1123 void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
1109 bool write_to_prefs) { 1124 bool write_to_prefs) {
1110 std::string error; 1125 std::string error;
1111 scoped_refptr<const Extension> extension(NULL); 1126 scoped_refptr<const Extension> extension(NULL);
1112 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) { 1127 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
1113 error = errors::kDisabledByPolicy; 1128 error = errors::kDisabledByPolicy;
1114 } else if (info.extension_manifest.get()) { 1129 } else if (info.extension_manifest.get()) {
1115 bool require_key = info.extension_location != Extension::LOAD; 1130 bool require_key = info.extension_location != Extension::LOAD;
1116 extension = Extension::Create( 1131 extension = Extension::Create(
1117 info.extension_path, info.extension_location, *info.extension_manifest, 1132 info.extension_path, info.extension_location, *info.extension_manifest,
1118 require_key, &error); 1133 require_key, &error);
1119 } else { 1134 } else {
1120 error = errors::kManifestUnreadable; 1135 error = errors::kManifestUnreadable;
1121 } 1136 }
1122 1137
1123 if (!extension) { 1138 if (!extension) {
1124 ReportExtensionLoadError(info.extension_path, 1139 ReportExtensionLoadError(info.extension_path,
1125 error, 1140 error,
1126 NotificationType::EXTENSION_INSTALL_ERROR, 1141 NotificationType::EXTENSION_INSTALL_ERROR,
1127 false); 1142 false);
1128 return; 1143 return;
1129 } 1144 }
1130 1145
1131 if (write_to_prefs) 1146 if (write_to_prefs)
1132 extension_prefs_->UpdateManifest(extension); 1147 extension_prefs_->UpdateManifest(extension);
1133 1148
1134 OnExtensionLoaded(extension, true); 1149 // External extensions are allowed to increase their privileges without
1135 1150 // prompting users.
1136 if (Extension::IsExternalLocation(info.extension_location)) { 1151 if (Extension::IsExternalLocation(info.extension_location)) {
1152 OnExtensionLoaded(extension, true);
1137 BrowserThread::PostTask( 1153 BrowserThread::PostTask(
1138 BrowserThread::FILE, FROM_HERE, 1154 BrowserThread::FILE, FROM_HERE,
1139 NewRunnableMethod( 1155 NewRunnableMethod(
1140 backend_.get(), 1156 backend_.get(),
1141 &ExtensionsServiceBackend::CheckExternalUninstall, 1157 &ExtensionsServiceBackend::CheckExternalUninstall,
1142 scoped_refptr<ExtensionsService>(this), 1158 scoped_refptr<ExtensionsService>(this),
1143 info.extension_id)); 1159 info.extension_id));
1160 } else {
1161 OnExtensionLoaded(extension, false);
1144 } 1162 }
1145 } 1163 }
1146 1164
1147 void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) { 1165 void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) {
1148 // The ChromeURLRequestContexts need to be first to know that the extension 1166 // The ChromeURLRequestContexts need to be first to know that the extension
1149 // was loaded, otherwise a race can arise where a renderer that is created 1167 // was loaded, otherwise a race can arise where a renderer that is created
1150 // for the extension may try to load an extension URL with an extension id 1168 // for the extension may try to load an extension URL with an extension id
1151 // that the request context doesn't yet know about. The profile is responsible 1169 // that the request context doesn't yet know about. The profile is responsible
1152 // for ensuring its URLRequestContexts appropriately discover the loaded 1170 // for ensuring its URLRequestContexts appropriately discover the loaded
1153 // extension. 1171 // extension.
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 // Ensure extension is deleted unless we transfer ownership. 1517 // Ensure extension is deleted unless we transfer ownership.
1500 scoped_refptr<const Extension> scoped_extension(extension); 1518 scoped_refptr<const Extension> scoped_extension(extension);
1501 1519
1502 // The extension is now loaded, remove its data from unloaded extension map. 1520 // The extension is now loaded, remove its data from unloaded extension map.
1503 unloaded_extension_paths_.erase(extension->id()); 1521 unloaded_extension_paths_.erase(extension->id());
1504 1522
1505 // If the extension was disabled for a reload, then enable it. 1523 // If the extension was disabled for a reload, then enable it.
1506 if (disabled_extension_paths_.erase(extension->id()) > 0) 1524 if (disabled_extension_paths_.erase(extension->id()) > 0)
1507 EnableExtension(extension->id()); 1525 EnableExtension(extension->id());
1508 1526
1509 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now 1527 // Check if the extension's privileges have changed and disable the extension
1510 // that extensions are enabled by default? 1528 // if necessary.
1511 if (extensions_enabled() || 1529 DisableIfPrivilegeIncrease(extension, allow_privilege_increase);
1512 extension->is_theme() ||
1513 extension->location() == Extension::LOAD ||
1514 extension->location() == Extension::COMPONENT ||
1515 Extension::IsExternalLocation(extension->location())) {
1516 const Extension* old = GetExtensionByIdInternal(extension->id(),
1517 true, true);
1518 if (old) {
1519 // CrxInstaller should have guaranteed that we aren't downgrading.
1520 CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
1521 1530
1522 bool allow_silent_upgrade = 1531 switch (extension_prefs_->GetExtensionState(extension->id())) {
1523 allow_privilege_increase || !Extension::IsPrivilegeIncrease( 1532 case Extension::ENABLED:
1524 old, extension); 1533 extensions_.push_back(scoped_extension);
1525 1534
1526 // Extensions get upgraded if silent upgrades are allowed, otherwise 1535 NotifyExtensionLoaded(extension);
1527 // they get disabled.
1528 if (allow_silent_upgrade) {
1529 SetBeingUpgraded(old, true);
1530 SetBeingUpgraded(extension, true);
1531 }
1532 1536
1533 // To upgrade an extension in place, unload the old one and 1537 ExtensionDOMUI::RegisterChromeURLOverrides(
1534 // then load the new one. 1538 profile_, extension->GetChromeURLOverrides());
1535 UnloadExtension(old->id()); 1539 break;
1536 old = NULL; 1540 case Extension::DISABLED:
1537 1541 disabled_extensions_.push_back(scoped_extension);
1538 if (!allow_silent_upgrade) { 1542 NotificationService::current()->Notify(
1539 // Extension has changed permissions significantly. Disable it. We 1543 NotificationType::EXTENSION_UPDATE_DISABLED,
1540 // send a notification below. 1544 Source<Profile>(profile_),
1541 extension_prefs_->SetExtensionState(extension, Extension::DISABLED); 1545 Details<const Extension>(extension));
1542 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); 1546 break;
1543 } 1547 default:
1544 } 1548 NOTREACHED();
1545 1549 break;
1546 switch (extension_prefs_->GetExtensionState(extension->id())) {
1547 case Extension::ENABLED:
1548 extensions_.push_back(scoped_extension);
1549
1550 NotifyExtensionLoaded(extension);
1551
1552 ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
1553 extension->GetChromeURLOverrides());
1554 break;
1555 case Extension::DISABLED:
1556 disabled_extensions_.push_back(scoped_extension);
1557 NotificationService::current()->Notify(
1558 NotificationType::EXTENSION_UPDATE_DISABLED,
1559 Source<Profile>(profile_),
1560 Details<const Extension>(extension));
1561 break;
1562 default:
1563 NOTREACHED();
1564 break;
1565 }
1566 } 1550 }
1567 1551
1568 SetBeingUpgraded(extension, false); 1552 SetBeingUpgraded(extension, false);
1569 1553
1570 UpdateActiveExtensionsInCrashReporter(); 1554 UpdateActiveExtensionsInCrashReporter();
1571 1555
1572 if (profile_->GetTemplateURLModel()) 1556 if (profile_->GetTemplateURLModel())
1573 profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension); 1557 profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension);
1574 1558
1575 // Load the icon for omnibox-enabled extensions so it will be ready to display 1559 // Load the icon for omnibox-enabled extensions so it will be ready to display
1576 // in the URL bar. 1560 // in the URL bar.
1577 if (!extension->omnibox_keyword().empty()) { 1561 if (!extension->omnibox_keyword().empty()) {
1578 omnibox_popup_icon_manager_.LoadIcon(extension); 1562 omnibox_popup_icon_manager_.LoadIcon(extension);
1579 omnibox_icon_manager_.LoadIcon(extension); 1563 omnibox_icon_manager_.LoadIcon(extension);
1580 } 1564 }
1581 } 1565 }
1582 1566
1567 void ExtensionsService::DisableIfPrivilegeIncrease(
1568 const Extension* extension, bool allow_privilege_increase) {
Aaron Boodman 2010/11/23 00:06:38 As we talked about in IRC, I think everything woul
1569 // We keep track of all permissions the user has granted each extension.
1570 // This allows extensions to gracefully support backwards compatibility
1571 // by including unknown permissions in their manifests. When the user
1572 // installs the extension, only the recognized permissions are recorded.
1573 // When the unknown permissions become recognized (e.g., through browser
1574 // upgrade), we can prompt the user to accept these new permissions.
1575 // Extensions can also silently upgrade to less permissions, and then
1576 // silently upgrade to a version that adds these permissions back.
1577 //
1578 // For example, pretend that Chrome 10 includes a permission "omnibox"
1579 // for an API that adds suggestions to the omnibox. An extension can
1580 // maintain backwards compatibility while still having "omnibox" in the
1581 // manifest. If a user installs the extension on Chrome 9, the browser
1582 // will record the permissions it recognized, not including "omnibox."
1583 // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
1584 // will disable the extension and prompt the user to approve the increase
1585 // in privileges. The extension could then release a new version that
1586 // removes the "omnibox" permission. When the user upgrades, Chrome will
1587 // still remember that "omnibox" had been granted, so that if the
1588 // extension once again includes "omnibox" in an upgrade, the extension
1589 // can upgrade without requiring this user's approval.
1590 const Extension* old = GetExtensionByIdInternal(extension->id(),
1591 true, true);
1592 std::set<std::string> granted_apis;
1593 ExtensionExtent granted_extent;
1594
1595 bool is_extension_upgrade = old != NULL;
1596 bool is_privilege_increase = false;
1597
1598 // We only record the granted permissions in the extension preferences
1599 // for extensions that aren't allowed to silently increase privileges.
1600 if (!allow_privilege_increase) {
1601 // Add all the recognized permissions to the extension's granted
1602 // permissions list if the granted permissions list hasn't been
1603 // initialized yet.
1604 if (!extension_prefs_->GetGrantedPermissions(
1605 extension->id(), &granted_apis, &granted_extent)) {
1606 GrantPermissions(extension);
1607 CHECK(extension_prefs_->GetGrantedPermissions(
1608 extension->id(), &granted_apis, &granted_extent));
1609 }
1610
1611 // Here, we check if an extension's privileges have increased in a manner
1612 // that requires the user's approval. This could occur because the browser
1613 // upgraded and recognized additional privileges, or an extension upgrades
1614 // to a version that requires additional privileges.
1615 is_privilege_increase = Extension::IsPrivilegeIncrease(
1616 granted_apis, granted_extent, old, extension);
1617 }
1618
1619 if (is_extension_upgrade) {
1620 // CrxInstaller should have guaranteed that we aren't downgrading.
1621 CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
1622
1623 // Extensions get upgraded if the privileges are allowed to increase or
1624 // the privileges haven't increased.
1625 if (allow_privilege_increase || !is_privilege_increase) {
1626 SetBeingUpgraded(old, true);
1627 SetBeingUpgraded(extension, true);
1628 }
1629
1630 // To upgrade an extension in place, unload the old one and
1631 // then load the new one.
1632 UnloadExtension(old->id());
1633 old = NULL;
1634 }
1635
1636 // Extension has changed permissions significantly. Disable it. A
1637 // notification should be sent by the caller.
1638 if (is_privilege_increase) {
1639 extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
1640 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
1641 }
1642 }
1643
1583 void ExtensionsService::UpdateActiveExtensionsInCrashReporter() { 1644 void ExtensionsService::UpdateActiveExtensionsInCrashReporter() {
1584 std::set<std::string> extension_ids; 1645 std::set<std::string> extension_ids;
1585 for (size_t i = 0; i < extensions_.size(); ++i) { 1646 for (size_t i = 0; i < extensions_.size(); ++i) {
1586 if (!extensions_[i]->is_theme() && 1647 if (!extensions_[i]->is_theme() &&
1587 extensions_[i]->location() != Extension::COMPONENT) 1648 extensions_[i]->location() != Extension::COMPONENT)
1588 extension_ids.insert(extensions_[i]->id()); 1649 extension_ids.insert(extensions_[i]->id());
1589 } 1650 }
1590 1651
1591 child_process_logging::SetActiveExtensions(extension_ids); 1652 child_process_logging::SetActiveExtensions(extension_ids);
1592 } 1653 }
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
1950 } 2011 }
1951 2012
1952 bool ExtensionsService::IsBeingUpgraded(const Extension* extension) { 2013 bool ExtensionsService::IsBeingUpgraded(const Extension* extension) {
1953 return extension_runtime_data_[extension->id()].being_upgraded; 2014 return extension_runtime_data_[extension->id()].being_upgraded;
1954 } 2015 }
1955 2016
1956 void ExtensionsService::SetBeingUpgraded(const Extension* extension, 2017 void ExtensionsService::SetBeingUpgraded(const Extension* extension,
1957 bool value) { 2018 bool value) {
1958 extension_runtime_data_[extension->id()].being_upgraded = value; 2019 extension_runtime_data_[extension->id()].being_upgraded = value;
1959 } 2020 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698