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 |