| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/install_verifier.h" | 5 #include "chrome/browser/extensions/install_verifier.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 | 123 |
| 124 INIT_RESULT_MAX | 124 INIT_RESULT_MAX |
| 125 }; | 125 }; |
| 126 | 126 |
| 127 void LogInitResultHistogram(InitResult result) { | 127 void LogInitResultHistogram(InitResult result) { |
| 128 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult", | 128 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult", |
| 129 result, INIT_RESULT_MAX); | 129 result, INIT_RESULT_MAX); |
| 130 } | 130 } |
| 131 | 131 |
| 132 bool FromStore(const Extension& extension) { | 132 bool FromStore(const Extension& extension) { |
| 133 bool updates_from_store = ManifestURL::UpdatesFromGallery(&extension); | 133 if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension)) |
| 134 return extension.from_webstore() || updates_from_store; | 134 return true; |
| 135 |
| 136 // If an extension has no update url, our autoupdate code will ask the |
| 137 // webstore about it (to aid in migrating to the webstore from self-hosting |
| 138 // or sideloading based installs). So we want to do verification checks on |
| 139 // such extensions too so that we don't accidentally disable old installs of |
| 140 // extensions that did migrate to the webstore. |
| 141 return (ManifestURL::GetUpdateURL(&extension).is_empty() && |
| 142 Manifest::IsAutoUpdateableLocation(extension.location())); |
| 135 } | 143 } |
| 136 | 144 |
| 137 bool CanUseExtensionApis(const Extension& extension) { | 145 bool CanUseExtensionApis(const Extension& extension) { |
| 138 return extension.is_extension() || extension.is_legacy_packaged_app(); | 146 return extension.is_extension() || extension.is_legacy_packaged_app(); |
| 139 } | 147 } |
| 140 | 148 |
| 141 } // namespace | 149 } // namespace |
| 142 | 150 |
| 143 // static | 151 // static |
| 144 bool InstallVerifier::NeedsVerification(const Extension& extension) { | 152 bool InstallVerifier::NeedsVerification(const Extension& extension) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 return signature_.get() == NULL && ShouldFetchSignature(); | 184 return signature_.get() == NULL && ShouldFetchSignature(); |
| 177 } | 185 } |
| 178 | 186 |
| 179 base::Time InstallVerifier::SignatureTimestamp() { | 187 base::Time InstallVerifier::SignatureTimestamp() { |
| 180 if (signature_.get()) | 188 if (signature_.get()) |
| 181 return signature_->timestamp; | 189 return signature_->timestamp; |
| 182 else | 190 else |
| 183 return base::Time(); | 191 return base::Time(); |
| 184 } | 192 } |
| 185 | 193 |
| 194 bool InstallVerifier::IsKnownId(const std::string& id) { |
| 195 return signature_.get() && (ContainsKey(signature_->ids, id) || |
| 196 ContainsKey(signature_->invalid_ids, id)); |
| 197 } |
| 198 |
| 186 void InstallVerifier::Add(const std::string& id, | 199 void InstallVerifier::Add(const std::string& id, |
| 187 const AddResultCallback& callback) { | 200 const AddResultCallback& callback) { |
| 188 ExtensionIdSet ids; | 201 ExtensionIdSet ids; |
| 189 ids.insert(id); | 202 ids.insert(id); |
| 190 AddMany(ids, callback); | 203 AddMany(ids, callback); |
| 191 } | 204 } |
| 192 | 205 |
| 193 void InstallVerifier::AddMany(const ExtensionIdSet& ids, | 206 void InstallVerifier::AddMany(const ExtensionIdSet& ids, |
| 194 const AddResultCallback& callback) { | 207 const AddResultCallback& callback) { |
| 195 if (!ShouldFetchSignature()) { | 208 if (!ShouldFetchSignature()) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 ids.insert(id); | 244 ids.insert(id); |
| 232 RemoveMany(ids); | 245 RemoveMany(ids); |
| 233 } | 246 } |
| 234 | 247 |
| 235 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) { | 248 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) { |
| 236 if (!signature_.get() || !ShouldFetchSignature()) | 249 if (!signature_.get() || !ShouldFetchSignature()) |
| 237 return; | 250 return; |
| 238 | 251 |
| 239 bool found_any = false; | 252 bool found_any = false; |
| 240 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) { | 253 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) { |
| 241 if (ContainsKey(signature_->ids, *i)) { | 254 if (ContainsKey(signature_->ids, *i) || |
| 255 ContainsKey(signature_->invalid_ids, *i)) { |
| 242 found_any = true; | 256 found_any = true; |
| 243 break; | 257 break; |
| 244 } | 258 } |
| 245 } | 259 } |
| 246 if (!found_any) | 260 if (!found_any) |
| 247 return; | 261 return; |
| 248 | 262 |
| 249 InstallVerifier::PendingOperation* operation = | 263 InstallVerifier::PendingOperation* operation = |
| 250 new InstallVerifier::PendingOperation(); | 264 new InstallVerifier::PendingOperation(); |
| 251 operation->type = InstallVerifier::REMOVE; | 265 operation->type = InstallVerifier::REMOVE; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 266 VERIFIED = 0, | 280 VERIFIED = 0, |
| 267 NOT_EXTENSION, | 281 NOT_EXTENSION, |
| 268 UNPACKED, | 282 UNPACKED, |
| 269 ENTERPRISE_POLICY_ALLOWED, | 283 ENTERPRISE_POLICY_ALLOWED, |
| 270 FORCED_NOT_VERIFIED, | 284 FORCED_NOT_VERIFIED, |
| 271 NOT_FROM_STORE, | 285 NOT_FROM_STORE, |
| 272 NO_SIGNATURE, | 286 NO_SIGNATURE, |
| 273 NOT_VERIFIED_BUT_NOT_ENFORCING, | 287 NOT_VERIFIED_BUT_NOT_ENFORCING, |
| 274 NOT_VERIFIED, | 288 NOT_VERIFIED, |
| 275 NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE, | 289 NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE, |
| 290 NOT_VERIFIED_BUT_UNKNOWN_ID, |
| 291 COMPONENT, |
| 276 | 292 |
| 277 // This is used in histograms - do not remove or reorder entries above! Also | 293 // This is used in histograms - do not remove or reorder entries above! Also |
| 278 // the "MAX" item below should always be the last element. | 294 // the "MAX" item below should always be the last element. |
| 279 MUST_REMAIN_DISABLED_OUTCOME_MAX | 295 MUST_REMAIN_DISABLED_OUTCOME_MAX |
| 280 }; | 296 }; |
| 281 | 297 |
| 282 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) { | 298 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) { |
| 283 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled", | 299 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled", |
| 284 outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX); | 300 outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX); |
| 285 } | 301 } |
| 286 | 302 |
| 287 } // namespace | 303 } // namespace |
| 288 | 304 |
| 289 bool InstallVerifier::MustRemainDisabled(const Extension* extension, | 305 bool InstallVerifier::MustRemainDisabled(const Extension* extension, |
| 290 Extension::DisableReason* reason, | 306 Extension::DisableReason* reason, |
| 291 base::string16* error) const { | 307 base::string16* error) const { |
| 292 CHECK(extension); | 308 CHECK(extension); |
| 293 if (!CanUseExtensionApis(*extension)) { | 309 if (!CanUseExtensionApis(*extension)) { |
| 294 MustRemainDisabledHistogram(NOT_EXTENSION); | 310 MustRemainDisabledHistogram(NOT_EXTENSION); |
| 295 return false; | 311 return false; |
| 296 } | 312 } |
| 297 if (Manifest::IsUnpackedLocation(extension->location())) { | 313 if (Manifest::IsUnpackedLocation(extension->location())) { |
| 298 MustRemainDisabledHistogram(UNPACKED); | 314 MustRemainDisabledHistogram(UNPACKED); |
| 299 return false; | 315 return false; |
| 300 } | 316 } |
| 317 if (extension->location() == Manifest::COMPONENT) { |
| 318 MustRemainDisabledHistogram(COMPONENT); |
| 319 return false; |
| 320 } |
| 301 if (AllowedByEnterprisePolicy(extension->id())) { | 321 if (AllowedByEnterprisePolicy(extension->id())) { |
| 302 MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED); | 322 MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED); |
| 303 return false; | 323 return false; |
| 304 } | 324 } |
| 305 | 325 |
| 306 bool verified = true; | 326 bool verified = true; |
| 307 MustRemainDisabledOutcome outcome = VERIFIED; | 327 MustRemainDisabledOutcome outcome = VERIFIED; |
| 308 if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) { | 328 if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) { |
| 309 verified = false; | 329 verified = false; |
| 310 outcome = FORCED_NOT_VERIFIED; | 330 outcome = FORCED_NOT_VERIFIED; |
| 311 } else if (!FromStore(*extension)) { | 331 } else if (!FromStore(*extension)) { |
| 312 verified = false; | 332 verified = false; |
| 313 outcome = NOT_FROM_STORE; | 333 outcome = NOT_FROM_STORE; |
| 314 } else if (signature_.get() == NULL) { | 334 } else if (signature_.get() == NULL) { |
| 315 // If we don't have a signature yet, we'll temporarily consider every | 335 // If we don't have a signature yet, we'll temporarily consider every |
| 316 // extension from the webstore verified to avoid false positives on existing | 336 // extension from the webstore verified to avoid false positives on existing |
| 317 // profiles hitting this code for the first time, and rely on consumers of | 337 // profiles hitting this code for the first time, and rely on consumers of |
| 318 // this class to check NeedsBootstrap() and schedule a first check so we can | 338 // this class to check NeedsBootstrap() and schedule a first check so we can |
| 319 // get a signature. | 339 // get a signature. |
| 320 outcome = NO_SIGNATURE; | 340 outcome = NO_SIGNATURE; |
| 321 } else if (!IsVerified(extension->id())) { | 341 } else if (!IsVerified(extension->id())) { |
| 322 if (WasInstalledAfterSignature(extension->id())) { | 342 if (!ContainsKey(signature_->invalid_ids, extension->id())) { |
| 323 outcome = NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE; | 343 outcome = NOT_VERIFIED_BUT_UNKNOWN_ID; |
| 324 } else { | 344 } else { |
| 325 verified = false; | 345 verified = false; |
| 326 outcome = NOT_VERIFIED; | 346 outcome = NOT_VERIFIED; |
| 327 } | 347 } |
| 328 } | 348 } |
| 329 if (!verified && !ShouldEnforce()) { | 349 if (!verified && !ShouldEnforce()) { |
| 330 verified = true; | 350 verified = true; |
| 331 outcome = NOT_VERIFIED_BUT_NOT_ENFORCING; | 351 outcome = NOT_VERIFIED_BUT_NOT_ENFORCING; |
| 332 } | 352 } |
| 333 MustRemainDisabledHistogram(outcome); | 353 MustRemainDisabledHistogram(outcome); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 349 | 369 |
| 350 InstallVerifier::PendingOperation::~PendingOperation() { | 370 InstallVerifier::PendingOperation::~PendingOperation() { |
| 351 } | 371 } |
| 352 | 372 |
| 353 void InstallVerifier::GarbageCollect() { | 373 void InstallVerifier::GarbageCollect() { |
| 354 if (!ShouldFetchSignature()) { | 374 if (!ShouldFetchSignature()) { |
| 355 return; | 375 return; |
| 356 } | 376 } |
| 357 CHECK(signature_.get()); | 377 CHECK(signature_.get()); |
| 358 ExtensionIdSet leftovers = signature_->ids; | 378 ExtensionIdSet leftovers = signature_->ids; |
| 379 leftovers.insert(signature_->invalid_ids.begin(), |
| 380 signature_->invalid_ids.end()); |
| 359 ExtensionIdList all_ids; | 381 ExtensionIdList all_ids; |
| 360 prefs_->GetExtensions(&all_ids); | 382 prefs_->GetExtensions(&all_ids); |
| 361 for (ExtensionIdList::const_iterator i = all_ids.begin(); | 383 for (ExtensionIdList::const_iterator i = all_ids.begin(); |
| 362 i != all_ids.end(); ++i) { | 384 i != all_ids.end(); ++i) { |
| 363 ExtensionIdSet::iterator found = leftovers.find(*i); | 385 ExtensionIdSet::iterator found = leftovers.find(*i); |
| 364 if (found != leftovers.end()) | 386 if (found != leftovers.end()) |
| 365 leftovers.erase(found); | 387 leftovers.erase(found); |
| 366 } | 388 } |
| 367 if (!leftovers.empty()) { | 389 if (!leftovers.empty()) { |
| 368 RemoveMany(leftovers); | 390 RemoveMany(leftovers); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 385 return true; | 407 return true; |
| 386 } | 408 } |
| 387 return false; | 409 return false; |
| 388 } | 410 } |
| 389 | 411 |
| 390 bool InstallVerifier::IsVerified(const std::string& id) const { | 412 bool InstallVerifier::IsVerified(const std::string& id) const { |
| 391 return ((signature_.get() && ContainsKey(signature_->ids, id)) || | 413 return ((signature_.get() && ContainsKey(signature_->ids, id)) || |
| 392 ContainsKey(provisional_, id)); | 414 ContainsKey(provisional_, id)); |
| 393 } | 415 } |
| 394 | 416 |
| 395 bool InstallVerifier::WasInstalledAfterSignature(const std::string& id) const { | |
| 396 if (!signature_.get() || signature_->timestamp.is_null()) | |
| 397 return true; | |
| 398 | |
| 399 base::Time install_time = prefs_->GetInstallTime(id); | |
| 400 // If the extension install time is in the future, just assume it isn't | |
| 401 // newer than the signature. (Either the clock went backwards, or | |
| 402 // an attacker changed the install time in the preferences). | |
| 403 if (install_time >= base::Time::Now()) | |
| 404 return false; | |
| 405 return install_time > signature_->timestamp; | |
| 406 } | |
| 407 | |
| 408 void InstallVerifier::BeginFetch() { | 417 void InstallVerifier::BeginFetch() { |
| 409 DCHECK(ShouldFetchSignature()); | 418 DCHECK(ShouldFetchSignature()); |
| 410 | 419 |
| 411 // TODO(asargent) - It would be possible to coalesce all operations in the | 420 // TODO(asargent) - It would be possible to coalesce all operations in the |
| 412 // queue into one fetch - we'd probably just need to change the queue to | 421 // queue into one fetch - we'd probably just need to change the queue to |
| 413 // hold (set of ids, list of callbacks) pairs. | 422 // hold (set of ids, list of callbacks) pairs. |
| 414 CHECK(!operation_queue_.empty()); | 423 CHECK(!operation_queue_.empty()); |
| 415 const PendingOperation& operation = *operation_queue_.front(); | 424 const PendingOperation& operation = *operation_queue_.front(); |
| 416 | 425 |
| 417 ExtensionIdSet ids_to_sign; | 426 ExtensionIdSet ids_to_sign; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 if (!operation->callback.is_null()) | 519 if (!operation->callback.is_null()) |
| 511 operation->callback.Run(success); | 520 operation->callback.Run(success); |
| 512 } | 521 } |
| 513 | 522 |
| 514 if (!operation_queue_.empty()) | 523 if (!operation_queue_.empty()) |
| 515 BeginFetch(); | 524 BeginFetch(); |
| 516 } | 525 } |
| 517 | 526 |
| 518 | 527 |
| 519 } // namespace extensions | 528 } // namespace extensions |
| OLD | NEW |