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

Side by Side Diff: chrome/browser/enumerate_modules_model_win.cc

Issue 5183007: Polish the Enumerate Modules implementation a bit.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 1 month 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/enumerate_modules_model_win.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 (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/enumerate_modules_model_win.h" 5 #include "chrome/browser/enumerate_modules_model_win.h"
6 6
7 #include <Tlhelp32.h> 7 #include <Tlhelp32.h>
8 #include <wintrust.h> 8 #include <wintrust.h>
9 9
10 #include "app/l10n_util.h" 10 #include "app/l10n_util.h"
11 #include "app/win_util.h" 11 #include "app/win_util.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/environment.h" 13 #include "base/environment.h"
14 #include "base/file_path.h" 14 #include "base/file_path.h"
15 #include "base/file_version_info_win.h" 15 #include "base/file_version_info_win.h"
16 #include "base/metrics/histogram.h"
16 #include "base/scoped_handle.h" 17 #include "base/scoped_handle.h"
17 #include "base/sha2.h" 18 #include "base/sha2.h"
18 #include "base/string_number_conversions.h" 19 #include "base/string_number_conversions.h"
19 #include "base/string_util.h" 20 #include "base/string_util.h"
21 #include "base/time.h"
20 #include "base/utf_string_conversions.h" 22 #include "base/utf_string_conversions.h"
21 #include "base/values.h" 23 #include "base/values.h"
22 #include "base/version.h" 24 #include "base/version.h"
23 #include "base/win/registry.h" 25 #include "base/win/registry.h"
24 #include "chrome/browser/net/service_providers_win.h" 26 #include "chrome/browser/net/service_providers_win.h"
25 #include "chrome/common/chrome_constants.h" 27 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/notification_service.h" 29 #include "chrome/common/notification_service.h"
28 #include "grit/generated_resources.h" 30 #include "grit/generated_resources.h"
29 31
(...skipping 16 matching lines...) Expand all
46 48
47 return a.location < b.location; 49 return a.location < b.location;
48 } 50 }
49 51
50 namespace { 52 namespace {
51 53
52 // Used to protect the LoadedModuleVector which is accessed 54 // Used to protect the LoadedModuleVector which is accessed
53 // from both the UI thread and the FILE thread. 55 // from both the UI thread and the FILE thread.
54 Lock* lock = NULL; 56 Lock* lock = NULL;
55 57
58 // A struct to help de-duping modules before adding them to the enumerated
59 // modules vector.
60 struct FindModule {
61 public:
62 explicit FindModule(const ModuleEnumerator::Module& x)
63 : module(x) {}
64 bool operator()(ModuleEnumerator::Module module_in) const {
65 return (module.type == module_in.type) &&
66 (module.location == module_in.location) &&
67 (module.name == module_in.name);
68 }
69
70 const ModuleEnumerator::Module& module;
71 };
72
56 } 73 }
57 74
58 // The browser process module blacklist. This lists all modules that are known 75 // The browser process module blacklist. This lists all modules that are known
59 // to cause compatibility issues within the browser process. When adding to this 76 // to cause compatibility issues within the browser process. When adding to this
60 // list, make sure that all paths are lower-case, in long pathname form, end 77 // list, make sure that all paths are lower-case, in long pathname form, end
61 // with a slash and use environments variables (or just look at one of the 78 // with a slash and use environments variables (or just look at one of the
62 // comments below and keep it consistent with that). When adding an entry with 79 // comments below and keep it consistent with that). When adding an entry with
63 // an environment variable not currently used in the list below, make sure to 80 // an environment variable not currently used in the list below, make sure to
64 // update the list in PreparePathMappings. Filename, Description/Signer, and 81 // update the list in PreparePathMappings. Filename, Description/Signer, and
65 // Location must be entered as hashes (see GenerateHash). Filename is mandatory. 82 // Location must be entered as hashes (see GenerateHash). Filename is mandatory.
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 236
220 void ModuleEnumerator::ScanNow(ModulesVector* list) { 237 void ModuleEnumerator::ScanNow(ModulesVector* list) {
221 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); 238 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE));
222 enumerated_modules_ = list; 239 enumerated_modules_ = list;
223 BrowserThread::PostTask( 240 BrowserThread::PostTask(
224 BrowserThread::FILE, FROM_HERE, 241 BrowserThread::FILE, FROM_HERE,
225 NewRunnableMethod(this, &ModuleEnumerator::ScanOnFileThread)); 242 NewRunnableMethod(this, &ModuleEnumerator::ScanOnFileThread));
226 } 243 }
227 244
228 void ModuleEnumerator::ScanOnFileThread() { 245 void ModuleEnumerator::ScanOnFileThread() {
246 base::TimeTicks start_time = base::TimeTicks::Now();
247
229 enumerated_modules_->clear(); 248 enumerated_modules_->clear();
230 249
231 // Make sure the path mapping vector is setup so we can collapse paths. 250 // Make sure the path mapping vector is setup so we can collapse paths.
232 PreparePathMappings(); 251 PreparePathMappings();
233 252
253 base::TimeTicks checkpoint = base::TimeTicks::Now();
234 EnumerateLoadedModules(); 254 EnumerateLoadedModules();
255 HISTOGRAM_TIMES("Conflicts.EnumerateLoadedModules",
256 base::TimeTicks::Now() - checkpoint);
257
258 checkpoint = base::TimeTicks::Now();
235 EnumerateShellExtensions(); 259 EnumerateShellExtensions();
236 EnumerateWinsockModule(); 260 HISTOGRAM_TIMES("Conflicts.EnumerateShellExtensions",
261 base::TimeTicks::Now() - checkpoint);
262
263 checkpoint = base::TimeTicks::Now();
264 EnumerateWinsockModules();
265 HISTOGRAM_TIMES("Conflicts.EnumerateWinsockModules",
266 base::TimeTicks::Now() - checkpoint);
237 267
238 MatchAgainstBlacklist(); 268 MatchAgainstBlacklist();
239 269
240 std::sort(enumerated_modules_->begin(), 270 std::sort(enumerated_modules_->begin(),
241 enumerated_modules_->end(), ModuleSort); 271 enumerated_modules_->end(), ModuleSort);
242 272
243 // Send a reply back on the UI thread. 273 // Send a reply back on the UI thread.
244 BrowserThread::PostTask( 274 BrowserThread::PostTask(
245 callback_thread_id_, FROM_HERE, 275 callback_thread_id_, FROM_HERE,
246 NewRunnableMethod(this, &ModuleEnumerator::ReportBack)); 276 NewRunnableMethod(this, &ModuleEnumerator::ReportBack));
277
278 HISTOGRAM_TIMES("Conflicts.EnumerationTotalTime",
279 base::TimeTicks::Now() - start_time);
247 } 280 }
248 281
249 void ModuleEnumerator::EnumerateLoadedModules() { 282 void ModuleEnumerator::EnumerateLoadedModules() {
250 // Get all modules in the current process. 283 // Get all modules in the current process.
251 ScopedHandle snap(::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 284 ScopedHandle snap(::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
252 ::GetCurrentProcessId())); 285 ::GetCurrentProcessId()));
253 if (!snap.Get()) 286 if (!snap.Get())
254 return; 287 return;
255 288
256 // Walk the module list. 289 // Walk the module list.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 } 329 }
297 clsid.Close(); 330 clsid.Close();
298 331
299 Module entry; 332 Module entry;
300 entry.type = SHELL_EXTENSION; 333 entry.type = SHELL_EXTENSION;
301 entry.location = dll; 334 entry.location = dll;
302 PopulateModuleInformation(&entry); 335 PopulateModuleInformation(&entry);
303 336
304 NormalizeModule(&entry); 337 NormalizeModule(&entry);
305 CollapsePath(&entry); 338 CollapsePath(&entry);
306 enumerated_modules_->push_back(entry); 339 AddToListWithoutDuplicating(entry);
307 340
308 ++registration; 341 ++registration;
309 } 342 }
310 } 343 }
311 344
312 void ModuleEnumerator::EnumerateWinsockModule() { 345 void ModuleEnumerator::EnumerateWinsockModules() {
313 // Add to this list the Winsock LSP DLLs. 346 // Add to this list the Winsock LSP DLLs.
314 WinsockLayeredServiceProviderList layered_providers; 347 WinsockLayeredServiceProviderList layered_providers;
315 GetWinsockLayeredServiceProviders(&layered_providers); 348 GetWinsockLayeredServiceProviders(&layered_providers);
316 for (size_t i = 0; i < layered_providers.size(); ++i) { 349 for (size_t i = 0; i < layered_providers.size(); ++i) {
317 Module entry; 350 Module entry;
318 entry.type = WINSOCK_MODULE_REGISTRATION; 351 entry.type = WINSOCK_MODULE_REGISTRATION;
319 entry.status = NOT_MATCHED; 352 entry.status = NOT_MATCHED;
320 entry.normalized = false; 353 entry.normalized = false;
321 entry.location = layered_providers[i].path; 354 entry.location = layered_providers[i].path;
322 entry.description = layered_providers[i].name; 355 entry.description = layered_providers[i].name;
323 entry.recommended_action = NONE; 356 entry.recommended_action = NONE;
357 entry.duplicate_count = 0;
324 358
325 wchar_t expanded[MAX_PATH]; 359 wchar_t expanded[MAX_PATH];
326 DWORD size = ExpandEnvironmentStrings( 360 DWORD size = ExpandEnvironmentStrings(
327 entry.location.c_str(), expanded, MAX_PATH); 361 entry.location.c_str(), expanded, MAX_PATH);
328 if (size != 0 && size <= MAX_PATH) { 362 if (size != 0 && size <= MAX_PATH) {
329 entry.digital_signer = 363 entry.digital_signer =
330 GetSubjectNameFromDigitalSignature(FilePath(expanded)); 364 GetSubjectNameFromDigitalSignature(FilePath(expanded));
331 } 365 }
332 entry.version = base::IntToString16(layered_providers[i].version); 366 entry.version = base::IntToString16(layered_providers[i].version);
333 367
334 // Paths have already been collapsed. 368 // Paths have already been collapsed.
335 NormalizeModule(&entry); 369 NormalizeModule(&entry);
336 enumerated_modules_->push_back(entry); 370 AddToListWithoutDuplicating(entry);
337 } 371 }
338 } 372 }
339 373
340 void ModuleEnumerator::PopulateModuleInformation(Module* module) { 374 void ModuleEnumerator::PopulateModuleInformation(Module* module) {
341 module->status = NOT_MATCHED; 375 module->status = NOT_MATCHED;
376 module->duplicate_count = 0;
342 module->normalized = false; 377 module->normalized = false;
343 module->digital_signer = 378 module->digital_signer =
344 GetSubjectNameFromDigitalSignature(FilePath(module->location)); 379 GetSubjectNameFromDigitalSignature(FilePath(module->location));
345 module->recommended_action = NONE; 380 module->recommended_action = NONE;
346 scoped_ptr<FileVersionInfo> version_info( 381 scoped_ptr<FileVersionInfo> version_info(
347 FileVersionInfo::CreateFileVersionInfo(FilePath(module->location))); 382 FileVersionInfo::CreateFileVersionInfo(FilePath(module->location)));
348 if (version_info.get()) { 383 if (version_info.get()) {
349 FileVersionInfoWin* version_info_win = 384 FileVersionInfoWin* version_info_win =
350 static_cast<FileVersionInfoWin*>(version_info.get()); 385 static_cast<FileVersionInfoWin*>(version_info.get());
351 386
352 VS_FIXEDFILEINFO* fixed_file_info = version_info_win->fixed_file_info(); 387 VS_FIXEDFILEINFO* fixed_file_info = version_info_win->fixed_file_info();
353 if (fixed_file_info) { 388 if (fixed_file_info) {
354 module->description = version_info_win->file_description(); 389 module->description = version_info_win->file_description();
355 module->version = version_info_win->file_version(); 390 module->version = version_info_win->file_version();
356 module->product_name = version_info_win->product_name(); 391 module->product_name = version_info_win->product_name();
357 } 392 }
358 } 393 }
359 } 394 }
360 395
396 void ModuleEnumerator::AddToListWithoutDuplicating(const Module& module) {
397 DCHECK(module.normalized);
398 // These are registered modules, not loaded modules so the same module
399 // can be registered multiple times, often dozens of times. There is no need
400 // to list each registration, so we just increment the count for each module
401 // that is counted multiple times.
402 ModulesVector::iterator iter;
403 iter = std::find_if(enumerated_modules_->begin(),
404 enumerated_modules_->end(),
405 FindModule(module));
406 if (iter != enumerated_modules_->end())
407 iter->duplicate_count++;
408 else
409 enumerated_modules_->push_back(module);
410 }
411
361 void ModuleEnumerator::PreparePathMappings() { 412 void ModuleEnumerator::PreparePathMappings() {
362 path_mapping_.clear(); 413 path_mapping_.clear();
363 414
364 scoped_ptr<base::Environment> environment(base::Environment::Create()); 415 scoped_ptr<base::Environment> environment(base::Environment::Create());
365 std::vector<string16> env_vars; 416 std::vector<string16> env_vars;
366 env_vars.push_back(L"LOCALAPPDATA"); 417 env_vars.push_back(L"LOCALAPPDATA");
367 env_vars.push_back(L"ProgramFiles"); 418 env_vars.push_back(L"ProgramFiles");
368 env_vars.push_back(L"USERPROFILE"); 419 env_vars.push_back(L"USERPROFILE");
369 env_vars.push_back(L"SystemRoot"); 420 env_vars.push_back(L"SystemRoot");
370 env_vars.push_back(L"TEMP"); 421 env_vars.push_back(L"TEMP");
422 env_vars.push_back(L"TMP");
371 for (std::vector<string16>::const_iterator variable = env_vars.begin(); 423 for (std::vector<string16>::const_iterator variable = env_vars.begin();
372 variable != env_vars.end(); ++variable) { 424 variable != env_vars.end(); ++variable) {
373 std::string path; 425 std::string path;
374 if (environment->GetVar(WideToASCII(*variable).c_str(), &path)) { 426 if (environment->GetVar(WideToASCII(*variable).c_str(), &path)) {
375 path_mapping_.push_back( 427 path_mapping_.push_back(
376 std::make_pair(l10n_util::ToLower(UTF8ToWide(path)) + L"\\", 428 std::make_pair(l10n_util::ToLower(UTF8ToWide(path)) + L"\\",
377 L"%" + l10n_util::ToLower(*variable) + L"%")); 429 L"%" + l10n_util::ToLower(*variable) + L"%"));
378 } 430 }
379 } 431 }
380 } 432 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 #endif 465 #endif
414 466
415 ModuleStatus status = Match(*module, kModuleBlacklist[i]); 467 ModuleStatus status = Match(*module, kModuleBlacklist[i]);
416 if (status != NOT_MATCHED) { 468 if (status != NOT_MATCHED) {
417 // We have a match against the blacklist. Mark it as such. 469 // We have a match against the blacklist. Mark it as such.
418 module->status = status; 470 module->status = status;
419 module->recommended_action = kModuleBlacklist[i].help_tip; 471 module->recommended_action = kModuleBlacklist[i].help_tip;
420 break; 472 break;
421 } 473 }
422 } 474 }
475
476 // Modules loaded from these locations are frequently malicious
477 // and notorious for changing frequently so they are not good candidates
478 // for blacklising individually. Mark them as suspicious if we haven't
479 // classified them as bad yet.
480 if (module->status == NOT_MATCHED || module->status == GOOD) {
481 if (StartsWith(module->location, L"%temp%", false) ||
482 StartsWith(module->location, L"%tmp%", false)) {
483 module->status = SUSPECTED_BAD;
484 }
485 }
423 } 486 }
424 } 487 }
425 488
426 void ModuleEnumerator::ReportBack() { 489 void ModuleEnumerator::ReportBack() {
427 DCHECK(BrowserThread::CurrentlyOn(callback_thread_id_)); 490 DCHECK(BrowserThread::CurrentlyOn(callback_thread_id_));
428 observer_->DoneScanning(); 491 observer_->DoneScanning();
429 } 492 }
430 493
431 string16 ModuleEnumerator::GetSubjectNameFromDigitalSignature( 494 string16 ModuleEnumerator::GetSubjectNameFromDigitalSignature(
432 const FilePath& filename) { 495 const FilePath& filename) {
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 module != enumerated_modules_.end(); ++module) { 702 module != enumerated_modules_.end(); ++module) {
640 if (module->status == ModuleEnumerator::CONFIRMED_BAD) 703 if (module->status == ModuleEnumerator::CONFIRMED_BAD)
641 ++confirmed_bad_modules_detected_; 704 ++confirmed_bad_modules_detected_;
642 if (module->status == ModuleEnumerator::SUSPECTED_BAD) 705 if (module->status == ModuleEnumerator::SUSPECTED_BAD)
643 ++suspected_bad_modules_detected_; 706 ++suspected_bad_modules_detected_;
644 } 707 }
645 708
646 scanning_ = false; 709 scanning_ = false;
647 lock->Release(); 710 lock->Release();
648 711
712 HISTOGRAM_COUNTS_100("Conflicts.SuspectedBadModules",
713 suspected_bad_modules_detected_);
714 HISTOGRAM_COUNTS_100("Conflicts.ConfirmedBadModules",
715 confirmed_bad_modules_detected_);
716
649 NotificationService::current()->Notify( 717 NotificationService::current()->Notify(
650 NotificationType::MODULE_LIST_ENUMERATED, 718 NotificationType::MODULE_LIST_ENUMERATED,
651 Source<EnumerateModulesModel>(this), 719 Source<EnumerateModulesModel>(this),
652 NotificationService::NoDetails()); 720 NotificationService::NoDetails());
653 721
654 if (suspected_bad_modules_detected_ || confirmed_bad_modules_detected_) { 722 if (suspected_bad_modules_detected_ || confirmed_bad_modules_detected_) {
655 bool found_confirmed_bad_modules = confirmed_bad_modules_detected_ > 0; 723 bool found_confirmed_bad_modules = confirmed_bad_modules_detected_ > 0;
656 NotificationService::current()->Notify( 724 NotificationService::current()->Notify(
657 NotificationType::MODULE_INCOMPATIBILITY_DETECTED, 725 NotificationType::MODULE_INCOMPATIBILITY_DETECTED,
658 Source<EnumerateModulesModel>(this), 726 Source<EnumerateModulesModel>(this),
(...skipping 11 matching lines...) Expand all
670 GenerateHash(WideToUTF8(module.name), &filename); 738 GenerateHash(WideToUTF8(module.name), &filename);
671 GenerateHash(WideToUTF8(module.location), &location); 739 GenerateHash(WideToUTF8(module.location), &location);
672 GenerateHash(WideToUTF8(module.description), &description); 740 GenerateHash(WideToUTF8(module.description), &description);
673 GenerateHash(WideToUTF8(module.digital_signer), &signer); 741 GenerateHash(WideToUTF8(module.digital_signer), &signer);
674 742
675 string16 url = l10n_util::GetStringF(IDS_HELP_CENTER_VIEW_CONFLICTS, 743 string16 url = l10n_util::GetStringF(IDS_HELP_CENTER_VIEW_CONFLICTS,
676 ASCIIToWide(filename), ASCIIToWide(location), 744 ASCIIToWide(filename), ASCIIToWide(location),
677 ASCIIToWide(description), ASCIIToWide(signer)); 745 ASCIIToWide(description), ASCIIToWide(signer));
678 return GURL(WideToUTF8(url)); 746 return GURL(WideToUTF8(url));
679 } 747 }
OLDNEW
« no previous file with comments | « chrome/browser/enumerate_modules_model_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698