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.
5 #include "chrome/browser/safe_browsing/database_manager.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/metrics/histogram_macros.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_util.h"
18 #include "base/threading/thread.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.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 "components/startup_metric_utils/startup_metric_utils.h"
34 #include "components/variations/variations_associated_data.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "url/url_constants.h"
39 using content::BrowserThread
;
43 // Timeout for match checks, e.g. download URLs, hashes.
44 const int kCheckTimeoutMs
= 10000;
46 // Records disposition information about the check. |hit| should be
47 // |true| if there were any prefix hits in |full_hashes|.
48 void RecordGetHashCheckStatus(
50 safe_browsing_util::ListType check_type
,
51 const std::vector
<SBFullHashResult
>& full_hashes
) {
52 SafeBrowsingProtocolManager::ResultType result
;
53 if (full_hashes
.empty()) {
54 result
= SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY
;
56 result
= SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT
;
58 result
= SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS
;
60 bool is_download
= check_type
== safe_browsing_util::BINURL
;
61 SafeBrowsingProtocolManager::RecordGetHashResult(is_download
, result
);
64 bool IsExpectedThreat(
65 const SBThreatType threat_type
,
66 const std::vector
<SBThreatType
>& expected_threats
) {
67 return expected_threats
.end() != std::find(expected_threats
.begin(),
68 expected_threats
.end(),
72 // Return the severest list id from the results in |full_hashes| which matches
73 // |hash|, or INVALID if none match.
74 safe_browsing_util::ListType
GetHashSeverestThreatListType(
75 const SBFullHash
& hash
,
76 const std::vector
<SBFullHashResult
>& full_hashes
,
78 safe_browsing_util::ListType pending_threat
= safe_browsing_util::INVALID
;
79 for (size_t i
= 0; i
< full_hashes
.size(); ++i
) {
80 if (SBFullHashEqual(hash
, full_hashes
[i
].hash
)) {
81 const safe_browsing_util::ListType threat
=
82 static_cast<safe_browsing_util::ListType
>(full_hashes
[i
].list_id
);
84 case safe_browsing_util::INVALID
:
85 // |full_hashes| should never contain INVALID as a |list_id|.
88 case safe_browsing_util::MALWARE
: // Falls through.
89 case safe_browsing_util::PHISH
: // Falls through.
90 case safe_browsing_util::BINURL
: // Falls through.
91 case safe_browsing_util::CSDWHITELIST
: // Falls through.
92 case safe_browsing_util::DOWNLOADWHITELIST
: // Falls through.
93 case safe_browsing_util::INCLUSIONWHITELIST
: // Falls through.
94 case safe_browsing_util::EXTENSIONBLACKLIST
: // Falls through.
95 case safe_browsing_util::SIDEEFFECTFREEWHITELIST
: // Falls through.
96 case safe_browsing_util::IPBLACKLIST
:
100 case safe_browsing_util::UNWANTEDURL
:
101 // UNWANTEDURL is considered less severe than other threats, keep
103 pending_threat
= threat
;
110 return pending_threat
;
113 // Given a URL, compare all the possible host + path full hashes to the set of
114 // provided full hashes. Returns the list id of the severest matching result
115 // from |full_hashes|, or INVALID if none match.
116 safe_browsing_util::ListType
GetUrlSeverestThreatListType(
118 const std::vector
<SBFullHashResult
>& full_hashes
,
120 if (full_hashes
.empty())
121 return safe_browsing_util::INVALID
;
123 std::vector
<std::string
> patterns
;
124 safe_browsing_util::GeneratePatternsToCheck(url
, &patterns
);
126 safe_browsing_util::ListType pending_threat
= safe_browsing_util::INVALID
;
127 for (size_t i
= 0; i
< patterns
.size(); ++i
) {
128 safe_browsing_util::ListType threat
= GetHashSeverestThreatListType(
129 SBFullHashForString(patterns
[i
]), full_hashes
, index
);
131 case safe_browsing_util::INVALID
:
132 // Ignore patterns with no matching threat.
134 case safe_browsing_util::MALWARE
: // Falls through.
135 case safe_browsing_util::PHISH
: // Falls through.
136 case safe_browsing_util::BINURL
: // Falls through.
137 case safe_browsing_util::CSDWHITELIST
: // Falls through.
138 case safe_browsing_util::DOWNLOADWHITELIST
: // Falls through.
139 case safe_browsing_util::INCLUSIONWHITELIST
: // Falls through.
140 case safe_browsing_util::EXTENSIONBLACKLIST
: // Falls through.
141 case safe_browsing_util::SIDEEFFECTFREEWHITELIST
: // Falls through.
142 case safe_browsing_util::IPBLACKLIST
:
144 case safe_browsing_util::UNWANTEDURL
:
145 // UNWANTEDURL is considered less severe than other threats, keep
147 pending_threat
= threat
;
151 return pending_threat
;
154 SBThreatType
GetThreatTypeFromListType(safe_browsing_util::ListType list_type
) {
156 case safe_browsing_util::PHISH
:
157 return SB_THREAT_TYPE_URL_PHISHING
;
158 case safe_browsing_util::MALWARE
:
159 return SB_THREAT_TYPE_URL_MALWARE
;
160 case safe_browsing_util::UNWANTEDURL
:
161 return SB_THREAT_TYPE_URL_UNWANTED
;
162 case safe_browsing_util::BINURL
:
163 return SB_THREAT_TYPE_BINARY_MALWARE_URL
;
164 case safe_browsing_util::EXTENSIONBLACKLIST
:
165 return SB_THREAT_TYPE_EXTENSION
;
167 DVLOG(1) << "Unknown safe browsing list id " << list_type
;
168 return SB_THREAT_TYPE_SAFE
;
175 SBThreatType
SafeBrowsingDatabaseManager::GetHashSeverestThreatType(
176 const SBFullHash
& hash
,
177 const std::vector
<SBFullHashResult
>& full_hashes
) {
178 return GetThreatTypeFromListType(
179 GetHashSeverestThreatListType(hash
, full_hashes
, NULL
));
183 SBThreatType
SafeBrowsingDatabaseManager::GetUrlSeverestThreatType(
185 const std::vector
<SBFullHashResult
>& full_hashes
,
187 return GetThreatTypeFromListType(
188 GetUrlSeverestThreatListType(url
, full_hashes
, index
));
191 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
192 const std::vector
<GURL
>& urls
,
193 const std::vector
<SBFullHash
>& full_hashes
,
195 safe_browsing_util::ListType check_type
,
196 const std::vector
<SBThreatType
>& expected_threats
)
198 url_results(urls
.size(), SB_THREAT_TYPE_SAFE
),
199 url_metadata(urls
.size()),
200 full_hashes(full_hashes
),
201 full_hash_results(full_hashes
.size(), SB_THREAT_TYPE_SAFE
),
203 need_get_hash(false),
204 check_type(check_type
),
205 expected_threats(expected_threats
) {
206 DCHECK_EQ(urls
.empty(), !full_hashes
.empty())
207 << "Exactly one of urls and full_hashes must be set";
210 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
212 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
213 const SafeBrowsingCheck
& check
) {
214 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
216 DCHECK_EQ(check
.urls
.size(), check
.url_results
.size());
217 DCHECK_EQ(check
.full_hashes
.size(), check
.full_hash_results
.size());
218 if (!check
.urls
.empty()) {
219 DCHECK(check
.full_hashes
.empty());
220 switch (check
.check_type
) {
221 case safe_browsing_util::MALWARE
:
222 case safe_browsing_util::PHISH
:
223 case safe_browsing_util::UNWANTEDURL
:
224 DCHECK_EQ(1u, check
.urls
.size());
225 OnCheckBrowseUrlResult(
226 check
.urls
[0], check
.url_results
[0], check
.url_metadata
[0]);
228 case safe_browsing_util::BINURL
:
229 DCHECK_EQ(check
.urls
.size(), check
.url_results
.size());
230 OnCheckDownloadUrlResult(
232 *std::max_element(check
.url_results
.begin(),
233 check
.url_results
.end()));
238 } else if (!check
.full_hashes
.empty()) {
239 switch (check
.check_type
) {
240 case safe_browsing_util::EXTENSIONBLACKLIST
: {
241 std::set
<std::string
> unsafe_extension_ids
;
242 for (size_t i
= 0; i
< check
.full_hashes
.size(); ++i
) {
243 std::string extension_id
=
244 safe_browsing_util::SBFullHashToString(check
.full_hashes
[i
]);
245 if (check
.full_hash_results
[i
] == SB_THREAT_TYPE_EXTENSION
)
246 unsafe_extension_ids
.insert(extension_id
);
248 OnCheckExtensionsResult(unsafe_extension_ids
);
259 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
260 const scoped_refptr
<SafeBrowsingService
>& service
)
261 : sb_service_(service
),
264 enable_download_protection_(false),
265 enable_csd_whitelist_(false),
266 enable_download_whitelist_(false),
267 enable_extension_blacklist_(false),
268 enable_side_effect_free_whitelist_(false),
269 enable_ip_blacklist_(false),
270 enable_unwanted_software_blacklist_(false),
271 update_in_progress_(false),
272 database_update_in_progress_(false),
273 closing_database_(false),
274 check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs
)) {
275 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
276 DCHECK(sb_service_
.get() != NULL
);
278 // Android only supports a subset of FULL_SAFE_BROWSING.
279 // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379>
280 #if !defined(OS_ANDROID)
281 base::CommandLine
* cmdline
= base::CommandLine::ForCurrentProcess();
282 enable_download_protection_
=
283 !cmdline
->HasSwitch(switches::kSbDisableDownloadProtection
);
285 // We only download the csd-whitelist if client-side phishing detection is
287 enable_csd_whitelist_
=
288 !cmdline
->HasSwitch(switches::kDisableClientSidePhishingDetection
);
290 // TODO(noelutz): remove this boolean variable since it should always be true
291 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this
292 // list right now. This means that we need to be able to disable this list
293 // for the SafeBrowsing test to pass.
294 enable_download_whitelist_
= enable_csd_whitelist_
;
296 // TODO(kalman): there really shouldn't be a flag for this.
297 enable_extension_blacklist_
=
298 !cmdline
->HasSwitch(switches::kSbDisableExtensionBlacklist
);
300 enable_side_effect_free_whitelist_
=
301 prerender::IsSideEffectFreeWhitelistEnabled() &&
302 !cmdline
->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist
);
304 // The client-side IP blacklist feature is tightly integrated with client-side
305 // phishing protection for now.
306 enable_ip_blacklist_
= enable_csd_whitelist_
;
308 // The UwS blacklist feature is controlled by a flag for M40.
309 enable_unwanted_software_blacklist_
=
310 safe_browsing_util::GetUnwantedTrialGroup() > safe_browsing_util::UWS_OFF
;
312 enum SideEffectFreeWhitelistStatus
{
313 SIDE_EFFECT_FREE_WHITELIST_ENABLED
,
314 SIDE_EFFECT_FREE_WHITELIST_DISABLED
,
315 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
318 SideEffectFreeWhitelistStatus side_effect_free_whitelist_status
=
319 enable_side_effect_free_whitelist_
? SIDE_EFFECT_FREE_WHITELIST_ENABLED
:
320 SIDE_EFFECT_FREE_WHITELIST_DISABLED
;
322 UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
323 side_effect_free_whitelist_status
,
324 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
);
328 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
329 // The DCHECK is disabled due to crbug.com/438754.
330 // DCHECK_CURRENTLY_ON(BrowserThread::UI);
332 // We should have already been shut down. If we're still enabled, then the
333 // database isn't going to be closed properly, which could lead to corruption.
337 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL
& url
) const {
338 return url
.SchemeIs(url::kFtpScheme
) ||
339 url
.SchemeIs(url::kHttpScheme
) ||
340 url
.SchemeIs(url::kHttpsScheme
);
343 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
344 const std::vector
<GURL
>& url_chain
,
346 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
347 if (!enabled_
|| !enable_download_protection_
)
350 // We need to check the database for url prefix, and later may fetch the url
351 // from the safebrowsing backends. These need to be asynchronous.
352 SafeBrowsingCheck
* check
=
353 new SafeBrowsingCheck(url_chain
,
354 std::vector
<SBFullHash
>(),
356 safe_browsing_util::BINURL
,
357 std::vector
<SBThreatType
>(1,
358 SB_THREAT_TYPE_BINARY_MALWARE_URL
));
359 StartSafeBrowsingCheck(
361 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread
, this,
366 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
367 const std::set
<std::string
>& extension_ids
,
369 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
371 if (!enabled_
|| !enable_extension_blacklist_
)
374 std::vector
<SBFullHash
> extension_id_hashes
;
375 std::transform(extension_ids
.begin(), extension_ids
.end(),
376 std::back_inserter(extension_id_hashes
),
377 safe_browsing_util::StringToSBFullHash
);
379 SafeBrowsingCheck
* check
= new SafeBrowsingCheck(
383 safe_browsing_util::EXTENSIONBLACKLIST
,
384 std::vector
<SBThreatType
>(1, SB_THREAT_TYPE_EXTENSION
));
386 StartSafeBrowsingCheck(
388 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread
,
394 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
399 if (!CanCheckUrl(url
))
402 return database_
->ContainsSideEffectFreeWhitelistUrl(url
);
405 bool SafeBrowsingDatabaseManager::MatchMalwareIP(
406 const std::string
& ip_address
) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
408 if (!enabled_
|| !enable_ip_blacklist_
|| !MakeDatabaseAvailable()) {
409 return false; // Fail open.
411 return database_
->ContainsMalwareIP(ip_address
);
414 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL
& url
) {
415 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
416 if (!enabled_
|| !enable_csd_whitelist_
|| !MakeDatabaseAvailable()) {
417 // There is something funky going on here -- for example, perhaps the user
418 // has not restarted since enabling metrics reporting, so we haven't
419 // enabled the csd whitelist yet. Just to be safe we return true in this
423 return database_
->ContainsCsdWhitelistedUrl(url
);
426 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL
& url
) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
428 if (!enabled_
|| !enable_download_whitelist_
|| !MakeDatabaseAvailable()) {
431 return database_
->ContainsDownloadWhitelistedUrl(url
);
434 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
435 const std::string
& str
) {
436 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
437 if (!enabled_
|| !enable_download_whitelist_
|| !MakeDatabaseAvailable()) {
440 return database_
->ContainsDownloadWhitelistedString(str
);
443 bool SafeBrowsingDatabaseManager::MatchInclusionWhitelistUrl(const GURL
& url
) {
444 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
445 if (!enabled_
|| !MakeDatabaseAvailable())
447 return database_
->ContainsInclusionWhitelistedUrl(url
);
450 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
451 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
452 if (!enabled_
|| !MakeDatabaseAvailable()) {
455 return database_
->IsMalwareIPMatchKillSwitchOn();
458 bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
459 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
460 if (!enabled_
|| !MakeDatabaseAvailable()) {
463 return database_
->IsCsdWhitelistKillSwitchOn();
466 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL
& url
,
468 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
472 if (!CanCheckUrl(url
))
475 std::vector
<SBThreatType
> expected_threats
;
476 expected_threats
.push_back(SB_THREAT_TYPE_URL_MALWARE
);
477 expected_threats
.push_back(SB_THREAT_TYPE_URL_PHISHING
);
478 expected_threats
.push_back(SB_THREAT_TYPE_URL_UNWANTED
);
480 const base::TimeTicks start
= base::TimeTicks::Now();
481 if (!MakeDatabaseAvailable()) {
482 QueuedCheck
queued_check(safe_browsing_util::MALWARE
, // or PHISH
487 queued_checks_
.push_back(queued_check
);
491 // Cache hits should, in general, be the same for both (ignoring potential
492 // cache evictions in the second call for entries that were just about to be
493 // evicted in the first call).
494 // TODO(gab): Refactor SafeBrowsingDatabase to avoid depending on this here.
495 std::vector
<SBFullHashResult
> cache_hits
;
497 std::vector
<SBPrefix
> browse_prefix_hits
;
498 bool browse_prefix_match
= database_
->ContainsBrowseUrl(
499 url
, &browse_prefix_hits
, &cache_hits
);
501 std::vector
<SBPrefix
> unwanted_prefix_hits
;
502 std::vector
<SBFullHashResult
> unused_cache_hits
;
503 bool unwanted_prefix_match
= database_
->ContainsUnwantedSoftwareUrl(
504 url
, &unwanted_prefix_hits
, &unused_cache_hits
);
506 // Merge the two pre-sorted prefix hits lists.
507 // TODO(gab): Refactor SafeBrowsingDatabase for it to return this merged list
508 // by default rather than building it here.
509 std::vector
<SBPrefix
> prefix_hits(browse_prefix_hits
.size() +
510 unwanted_prefix_hits
.size());
511 std::merge(browse_prefix_hits
.begin(),
512 browse_prefix_hits
.end(),
513 unwanted_prefix_hits
.begin(),
514 unwanted_prefix_hits
.end(),
515 prefix_hits
.begin());
516 prefix_hits
.erase(std::unique(prefix_hits
.begin(), prefix_hits
.end()),
519 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start
);
521 if (!browse_prefix_match
&& !unwanted_prefix_match
)
522 return true; // URL is okay.
524 // Needs to be asynchronous, since we could be in the constructor of a
525 // ResourceDispatcherHost event handler which can't pause there.
526 // This check will ping the Safe Browsing servers and get all lists which it
527 // matches. These lists will then be filtered against the |expected_threats|
528 // and the result callback for MALWARE (which is the same as for PHISH and
529 // UNWANTEDURL) will eventually be invoked with the final decision.
530 SafeBrowsingCheck
* check
= new SafeBrowsingCheck(std::vector
<GURL
>(1, url
),
531 std::vector
<SBFullHash
>(),
533 safe_browsing_util::MALWARE
,
535 check
->need_get_hash
= cache_hits
.empty();
536 check
->prefix_hits
.swap(prefix_hits
);
537 check
->cache_hits
.swap(cache_hits
);
538 checks_
.insert(check
);
540 BrowserThread::PostTask(
541 BrowserThread::IO
, FROM_HERE
,
542 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
547 void SafeBrowsingDatabaseManager::CancelCheck(Client
* client
) {
548 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
549 for (CurrentChecks::iterator i
= checks_
.begin(); i
!= checks_
.end(); ++i
) {
550 // We can't delete matching checks here because the db thread has a copy of
551 // the pointer. Instead, we simply NULL out the client, and when the db
552 // thread calls us back, we'll clean up the check.
553 if ((*i
)->client
== client
)
557 // Scan the queued clients store. Clients may be here if they requested a URL
558 // check before the database has finished loading.
559 for (std::deque
<QueuedCheck
>::iterator
it(queued_checks_
.begin());
560 it
!= queued_checks_
.end(); ) {
561 // In this case it's safe to delete matches entirely since nothing has a
563 if (it
->client
== client
)
564 it
= queued_checks_
.erase(it
);
570 void SafeBrowsingDatabaseManager::HandleGetHashResults(
571 SafeBrowsingCheck
* check
,
572 const std::vector
<SBFullHashResult
>& full_hashes
,
573 const base::TimeDelta
& cache_lifetime
) {
574 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
579 // If the service has been shut down, |check| should have been deleted.
580 DCHECK(checks_
.find(check
) != checks_
.end());
582 // |start| is set before calling |GetFullHash()|, which should be
583 // the only path which gets to here.
584 DCHECK(!check
->start
.is_null());
585 UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
586 base::TimeTicks::Now() - check
->start
);
588 std::vector
<SBPrefix
> prefixes
= check
->prefix_hits
;
589 OnHandleGetHashResults(check
, full_hashes
); // 'check' is deleted here.
591 // Cache the GetHash results.
592 if (cache_lifetime
!= base::TimeDelta() && MakeDatabaseAvailable())
593 database_
->CacheHashResults(prefixes
, full_hashes
, cache_lifetime
);
596 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback
) {
597 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
599 DCHECK(!callback
.is_null());
600 safe_browsing_task_runner_
->PostTask(
602 base::Bind(&SafeBrowsingDatabaseManager::GetAllChunksFromDatabase
, this,
606 void SafeBrowsingDatabaseManager::AddChunks(
607 const std::string
& list
,
608 scoped_ptr
<ScopedVector
<SBChunkData
> > chunks
,
609 AddChunksCallback callback
) {
610 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
612 DCHECK(!callback
.is_null());
613 safe_browsing_task_runner_
->PostTask(
614 FROM_HERE
, base::Bind(&SafeBrowsingDatabaseManager::AddDatabaseChunks
,
615 this, list
, base::Passed(&chunks
), callback
));
618 void SafeBrowsingDatabaseManager::DeleteChunks(
619 scoped_ptr
<std::vector
<SBChunkDelete
> > chunk_deletes
) {
620 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
622 safe_browsing_task_runner_
->PostTask(
623 FROM_HERE
, base::Bind(&SafeBrowsingDatabaseManager::DeleteDatabaseChunks
,
624 this, base::Passed(&chunk_deletes
)));
627 void SafeBrowsingDatabaseManager::UpdateStarted() {
628 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
630 DCHECK(!update_in_progress_
);
631 update_in_progress_
= true;
634 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded
) {
635 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
637 if (update_in_progress_
) {
638 update_in_progress_
= false;
639 safe_browsing_task_runner_
->PostTask(
641 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished
, this,
646 void SafeBrowsingDatabaseManager::ResetDatabase() {
647 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
649 safe_browsing_task_runner_
->PostTask(
651 base::Bind(&SafeBrowsingDatabaseManager::OnResetDatabase
, this));
654 void SafeBrowsingDatabaseManager::StartOnIOThread() {
655 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed.
656 tracked_objects::ScopedTracker
tracking_profile1(
657 FROM_HERE_WITH_EXPLICIT_FUNCTION(
658 "455469 SafeBrowsingDatabaseManager::StartOnIOThread1"));
659 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
663 DCHECK(!safe_browsing_task_runner_
);
664 // Use the blocking pool instead of a dedicated thread for safe browsing work,
665 // if specified by an experiment.
666 const bool use_blocking_pool
=
667 variations::GetVariationParamValue("LightSpeed", "SBThreadingMode") ==
669 if (use_blocking_pool
) {
670 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is
672 tracked_objects::ScopedTracker
tracking_profile2(
673 FROM_HERE_WITH_EXPLICIT_FUNCTION(
674 "455469 SafeBrowsingDatabaseManager::StartOnIOThread2"));
675 base::SequencedWorkerPool
* pool
= BrowserThread::GetBlockingPool();
676 safe_browsing_task_runner_
=
677 pool
->GetSequencedTaskRunnerWithShutdownBehavior(
678 pool
->GetSequenceToken(),
679 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
);
681 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is
683 tracked_objects::ScopedTracker
tracking_profile3(
684 FROM_HERE_WITH_EXPLICIT_FUNCTION(
685 "455469 SafeBrowsingDatabaseManager::StartOnIOThread3"));
686 DCHECK(!safe_browsing_thread_
.get());
688 safe_browsing_thread_
.reset(new base::Thread("Chrome_SafeBrowsingThread"));
689 if (!safe_browsing_thread_
->Start())
691 safe_browsing_task_runner_
= safe_browsing_thread_
->task_runner();
696 MakeDatabaseAvailable();
699 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown
) {
700 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
708 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
709 bool update_succeeded
) {
710 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
711 content::NotificationService::current()->Notify(
712 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE
,
713 content::Source
<SafeBrowsingDatabaseManager
>(this),
714 content::Details
<bool>(&update_succeeded
));
717 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
718 const safe_browsing_util::ListType check_type
,
721 const std::vector
<SBThreatType
>& expected_threats
,
722 const base::TimeTicks
& start
)
723 : check_type(check_type
),
726 expected_threats(expected_threats
),
730 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
733 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
734 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
741 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
742 while (!queued_checks_
.empty()) {
743 QueuedCheck queued
= queued_checks_
.front();
745 SafeBrowsingCheck
sb_check(std::vector
<GURL
>(1, queued
.url
),
746 std::vector
<SBFullHash
>(),
749 queued
.expected_threats
);
750 queued
.client
->OnSafeBrowsingResult(sb_check
);
752 queued_checks_
.pop_front();
755 // Close the database. Cases to avoid:
756 // * If |closing_database_| is true, continuing will queue up a second
757 // request, |closing_database_| will be reset after handling the first
758 // request, and if any functions on the db thread recreate the database, we
759 // could start using it on the IO thread and then have the second request
760 // handler delete it out from under us.
761 // * If |database_| is NULL, then either no creation request is in flight, in
762 // which case we don't need to do anything, or one is in flight, in which
763 // case the database will be recreated before our deletion request is
764 // handled, and could be used on the IO thread in that time period, leading
765 // to the same problem as above.
766 // Checking DatabaseAvailable() avoids both of these.
767 if (DatabaseAvailable()) {
768 closing_database_
= true;
769 safe_browsing_task_runner_
->PostTask(
771 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase
, this));
774 // Flush the database thread. Any in-progress database check results will be
775 // ignored and cleaned up below.
777 // Note that to avoid leaking the database, we rely on the fact that no new
778 // tasks will be added to the db thread between the call above and this one.
779 // See comments on the declaration of |safe_browsing_thread_|.
780 if (safe_browsing_thread_
) {
781 // A ScopedAllowIO object is required to join the thread when calling Stop.
782 // See http://crbug.com/72696. Note that we call Stop() first to clear out
783 // any remaining tasks before clearing safe_browsing_thread_.
784 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join
;
785 safe_browsing_thread_
->Stop();
786 safe_browsing_thread_
.reset();
788 safe_browsing_task_runner_
= nullptr;
790 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
791 // We have to do this after the db thread returns because methods on it can
792 // have copies of these pointers, so deleting them might lead to accessing
794 for (CurrentChecks::iterator it
= checks_
.begin();
795 it
!= checks_
.end(); ++it
) {
796 SafeBrowsingCheck
* check
= *it
;
798 check
->client
->OnSafeBrowsingResult(*check
);
800 STLDeleteElements(&checks_
);
802 gethash_requests_
.clear();
805 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
806 base::AutoLock
lock(database_lock_
);
807 return !closing_database_
&& (database_
!= NULL
);
810 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
811 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
813 if (DatabaseAvailable())
815 safe_browsing_task_runner_
->PostTask(
817 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase
),
822 SafeBrowsingDatabase
* SafeBrowsingDatabaseManager::GetDatabase() {
823 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
827 startup_metric_utils::ScopedSlowStartupUMA
828 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
829 const base::TimeTicks before
= base::TimeTicks::Now();
831 SafeBrowsingDatabase
* database
= SafeBrowsingDatabase::Create(
832 safe_browsing_task_runner_
, enable_download_protection_
,
833 enable_csd_whitelist_
, enable_download_whitelist_
,
834 enable_extension_blacklist_
, enable_side_effect_free_whitelist_
,
835 enable_ip_blacklist_
, enable_unwanted_software_blacklist_
);
837 database
->Init(SafeBrowsingService::GetBaseFilename());
839 // Acquiring the lock here guarantees correct ordering between the writes to
840 // the new database object above, and the setting of |database_| below.
841 base::AutoLock
lock(database_lock_
);
842 database_
= database
;
845 BrowserThread::PostTask(
846 BrowserThread::IO
, FROM_HERE
,
847 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete
, this));
849 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before
);
853 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck
* check
) {
854 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
859 // If the service has been shut down, |check| should have been deleted.
860 DCHECK(checks_
.find(check
) != checks_
.end());
862 if (check
->client
&& check
->need_get_hash
) {
863 // We have a partial match so we need to query Google for the full hash.
864 // Clean up will happen in HandleGetHashResults.
866 // See if we have a GetHash request already in progress for this particular
867 // prefix. If so, we just append ourselves to the list of interested parties
868 // when the results arrive. We only do this for checks involving one prefix,
869 // since that is the common case (multiple prefixes will issue the request
871 if (check
->prefix_hits
.size() == 1) {
872 SBPrefix prefix
= check
->prefix_hits
[0];
873 GetHashRequests::iterator it
= gethash_requests_
.find(prefix
);
874 if (it
!= gethash_requests_
.end()) {
875 // There's already a request in progress.
876 it
->second
.push_back(check
);
880 // No request in progress, so we're the first for this prefix.
881 GetHashRequestors requestors
;
882 requestors
.push_back(check
);
883 gethash_requests_
[prefix
] = requestors
;
886 // Reset the start time so that we can measure the network time without the
888 check
->start
= base::TimeTicks::Now();
889 // Note: If |this| is deleted or stopped, the protocol_manager will
890 // be destroyed as well - hence it's OK to do unretained in this case.
891 bool is_download
= check
->check_type
== safe_browsing_util::BINURL
;
892 sb_service_
->protocol_manager()->GetFullHash(
894 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults
,
895 base::Unretained(this),
899 // We may have cached results for previous GetHash queries. Since
900 // this data comes from cache, don't histogram hits.
901 HandleOneCheck(check
, check
->cache_hits
);
905 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
906 GetChunksCallback callback
) {
907 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
909 bool database_error
= true;
910 std::vector
<SBListChunkRanges
> lists
;
911 DCHECK(!database_update_in_progress_
);
912 database_update_in_progress_
= true;
913 GetDatabase(); // This guarantees that |database_| is non-NULL.
914 if (database_
->UpdateStarted(&lists
)) {
915 database_error
= false;
917 database_
->UpdateFinished(false);
920 BrowserThread::PostTask(
921 BrowserThread::IO
, FROM_HERE
,
922 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase
,
923 this, lists
, database_error
, callback
));
926 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
927 const std::vector
<SBListChunkRanges
>& lists
, bool database_error
,
928 GetChunksCallback callback
) {
929 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
931 callback
.Run(lists
, database_error
);
934 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
935 AddChunksCallback callback
) {
936 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
941 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
942 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
946 LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_
.size());
947 if (queued_checks_
.empty())
950 // If the database isn't already available, calling CheckUrl() in the loop
951 // below will add the check back to the queue, and we'll infinite-loop.
952 DCHECK(DatabaseAvailable());
953 while (!queued_checks_
.empty()) {
954 QueuedCheck check
= queued_checks_
.front();
955 DCHECK(!check
.start
.is_null());
956 LOCAL_HISTOGRAM_TIMES("SB.QueueDelay",
957 base::TimeTicks::Now() - check
.start
);
958 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
959 // client's handler function (because normally it's being directly called by
960 // the client). Since we're not the client, we have to convey this result.
961 if (check
.client
&& CheckBrowseUrl(check
.url
, check
.client
)) {
962 SafeBrowsingCheck
sb_check(std::vector
<GURL
>(1, check
.url
),
963 std::vector
<SBFullHash
>(),
966 check
.expected_threats
);
967 check
.client
->OnSafeBrowsingResult(sb_check
);
969 queued_checks_
.pop_front();
973 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
974 const std::string
& list_name
,
975 scoped_ptr
<ScopedVector
<SBChunkData
> > chunks
,
976 AddChunksCallback callback
) {
977 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
979 GetDatabase()->InsertChunks(list_name
, chunks
->get());
980 BrowserThread::PostTask(
981 BrowserThread::IO
, FROM_HERE
,
982 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete
, this,
986 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
987 scoped_ptr
<std::vector
<SBChunkDelete
> > chunk_deletes
) {
988 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
990 GetDatabase()->DeleteChunks(*chunk_deletes
);
993 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
994 bool update_succeeded
) {
995 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
996 GetDatabase()->UpdateFinished(update_succeeded
);
997 DCHECK(database_update_in_progress_
);
998 database_update_in_progress_
= false;
999 BrowserThread::PostTask(
1000 BrowserThread::UI
, FROM_HERE
,
1001 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished
,
1002 this, update_succeeded
));
1005 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
1006 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
1007 DCHECK(closing_database_
);
1009 // Because |closing_database_| is true, nothing on the IO thread will be
1010 // accessing the database, so it's safe to delete and then NULL the pointer.
1014 // Acquiring the lock here guarantees correct ordering between the resetting
1015 // of |database_| above and of |closing_database_| below, which ensures there
1016 // won't be a window during which the IO thread falsely believes the database
1018 base::AutoLock
lock(database_lock_
);
1019 closing_database_
= false;
1022 void SafeBrowsingDatabaseManager::OnResetDatabase() {
1023 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
1025 GetDatabase()->ResetDatabase();
1028 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
1029 SafeBrowsingCheck
* check
,
1030 const std::vector
<SBFullHashResult
>& full_hashes
) {
1031 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1032 safe_browsing_util::ListType check_type
= check
->check_type
;
1033 SBPrefix prefix
= check
->prefix_hits
[0];
1034 GetHashRequests::iterator it
= gethash_requests_
.find(prefix
);
1035 if (check
->prefix_hits
.size() > 1 || it
== gethash_requests_
.end()) {
1036 const bool hit
= HandleOneCheck(check
, full_hashes
);
1037 RecordGetHashCheckStatus(hit
, check_type
, full_hashes
);
1041 // Call back all interested parties, noting if any has a hit.
1042 GetHashRequestors
& requestors
= it
->second
;
1044 for (GetHashRequestors::iterator r
= requestors
.begin();
1045 r
!= requestors
.end(); ++r
) {
1046 if (HandleOneCheck(*r
, full_hashes
))
1049 RecordGetHashCheckStatus(hit
, check_type
, full_hashes
);
1051 gethash_requests_
.erase(it
);
1054 bool SafeBrowsingDatabaseManager::HandleOneCheck(
1055 SafeBrowsingCheck
* check
,
1056 const std::vector
<SBFullHashResult
>& full_hashes
) {
1057 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1060 bool is_threat
= false;
1062 // TODO(shess): GetHashSeverestThreadListType() contains a loop,
1063 // GetUrlSeverestThreatListType() a loop around that loop. Having another
1064 // loop out here concerns me. It is likely that SAFE is an expected outcome,
1065 // which means all of those loops run to completion. Refactoring this to
1066 // generate a set of sorted items to compare in sequence would probably
1069 // Additionally, the set of patterns generated from the urls is very similar
1070 // to the patterns generated in ContainsBrowseUrl() and other database checks,
1071 // which are called from this code. Refactoring that across the checks could
1072 // interact well with batching the checks here.
1074 // TODO(gab): Fix the fact that Get(Url|Hash)SeverestThreatType() may return a
1075 // threat for which IsExpectedThreat() returns false even if |full_hashes|
1076 // actually contains an expected threat.
1078 for (size_t i
= 0; i
< check
->urls
.size(); ++i
) {
1079 size_t threat_index
;
1080 SBThreatType threat
=
1081 GetUrlSeverestThreatType(check
->urls
[i
], full_hashes
, &threat_index
);
1082 if (threat
!= SB_THREAT_TYPE_SAFE
&&
1083 IsExpectedThreat(threat
, check
->expected_threats
)) {
1084 check
->url_results
[i
] = threat
;
1085 check
->url_metadata
[i
] = full_hashes
[threat_index
].metadata
;
1090 for (size_t i
= 0; i
< check
->full_hashes
.size(); ++i
) {
1091 SBThreatType threat
=
1092 GetHashSeverestThreatType(check
->full_hashes
[i
], full_hashes
);
1093 if (threat
!= SB_THREAT_TYPE_SAFE
&&
1094 IsExpectedThreat(threat
, check
->expected_threats
)) {
1095 check
->full_hash_results
[i
] = threat
;
1100 SafeBrowsingCheckDone(check
);
1104 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
1105 SafeBrowsingCheck
* check
) {
1106 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
1107 DCHECK(enable_download_protection_
);
1109 std::vector
<SBPrefix
> prefix_hits
;
1111 if (!database_
->ContainsDownloadUrl(check
->urls
, &prefix_hits
)) {
1112 // Good, we don't have hash for this url prefix.
1113 BrowserThread::PostTask(
1114 BrowserThread::IO
, FROM_HERE
,
1115 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone
, this,
1120 check
->need_get_hash
= true;
1121 check
->prefix_hits
.clear();
1122 check
->prefix_hits
= prefix_hits
;
1123 BrowserThread::PostTask(
1124 BrowserThread::IO
, FROM_HERE
,
1125 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
1128 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
1129 SafeBrowsingCheck
* check
) {
1130 DCHECK(safe_browsing_task_runner_
->RunsTasksOnCurrentThread());
1132 std::vector
<SBPrefix
> prefixes
;
1133 for (std::vector
<SBFullHash
>::iterator it
= check
->full_hashes
.begin();
1134 it
!= check
->full_hashes
.end(); ++it
) {
1135 prefixes
.push_back((*it
).prefix
);
1137 database_
->ContainsExtensionPrefixes(prefixes
, &check
->prefix_hits
);
1139 if (check
->prefix_hits
.empty()) {
1140 // No matches for any extensions.
1141 BrowserThread::PostTask(
1144 base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone
, this,
1147 // Some prefixes matched, we need to ask Google whether they're legit.
1148 check
->need_get_hash
= true;
1149 BrowserThread::PostTask(
1152 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
1156 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck
* check
) {
1157 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1163 DCHECK(checks_
.find(check
) != checks_
.end());
1164 if (check
->client
) {
1165 check
->client
->OnSafeBrowsingResult(*check
);
1166 check
->client
= NULL
;
1170 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
1171 SafeBrowsingCheck
* check
) {
1172 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1173 DCHECK(enable_download_protection_
);
1174 SafeBrowsingCheckDone(check
);
1177 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
1178 SafeBrowsingCheck
* check
) {
1179 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1185 DVLOG(1) << "SafeBrowsingCheckDone";
1186 DCHECK(checks_
.find(check
) != checks_
.end());
1188 check
->client
->OnSafeBrowsingResult(*check
);
1189 checks_
.erase(check
);
1193 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1194 SafeBrowsingCheck
* check
,
1195 const base::Closure
& task
) {
1196 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1197 check
->timeout_factory_
.reset(
1198 new base::WeakPtrFactory
<SafeBrowsingDatabaseManager
>(this));
1199 checks_
.insert(check
);
1201 safe_browsing_task_runner_
->PostTask(FROM_HERE
, task
);
1203 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
1204 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback
,
1205 check
->timeout_factory_
->GetWeakPtr(), check
),