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