1 // Copyright 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/browser/extensions/install_verifier.h" 6 7 #include <algorithm> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/command_line.h" 12 #include "base/metrics/field_trial.h" 13 #include "base/metrics/histogram.h" 14 #include "base/prefs/pref_service.h" 15 #include "base/stl_util.h" 16 #include "chrome/browser/extensions/extension_management.h" 17 #include "chrome/browser/extensions/extension_service.h" 18 #include "chrome/browser/extensions/install_signer.h" 19 #include "chrome/common/chrome_switches.h" 20 #include "chrome/common/extensions/manifest_url_handler.h" 21 #include "chrome/common/pref_names.h" 22 #include "chrome/grit/generated_resources.h" 23 #include "content/public/browser/browser_context.h" 24 #include "content/public/common/content_switches.h" 25 #include "extensions/browser/extension_prefs.h" 26 #include "extensions/browser/extension_registry.h" 27 #include "extensions/browser/extension_system.h" 28 #include "extensions/browser/pref_names.h" 29 #include "extensions/common/extension_set.h" 30 #include "extensions/common/manifest.h" 31 #include "extensions/common/one_shot_event.h" 32 #include "ui/base/l10n/l10n_util.h" 33 34 namespace extensions { 35 36 namespace { 37 38 enum VerifyStatus { 39 NONE = 0, // Do not request install signatures, and do not enforce them. 40 BOOTSTRAP, // Request install signatures, but do not enforce them. 41 ENFORCE, // Request install signatures, and enforce them. 42 ENFORCE_STRICT, // Same as ENFORCE, but hard fail if we can't fetch 43 // signatures. 44 45 // This is used in histograms - do not remove or reorder entries above! Also 46 // the "MAX" item below should always be the last element. 47 VERIFY_STATUS_MAX 48 }; 49 50 #if defined(GOOGLE_CHROME_BUILD) 51 const char kExperimentName[] = "ExtensionInstallVerification"; 52 #endif // defined(GOOGLE_CHROME_BUILD) 53 54 VerifyStatus GetExperimentStatus() { 55 #if defined(GOOGLE_CHROME_BUILD) 56 const std::string group = base::FieldTrialList::FindFullName( 57 kExperimentName); 58 59 std::string forced_trials = CommandLine::ForCurrentProcess()-> 60 GetSwitchValueASCII(switches::kForceFieldTrials); 61 if (forced_trials.find(kExperimentName) != std::string::npos) { 62 // We don't want to allow turning off enforcement by forcing the field 63 // trial group to something other than enforcement. 64 return ENFORCE_STRICT; 65 } 66 67 VerifyStatus default_status = NONE; 68 69 if (group == "EnforceStrict") 70 return ENFORCE_STRICT; 71 else if (group == "Enforce") 72 return ENFORCE; 73 else if (group == "Bootstrap") 74 return BOOTSTRAP; 75 else if (group == "None" || group == "Control") 76 return NONE; 77 else 78 return default_status; 79 #endif // defined(GOOGLE_CHROME_BUILD) 80 81 return NONE; 82 } 83 84 VerifyStatus GetCommandLineStatus() { 85 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); 86 if (!InstallSigner::GetForcedNotFromWebstore().empty()) 87 return ENFORCE; 88 89 if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) { 90 std::string value = cmdline->GetSwitchValueASCII( 91 switches::kExtensionsInstallVerification); 92 if (value == "bootstrap") 93 return BOOTSTRAP; 94 else if (value == "enforce_strict") 95 return ENFORCE_STRICT; 96 else 97 return ENFORCE; 98 } 99 100 return NONE; 101 } 102 103 VerifyStatus GetStatus() { 104 return std::max(GetExperimentStatus(), GetCommandLineStatus()); 105 } 106 107 bool ShouldFetchSignature() { 108 return GetStatus() >= BOOTSTRAP; 109 } 110 111 bool ShouldEnforce() { 112 return GetStatus() >= ENFORCE; 113 } 114 115 enum InitResult { 116 INIT_NO_PREF = 0, 117 INIT_UNPARSEABLE_PREF, 118 INIT_INVALID_SIGNATURE, 119 INIT_VALID_SIGNATURE, 120 121 // This is used in histograms - do not remove or reorder entries above! Also 122 // the "MAX" item below should always be the last element. 123 124 INIT_RESULT_MAX 125 }; 126 127 void LogInitResultHistogram(InitResult result) { 128 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult", 129 result, INIT_RESULT_MAX); 130 } 131 132 bool CanUseExtensionApis(const Extension& extension) { 133 return extension.is_extension() || extension.is_legacy_packaged_app(); 134 } 135 136 enum VerifyAllSuccess { 137 VERIFY_ALL_BOOTSTRAP_SUCCESS = 0, 138 VERIFY_ALL_BOOTSTRAP_FAILURE, 139 VERIFY_ALL_NON_BOOTSTRAP_SUCCESS, 140 VERIFY_ALL_NON_BOOTSTRAP_FAILURE, 141 142 // Used in histograms. Do not remove/reorder any entries above, and the below 143 // MAX entry should always come last. 144 VERIFY_ALL_SUCCESS_MAX 145 }; 146 147 // Record the success or failure of verifying all extensions, and whether or 148 // not it was a bootstrapping. 149 void LogVerifyAllSuccessHistogram(bool bootstrap, bool success) { 150 VerifyAllSuccess result; 151 if (bootstrap && success) 152 result = VERIFY_ALL_BOOTSTRAP_SUCCESS; 153 else if (bootstrap && !success) 154 result = VERIFY_ALL_BOOTSTRAP_FAILURE; 155 else if (!bootstrap && success) 156 result = VERIFY_ALL_NON_BOOTSTRAP_SUCCESS; 157 else 158 result = VERIFY_ALL_NON_BOOTSTRAP_FAILURE; 159 160 // This used to be part of ExtensionService, but moved here. In order to keep 161 // our histograms accurate, the name is unchanged. 162 UMA_HISTOGRAM_ENUMERATION( 163 "ExtensionService.VerifyAllSuccess", result, VERIFY_ALL_SUCCESS_MAX); 164 } 165 166 // Record the success or failure of a single verification. 167 void LogAddVerifiedSuccess(bool success) { 168 // This used to be part of ExtensionService, but moved here. In order to keep 169 // our histograms accurate, the name is unchanged. 170 UMA_HISTOGRAM_BOOLEAN("ExtensionService.AddVerified", success); 171 } 172 173 } // namespace 174 175 InstallVerifier::InstallVerifier(ExtensionPrefs* prefs, 176 content::BrowserContext* context) 177 : prefs_(prefs), 178 context_(context), 179 bootstrap_check_complete_(false), 180 weak_factory_(this) { 181 } 182 183 InstallVerifier::~InstallVerifier() {} 184 185 // static 186 bool InstallVerifier::NeedsVerification(const Extension& extension) { 187 return IsFromStore(extension) && CanUseExtensionApis(extension); 188 } 189 190 191 192 // static 193 bool InstallVerifier::IsFromStore(const Extension& extension) { 194 if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension)) 195 return true; 196 197 // If an extension has no update url, our autoupdate code will ask the 198 // webstore about it (to aid in migrating to the webstore from self-hosting 199 // or sideloading based installs). So we want to do verification checks on 200 // such extensions too so that we don't accidentally disable old installs of 201 // extensions that did migrate to the webstore. 202 return (ManifestURL::GetUpdateURL(&extension).is_empty() && 203 Manifest::IsAutoUpdateableLocation(extension.location())); 204 } 205 206 void InstallVerifier::Init() { 207 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus", 208 GetExperimentStatus(), VERIFY_STATUS_MAX); 209 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus", 210 GetStatus(), VERIFY_STATUS_MAX); 211 212 const base::DictionaryValue* pref = prefs_->GetInstallSignature(); 213 if (pref) { 214 scoped_ptr<InstallSignature> signature_from_prefs = 215 InstallSignature::FromValue(*pref); 216 if (!signature_from_prefs.get()) { 217 LogInitResultHistogram(INIT_UNPARSEABLE_PREF); 218 } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) { 219 LogInitResultHistogram(INIT_INVALID_SIGNATURE); 220 DVLOG(1) << "Init - ignoring invalid signature"; 221 } else { 222 signature_ = signature_from_prefs.Pass(); 223 LogInitResultHistogram(INIT_VALID_SIGNATURE); 224 UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount", 225 signature_->ids.size()); 226 GarbageCollect(); 227 } 228 } else { 229 LogInitResultHistogram(INIT_NO_PREF); 230 } 231 232 ExtensionSystem::Get(context_)->ready().Post( 233 FROM_HERE, 234 base::Bind(&InstallVerifier::MaybeBootstrapSelf, 235 weak_factory_.GetWeakPtr())); 236 } 237 238 void InstallVerifier::VerifyAllExtensions() { 239 AddMany(GetExtensionsToVerify(), ADD_ALL); 240 } 241 242 base::Time InstallVerifier::SignatureTimestamp() { 243 if (signature_.get()) 244 return signature_->timestamp; 245 else 246 return base::Time(); 247 } 248 249 bool InstallVerifier::IsKnownId(const std::string& id) const { 250 return signature_.get() && (ContainsKey(signature_->ids, id) || 251 ContainsKey(signature_->invalid_ids, id)); 252 } 253 254 bool InstallVerifier::IsInvalid(const std::string& id) const { 255 return ((signature_.get() && ContainsKey(signature_->invalid_ids, id))); 256 } 257 258 void InstallVerifier::VerifyExtension(const std::string& extension_id) { 259 ExtensionIdSet ids; 260 ids.insert(extension_id); 261 AddMany(ids, ADD_SINGLE); 262 } 263 264 void InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) { 265 if (!ShouldFetchSignature()) { 266 OnVerificationComplete(true, type); // considered successful. 267 return; 268 } 269 270 if (signature_.get()) { 271 ExtensionIdSet not_allowed_yet = 272 base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids); 273 if (not_allowed_yet.empty()) { 274 OnVerificationComplete(true, type); // considered successful. 275 return; 276 } 277 } 278 279 InstallVerifier::PendingOperation* operation = 280 new InstallVerifier::PendingOperation(type); 281 operation->ids.insert(ids.begin(), ids.end()); 282 283 operation_queue_.push(linked_ptr<PendingOperation>(operation)); 284 285 // If there are no ongoing pending requests, we need to kick one off. 286 if (operation_queue_.size() == 1) 287 BeginFetch(); 288 } 289 290 void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) { 291 provisional_.insert(ids.begin(), ids.end()); 292 AddMany(ids, ADD_PROVISIONAL); 293 } 294 295 void InstallVerifier::Remove(const std::string& id) { 296 ExtensionIdSet ids; 297 ids.insert(id); 298 RemoveMany(ids); 299 } 300 301 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) { 302 if (!signature_.get() || !ShouldFetchSignature()) 303 return; 304 305 bool found_any = false; 306 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) { 307 if (ContainsKey(signature_->ids, *i) || 308 ContainsKey(signature_->invalid_ids, *i)) { 309 found_any = true; 310 break; 311 } 312 } 313 if (!found_any) 314 return; 315 316 InstallVerifier::PendingOperation* operation = 317 new InstallVerifier::PendingOperation(InstallVerifier::REMOVE); 318 operation->ids = ids; 319 320 operation_queue_.push(linked_ptr<PendingOperation>(operation)); 321 if (operation_queue_.size() == 1) 322 BeginFetch(); 323 } 324 325 bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const { 326 return ExtensionManagementFactory::GetForBrowserContext(context_) 327 ->IsInstallationExplicitlyAllowed(id); 328 } 329 330 std::string InstallVerifier::GetDebugPolicyProviderName() const { 331 return std::string("InstallVerifier"); 332 } 333 334 namespace { 335 336 enum MustRemainDisabledOutcome { 337 VERIFIED = 0, 338 NOT_EXTENSION, 339 UNPACKED, 340 ENTERPRISE_POLICY_ALLOWED, 341 FORCED_NOT_VERIFIED, 342 NOT_FROM_STORE, 343 NO_SIGNATURE, 344 NOT_VERIFIED_BUT_NOT_ENFORCING, 345 NOT_VERIFIED, 346 NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE, 347 NOT_VERIFIED_BUT_UNKNOWN_ID, 348 COMPONENT, 349 350 // This is used in histograms - do not remove or reorder entries above! Also 351 // the "MAX" item below should always be the last element. 352 MUST_REMAIN_DISABLED_OUTCOME_MAX 353 }; 354 355 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) { 356 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled", 357 outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX); 358 } 359 360 } // namespace 361 362 bool InstallVerifier::MustRemainDisabled(const Extension* extension, 363 Extension::DisableReason* reason, 364 base::string16* error) const { 365 CHECK(extension); 366 if (!CanUseExtensionApis(*extension)) { 367 MustRemainDisabledHistogram(NOT_EXTENSION); 368 return false; 369 } 370 if (Manifest::IsUnpackedLocation(extension->location())) { 371 MustRemainDisabledHistogram(UNPACKED); 372 return false; 373 } 374 if (extension->location() == Manifest::COMPONENT) { 375 MustRemainDisabledHistogram(COMPONENT); 376 return false; 377 } 378 if (AllowedByEnterprisePolicy(extension->id())) { 379 MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED); 380 return false; 381 } 382 383 bool verified = true; 384 MustRemainDisabledOutcome outcome = VERIFIED; 385 if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) { 386 verified = false; 387 outcome = FORCED_NOT_VERIFIED; 388 } else if (!IsFromStore(*extension)) { 389 verified = false; 390 outcome = NOT_FROM_STORE; 391 } else if (signature_.get() == NULL && 392 (!bootstrap_check_complete_ || GetStatus() < ENFORCE_STRICT)) { 393 // If we don't have a signature yet, we'll temporarily consider every 394 // extension from the webstore verified to avoid false positives on existing 395 // profiles hitting this code for the first time. The InstallVerifier 396 // will bootstrap itself once the ExtensionsSystem is ready. 397 outcome = NO_SIGNATURE; 398 } else if (!IsVerified(extension->id())) { 399 if (signature_.get() && 400 !ContainsKey(signature_->invalid_ids, extension->id())) { 401 outcome = NOT_VERIFIED_BUT_UNKNOWN_ID; 402 } else { 403 verified = false; 404 outcome = NOT_VERIFIED; 405 } 406 } 407 if (!verified && !ShouldEnforce()) { 408 verified = true; 409 outcome = NOT_VERIFIED_BUT_NOT_ENFORCING; 410 } 411 MustRemainDisabledHistogram(outcome); 412 413 if (!verified) { 414 if (reason) 415 *reason = Extension::DISABLE_NOT_VERIFIED; 416 if (error) 417 *error = l10n_util::GetStringFUTF16( 418 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE, 419 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); 420 } 421 return !verified; 422 } 423 424 InstallVerifier::PendingOperation::PendingOperation(OperationType type) 425 : type(type) {} 426 427 InstallVerifier::PendingOperation::~PendingOperation() { 428 } 429 430 ExtensionIdSet InstallVerifier::GetExtensionsToVerify() const { 431 ExtensionIdSet result; 432 scoped_ptr<ExtensionSet> extensions = 433 ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet(); 434 for (ExtensionSet::const_iterator iter = extensions->begin(); 435 iter != extensions->end(); 436 ++iter) { 437 if (NeedsVerification(*iter->get())) 438 result.insert((*iter)->id()); 439 } 440 return result; 441 } 442 443 void InstallVerifier::MaybeBootstrapSelf() { 444 bool needs_bootstrap = false; 445 446 ExtensionIdSet extension_ids = GetExtensionsToVerify(); 447 if (signature_.get() == NULL && ShouldFetchSignature()) { 448 needs_bootstrap = true; 449 } else { 450 for (ExtensionIdSet::const_iterator iter = extension_ids.begin(); 451 iter != extension_ids.end(); 452 ++iter) { 453 if (!IsKnownId(*iter)) { 454 needs_bootstrap = true; 455 break; 456 } 457 } 458 } 459 460 if (needs_bootstrap) 461 AddMany(extension_ids, ADD_ALL_BOOTSTRAP); 462 else 463 bootstrap_check_complete_ = true; 464 } 465 466 void InstallVerifier::OnVerificationComplete(bool success, OperationType type) { 467 switch (type) { 468 case ADD_SINGLE: 469 LogAddVerifiedSuccess(success); 470 break; 471 case ADD_ALL: 472 case ADD_ALL_BOOTSTRAP: 473 LogVerifyAllSuccessHistogram(type == ADD_ALL_BOOTSTRAP, success); 474 bootstrap_check_complete_ = true; 475 if (success) { 476 // Iterate through the extensions and, if any are newly-verified and 477 // should have the DISABLE_NOT_VERIFIED reason lifted, do so. 478 const ExtensionSet& disabled_extensions = 479 ExtensionRegistry::Get(context_)->disabled_extensions(); 480 for (ExtensionSet::const_iterator iter = disabled_extensions.begin(); 481 iter != disabled_extensions.end(); 482 ++iter) { 483 int disable_reasons = prefs_->GetDisableReasons((*iter)->id()); 484 if (disable_reasons & Extension::DISABLE_NOT_VERIFIED && 485 !MustRemainDisabled(iter->get(), NULL, NULL)) { 486 prefs_->RemoveDisableReason((*iter)->id(), 487 Extension::DISABLE_NOT_VERIFIED); 488 } 489 } 490 } 491 if (success || GetStatus() == ENFORCE_STRICT) { 492 ExtensionSystem::Get(context_) 493 ->extension_service() 494 ->CheckManagementPolicy(); 495 } 496 break; 497 // We don't need to check disable reasons or report UMA stats for 498 // provisional adds or removals. 499 case ADD_PROVISIONAL: 500 case REMOVE: 501 break; 502 } 503 } 504 505 void InstallVerifier::GarbageCollect() { 506 if (!ShouldFetchSignature()) { 507 return; 508 } 509 CHECK(signature_.get()); 510 ExtensionIdSet leftovers = signature_->ids; 511 leftovers.insert(signature_->invalid_ids.begin(), 512 signature_->invalid_ids.end()); 513 ExtensionIdList all_ids; 514 prefs_->GetExtensions(&all_ids); 515 for (ExtensionIdList::const_iterator i = all_ids.begin(); 516 i != all_ids.end(); ++i) { 517 ExtensionIdSet::iterator found = leftovers.find(*i); 518 if (found != leftovers.end()) 519 leftovers.erase(found); 520 } 521 if (!leftovers.empty()) { 522 RemoveMany(leftovers); 523 } 524 } 525 526 bool InstallVerifier::IsVerified(const std::string& id) const { 527 return ((signature_.get() && ContainsKey(signature_->ids, id)) || 528 ContainsKey(provisional_, id)); 529 } 530 531 void InstallVerifier::BeginFetch() { 532 DCHECK(ShouldFetchSignature()); 533 534 // TODO(asargent) - It would be possible to coalesce all operations in the 535 // queue into one fetch - we'd probably just need to change the queue to 536 // hold (set of ids, list of operation type) pairs. 537 CHECK(!operation_queue_.empty()); 538 const PendingOperation& operation = *operation_queue_.front(); 539 540 ExtensionIdSet ids_to_sign; 541 if (signature_.get()) { 542 ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end()); 543 } 544 if (operation.type == InstallVerifier::REMOVE) { 545 for (ExtensionIdSet::const_iterator i = operation.ids.begin(); 546 i != operation.ids.end(); ++i) { 547 if (ContainsKey(ids_to_sign, *i)) 548 ids_to_sign.erase(*i); 549 } 550 } else { // All other operation types are some form of "ADD". 551 ids_to_sign.insert(operation.ids.begin(), operation.ids.end()); 552 } 553 554 signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign)); 555 signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback, 556 weak_factory_.GetWeakPtr())); 557 } 558 559 void InstallVerifier::SaveToPrefs() { 560 if (signature_.get()) 561 DCHECK(InstallSigner::VerifySignature(*signature_)); 562 563 if (!signature_.get() || signature_->ids.empty()) { 564 DVLOG(1) << "SaveToPrefs - saving NULL"; 565 prefs_->SetInstallSignature(NULL); 566 } else { 567 base::DictionaryValue pref; 568 signature_->ToValue(&pref); 569 if (VLOG_IS_ON(1)) { 570 DVLOG(1) << "SaveToPrefs - saving"; 571 572 DCHECK(InstallSigner::VerifySignature(*signature_.get())); 573 scoped_ptr<InstallSignature> rehydrated = 574 InstallSignature::FromValue(pref); 575 DCHECK(InstallSigner::VerifySignature(*rehydrated.get())); 576 } 577 prefs_->SetInstallSignature(&pref); 578 } 579 } 580 581 namespace { 582 583 enum CallbackResult { 584 CALLBACK_NO_SIGNATURE = 0, 585 CALLBACK_INVALID_SIGNATURE, 586 CALLBACK_VALID_SIGNATURE, 587 588 // This is used in histograms - do not remove or reorder entries above! Also 589 // the "MAX" item below should always be the last element. 590 591 CALLBACK_RESULT_MAX 592 }; 593 594 void GetSignatureResultHistogram(CallbackResult result) { 595 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult", 596 result, CALLBACK_RESULT_MAX); 597 } 598 599 } // namespace 600 601 void InstallVerifier::SignatureCallback( 602 scoped_ptr<InstallSignature> signature) { 603 604 linked_ptr<PendingOperation> operation = operation_queue_.front(); 605 operation_queue_.pop(); 606 607 bool success = false; 608 if (!signature.get()) { 609 GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE); 610 } else if (!InstallSigner::VerifySignature(*signature)) { 611 GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE); 612 } else { 613 GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE); 614 success = true; 615 } 616 617 if (!success) { 618 OnVerificationComplete(false, operation->type); 619 620 // TODO(asargent) - if this was something like a network error, we need to 621 // do retries with exponential back off. 622 } else { 623 signature_ = signature.Pass(); 624 SaveToPrefs(); 625 626 if (!provisional_.empty()) { 627 // Update |provisional_| to remove ids that were successfully signed. 628 provisional_ = base::STLSetDifference<ExtensionIdSet>( 629 provisional_, signature_->ids); 630 } 631 632 OnVerificationComplete(success, operation->type); 633 } 634 635 if (!operation_queue_.empty()) 636 BeginFetch(); 637 } 638 639 } // namespace extensions 640