1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/common/extensions/permissions/permissions_data.h" 6 7 #include "base/command_line.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/strings/string16.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/values.h" 14 #include "chrome/common/extensions/extension.h" 15 #include "chrome/common/extensions/extension_manifest_constants.h" 16 #include "chrome/common/extensions/features/base_feature_provider.h" 17 #include "chrome/common/extensions/features/feature.h" 18 #include "chrome/common/extensions/manifest.h" 19 #include "chrome/common/extensions/permissions/api_permission_set.h" 20 #include "chrome/common/extensions/permissions/chrome_scheme_hosts.h" 21 #include "chrome/common/extensions/permissions/permission_set.h" 22 #include "chrome/common/extensions/permissions/permissions_info.h" 23 #include "content/public/common/url_constants.h" 24 #include "extensions/common/constants.h" 25 #include "extensions/common/error_utils.h" 26 #include "extensions/common/switches.h" 27 #include "extensions/common/url_pattern_set.h" 28 #include "extensions/common/user_script.h" 29 #include "url/gurl.h" 30 31 namespace keys = extension_manifest_keys; 32 namespace errors = extension_manifest_errors; 33 34 namespace extensions { 35 36 namespace { 37 38 PermissionsData::PolicyDelegate* g_policy_delegate = NULL; 39 40 bool ContainsManifestForbiddenPermission(const APIPermissionSet& apis, 41 string16* error) { 42 CHECK(error); 43 for (APIPermissionSet::const_iterator iter = apis.begin(); 44 iter != apis.end(); ++iter) { 45 if ((*iter)->ManifestEntryForbidden()) { 46 *error = ErrorUtils::FormatErrorMessageUTF16( 47 errors::kPermissionNotAllowedInManifest, 48 (*iter)->info()->name()); 49 return true; 50 } 51 } 52 return false; 53 } 54 55 // Custom checks for the experimental permission that can't be expressed in 56 // _permission_features.json. 57 bool CanSpecifyExperimentalPermission(const Extension* extension) { 58 if (extension->location() == Manifest::COMPONENT) 59 return true; 60 61 if (CommandLine::ForCurrentProcess()->HasSwitch( 62 switches::kEnableExperimentalExtensionApis)) { 63 return true; 64 } 65 66 // We rely on the webstore to check access to experimental. This way we can 67 // whitelist extensions to have access to experimental in just the store, and 68 // not have to push a new version of the client. 69 if (extension->from_webstore()) 70 return true; 71 72 return false; 73 } 74 75 // Checks whether the host |pattern| is allowed for the given |extension|, 76 // given API permissions |permissions|. 77 bool CanSpecifyHostPermission(const Extension* extension, 78 const URLPattern& pattern, 79 const APIPermissionSet& permissions) { 80 if (!pattern.match_all_urls() && 81 pattern.MatchesScheme(chrome::kChromeUIScheme)) { 82 URLPatternSet chrome_scheme_hosts = 83 GetPermittedChromeSchemeHosts(extension, permissions); 84 if (chrome_scheme_hosts.ContainsPattern(pattern)) 85 return true; 86 87 // Component extensions can have access to all of chrome://*. 88 if (PermissionsData::CanExecuteScriptEverywhere(extension)) 89 return true; 90 91 if (CommandLine::ForCurrentProcess()->HasSwitch( 92 switches::kExtensionsOnChromeURLs)) { 93 return true; 94 } 95 96 // TODO(aboxhall): return from_webstore() when webstore handles blocking 97 // extensions which request chrome:// urls 98 return false; 99 } 100 101 // Otherwise, the valid schemes were handled by URLPattern. 102 return true; 103 } 104 105 // Parses the host and api permissions from the specified permission |key| 106 // from |extension|'s manifest. 107 bool ParseHelper(Extension* extension, 108 const char* key, 109 APIPermissionSet* api_permissions, 110 URLPatternSet* host_permissions, 111 string16* error) { 112 if (!extension->manifest()->HasKey(key)) 113 return true; 114 115 const base::ListValue* permissions = NULL; 116 if (!extension->manifest()->GetList(key, &permissions)) { 117 *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions, 118 std::string()); 119 return false; 120 } 121 122 // NOTE: We need to get the APIPermission before we check if features 123 // associated with them are available because the feature system does not 124 // know about aliases. 125 126 std::vector<std::string> host_data; 127 if (!APIPermissionSet::ParseFromJSON( 128 permissions, APIPermissionSet::kDisallowInternalPermissions, 129 api_permissions, error, &host_data)) { 130 return false; 131 } 132 133 // Verify feature availability of permissions. 134 std::vector<APIPermission::ID> to_remove; 135 FeatureProvider* permission_features = 136 BaseFeatureProvider::GetByName("permission"); 137 for (APIPermissionSet::const_iterator iter = api_permissions->begin(); 138 iter != api_permissions->end(); ++iter) { 139 Feature* feature = permission_features->GetFeature(iter->name()); 140 141 // The feature should exist since we just got an APIPermission for it. The 142 // two systems should be updated together whenever a permission is added. 143 DCHECK(feature); 144 // http://crbug.com/176381 145 if (!feature) { 146 to_remove.push_back(iter->id()); 147 continue; 148 } 149 150 Feature::Availability availability = feature->IsAvailableToManifest( 151 extension->id(), 152 extension->GetType(), 153 Feature::ConvertLocation(extension->location()), 154 extension->manifest_version()); 155 156 if (!availability.is_available()) { 157 // Don't fail, but warn the developer that the manifest contains 158 // unrecognized permissions. This may happen legitimately if the 159 // extensions requests platform- or channel-specific permissions. 160 extension->AddInstallWarning(InstallWarning(InstallWarning::FORMAT_TEXT, 161 availability.message())); 162 to_remove.push_back(iter->id()); 163 continue; 164 } 165 166 if (iter->id() == APIPermission::kExperimental) { 167 if (!CanSpecifyExperimentalPermission(extension)) { 168 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); 169 return false; 170 } 171 } 172 } 173 174 // Remove permissions that are not available to this extension. 175 for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin(); 176 iter != to_remove.end(); ++iter) { 177 api_permissions->erase(*iter); 178 } 179 180 // Parse host pattern permissions. 181 const int kAllowedSchemes = 182 PermissionsData::CanExecuteScriptEverywhere(extension) ? 183 URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes; 184 185 for (std::vector<std::string>::const_iterator iter = host_data.begin(); 186 iter != host_data.end(); ++iter) { 187 const std::string& permission_str = *iter; 188 189 // Check if it's a host pattern permission. 190 URLPattern pattern = URLPattern(kAllowedSchemes); 191 URLPattern::ParseResult parse_result = pattern.Parse(permission_str); 192 if (parse_result == URLPattern::PARSE_SUCCESS) { 193 // The path component is not used for host permissions, so we force it 194 // to match all paths. 195 pattern.SetPath("/*"); 196 int valid_schemes = pattern.valid_schemes(); 197 if (pattern.MatchesScheme(chrome::kFileScheme) && 198 !PermissionsData::CanExecuteScriptEverywhere(extension)) { 199 extension->set_wants_file_access(true); 200 if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS)) 201 valid_schemes &= ~URLPattern::SCHEME_FILE; 202 } 203 204 if (pattern.scheme() != chrome::kChromeUIScheme && 205 !PermissionsData::CanExecuteScriptEverywhere(extension)) { 206 // Keep chrome:// in allowed schemes only if it's explicitly requested 207 // or CanExecuteScriptEverywhere is true. If the 208 // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission 209 // will fail, so don't check the flag here. 210 valid_schemes &= ~URLPattern::SCHEME_CHROMEUI; 211 } 212 pattern.SetValidSchemes(valid_schemes); 213 214 if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) { 215 // TODO(aboxhall): make a warning (see pattern.match_all_urls() block 216 // below). 217 *error = ErrorUtils::FormatErrorMessageUTF16( 218 errors::kInvalidPermissionScheme, permission_str); 219 return false; 220 } 221 222 host_permissions->AddPattern(pattern); 223 // We need to make sure all_urls matches chrome://favicon and (maybe) 224 // chrome://thumbnail, so add them back in to host_permissions separately. 225 if (pattern.match_all_urls()) 226 host_permissions->AddPatterns(GetPermittedChromeSchemeHosts( 227 extension, *api_permissions)); 228 continue; 229 } 230 231 // It's probably an unknown API permission. Do not throw an error so 232 // extensions can retain backwards compatability (http://crbug.com/42742). 233 extension->AddInstallWarning(InstallWarning( 234 InstallWarning::FORMAT_TEXT, 235 base::StringPrintf( 236 "Permission '%s' is unknown or URL pattern is malformed.", 237 permission_str.c_str()))); 238 } 239 240 return true; 241 } 242 243 // Returns true if this extension id is from a trusted provider. 244 bool IsTrustedId(const std::string& extension_id) { 245 // See http://b/4946060 for more details. 246 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); 247 } 248 249 } // namespace 250 251 struct PermissionsData::InitialPermissions { 252 APIPermissionSet api_permissions; 253 URLPatternSet host_permissions; 254 URLPatternSet scriptable_hosts; 255 }; 256 257 PermissionsData::PermissionsData() { 258 } 259 260 PermissionsData::~PermissionsData() { 261 } 262 263 // static 264 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) { 265 g_policy_delegate = delegate; 266 } 267 268 // static 269 const PermissionSet* PermissionsData::GetOptionalPermissions( 270 const Extension* extension) { 271 return extension->permissions_data()->optional_permission_set_.get(); 272 } 273 274 // static 275 const PermissionSet* PermissionsData::GetRequiredPermissions( 276 const Extension* extension) { 277 return extension->permissions_data()->required_permission_set_.get(); 278 } 279 280 // static 281 const APIPermissionSet* PermissionsData::GetInitialAPIPermissions( 282 const Extension* extension) { 283 return &extension->permissions_data()-> 284 initial_required_permissions_->api_permissions; 285 } 286 287 // static 288 APIPermissionSet* PermissionsData::GetInitialAPIPermissions( 289 Extension* extension) { 290 return &extension->permissions_data()-> 291 initial_required_permissions_->api_permissions; 292 } 293 294 // static 295 void PermissionsData::SetInitialScriptableHosts( 296 Extension* extension, const URLPatternSet& scriptable_hosts) { 297 extension->permissions_data()-> 298 initial_required_permissions_->scriptable_hosts = scriptable_hosts; 299 } 300 301 // static 302 void PermissionsData::SetActivePermissions(const Extension* extension, 303 const PermissionSet* permissions) { 304 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 305 extension->permissions_data()->active_permissions_ = permissions; 306 } 307 308 // static 309 scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions( 310 const Extension* extension) { 311 return extension->permissions_data()->active_permissions_; 312 } 313 314 // static 315 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions( 316 const Extension* extension, 317 int tab_id) { 318 CHECK_GE(tab_id, 0); 319 TabPermissionsMap::const_iterator iter = 320 extension->permissions_data()->tab_specific_permissions_.find(tab_id); 321 return 322 (iter != extension->permissions_data()->tab_specific_permissions_.end()) 323 ? iter->second 324 : NULL; 325 } 326 327 // static 328 void PermissionsData::UpdateTabSpecificPermissions( 329 const Extension* extension, 330 int tab_id, 331 scoped_refptr<const PermissionSet> permissions) { 332 CHECK_GE(tab_id, 0); 333 TabPermissionsMap* tab_permissions = 334 &extension->permissions_data()->tab_specific_permissions_; 335 if (tab_permissions->count(tab_id)) { 336 (*tab_permissions)[tab_id] = PermissionSet::CreateUnion( 337 (*tab_permissions)[tab_id].get(), permissions.get()); 338 } else { 339 (*tab_permissions)[tab_id] = permissions; 340 } 341 } 342 343 // static 344 void PermissionsData::ClearTabSpecificPermissions( 345 const Extension* extension, 346 int tab_id) { 347 CHECK_GE(tab_id, 0); 348 extension->permissions_data()->tab_specific_permissions_.erase(tab_id); 349 } 350 351 // static 352 bool PermissionsData::HasAPIPermission(const Extension* extension, 353 APIPermission::ID permission) { 354 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 355 return GetActivePermissions(extension)->HasAPIPermission(permission); 356 } 357 358 // static 359 bool PermissionsData::HasAPIPermission( 360 const Extension* extension, 361 const std::string& permission_name) { 362 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 363 return GetActivePermissions(extension)->HasAPIPermission(permission_name); 364 } 365 366 // static 367 bool PermissionsData::HasAPIPermissionForTab( 368 const Extension* extension, 369 int tab_id, 370 APIPermission::ID permission) { 371 if (HasAPIPermission(extension, permission)) 372 return true; 373 374 // Place autolock below the HasAPIPermission() check, since HasAPIPermission 375 // also acquires the lock. 376 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 377 scoped_refptr<const PermissionSet> tab_permissions = 378 GetTabSpecificPermissions(extension, tab_id); 379 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission); 380 } 381 382 // static 383 bool PermissionsData::CheckAPIPermissionWithParam( 384 const Extension* extension, 385 APIPermission::ID permission, 386 const APIPermission::CheckParam* param) { 387 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 388 return GetActivePermissions(extension)->CheckAPIPermissionWithParam( 389 permission, param); 390 } 391 392 // static 393 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions( 394 const Extension* extension) { 395 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 396 return GetActivePermissions(extension)->effective_hosts(); 397 } 398 399 // static 400 bool PermissionsData::CanSilentlyIncreasePermissions( 401 const Extension* extension) { 402 return extension->location() != Manifest::INTERNAL; 403 } 404 405 // static 406 bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) { 407 return IsTrustedId(extension->id()); 408 } 409 410 // static 411 bool PermissionsData::HasHostPermission(const Extension* extension, 412 const GURL& url) { 413 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 414 return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url); 415 } 416 417 // static 418 bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) { 419 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 420 return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts(); 421 } 422 423 // static 424 PermissionMessages PermissionsData::GetPermissionMessages( 425 const Extension* extension) { 426 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 427 if (ShouldSkipPermissionWarnings(extension)) { 428 return PermissionMessages(); 429 } else { 430 return GetActivePermissions(extension)->GetPermissionMessages( 431 extension->GetType()); 432 } 433 } 434 435 // static 436 std::vector<string16> PermissionsData::GetPermissionMessageStrings( 437 const Extension* extension) { 438 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 439 if (ShouldSkipPermissionWarnings(extension)) { 440 return std::vector<string16>(); 441 } else { 442 return GetActivePermissions(extension)->GetWarningMessages( 443 extension->GetType()); 444 } 445 } 446 447 // static 448 std::vector<string16> PermissionsData::GetPermissionMessageDetailsStrings( 449 const Extension* extension) { 450 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 451 if (ShouldSkipPermissionWarnings(extension)) { 452 return std::vector<string16>(); 453 } else { 454 return GetActivePermissions(extension)->GetWarningMessagesDetails( 455 extension->GetType()); 456 } 457 } 458 459 // static 460 bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension, 461 const GURL& document_url, 462 const GURL& top_frame_url, 463 int tab_id, 464 const UserScript* script, 465 int process_id, 466 std::string* error) { 467 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 468 // The gallery is special-cased as a restricted URL for scripting to prevent 469 // access to special JS bindings we expose to the gallery (and avoid things 470 // like extensions removing the "report abuse" link). 471 // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing 472 // against the store app extent? 473 GURL store_url(extension_urls::GetWebstoreLaunchURL()); 474 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 475 bool can_execute_everywhere = CanExecuteScriptEverywhere(extension); 476 477 if (g_policy_delegate && 478 !g_policy_delegate->CanExecuteScriptOnPage( 479 extension, document_url, top_frame_url, tab_id, 480 script, process_id, error)) 481 return false; 482 483 if ((document_url.host() == store_url.host()) && 484 !can_execute_everywhere && 485 !command_line->HasSwitch(switches::kAllowScriptingGallery)) { 486 if (error) 487 *error = errors::kCannotScriptGallery; 488 return false; 489 } 490 491 if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) { 492 if (document_url.SchemeIs(chrome::kChromeUIScheme) && 493 !can_execute_everywhere) { 494 if (error) 495 *error = errors::kCannotAccessChromeUrl; 496 return false; 497 } 498 } 499 500 if (top_frame_url.SchemeIs(extensions::kExtensionScheme) && 501 top_frame_url.GetOrigin() != 502 Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() && 503 !can_execute_everywhere) { 504 if (error) 505 *error = errors::kCannotAccessExtensionUrl; 506 return false; 507 } 508 509 // If a tab ID is specified, try the tab-specific permissions. 510 if (tab_id >= 0) { 511 scoped_refptr<const PermissionSet> tab_permissions = 512 GetTabSpecificPermissions(extension, tab_id); 513 if (tab_permissions.get() && 514 tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) { 515 return true; 516 } 517 } 518 519 bool can_access = false; 520 521 if (script) { 522 // If a script is specified, use its matches. 523 can_access = script->MatchesURL(document_url); 524 } else { 525 // Otherwise, see if this extension has permission to execute script 526 // programmatically on pages. 527 can_access = GetActivePermissions(extension)-> 528 HasExplicitAccessToOrigin(document_url); 529 } 530 531 if (!can_access && error) { 532 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, 533 document_url.spec()); 534 } 535 536 return can_access; 537 } 538 539 // static 540 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) { 541 if (extension->location() == Manifest::COMPONENT) 542 return true; 543 544 const Extension::ScriptingWhitelist* whitelist = 545 Extension::GetScriptingWhitelist(); 546 547 for (Extension::ScriptingWhitelist::const_iterator iter = whitelist->begin(); 548 iter != whitelist->end(); ++iter) { 549 if (extension->id() == *iter) 550 return true; 551 } 552 553 return false; 554 } 555 556 // static 557 bool PermissionsData::CanCaptureVisiblePage(const Extension* extension, 558 const GURL& page_url, 559 int tab_id, 560 std::string* error) { 561 if (tab_id >= 0) { 562 scoped_refptr<const PermissionSet> tab_permissions = 563 GetTabSpecificPermissions(extension, tab_id); 564 if (tab_permissions.get() && 565 tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) { 566 return true; 567 } 568 } 569 570 if (HasHostPermission(extension, page_url) || 571 page_url.GetOrigin() == extension->url()) { 572 return true; 573 } 574 575 if (error) { 576 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, 577 page_url.spec()); 578 } 579 return false; 580 } 581 582 bool PermissionsData::ParsePermissions(Extension* extension, string16* error) { 583 initial_required_permissions_.reset(new InitialPermissions); 584 if (!ParseHelper(extension, 585 keys::kPermissions, 586 &initial_required_permissions_->api_permissions, 587 &initial_required_permissions_->host_permissions, 588 error)) { 589 return false; 590 } 591 592 // TODO(jeremya/kalman) do this via the features system by exposing the 593 // app.window API to platform apps, with no dependency on any permissions. 594 // See http://crbug.com/120069. 595 if (extension->is_platform_app()) { 596 initial_required_permissions_->api_permissions.insert( 597 APIPermission::kAppCurrentWindowInternal); 598 initial_required_permissions_->api_permissions.insert( 599 APIPermission::kAppRuntime); 600 initial_required_permissions_->api_permissions.insert( 601 APIPermission::kAppWindow); 602 } 603 604 initial_optional_permissions_.reset(new InitialPermissions); 605 if (!ParseHelper(extension, 606 keys::kOptionalPermissions, 607 &initial_optional_permissions_->api_permissions, 608 &initial_optional_permissions_->host_permissions, 609 error)) { 610 return false; 611 } 612 613 if (ContainsManifestForbiddenPermission( 614 initial_required_permissions_->api_permissions, error) || 615 ContainsManifestForbiddenPermission( 616 initial_optional_permissions_->api_permissions, error)) { 617 return false; 618 } 619 620 return true; 621 } 622 623 void PermissionsData::FinalizePermissions(Extension* extension) { 624 active_permissions_ = new PermissionSet( 625 initial_required_permissions_->api_permissions, 626 initial_required_permissions_->host_permissions, 627 initial_required_permissions_->scriptable_hosts); 628 629 required_permission_set_ = new PermissionSet( 630 initial_required_permissions_->api_permissions, 631 initial_required_permissions_->host_permissions, 632 initial_required_permissions_->scriptable_hosts); 633 634 optional_permission_set_ = new PermissionSet( 635 initial_optional_permissions_->api_permissions, 636 initial_optional_permissions_->host_permissions, 637 URLPatternSet()); 638 639 initial_required_permissions_.reset(); 640 initial_optional_permissions_.reset(); 641 } 642 643 } // namespace extensions 644