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

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

Issue 189003004: Fix install verification for sideloaded extensions without update urls (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added comment Created 6 years, 9 months 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
« no previous file with comments | « chrome/browser/extensions/install_verifier.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/extensions/install_verifier.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698