1 // Copyright (c) 2011 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/safe_browsing_service.h" 6 7 #include "base/callback.h" 8 #include "base/command_line.h" 9 #include "base/lazy_instance.h" 10 #include "base/path_service.h" 11 #include "base/stl_util-inl.h" 12 #include "base/string_util.h" 13 #include "base/threading/thread_restrictions.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/metrics/metrics_service.h" 16 #include "chrome/browser/prefs/pref_service.h" 17 #include "chrome/browser/profiles/profile_manager.h" 18 #include "chrome/browser/safe_browsing/malware_details.h" 19 #include "chrome/browser/safe_browsing/protocol_manager.h" 20 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h" 21 #include "chrome/browser/safe_browsing/safe_browsing_database.h" 22 #include "chrome/browser/tab_contents/tab_util.h" 23 #include "chrome/common/chrome_constants.h" 24 #include "chrome/common/chrome_paths.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/pref_names.h" 27 #include "chrome/common/url_constants.h" 28 #include "content/browser/browser_thread.h" 29 #include "content/browser/tab_contents/tab_contents.h" 30 #include "net/base/registry_controlled_domain.h" 31 #include "net/url_request/url_request_context_getter.h" 32 33 #if defined(OS_WIN) 34 #include "chrome/installer/util/browser_distribution.h" 35 #endif 36 37 namespace { 38 39 // The default URL prefix where browser fetches chunk updates, hashes, 40 // and reports safe browsing hits. 41 const char* const kSbDefaultInfoURLPrefix = 42 "http://safebrowsing.clients.google.com/safebrowsing"; 43 44 // The default URL prefix where browser fetches MAC client key and reports 45 // malware details. 46 const char* const kSbDefaultMacKeyURLPrefix = 47 "https://sb-ssl.google.com/safebrowsing"; 48 49 // When download url check takes this long, client's callback will be called 50 // without waiting for the result. 51 const int64 kDownloadUrlCheckTimeoutMs = 10000; 52 53 // Similar to kDownloadUrlCheckTimeoutMs, but for download hash checks. 54 const int64 kDownloadHashCheckTimeoutMs = 10000; 55 56 // TODO(lzheng): Replace this with Profile* ProfileManager::GetDefaultProfile(). 57 Profile* GetDefaultProfile() { 58 FilePath user_data_dir; 59 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 60 ProfileManager* profile_manager = g_browser_process->profile_manager(); 61 return profile_manager->GetDefaultProfile(user_data_dir); 62 } 63 64 // Records disposition information about the check. |hit| should be 65 // |true| if there were any prefix hits in |full_hashes|. 66 void RecordGetHashCheckStatus( 67 bool hit, 68 bool is_download, 69 const std::vector<SBFullHashResult>& full_hashes) { 70 SafeBrowsingProtocolManager::ResultType result; 71 if (full_hashes.empty()) { 72 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY; 73 } else if (hit) { 74 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT; 75 } else { 76 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS; 77 } 78 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); 79 } 80 81 } // namespace 82 83 // static 84 SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL; 85 86 // The default SafeBrowsingServiceFactory. Global, made a singleton so we 87 // don't leak it. 88 class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory { 89 public: 90 virtual SafeBrowsingService* CreateSafeBrowsingService() { 91 return new SafeBrowsingService(); 92 } 93 94 private: 95 friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>; 96 97 SafeBrowsingServiceFactoryImpl() { } 98 99 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl); 100 }; 101 102 static base::LazyInstance<SafeBrowsingServiceFactoryImpl> 103 g_safe_browsing_service_factory_impl(base::LINKER_INITIALIZED); 104 105 struct SafeBrowsingService::WhiteListedEntry { 106 int render_process_host_id; 107 int render_view_id; 108 std::string domain; 109 UrlCheckResult result; 110 }; 111 112 SafeBrowsingService::UnsafeResource::UnsafeResource() 113 : resource_type(ResourceType::MAIN_FRAME), 114 threat_type(SAFE), 115 client(NULL), 116 render_process_host_id(-1), 117 render_view_id(-1) { 118 } 119 120 SafeBrowsingService::UnsafeResource::~UnsafeResource() {} 121 122 SafeBrowsingService::SafeBrowsingCheck::SafeBrowsingCheck() 123 : full_hash(NULL), 124 client(NULL), 125 need_get_hash(false), 126 result(SAFE), 127 is_download(false), 128 timeout_task(NULL) { 129 } 130 131 SafeBrowsingService::SafeBrowsingCheck::~SafeBrowsingCheck() {} 132 133 void SafeBrowsingService::Client::OnSafeBrowsingResult( 134 const SafeBrowsingCheck& check) { 135 if (!check.urls.empty()) { 136 137 DCHECK(!check.full_hash.get()); 138 if (!check.is_download) { 139 DCHECK_EQ(1U, check.urls.size()); 140 OnBrowseUrlCheckResult(check.urls[0], check.result); 141 } else { 142 OnDownloadUrlCheckResult(check.urls, check.result); 143 } 144 } else if (check.full_hash.get()) { 145 OnDownloadHashCheckResult( 146 safe_browsing_util::SBFullHashToString(*check.full_hash), 147 check.result); 148 } else { 149 NOTREACHED(); 150 } 151 } 152 153 /* static */ 154 SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() { 155 if (!factory_) 156 factory_ = g_safe_browsing_service_factory_impl.Pointer(); 157 return factory_->CreateSafeBrowsingService(); 158 } 159 160 SafeBrowsingService::SafeBrowsingService() 161 : database_(NULL), 162 protocol_manager_(NULL), 163 enabled_(false), 164 enable_download_protection_(false), 165 enable_csd_whitelist_(false), 166 update_in_progress_(false), 167 database_update_in_progress_(false), 168 closing_database_(false), 169 download_urlcheck_timeout_ms_(kDownloadUrlCheckTimeoutMs), 170 download_hashcheck_timeout_ms_(kDownloadHashCheckTimeoutMs) { 171 } 172 173 void SafeBrowsingService::Initialize() { 174 // Get the profile's preference for SafeBrowsing. 175 PrefService* pref_service = GetDefaultProfile()->GetPrefs(); 176 if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled)) 177 Start(); 178 } 179 180 void SafeBrowsingService::ShutDown() { 181 BrowserThread::PostTask( 182 BrowserThread::IO, FROM_HERE, 183 NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown)); 184 } 185 186 bool SafeBrowsingService::CanCheckUrl(const GURL& url) const { 187 return url.SchemeIs(chrome::kFtpScheme) || 188 url.SchemeIs(chrome::kHttpScheme) || 189 url.SchemeIs(chrome::kHttpsScheme); 190 } 191 192 // Only report SafeBrowsing related stats when UMA is enabled and 193 // safe browsing is enabled. 194 bool SafeBrowsingService::CanReportStats() const { 195 const MetricsService* metrics = g_browser_process->metrics_service(); 196 const PrefService* pref_service = GetDefaultProfile()->GetPrefs(); 197 return metrics && metrics->reporting_active() && 198 pref_service && pref_service->GetBoolean(prefs::kSafeBrowsingEnabled); 199 } 200 201 // Binhash verification is only enabled for UMA users for now. 202 bool SafeBrowsingService::DownloadBinHashNeeded() const { 203 return enable_download_protection_ && CanReportStats(); 204 } 205 206 bool SafeBrowsingService::CheckDownloadUrl(const std::vector<GURL>& url_chain, 207 Client* client) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 209 if (!enabled_ || !enable_download_protection_) 210 return true; 211 212 // We need to check the database for url prefix, and later may fetch the url 213 // from the safebrowsing backends. These need to be asynchronous. 214 SafeBrowsingCheck* check = new SafeBrowsingCheck(); 215 check->urls = url_chain; 216 StartDownloadCheck( 217 check, 218 client, 219 NewRunnableMethod(this, 220 &SafeBrowsingService::CheckDownloadUrlOnSBThread, 221 check), 222 download_urlcheck_timeout_ms_); 223 return false; 224 } 225 226 bool SafeBrowsingService::CheckDownloadHash(const std::string& full_hash, 227 Client* client) { 228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 229 DCHECK(!full_hash.empty()); 230 if (!enabled_ || !enable_download_protection_ || full_hash.empty()) 231 return true; 232 233 // We need to check the database for url prefix, and later may fetch the url 234 // from the safebrowsing backends. These need to be asynchronous. 235 SafeBrowsingCheck* check = new SafeBrowsingCheck(); 236 check->full_hash.reset(new SBFullHash); 237 safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get()); 238 StartDownloadCheck( 239 check, 240 client, 241 NewRunnableMethod(this, 242 &SafeBrowsingService::CheckDownloadHashOnSBThread, 243 check), 244 download_hashcheck_timeout_ms_); 245 return false; 246 } 247 248 bool SafeBrowsingService::MatchCsdWhitelistUrl(const GURL& url) { 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 250 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { 251 // There is something funky going on here -- for example, perhaps the user 252 // has not restarted since enabling metrics reporting, so we haven't 253 // enabled the csd whitelist yet. Just to be safe we return true in this 254 // case. 255 return true; 256 } 257 return database_->ContainsCsdWhitelistedUrl(url); 258 } 259 260 bool SafeBrowsingService::CheckBrowseUrl(const GURL& url, 261 Client* client) { 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 263 if (!enabled_) 264 return true; 265 266 if (!CanCheckUrl(url)) 267 return true; 268 269 const base::TimeTicks start = base::TimeTicks::Now(); 270 if (!MakeDatabaseAvailable()) { 271 QueuedCheck check; 272 check.client = client; 273 check.url = url; 274 check.start = start; 275 queued_checks_.push_back(check); 276 return false; 277 } 278 279 std::string list; 280 std::vector<SBPrefix> prefix_hits; 281 std::vector<SBFullHashResult> full_hits; 282 bool prefix_match = 283 database_->ContainsBrowseUrl(url, &list, &prefix_hits, 284 &full_hits, 285 protocol_manager_->last_update()); 286 287 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); 288 289 if (!prefix_match) 290 return true; // URL is okay. 291 292 // Needs to be asynchronous, since we could be in the constructor of a 293 // ResourceDispatcherHost event handler which can't pause there. 294 SafeBrowsingCheck* check = new SafeBrowsingCheck(); 295 check->urls.push_back(url); 296 check->client = client; 297 check->result = SAFE; 298 check->is_download = false; 299 check->need_get_hash = full_hits.empty(); 300 check->prefix_hits.swap(prefix_hits); 301 check->full_hits.swap(full_hits); 302 checks_.insert(check); 303 304 BrowserThread::PostTask( 305 BrowserThread::IO, FROM_HERE, 306 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check)); 307 308 return false; 309 } 310 311 void SafeBrowsingService::CancelCheck(Client* client) { 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 313 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) { 314 // We can't delete matching checks here because the db thread has a copy of 315 // the pointer. Instead, we simply NULL out the client, and when the db 316 // thread calls us back, we'll clean up the check. 317 if ((*i)->client == client) 318 (*i)->client = NULL; 319 } 320 321 // Scan the queued clients store. Clients may be here if they requested a URL 322 // check before the database has finished loading. 323 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin()); 324 it != queued_checks_.end(); ) { 325 // In this case it's safe to delete matches entirely since nothing has a 326 // pointer to them. 327 if (it->client == client) 328 it = queued_checks_.erase(it); 329 else 330 ++it; 331 } 332 } 333 334 void SafeBrowsingService::DisplayBlockingPage( 335 const GURL& url, 336 const GURL& original_url, 337 const std::vector<GURL>& redirect_urls, 338 ResourceType::Type resource_type, 339 UrlCheckResult result, 340 Client* client, 341 int render_process_host_id, 342 int render_view_id) { 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 344 345 // Check if the user has already ignored our warning for this render_view 346 // and domain. 347 for (size_t i = 0; i < white_listed_entries_.size(); ++i) { 348 const WhiteListedEntry& entry = white_listed_entries_[i]; 349 if (entry.render_process_host_id == render_process_host_id && 350 entry.render_view_id == render_view_id && 351 entry.result == result && 352 entry.domain == 353 net::RegistryControlledDomainService::GetDomainAndRegistry(url)) { 354 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 355 this, &SafeBrowsingService::NotifyClientBlockingComplete, 356 client, true)); 357 return; 358 } 359 } 360 361 UnsafeResource resource; 362 resource.url = url; 363 resource.original_url = original_url; 364 resource.redirect_urls = redirect_urls; 365 resource.resource_type = resource_type; 366 resource.threat_type= result; 367 resource.client = client; 368 resource.render_process_host_id = render_process_host_id; 369 resource.render_view_id = render_view_id; 370 371 // The blocking page must be created from the UI thread. 372 BrowserThread::PostTask( 373 BrowserThread::UI, FROM_HERE, 374 NewRunnableMethod( 375 this, &SafeBrowsingService::DoDisplayBlockingPage, resource)); 376 } 377 378 void SafeBrowsingService::HandleGetHashResults( 379 SafeBrowsingCheck* check, 380 const std::vector<SBFullHashResult>& full_hashes, 381 bool can_cache) { 382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 383 384 if (!enabled_) 385 return; 386 387 // If the service has been shut down, |check| should have been deleted. 388 DCHECK(checks_.find(check) != checks_.end()); 389 390 // |start| is set before calling |GetFullHash()|, which should be 391 // the only path which gets to here. 392 DCHECK(!check->start.is_null()); 393 UMA_HISTOGRAM_LONG_TIMES("SB2.Network", 394 base::TimeTicks::Now() - check->start); 395 396 std::vector<SBPrefix> prefixes = check->prefix_hits; 397 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here. 398 399 if (can_cache && MakeDatabaseAvailable()) { 400 // Cache the GetHash results in memory: 401 database_->CacheHashResults(prefixes, full_hashes); 402 } 403 } 404 405 void SafeBrowsingService::HandleChunk(const std::string& list, 406 SBChunkList* chunks) { 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 408 DCHECK(enabled_); 409 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 410 this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks)); 411 } 412 413 void SafeBrowsingService::HandleChunkDelete( 414 std::vector<SBChunkDelete>* chunk_deletes) { 415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 416 DCHECK(enabled_); 417 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 418 this, &SafeBrowsingService::DeleteChunks, chunk_deletes)); 419 } 420 421 void SafeBrowsingService::UpdateStarted() { 422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 423 DCHECK(enabled_); 424 DCHECK(!update_in_progress_); 425 update_in_progress_ = true; 426 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 427 this, &SafeBrowsingService::GetAllChunksFromDatabase)); 428 } 429 430 void SafeBrowsingService::UpdateFinished(bool update_succeeded) { 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 432 DCHECK(enabled_); 433 if (update_in_progress_) { 434 update_in_progress_ = false; 435 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, 436 NewRunnableMethod(this, 437 &SafeBrowsingService::DatabaseUpdateFinished, 438 update_succeeded)); 439 } 440 } 441 442 bool SafeBrowsingService::IsUpdateInProgress() const { 443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 444 return update_in_progress_; 445 } 446 447 void SafeBrowsingService::OnBlockingPageDone( 448 const std::vector<UnsafeResource>& resources, 449 bool proceed) { 450 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin(); 451 iter != resources.end(); ++iter) { 452 const UnsafeResource& resource = *iter; 453 NotifyClientBlockingComplete(resource.client, proceed); 454 455 if (proceed) { 456 // Whitelist this domain and warning type for the given tab. 457 WhiteListedEntry entry; 458 entry.render_process_host_id = resource.render_process_host_id; 459 entry.render_view_id = resource.render_view_id; 460 entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry( 461 resource.url); 462 entry.result = resource.threat_type; 463 white_listed_entries_.push_back(entry); 464 } 465 } 466 } 467 468 void SafeBrowsingService::OnNewMacKeys(const std::string& client_key, 469 const std::string& wrapped_key) { 470 PrefService* prefs = g_browser_process->local_state(); 471 if (prefs) { 472 prefs->SetString(prefs::kSafeBrowsingClientKey, client_key); 473 prefs->SetString(prefs::kSafeBrowsingWrappedKey, wrapped_key); 474 } 475 } 476 477 void SafeBrowsingService::OnEnable(bool enabled) { 478 if (enabled) 479 Start(); 480 else 481 ShutDown(); 482 } 483 484 // static 485 void SafeBrowsingService::RegisterPrefs(PrefService* prefs) { 486 prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, ""); 487 prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, ""); 488 } 489 490 void SafeBrowsingService::CloseDatabase() { 491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 492 493 // Cases to avoid: 494 // * If |closing_database_| is true, continuing will queue up a second 495 // request, |closing_database_| will be reset after handling the first 496 // request, and if any functions on the db thread recreate the database, we 497 // could start using it on the IO thread and then have the second request 498 // handler delete it out from under us. 499 // * If |database_| is NULL, then either no creation request is in flight, in 500 // which case we don't need to do anything, or one is in flight, in which 501 // case the database will be recreated before our deletion request is 502 // handled, and could be used on the IO thread in that time period, leading 503 // to the same problem as above. 504 // * If |queued_checks_| is non-empty and |database_| is non-NULL, we're 505 // about to be called back (in DatabaseLoadComplete()). This will call 506 // CheckUrl(), which will want the database. Closing the database here 507 // would lead to an infinite loop in DatabaseLoadComplete(), and even if it 508 // didn't, it would be pointless since we'd just want to recreate. 509 // 510 // The first two cases above are handled by checking DatabaseAvailable(). 511 if (!DatabaseAvailable() || !queued_checks_.empty()) 512 return; 513 514 closing_database_ = true; 515 if (safe_browsing_thread_.get()) { 516 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, 517 NewRunnableMethod(this, &SafeBrowsingService::OnCloseDatabase)); 518 } 519 } 520 521 void SafeBrowsingService::ResetDatabase() { 522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 523 DCHECK(enabled_); 524 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 525 this, &SafeBrowsingService::OnResetDatabase)); 526 } 527 528 void SafeBrowsingService::LogPauseDelay(base::TimeDelta time) { 529 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time); 530 } 531 532 SafeBrowsingService::~SafeBrowsingService() { 533 // We should have already been shut down. If we're still enabled, then the 534 // database isn't going to be closed properly, which could lead to corruption. 535 DCHECK(!enabled_); 536 } 537 538 void SafeBrowsingService::OnIOInitialize( 539 const std::string& client_key, 540 const std::string& wrapped_key, 541 net::URLRequestContextGetter* request_context_getter) { 542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 543 enabled_ = true; 544 545 MakeDatabaseAvailable(); 546 547 // On Windows, get the safe browsing client name from the browser 548 // distribution classes in installer util. These classes don't yet have 549 // an analog on non-Windows builds so just keep the name specified here. 550 #if defined(OS_WIN) 551 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 552 std::string client_name(dist->GetSafeBrowsingName()); 553 #else 554 #if defined(GOOGLE_CHROME_BUILD) 555 std::string client_name("googlechrome"); 556 #else 557 std::string client_name("chromium"); 558 #endif 559 #endif 560 CommandLine* cmdline = CommandLine::ForCurrentProcess(); 561 bool disable_auto_update = 562 cmdline->HasSwitch(switches::kSbDisableAutoUpdate) || 563 cmdline->HasSwitch(switches::kDisableBackgroundNetworking); 564 std::string info_url_prefix = 565 cmdline->HasSwitch(switches::kSbInfoURLPrefix) ? 566 cmdline->GetSwitchValueASCII(switches::kSbInfoURLPrefix) : 567 kSbDefaultInfoURLPrefix; 568 std::string mackey_url_prefix = 569 cmdline->HasSwitch(switches::kSbMacKeyURLPrefix) ? 570 cmdline->GetSwitchValueASCII(switches::kSbMacKeyURLPrefix) : 571 kSbDefaultMacKeyURLPrefix; 572 573 DCHECK(!protocol_manager_); 574 protocol_manager_ = 575 SafeBrowsingProtocolManager::Create(this, 576 client_name, 577 client_key, 578 wrapped_key, 579 request_context_getter, 580 info_url_prefix, 581 mackey_url_prefix, 582 disable_auto_update); 583 584 protocol_manager_->Initialize(); 585 } 586 587 void SafeBrowsingService::OnIOShutdown() { 588 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 589 if (!enabled_) 590 return; 591 592 enabled_ = false; 593 594 // This cancels all in-flight GetHash requests. 595 delete protocol_manager_; 596 protocol_manager_ = NULL; 597 598 // Delete queued checks, calling back any clients with 'SAFE'. 599 // If we don't do this here we may fail to close the database below. 600 while (!queued_checks_.empty()) { 601 QueuedCheck queued = queued_checks_.front(); 602 if (queued.client) { 603 SafeBrowsingCheck sb_check; 604 sb_check.urls.push_back(queued.url); 605 sb_check.client = queued.client; 606 sb_check.result = SAFE; 607 queued.client->OnSafeBrowsingResult(sb_check); 608 } 609 queued_checks_.pop_front(); 610 } 611 612 // Close the database. We don't simply DeleteSoon() because if a close is 613 // already pending, we'll double-free, and we don't set |database_| to NULL 614 // because if there is still anything running on the db thread, it could 615 // create a new database object (via GetDatabase()) that would then leak. 616 CloseDatabase(); 617 618 // Flush the database thread. Any in-progress database check results will be 619 // ignored and cleaned up below. 620 // 621 // Note that to avoid leaking the database, we rely on the fact that no new 622 // tasks will be added to the db thread between the call above and this one. 623 // See comments on the declaration of |safe_browsing_thread_|. 624 { 625 // A ScopedAllowIO object is required to join the thread when calling Stop. 626 // See http://crbug.com/72696. 627 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join; 628 safe_browsing_thread_.reset(); 629 } 630 631 // Delete pending checks, calling back any clients with 'SAFE'. We have 632 // to do this after the db thread returns because methods on it can have 633 // copies of these pointers, so deleting them might lead to accessing garbage. 634 for (CurrentChecks::iterator it = checks_.begin(); 635 it != checks_.end(); ++it) { 636 SafeBrowsingCheck* check = *it; 637 if (check->client) { 638 check->result = SAFE; 639 check->client->OnSafeBrowsingResult(*check); 640 } 641 if (check->timeout_task) 642 check->timeout_task->Cancel(); 643 } 644 STLDeleteElements(&checks_); 645 646 gethash_requests_.clear(); 647 } 648 649 bool SafeBrowsingService::DatabaseAvailable() const { 650 base::AutoLock lock(database_lock_); 651 return !closing_database_ && (database_ != NULL); 652 } 653 654 bool SafeBrowsingService::MakeDatabaseAvailable() { 655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 656 DCHECK(enabled_); 657 if (DatabaseAvailable()) 658 return true; 659 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, 660 NewRunnableMethod(this, &SafeBrowsingService::GetDatabase)); 661 return false; 662 } 663 664 SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() { 665 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 666 if (database_) 667 return database_; 668 669 FilePath path; 670 bool result = PathService::Get(chrome::DIR_USER_DATA, &path); 671 DCHECK(result); 672 path = path.Append(chrome::kSafeBrowsingBaseFilename); 673 674 const base::TimeTicks before = base::TimeTicks::Now(); 675 676 SafeBrowsingDatabase* database = 677 SafeBrowsingDatabase::Create(enable_download_protection_, 678 enable_csd_whitelist_); 679 680 database->Init(path); 681 { 682 // Acquiring the lock here guarantees correct ordering between the writes to 683 // the new database object above, and the setting of |databse_| below. 684 base::AutoLock lock(database_lock_); 685 database_ = database; 686 } 687 688 BrowserThread::PostTask( 689 BrowserThread::IO, FROM_HERE, 690 NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete)); 691 692 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before); 693 return database_; 694 } 695 696 void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) { 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 698 699 if (!enabled_) 700 return; 701 702 // If the service has been shut down, |check| should have been deleted. 703 DCHECK(checks_.find(check) != checks_.end()); 704 705 if (check->client && check->need_get_hash) { 706 // We have a partial match so we need to query Google for the full hash. 707 // Clean up will happen in HandleGetHashResults. 708 709 // See if we have a GetHash request already in progress for this particular 710 // prefix. If so, we just append ourselves to the list of interested parties 711 // when the results arrive. We only do this for checks involving one prefix, 712 // since that is the common case (multiple prefixes will issue the request 713 // as normal). 714 if (check->prefix_hits.size() == 1) { 715 SBPrefix prefix = check->prefix_hits[0]; 716 GetHashRequests::iterator it = gethash_requests_.find(prefix); 717 if (it != gethash_requests_.end()) { 718 // There's already a request in progress. 719 it->second.push_back(check); 720 return; 721 } 722 723 // No request in progress, so we're the first for this prefix. 724 GetHashRequestors requestors; 725 requestors.push_back(check); 726 gethash_requests_[prefix] = requestors; 727 } 728 729 // Reset the start time so that we can measure the network time without the 730 // database time. 731 check->start = base::TimeTicks::Now(); 732 protocol_manager_->GetFullHash(check, check->prefix_hits); 733 } else { 734 // We may have cached results for previous GetHash queries. Since 735 // this data comes from cache, don't histogram hits. 736 HandleOneCheck(check, check->full_hits); 737 } 738 } 739 740 void SafeBrowsingService::GetAllChunksFromDatabase() { 741 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 742 743 bool database_error = true; 744 std::vector<SBListChunkRanges> lists; 745 DCHECK(!database_update_in_progress_); 746 database_update_in_progress_ = true; 747 GetDatabase(); // This guarantees that |database_| is non-NULL. 748 if (database_->UpdateStarted(&lists)) { 749 database_error = false; 750 } else { 751 database_->UpdateFinished(false); 752 } 753 754 BrowserThread::PostTask( 755 BrowserThread::IO, FROM_HERE, 756 NewRunnableMethod( 757 this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists, 758 database_error)); 759 } 760 761 void SafeBrowsingService::OnGetAllChunksFromDatabase( 762 const std::vector<SBListChunkRanges>& lists, bool database_error) { 763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 764 if (enabled_) 765 protocol_manager_->OnGetChunksComplete(lists, database_error); 766 } 767 768 void SafeBrowsingService::OnChunkInserted() { 769 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 770 if (enabled_) 771 protocol_manager_->OnChunkInserted(); 772 } 773 774 void SafeBrowsingService::DatabaseLoadComplete() { 775 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 776 if (!enabled_) 777 return; 778 779 HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size()); 780 if (queued_checks_.empty()) 781 return; 782 783 // If the database isn't already available, calling CheckUrl() in the loop 784 // below will add the check back to the queue, and we'll infinite-loop. 785 DCHECK(DatabaseAvailable()); 786 while (!queued_checks_.empty()) { 787 QueuedCheck check = queued_checks_.front(); 788 DCHECK(!check.start.is_null()); 789 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start); 790 // If CheckUrl() determines the URL is safe immediately, it doesn't call the 791 // client's handler function (because normally it's being directly called by 792 // the client). Since we're not the client, we have to convey this result. 793 if (check.client && CheckBrowseUrl(check.url, check.client)) { 794 SafeBrowsingCheck sb_check; 795 sb_check.urls.push_back(check.url); 796 sb_check.client = check.client; 797 sb_check.result = SAFE; 798 check.client->OnSafeBrowsingResult(sb_check); 799 } 800 queued_checks_.pop_front(); 801 } 802 } 803 804 void SafeBrowsingService::HandleChunkForDatabase( 805 const std::string& list_name, SBChunkList* chunks) { 806 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 807 if (chunks) { 808 GetDatabase()->InsertChunks(list_name, *chunks); 809 delete chunks; 810 } 811 BrowserThread::PostTask( 812 BrowserThread::IO, FROM_HERE, 813 NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted)); 814 } 815 816 void SafeBrowsingService::DeleteChunks( 817 std::vector<SBChunkDelete>* chunk_deletes) { 818 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 819 if (chunk_deletes) { 820 GetDatabase()->DeleteChunks(*chunk_deletes); 821 delete chunk_deletes; 822 } 823 } 824 825 SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname( 826 const std::string& list_name) { 827 if (safe_browsing_util::IsPhishingList(list_name)) { 828 return URL_PHISHING; 829 } 830 831 if (safe_browsing_util::IsMalwareList(list_name)) { 832 return URL_MALWARE; 833 } 834 835 if (safe_browsing_util::IsBadbinurlList(list_name)) { 836 return BINARY_MALWARE_URL; 837 } 838 839 if (safe_browsing_util::IsBadbinhashList(list_name)) { 840 return BINARY_MALWARE_HASH; 841 } 842 843 DVLOG(1) << "Unknown safe browsing list " << list_name; 844 return SAFE; 845 } 846 847 void SafeBrowsingService::NotifyClientBlockingComplete(Client* client, 848 bool proceed) { 849 client->OnBlockingPageComplete(proceed); 850 } 851 852 void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) { 853 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 854 GetDatabase()->UpdateFinished(update_succeeded); 855 DCHECK(database_update_in_progress_); 856 database_update_in_progress_ = false; 857 } 858 859 void SafeBrowsingService::Start() { 860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 861 DCHECK(!safe_browsing_thread_.get()); 862 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread")); 863 if (!safe_browsing_thread_->Start()) 864 return; 865 866 // Retrieve client MAC keys. 867 PrefService* local_state = g_browser_process->local_state(); 868 DCHECK(local_state); 869 std::string client_key, wrapped_key; 870 if (local_state) { 871 client_key = 872 local_state->GetString(prefs::kSafeBrowsingClientKey); 873 wrapped_key = 874 local_state->GetString(prefs::kSafeBrowsingWrappedKey); 875 } 876 877 // We will issue network fetches using the default profile's request context. 878 scoped_refptr<net::URLRequestContextGetter> request_context_getter( 879 GetDefaultProfile()->GetRequestContext()); 880 881 CommandLine* cmdline = CommandLine::ForCurrentProcess(); 882 enable_download_protection_ = 883 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); 884 885 // We only download the csd-whitelist if client-side phishing detection is 886 // enabled and if the user has opted in with stats collection. Note: we 887 // cannot check whether the metrics_service() object is created because it 888 // may be initialized after this method is called. 889 #ifdef OS_CHROMEOS 890 // Client-side detection is disabled on ChromeOS for now, so don't bother 891 // downloading the whitelist. 892 enable_csd_whitelist_ = false; 893 #else 894 enable_csd_whitelist_ = 895 (!cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection) && 896 local_state && local_state->GetBoolean(prefs::kMetricsReportingEnabled)); 897 #endif 898 899 BrowserThread::PostTask( 900 BrowserThread::IO, FROM_HERE, 901 NewRunnableMethod( 902 this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key, 903 request_context_getter)); 904 } 905 906 void SafeBrowsingService::OnCloseDatabase() { 907 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 908 DCHECK(closing_database_); 909 910 // Because |closing_database_| is true, nothing on the IO thread will be 911 // accessing the database, so it's safe to delete and then NULL the pointer. 912 delete database_; 913 database_ = NULL; 914 915 // Acquiring the lock here guarantees correct ordering between the resetting 916 // of |database_| above and of |closing_database_| below, which ensures there 917 // won't be a window during which the IO thread falsely believes the database 918 // is available. 919 base::AutoLock lock(database_lock_); 920 closing_database_ = false; 921 } 922 923 void SafeBrowsingService::OnResetDatabase() { 924 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 925 GetDatabase()->ResetDatabase(); 926 } 927 928 void SafeBrowsingService::CacheHashResults( 929 const std::vector<SBPrefix>& prefixes, 930 const std::vector<SBFullHashResult>& full_hashes) { 931 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 932 GetDatabase()->CacheHashResults(prefixes, full_hashes); 933 } 934 935 void SafeBrowsingService::OnHandleGetHashResults( 936 SafeBrowsingCheck* check, 937 const std::vector<SBFullHashResult>& full_hashes) { 938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 939 bool is_download = check->is_download; 940 SBPrefix prefix = check->prefix_hits[0]; 941 GetHashRequests::iterator it = gethash_requests_.find(prefix); 942 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { 943 const bool hit = HandleOneCheck(check, full_hashes); 944 RecordGetHashCheckStatus(hit, is_download, full_hashes); 945 return; 946 } 947 948 // Call back all interested parties, noting if any has a hit. 949 GetHashRequestors& requestors = it->second; 950 bool hit = false; 951 for (GetHashRequestors::iterator r = requestors.begin(); 952 r != requestors.end(); ++r) { 953 if (HandleOneCheck(*r, full_hashes)) 954 hit = true; 955 } 956 RecordGetHashCheckStatus(hit, is_download, full_hashes); 957 958 gethash_requests_.erase(it); 959 } 960 961 bool SafeBrowsingService::HandleOneCheck( 962 SafeBrowsingCheck* check, 963 const std::vector<SBFullHashResult>& full_hashes) { 964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 965 DCHECK(check); 966 967 // Always calculate the index, for recording hits. 968 int index = -1; 969 if (!check->urls.empty()) { 970 for (size_t i = 0; i < check->urls.size(); ++i) { 971 index = safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes); 972 if (index != -1) 973 break; 974 } 975 } else { 976 index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes); 977 } 978 979 // |client| is NULL if the request was cancelled. 980 if (check->client) { 981 check->result = SAFE; 982 if (index != -1) 983 check->result = GetResultFromListname(full_hashes[index].list_name); 984 } 985 SafeBrowsingCheckDone(check); 986 return (index != -1); 987 } 988 989 void SafeBrowsingService::DoDisplayBlockingPage( 990 const UnsafeResource& resource) { 991 // The tab might have been closed. 992 TabContents* wc = 993 tab_util::GetTabContentsByID(resource.render_process_host_id, 994 resource.render_view_id); 995 996 if (!wc) { 997 // The tab is gone and we did not have a chance at showing the interstitial. 998 // Just act as "Don't Proceed" was chosen. 999 std::vector<UnsafeResource> resources; 1000 resources.push_back(resource); 1001 BrowserThread::PostTask( 1002 BrowserThread::IO, FROM_HERE, 1003 NewRunnableMethod( 1004 this, &SafeBrowsingService::OnBlockingPageDone, resources, false)); 1005 return; 1006 } 1007 1008 if (resource.threat_type != SafeBrowsingService::SAFE && CanReportStats()) { 1009 GURL page_url = wc->GetURL(); 1010 GURL referrer_url; 1011 NavigationEntry* entry = wc->controller().GetActiveEntry(); 1012 if (entry) 1013 referrer_url = entry->referrer(); 1014 bool is_subresource = resource.resource_type != ResourceType::MAIN_FRAME; 1015 1016 // When the malicious url is on the main frame, and resource.original_url 1017 // is not the same as the resource.url, that means we have a redirect from 1018 // resource.original_url to resource.url. 1019 // Also, at this point, page_url points to the _previous_ page that we 1020 // were on. We replace page_url with resource.original_url and referrer 1021 // with page_url. 1022 if (!is_subresource && 1023 !resource.original_url.is_empty() && 1024 resource.original_url != resource.url) { 1025 referrer_url = page_url; 1026 page_url = resource.original_url; 1027 } 1028 ReportSafeBrowsingHit(resource.url, page_url, referrer_url, is_subresource, 1029 resource.threat_type, std::string() /* post_data */); 1030 } 1031 1032 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource); 1033 } 1034 1035 // A safebrowsing hit is sent after a blocking page for malware/phishing 1036 // or after the warning dialog for download urls, only for UMA users. 1037 void SafeBrowsingService::ReportSafeBrowsingHit( 1038 const GURL& malicious_url, 1039 const GURL& page_url, 1040 const GURL& referrer_url, 1041 bool is_subresource, 1042 SafeBrowsingService::UrlCheckResult threat_type, 1043 const std::string& post_data) { 1044 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1045 if (!CanReportStats()) 1046 return; 1047 1048 BrowserThread::PostTask( 1049 BrowserThread::IO, FROM_HERE, 1050 NewRunnableMethod( 1051 this, 1052 &SafeBrowsingService::ReportSafeBrowsingHitOnIOThread, 1053 malicious_url, 1054 page_url, 1055 referrer_url, 1056 is_subresource, 1057 threat_type, 1058 post_data)); 1059 } 1060 1061 void SafeBrowsingService::ReportSafeBrowsingHitOnIOThread( 1062 const GURL& malicious_url, 1063 const GURL& page_url, 1064 const GURL& referrer_url, 1065 bool is_subresource, 1066 SafeBrowsingService::UrlCheckResult threat_type, 1067 const std::string& post_data) { 1068 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1069 if (!enabled_) 1070 return; 1071 1072 DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url 1073 << " " << referrer_url << " " << is_subresource << " " 1074 << threat_type; 1075 protocol_manager_->ReportSafeBrowsingHit(malicious_url, page_url, 1076 referrer_url, is_subresource, 1077 threat_type, post_data); 1078 } 1079 1080 // If the user had opted-in to send MalwareDetails, this gets called 1081 // when the report is ready. 1082 void SafeBrowsingService::SendSerializedMalwareDetails( 1083 const std::string& serialized) { 1084 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1085 if (!serialized.empty()) { 1086 DVLOG(1) << "Sending serialized malware details."; 1087 protocol_manager_->ReportMalwareDetails(serialized); 1088 } 1089 } 1090 1091 void SafeBrowsingService::CheckDownloadHashOnSBThread( 1092 SafeBrowsingCheck* check) { 1093 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 1094 DCHECK(enable_download_protection_); 1095 1096 if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) { 1097 // Good, we don't have hash for this url prefix. 1098 check->result = SAFE; 1099 BrowserThread::PostTask( 1100 BrowserThread::IO, FROM_HERE, 1101 NewRunnableMethod(this, 1102 &SafeBrowsingService::CheckDownloadHashDone, 1103 check)); 1104 return; 1105 } 1106 1107 check->need_get_hash = true; 1108 check->prefix_hits.push_back(check->full_hash->prefix); 1109 BrowserThread::PostTask( 1110 BrowserThread::IO, FROM_HERE, 1111 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check)); 1112 } 1113 1114 void SafeBrowsingService::CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check) { 1115 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); 1116 DCHECK(enable_download_protection_); 1117 1118 std::vector<SBPrefix> prefix_hits; 1119 1120 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) { 1121 // Good, we don't have hash for this url prefix. 1122 check->result = SAFE; 1123 BrowserThread::PostTask( 1124 BrowserThread::IO, FROM_HERE, 1125 NewRunnableMethod(this, 1126 &SafeBrowsingService::CheckDownloadUrlDone, 1127 check)); 1128 return; 1129 } 1130 1131 check->need_get_hash = true; 1132 check->prefix_hits.clear(); 1133 check->prefix_hits = prefix_hits; 1134 BrowserThread::PostTask( 1135 BrowserThread::IO, FROM_HERE, 1136 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check)); 1137 } 1138 1139 void SafeBrowsingService::TimeoutCallback(SafeBrowsingCheck* check) { 1140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1141 DCHECK(check); 1142 1143 if (!enabled_) 1144 return; 1145 1146 DCHECK(checks_.find(check) != checks_.end()); 1147 DCHECK_EQ(check->result, SAFE); 1148 if (check->client) { 1149 check->client->OnSafeBrowsingResult(*check); 1150 check->client = NULL; 1151 } 1152 check->timeout_task = NULL; 1153 } 1154 1155 void SafeBrowsingService::CheckDownloadUrlDone(SafeBrowsingCheck* check) { 1156 DCHECK(enable_download_protection_); 1157 SafeBrowsingCheckDone(check); 1158 } 1159 1160 void SafeBrowsingService::CheckDownloadHashDone(SafeBrowsingCheck* check) { 1161 DCHECK(enable_download_protection_); 1162 SafeBrowsingCheckDone(check); 1163 } 1164 1165 void SafeBrowsingService::SafeBrowsingCheckDone(SafeBrowsingCheck* check) { 1166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1167 DCHECK(check); 1168 1169 if (!enabled_) 1170 return; 1171 1172 VLOG(1) << "SafeBrowsingCheckDone: " << check->result; 1173 DCHECK(checks_.find(check) != checks_.end()); 1174 if (check->client) 1175 check->client->OnSafeBrowsingResult(*check); 1176 if (check->timeout_task) 1177 check->timeout_task->Cancel(); 1178 checks_.erase(check); 1179 delete check; 1180 } 1181 1182 void SafeBrowsingService::StartDownloadCheck(SafeBrowsingCheck* check, 1183 Client* client, 1184 CancelableTask* task, 1185 int64 timeout_ms) { 1186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1187 check->client = client; 1188 check->result = SAFE; 1189 check->is_download = true; 1190 check->timeout_task = 1191 NewRunnableMethod(this, &SafeBrowsingService::TimeoutCallback, check); 1192 checks_.insert(check); 1193 1194 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task); 1195 1196 MessageLoop::current()->PostDelayedTask( 1197 FROM_HERE, check->timeout_task, timeout_ms); 1198 } 1199