1 // Copyright (c) 2012 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/safe_browsing/database_manager.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/callback.h" 12 #include "base/command_line.h" 13 #include "base/debug/leak_tracker.h" 14 #include "base/path_service.h" 15 #include "base/stl_util.h" 16 #include "base/strings/string_util.h" 17 #include "base/threading/thread.h" 18 #include "base/threading/thread_restrictions.h" 19 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/prerender/prerender_field_trial.h" 22 #include "chrome/browser/safe_browsing/client_side_detection_service.h" 23 #include "chrome/browser/safe_browsing/download_protection_service.h" 24 #include "chrome/browser/safe_browsing/malware_details.h" 25 #include "chrome/browser/safe_browsing/protocol_manager.h" 26 #include "chrome/browser/safe_browsing/safe_browsing_database.h" 27 #include "chrome/browser/safe_browsing/safe_browsing_service.h" 28 #include "chrome/browser/safe_browsing/ui_manager.h" 29 #include "chrome/common/chrome_constants.h" 30 #include "chrome/common/chrome_paths.h" 31 #include "chrome/common/chrome_switches.h" 32 #include "components/metrics/metrics_service.h" 33 #include "components/startup_metric_utils/startup_metric_utils.h" 34 #include "content/public/browser/browser_thread.h" 35 #include "content/public/browser/notification_service.h" 36 #include "url/url_constants.h" 37 38 using content::BrowserThread; 39 40 namespace { 41 42 // Timeout for match checks, e.g. download URLs, hashes. 43 const int kCheckTimeoutMs = 10000; 44 45 // Records disposition information about the check. |hit| should be 46 // |true| if there were any prefix hits in |full_hashes|. 47 void RecordGetHashCheckStatus( 48 bool hit, 49 safe_browsing_util::ListType check_type, 50 const std::vector<SBFullHashResult>& full_hashes) { 51 SafeBrowsingProtocolManager::ResultType result; 52 if (full_hashes.empty()) { 53 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY; 54 } else if (hit) { 55 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT; 56 } else { 57 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS; 58 } 59 bool is_download = check_type == safe_browsing_util::BINURL; 60 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); 61 } 62 63 bool IsExpectedThreat( 64 const SBThreatType threat_type, 65 const std::vector<SBThreatType>& expected_threats) { 66 return expected_threats.end() != std::find(expected_threats.begin(), 67 expected_threats.end(), 68 threat_type); 69 } 70 71 // Return the list id from the first result in |full_hashes| which matches 72 // |hash|, or INVALID if none match. 73 safe_browsing_util::ListType GetHashThreatListType( 74 const SBFullHash& hash, 75 const std::vector<SBFullHashResult>& full_hashes, 76 size_t* index) { 77 for (size_t i = 0; i < full_hashes.size(); ++i) { 78 if (SBFullHashEqual(hash, full_hashes[i].hash)) { 79 if (index) 80 *index = i; 81 return static_cast<safe_browsing_util::ListType>(full_hashes[i].list_id); 82 } 83 } 84 return safe_browsing_util::INVALID; 85 } 86 87 // Given a URL, compare all the possible host + path full hashes to the set of 88 // provided full hashes. Returns the list id of the a matching result from 89 // |full_hashes|, or INVALID if none match. 90 safe_browsing_util::ListType GetUrlThreatListType( 91 const GURL& url, 92 const std::vector<SBFullHashResult>& full_hashes, 93 size_t* index) { 94 if (full_hashes.empty()) 95 return safe_browsing_util::INVALID; 96 97 std::vector<std::string> patterns; 98 safe_browsing_util::GeneratePatternsToCheck(url, &patterns); 99 100 for (size_t i = 0; i < patterns.size(); ++i) { 101 safe_browsing_util::ListType threat = GetHashThreatListType( 102 SBFullHashForString(patterns[i]), full_hashes, index); 103 if (threat != safe_browsing_util::INVALID) 104 return threat; 105 } 106 return safe_browsing_util::INVALID; 107 } 108 109 SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) { 110 switch (list_type) { 111 case safe_browsing_util::PHISH: 112 return SB_THREAT_TYPE_URL_PHISHING; 113 case safe_browsing_util::MALWARE: 114 return SB_THREAT_TYPE_URL_MALWARE; 115 case safe_browsing_util::BINURL: 116 return SB_THREAT_TYPE_BINARY_MALWARE_URL; 117 case safe_browsing_util::EXTENSIONBLACKLIST: 118 return SB_THREAT_TYPE_EXTENSION; 119 default: 120 DVLOG(1) << "Unknown safe browsing list id " << list_type; 121 return SB_THREAT_TYPE_SAFE; 122 } 123 } 124 125 } // namespace 126 127 // static 128 SBThreatType SafeBrowsingDatabaseManager::GetHashThreatType( 129 const SBFullHash& hash, 130 const std::vector<SBFullHashResult>& full_hashes) { 131 return GetThreatTypeFromListType( 132 GetHashThreatListType(hash, full_hashes, NULL)); 133 } 134 135 // static 136 SBThreatType SafeBrowsingDatabaseManager::GetUrlThreatType( 137 const GURL& url, 138 const std::vector<SBFullHashResult>& full_hashes, 139 size_t* index) { 140 return GetThreatTypeFromListType( 141 GetUrlThreatListType(url, full_hashes, index)); 142 } 143 144 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck( 145 const std::vector<GURL>& urls, 146 const std::vector<SBFullHash>& full_hashes, 147 Client* client, 148 safe_browsing_util::ListType check_type, 149 const std::vector<SBThreatType>& expected_threats) 150 : urls(urls), 151 url_results(urls.size(), SB_THREAT_TYPE_SAFE), 152 url_metadata(urls.size()), 153 full_hashes(full_hashes), 154 full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE), 155 client(client), 156 need_get_hash(false), 157 check_type(check_type), 158 expected_threats(expected_threats) { 159 DCHECK_EQ(urls.empty(), !full_hashes.empty()) 160 << "Exactly one of urls and full_hashes must be set"; 161 } 162 163 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {} 164 165 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( 166 const SafeBrowsingCheck& check) { 167 DCHECK_EQ(check.urls.size(), check.url_results.size()); 168 DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size()); 169 if (!check.urls.empty()) { 170 DCHECK(check.full_hashes.empty()); 171 switch (check.check_type) { 172 case safe_browsing_util::MALWARE: 173 case safe_browsing_util::PHISH: 174 DCHECK_EQ(1u, check.urls.size()); 175 OnCheckBrowseUrlResult( 176 check.urls[0], check.url_results[0], check.url_metadata[0]); 177 break; 178 case safe_browsing_util::BINURL: 179 DCHECK_EQ(check.urls.size(), check.url_results.size()); 180 OnCheckDownloadUrlResult( 181 check.urls, 182 *std::max_element(check.url_results.begin(), 183 check.url_results.end())); 184 break; 185 default: 186 NOTREACHED(); 187 } 188 } else if (!check.full_hashes.empty()) { 189 switch (check.check_type) { 190 case safe_browsing_util::EXTENSIONBLACKLIST: { 191 std::set<std::string> unsafe_extension_ids; 192 for (size_t i = 0; i < check.full_hashes.size(); ++i) { 193 std::string extension_id = 194 safe_browsing_util::SBFullHashToString(check.full_hashes[i]); 195 if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION) 196 unsafe_extension_ids.insert(extension_id); 197 } 198 OnCheckExtensionsResult(unsafe_extension_ids); 199 break; 200 } 201 default: 202 NOTREACHED(); 203 } 204 } else { 205 NOTREACHED(); 206 } 207 } 208 209 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( 210 const scoped_refptr<SafeBrowsingService>& service) 211 : sb_service_(service), 212 database_(NULL), 213 enabled_(false), 214 enable_download_protection_(false), 215 enable_csd_whitelist_(false), 216 enable_download_whitelist_(false), 217 enable_extension_blacklist_(false), 218 enable_side_effect_free_whitelist_(false), 219 enable_ip_blacklist_(false), 220 update_in_progress_(false), 221 database_update_in_progress_(false), 222 closing_database_(false), 223 check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) { 224 DCHECK(sb_service_.get() != NULL); 225 226 // Android only supports a subset of FULL_SAFE_BROWSING. 227 // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379> 228 #if !defined(OS_ANDROID) 229 CommandLine* cmdline = CommandLine::ForCurrentProcess(); 230 enable_download_protection_ = 231 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); 232 233 // We only download the csd-whitelist if client-side phishing detection is 234 // enabled. 235 enable_csd_whitelist_ = 236 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection); 237 238 // TODO(noelutz): remove this boolean variable since it should always be true 239 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this 240 // list right now. This means that we need to be able to disable this list 241 // for the SafeBrowsing test to pass. 242 enable_download_whitelist_ = enable_csd_whitelist_; 243 244 // TODO(kalman): there really shouldn't be a flag for this. 245 enable_extension_blacklist_ = 246 !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist); 247 248 enable_side_effect_free_whitelist_ = 249 prerender::IsSideEffectFreeWhitelistEnabled() && 250 !cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist); 251 252 // The client-side IP blacklist feature is tightly integrated with client-side 253 // phishing protection for now. 254 enable_ip_blacklist_ = enable_csd_whitelist_; 255 256 enum SideEffectFreeWhitelistStatus { 257 SIDE_EFFECT_FREE_WHITELIST_ENABLED, 258 SIDE_EFFECT_FREE_WHITELIST_DISABLED, 259 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX 260 }; 261 262 SideEffectFreeWhitelistStatus side_effect_free_whitelist_status = 263 enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED : 264 SIDE_EFFECT_FREE_WHITELIST_DISABLED; 265 266 UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus", 267 side_effect_free_whitelist_status, 268 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX); 269 #endif 270 } 271 272 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() { 273 // We should have already been shut down. If we're still enabled, then the 274 // database isn't going to be closed properly, which could lead to corruption. 275 DCHECK(!enabled_); 276 } 277 278 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const { 279 return url.SchemeIs(url::kFtpScheme) || 280 url.SchemeIs(url::kHttpScheme) || 281 url.SchemeIs(url::kHttpsScheme); 282 } 283 284 bool SafeBrowsingDatabaseManager::CheckDownloadUrl( 285 const std::vector<GURL>& url_chain, 286 Client* client) { 287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 288 if (!enabled_ || !enable_download_protection_) 289 return true; 290 291 // We need to check the database for url prefix, and later may fetch the url 292 // from the safebrowsing backends. These need to be asynchronous. 293 SafeBrowsingCheck* check = 294 new SafeBrowsingCheck(url_chain, 295 std::vector<SBFullHash>(), 296 client, 297 safe_browsing_util::BINURL, 298 std::vector<SBThreatType>(1, 299 SB_THREAT_TYPE_BINARY_MALWARE_URL)); 300 StartSafeBrowsingCheck( 301 check, 302 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this, 303 check)); 304 return false; 305 } 306 307 bool SafeBrowsingDatabaseManager::CheckExtensionIDs( 308 const std::set<std::string>& extension_ids, 309 Client* client) { 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 311 312 if (!enabled_ || !enable_extension_blacklist_) 313 return true; 314 315 std::vector<SBFullHash> extension_id_hashes; 316 std::transform(extension_ids.begin(), extension_ids.end(), 317 std::back_inserter(extension_id_hashes), 318 safe_browsing_util::StringToSBFullHash); 319 320 SafeBrowsingCheck* check = new SafeBrowsingCheck( 321 std::vector<GURL>(), 322 extension_id_hashes, 323 client, 324 safe_browsing_util::EXTENSIONBLACKLIST, 325 std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION)); 326 327 StartSafeBrowsingCheck( 328 check, 329 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread, 330 this, 331 check)); 332 return false; 333 } 334 335 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl( 336 const GURL& url) { 337 if (!enabled_) 338 return false; 339 340 if (!CanCheckUrl(url)) 341 return false; 342 343 return database_->ContainsSideEffectFreeWhitelistUrl(url); 344 } 345 346 bool SafeBrowsingDatabaseManager::MatchMalwareIP( 347 const std::string& ip_address) { 348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 349 if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) { 350 return false; // Fail open. 351 } 352 return database_->ContainsMalwareIP(ip_address); 353 } 354 355 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { 356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 357 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { 358 // There is something funky going on here -- for example, perhaps the user 359 // has not restarted since enabling metrics reporting, so we haven't 360 // enabled the csd whitelist yet. Just to be safe we return true in this 361 // case. 362 return true; 363 } 364 return database_->ContainsCsdWhitelistedUrl(url); 365 } 366 367 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) { 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 369 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) { 370 return true; 371 } 372 return database_->ContainsDownloadWhitelistedUrl(url); 373 } 374 375 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString( 376 const std::string& str) { 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 378 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) { 379 return true; 380 } 381 return database_->ContainsDownloadWhitelistedString(str); 382 } 383 384 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() { 385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 386 if (!enabled_ || !MakeDatabaseAvailable()) { 387 return true; 388 } 389 return database_->IsMalwareIPMatchKillSwitchOn(); 390 } 391 392 bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() { 393 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 394 if (!enabled_ || !MakeDatabaseAvailable()) { 395 return true; 396 } 397 return database_->IsCsdWhitelistKillSwitchOn(); 398 } 399 400 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url, 401 Client* client) { 402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 403 if (!enabled_) 404 return true; 405 406 if (!CanCheckUrl(url)) 407 return true; 408 409 std::vector<SBThreatType> expected_threats; 410 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE); 411 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING); 412 413 const base::TimeTicks start = base::TimeTicks::Now(); 414 if (!MakeDatabaseAvailable()) { 415 QueuedCheck queued_check(safe_browsing_util::MALWARE, // or PHISH 416 client, 417 url, 418 expected_threats, 419 start); 420 queued_checks_.push_back(queued_check); 421 return false; 422 } 423 424 std::vector<SBPrefix> prefix_hits; 425 std::vector<SBFullHashResult> cache_hits; 426 427 bool prefix_match = 428 database_->ContainsBrowseUrl(url, &prefix_hits, &cache_hits); 429 430 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); 431 432 if (!prefix_match) 433 return true; // URL is okay. 434 435 // Needs to be asynchronous, since we could be in the constructor of a 436 // ResourceDispatcherHost event handler which can't pause there. 437 SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url), 438 std::vector<SBFullHash>(), 439 client, 440 safe_browsing_util::MALWARE, 441 expected_threats); 442 check->need_get_hash = cache_hits.empty(); 443 check->prefix_hits.swap(prefix_hits); 444 check->cache_hits.swap(cache_hits); 445 checks_.insert(check); 446 447 BrowserThread::PostTask( 448 BrowserThread::IO, FROM_HERE, 449 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); 450 451 return false; 452 } 453 454 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) { 455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 456 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) { 457 // We can't delete matching checks here because the db thread has a copy of 458 // the pointer. Instead, we simply NULL out the client, and when the db 459 // thread calls us back, we'll clean up the check. 460 if ((*i)->client == client) 461 (*i)->client = NULL; 462 } 463 464 // Scan the queued clients store. Clients may be here if they requested a URL 465 // check before the database has finished loading. 466 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin()); 467 it != queued_checks_.end(); ) { 468 // In this case it's safe to delete matches entirely since nothing has a 469 // pointer to them. 470 if (it->client == client) 471 it = queued_checks_.erase(it); 472 else 473 ++it; 474 } 475 } 476 477 void SafeBrowsingDatabaseManager::HandleGetHashResults( 478 SafeBrowsingCheck* check, 479 const std::vector<SBFullHashResult>& full_hashes, 480 const base::TimeDelta& cache_lifetime) { 481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 482 483 if (!enabled_) 484 return; 485 486 // If the service has been shut down, |check| should have been deleted. 487 DCHECK(checks_.find(check) != checks_.end()); 488 489 // |start| is set before calling |GetFullHash()|, which should be 490 // the only path which gets to here. 491 DCHECK(!check->start.is_null()); 492 UMA_HISTOGRAM_LONG_TIMES("SB2.Network", 493 base::TimeTicks::Now() - check->start); 494 495 std::vector<SBPrefix> prefixes = check->prefix_hits; 496 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here. 497 498 // Cache the GetHash results. 499 if (cache_lifetime != base::TimeDelta() && MakeDatabaseAvailable()) 500 database_->CacheHashResults(prefixes, full_hashes, cache_lifetime); 501 } 502 503 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) { 504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 505 DCHECK(enabled_); 506 DCHECK(!callback.is_null()); 507 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind( 508 &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, callback)); 509 } 510 511 void SafeBrowsingDatabaseManager::AddChunks( 512 const std::string& list, 513 scoped_ptr<ScopedVector<SBChunkData> > chunks, 514 AddChunksCallback callback) { 515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 516 DCHECK(enabled_); 517 DCHECK(!callback.is_null()); 518 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind( 519 &SafeBrowsingDatabaseManager::AddDatabaseChunks, this, list, 520 base::Passed(&chunks), callback)); 521 } 522 523 void SafeBrowsingDatabaseManager::DeleteChunks( 524 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) { 525 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 526 DCHECK(enabled_); 527 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind( 528 &SafeBrowsingDatabaseManager::DeleteDatabaseChunks, this, 529 base::Passed(&chunk_deletes))); 530 } 531 532 void SafeBrowsingDatabaseManager::UpdateStarted() { 533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 534 DCHECK(enabled_); 535 DCHECK(!update_in_progress_); 536 update_in_progress_ = true; 537 } 538 539 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) { 540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 541 DCHECK(enabled_); 542 if (update_in_progress_) { 543 update_in_progress_ = false; 544 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, 545 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished, 546 this, update_succeeded)); 547 } 548 } 549 550 void SafeBrowsingDatabaseManager::ResetDatabase() { 551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 552 DCHECK(enabled_); 553 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind( 554 &SafeBrowsingDatabaseManager::OnResetDatabase, this)); 555 } 556 557 void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time) { 558 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time); 559 } 560 561 void SafeBrowsingDatabaseManager::StartOnIOThread() { 562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 563 if (enabled_) 564 return; 565 566 DCHECK(!safe_browsing_thread_.get()); 567 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread")); 568 if (!safe_browsing_thread_->Start()) 569 return; 570 enabled_ = true; 571 572 MakeDatabaseAvailable(); 573 } 574 575 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) { 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 577 578 DoStopOnIOThread(); 579 if (shutdown) { 580 sb_service_ = NULL; 581 } 582 } 583 584 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished( 585 bool update_succeeded) { 586 content::NotificationService::current()->Notify( 587 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, 588 content::Source<SafeBrowsingDatabaseManager>(this), 589 content::Details<bool>(&update_succeeded)); 590 } 591 592 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck( 593 const safe_browsing_util::ListType check_type, 594 Client* client, 595 const GURL& url, 596 const std::vector<SBThreatType>& expected_threats, 597 const base::TimeTicks& start) 598 : check_type(check_type), 599 client(client), 600 url(url), 601 expected_threats(expected_threats), 602 start(start) { 603 } 604 605 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() { 606 } 607 608 void SafeBrowsingDatabaseManager::DoStopOnIOThread() { 609 if (!enabled_) 610 return; 611 612 enabled_ = false; 613 614 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. 615 while (!queued_checks_.empty()) { 616 QueuedCheck queued = queued_checks_.front(); 617 if (queued.client) { 618 SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url), 619 std::vector<SBFullHash>(), 620 queued.client, 621 queued.check_type, 622 queued.expected_threats); 623 queued.client->OnSafeBrowsingResult(sb_check); 624 } 625 queued_checks_.pop_front(); 626 } 627 628 // Close the database. Cases to avoid: 629 // * If |closing_database_| is true, continuing will queue up a second 630 // request, |closing_database_| will be reset after handling the first 631 // request, and if any functions on the db thread recreate the database, we 632 // could start using it on the IO thread and then have the second request 633 // handler delete it out from under us. 634 // * If |database_| is NULL, then either no creation request is in flight, in 635 // which case we don't need to do anything, or one is in flight, in which 636 // case the database will be recreated before our deletion request is 637 // handled, and could be used on the IO thread in that time period, leading 638 // to the same problem as above. 639 // Checking DatabaseAvailable() avoids both of these. 640 if (DatabaseAvailable()) { 641 closing_database_ = true; 642 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, 643 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this)); 644 } 645 646 // Flush the database thread. Any in-progress database check results will be 647 // ignored and cleaned up below. 648 // 649 // Note that to avoid leaking the database, we rely on the fact that no new 650 // tasks will be added to the db thread between the call above and this one. 651 // See comments on the declaration of |safe_browsing_thread_|. 652 { 653 // A ScopedAllowIO object is required to join the thread when calling Stop. 654 // See http://crbug.com/72696. Note that we call Stop() first to clear out 655 // any remaining tasks before clearing safe_browsing_thread_. 656 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join; 657 safe_browsing_thread_->Stop(); 658 safe_browsing_thread_.reset(); 659 } 660 661 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. 662 // We have to do this after the db thread returns because methods on it can 663 // have copies of these pointers, so deleting them might lead to accessing 664 // garbage. 665 for (CurrentChecks::iterator it = checks_.begin(); 666 it != checks_.end(); ++it) { 667 SafeBrowsingCheck* check = *it; 668 if (check->client) 669 check->client->OnSafeBrowsingResult(*check); 670 } 671 STLDeleteElements(&checks_); 672 673 gethash_requests_.clear(); 674 } 675 676 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const { 677 base::AutoLock lock(database_lock_); 678 return !closing_database_ && (database_ != NULL); 679 } 680 681 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() { 682 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 683 DCHECK(enabled_); 684 if (DatabaseAvailable()) 685 return true; 686 safe_browsing_thread_->message_loop()->PostTask( 687 FROM_HERE, 688 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase), 689 this)); 690 return false; 691 } 692 693 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() { 694 DCHECK_EQ(base::MessageLoop::current(), 695 safe_browsing_thread_->message_loop()); 696 if (database_) 697 return database_; 698 startup_metric_utils::ScopedSlowStartupUMA 699 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase"); 700 const base::TimeTicks before = base::TimeTicks::Now(); 701 702 SafeBrowsingDatabase* database = 703 SafeBrowsingDatabase::Create(enable_download_protection_, 704 enable_csd_whitelist_, 705 enable_download_whitelist_, 706 enable_extension_blacklist_, 707 enable_side_effect_free_whitelist_, 708 enable_ip_blacklist_); 709 710 database->Init(SafeBrowsingService::GetBaseFilename()); 711 { 712 // Acquiring the lock here guarantees correct ordering between the writes to 713 // the new database object above, and the setting of |databse_| below. 714 base::AutoLock lock(database_lock_); 715 database_ = database; 716 } 717 718 BrowserThread::PostTask( 719 BrowserThread::IO, FROM_HERE, 720 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this)); 721 722 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before); 723 return database_; 724 } 725 726 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) { 727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 728 729 if (!enabled_) 730 return; 731 732 // If the service has been shut down, |check| should have been deleted. 733 DCHECK(checks_.find(check) != checks_.end()); 734 735 if (check->client && check->need_get_hash) { 736 // We have a partial match so we need to query Google for the full hash. 737 // Clean up will happen in HandleGetHashResults. 738 739 // See if we have a GetHash request already in progress for this particular 740 // prefix. If so, we just append ourselves to the list of interested parties 741 // when the results arrive. We only do this for checks involving one prefix, 742 // since that is the common case (multiple prefixes will issue the request 743 // as normal). 744 if (check->prefix_hits.size() == 1) { 745 SBPrefix prefix = check->prefix_hits[0]; 746 GetHashRequests::iterator it = gethash_requests_.find(prefix); 747 if (it != gethash_requests_.end()) { 748 // There's already a request in progress. 749 it->second.push_back(check); 750 return; 751 } 752 753 // No request in progress, so we're the first for this prefix. 754 GetHashRequestors requestors; 755 requestors.push_back(check); 756 gethash_requests_[prefix] = requestors; 757 } 758 759 // Reset the start time so that we can measure the network time without the 760 // database time. 761 check->start = base::TimeTicks::Now(); 762 // Note: If |this| is deleted or stopped, the protocol_manager will 763 // be destroyed as well - hence it's OK to do unretained in this case. 764 bool is_download = check->check_type == safe_browsing_util::BINURL; 765 sb_service_->protocol_manager()->GetFullHash( 766 check->prefix_hits, 767 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults, 768 base::Unretained(this), 769 check), 770 is_download); 771 } else { 772 // We may have cached results for previous GetHash queries. Since 773 // this data comes from cache, don't histogram hits. 774 bool is_threat = HandleOneCheck(check, check->cache_hits); 775 // cache_hits should only contain hits for a fullhash we searched for, so if 776 // we got to this point it should always result in a threat match. 777 DCHECK(is_threat); 778 } 779 } 780 781 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase( 782 GetChunksCallback callback) { 783 DCHECK_EQ(base::MessageLoop::current(), 784 safe_browsing_thread_->message_loop()); 785 786 bool database_error = true; 787 std::vector<SBListChunkRanges> lists; 788 DCHECK(!database_update_in_progress_); 789 database_update_in_progress_ = true; 790 GetDatabase(); // This guarantees that |database_| is non-NULL. 791 if (database_->UpdateStarted(&lists)) { 792 database_error = false; 793 } else { 794 database_->UpdateFinished(false); 795 } 796 797 BrowserThread::PostTask( 798 BrowserThread::IO, FROM_HERE, 799 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase, 800 this, lists, database_error, callback)); 801 } 802 803 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase( 804 const std::vector<SBListChunkRanges>& lists, bool database_error, 805 GetChunksCallback callback) { 806 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 807 if (enabled_) 808 callback.Run(lists, database_error); 809 } 810 811 void SafeBrowsingDatabaseManager::OnAddChunksComplete( 812 AddChunksCallback callback) { 813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 814 if (enabled_) 815 callback.Run(); 816 } 817 818 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() { 819 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 820 if (!enabled_) 821 return; 822 823 LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size()); 824 if (queued_checks_.empty()) 825 return; 826 827 // If the database isn't already available, calling CheckUrl() in the loop 828 // below will add the check back to the queue, and we'll infinite-loop. 829 DCHECK(DatabaseAvailable()); 830 while (!queued_checks_.empty()) { 831 QueuedCheck check = queued_checks_.front(); 832 DCHECK(!check.start.is_null()); 833 LOCAL_HISTOGRAM_TIMES("SB.QueueDelay", 834 base::TimeTicks::Now() - check.start); 835 // If CheckUrl() determines the URL is safe immediately, it doesn't call the 836 // client's handler function (because normally it's being directly called by 837 // the client). Since we're not the client, we have to convey this result. 838 if (check.client && CheckBrowseUrl(check.url, check.client)) { 839 SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url), 840 std::vector<SBFullHash>(), 841 check.client, 842 check.check_type, 843 check.expected_threats); 844 check.client->OnSafeBrowsingResult(sb_check); 845 } 846 queued_checks_.pop_front(); 847 } 848 } 849 850 void SafeBrowsingDatabaseManager::AddDatabaseChunks( 851 const std::string& list_name, 852 scoped_ptr<ScopedVector<SBChunkData> > chunks, 853 AddChunksCallback callback) { 854 DCHECK_EQ(base::MessageLoop::current(), 855 safe_browsing_thread_->message_loop()); 856 if (chunks) 857 GetDatabase()->InsertChunks(list_name, chunks->get()); 858 BrowserThread::PostTask( 859 BrowserThread::IO, FROM_HERE, 860 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this, 861 callback)); 862 } 863 864 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks( 865 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) { 866 DCHECK_EQ(base::MessageLoop::current(), 867 safe_browsing_thread_->message_loop()); 868 if (chunk_deletes) 869 GetDatabase()->DeleteChunks(*chunk_deletes); 870 } 871 872 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished( 873 bool update_succeeded) { 874 DCHECK_EQ(base::MessageLoop::current(), 875 safe_browsing_thread_->message_loop()); 876 GetDatabase()->UpdateFinished(update_succeeded); 877 DCHECK(database_update_in_progress_); 878 database_update_in_progress_ = false; 879 BrowserThread::PostTask( 880 BrowserThread::UI, FROM_HERE, 881 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished, 882 this, update_succeeded)); 883 } 884 885 void SafeBrowsingDatabaseManager::OnCloseDatabase() { 886 DCHECK_EQ(base::MessageLoop::current(), 887 safe_browsing_thread_->message_loop()); 888 DCHECK(closing_database_); 889 890 // Because |closing_database_| is true, nothing on the IO thread will be 891 // accessing the database, so it's safe to delete and then NULL the pointer. 892 delete database_; 893 database_ = NULL; 894 895 // Acquiring the lock here guarantees correct ordering between the resetting 896 // of |database_| above and of |closing_database_| below, which ensures there 897 // won't be a window during which the IO thread falsely believes the database 898 // is available. 899 base::AutoLock lock(database_lock_); 900 closing_database_ = false; 901 } 902 903 void SafeBrowsingDatabaseManager::OnResetDatabase() { 904 DCHECK_EQ(base::MessageLoop::current(), 905 safe_browsing_thread_->message_loop()); 906 GetDatabase()->ResetDatabase(); 907 } 908 909 void SafeBrowsingDatabaseManager::OnHandleGetHashResults( 910 SafeBrowsingCheck* check, 911 const std::vector<SBFullHashResult>& full_hashes) { 912 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 913 safe_browsing_util::ListType check_type = check->check_type; 914 SBPrefix prefix = check->prefix_hits[0]; 915 GetHashRequests::iterator it = gethash_requests_.find(prefix); 916 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { 917 const bool hit = HandleOneCheck(check, full_hashes); 918 RecordGetHashCheckStatus(hit, check_type, full_hashes); 919 return; 920 } 921 922 // Call back all interested parties, noting if any has a hit. 923 GetHashRequestors& requestors = it->second; 924 bool hit = false; 925 for (GetHashRequestors::iterator r = requestors.begin(); 926 r != requestors.end(); ++r) { 927 if (HandleOneCheck(*r, full_hashes)) 928 hit = true; 929 } 930 RecordGetHashCheckStatus(hit, check_type, full_hashes); 931 932 gethash_requests_.erase(it); 933 } 934 935 bool SafeBrowsingDatabaseManager::HandleOneCheck( 936 SafeBrowsingCheck* check, 937 const std::vector<SBFullHashResult>& full_hashes) { 938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 939 DCHECK(check); 940 941 bool is_threat = false; 942 943 // TODO(shess): GetHashThreadListType() contains a loop, 944 // GetUrlThreatListType() a loop around that loop. Having another loop out 945 // here concerns me. It is likely that SAFE is an expected outcome, which 946 // means all of those loops run to completion. Refactoring this to generate a 947 // set of sorted items to compare in sequence would probably improve things. 948 // 949 // Additionally, the set of patterns generated from the urls is very similar 950 // to the patterns generated in ContainsBrowseUrl() and other database checks, 951 // which are called from this code. Refactoring that across the checks could 952 // interact well with batching the checks here. 953 954 for (size_t i = 0; i < check->urls.size(); ++i) { 955 size_t threat_index; 956 SBThreatType threat = 957 GetUrlThreatType(check->urls[i], full_hashes, &threat_index); 958 if (threat != SB_THREAT_TYPE_SAFE && 959 IsExpectedThreat(threat, check->expected_threats)) { 960 check->url_results[i] = threat; 961 check->url_metadata[i] = full_hashes[threat_index].metadata; 962 is_threat = true; 963 } 964 } 965 966 for (size_t i = 0; i < check->full_hashes.size(); ++i) { 967 SBThreatType threat = GetHashThreatType(check->full_hashes[i], full_hashes); 968 if (threat != SB_THREAT_TYPE_SAFE && 969 IsExpectedThreat(threat, check->expected_threats)) { 970 check->full_hash_results[i] = threat; 971 is_threat = true; 972 } 973 } 974 975 SafeBrowsingCheckDone(check); 976 return is_threat; 977 } 978 979 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread( 980 SafeBrowsingCheck* check) { 981 DCHECK_EQ(base::MessageLoop::current(), 982 safe_browsing_thread_->message_loop()); 983 DCHECK(enable_download_protection_); 984 985 std::vector<SBPrefix> prefix_hits; 986 987 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) { 988 // Good, we don't have hash for this url prefix. 989 BrowserThread::PostTask( 990 BrowserThread::IO, FROM_HERE, 991 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this, 992 check)); 993 return; 994 } 995 996 check->need_get_hash = true; 997 check->prefix_hits.clear(); 998 check->prefix_hits = prefix_hits; 999 BrowserThread::PostTask( 1000 BrowserThread::IO, FROM_HERE, 1001 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); 1002 } 1003 1004 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread( 1005 SafeBrowsingCheck* check) { 1006 DCHECK_EQ(base::MessageLoop::current(), 1007 safe_browsing_thread_->message_loop()); 1008 1009 std::vector<SBPrefix> prefixes; 1010 for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin(); 1011 it != check->full_hashes.end(); ++it) { 1012 prefixes.push_back((*it).prefix); 1013 } 1014 database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits); 1015 1016 if (check->prefix_hits.empty()) { 1017 // No matches for any extensions. 1018 BrowserThread::PostTask( 1019 BrowserThread::IO, 1020 FROM_HERE, 1021 base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this, 1022 check)); 1023 } else { 1024 // Some prefixes matched, we need to ask Google whether they're legit. 1025 check->need_get_hash = true; 1026 BrowserThread::PostTask( 1027 BrowserThread::IO, 1028 FROM_HERE, 1029 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); 1030 } 1031 } 1032 1033 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) { 1034 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1035 DCHECK(check); 1036 1037 if (!enabled_) 1038 return; 1039 1040 DCHECK(checks_.find(check) != checks_.end()); 1041 if (check->client) { 1042 check->client->OnSafeBrowsingResult(*check); 1043 check->client = NULL; 1044 } 1045 } 1046 1047 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone( 1048 SafeBrowsingCheck* check) { 1049 DCHECK(enable_download_protection_); 1050 SafeBrowsingCheckDone(check); 1051 } 1052 1053 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone( 1054 SafeBrowsingCheck* check) { 1055 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1056 DCHECK(check); 1057 1058 if (!enabled_) 1059 return; 1060 1061 VLOG(1) << "SafeBrowsingCheckDone"; 1062 DCHECK(checks_.find(check) != checks_.end()); 1063 if (check->client) 1064 check->client->OnSafeBrowsingResult(*check); 1065 checks_.erase(check); 1066 delete check; 1067 } 1068 1069 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck( 1070 SafeBrowsingCheck* check, 1071 const base::Closure& task) { 1072 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1073 check->timeout_factory_.reset( 1074 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this)); 1075 checks_.insert(check); 1076 1077 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task); 1078 1079 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 1080 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback, 1081 check->timeout_factory_->GetWeakPtr(), check), 1082 check_timeout_); 1083 } 1084