diff options
author | lzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-16 01:59:11 +0000 |
---|---|---|
committer | lzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-16 01:59:11 +0000 |
commit | 9cadfb34adaf42ad30e398b24ab06e5bc587e57a (patch) | |
tree | feac40cac461f17b3b8decd17f3696de43e0043c | |
parent | 58d1666040e4750a0d5662d35b44ab22c891c57c (diff) | |
download | chromium_src-9cadfb34adaf42ad30e398b24ab06e5bc587e57a.zip chromium_src-9cadfb34adaf42ad30e398b24ab06e5bc587e57a.tar.gz chromium_src-9cadfb34adaf42ad30e398b24ab06e5bc587e57a.tar.bz2 |
Lookup hash prefix in safebrowsing service.
To achieve that, added an interface in safe browsing database and safe browsing service.
TEST=safe_browsing_service_browsertest, safe_browsing_util_unittest, safe_browsing_database_unittest
BUG=60822
Review URL: http://codereview.chromium.org/6299007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75049 0039d316-1c4b-4281-b951-d872f2087c98
15 files changed, 463 insertions, 186 deletions
diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc index a297244..246b995 100644 --- a/chrome/browser/renderer_host/download_resource_handler.cc +++ b/chrome/browser/renderer_host/download_resource_handler.cc @@ -74,7 +74,7 @@ void DownloadResourceHandler::OnDownloadUrlCheckResult( UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration", base::TimeTicks::Now() - download_start_time_); - if (result == SafeBrowsingService::BINARY_MALWARE) { + if (result == SafeBrowsingService::BINARY_MALWARE_URL) { // TODO(lzheng): More UI work to show warnings properly on download shelf. DLOG(WARNING) << "This url leads to a malware downloading: " << url.spec(); diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc index a8b171e..32d4a59 100644 --- a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc +++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc @@ -29,7 +29,7 @@ SafeBrowsingResourceHandler::SafeBrowsingResourceHandler( ResourceDispatcherHost* resource_dispatcher_host) : state_(STATE_NONE), defer_state_(DEFERRED_NONE), - safe_browsing_result_(SafeBrowsingService::URL_SAFE), + safe_browsing_result_(SafeBrowsingService::SAFE), deferred_request_id_(-1), next_handler_(handler), render_process_host_id_(render_process_host_id), @@ -89,7 +89,7 @@ void SafeBrowsingResourceHandler::OnCheckUrlTimeout() { CHECK(state_ == STATE_CHECKING_URL); CHECK(defer_state_ != DEFERRED_NONE); safe_browsing_->CancelCheck(this); - OnBrowseUrlCheckResult(deferred_url_, SafeBrowsingService::URL_SAFE); + OnBrowseUrlCheckResult(deferred_url_, SafeBrowsingService::SAFE); } bool SafeBrowsingResourceHandler::OnWillStart(int request_id, @@ -149,7 +149,7 @@ void SafeBrowsingResourceHandler::OnBrowseUrlCheckResult( safe_browsing_result_ = result; state_ = STATE_NONE; - if (result == SafeBrowsingService::URL_SAFE) { + if (result == SafeBrowsingService::SAFE) { // Log how much time the safe browsing check cost us. base::TimeDelta pause_delta; pause_delta = base::TimeTicks::Now() - url_check_start_time_; @@ -195,7 +195,7 @@ void SafeBrowsingResourceHandler::OnBlockingPageComplete(bool proceed) { state_ = STATE_NONE; if (proceed) { - safe_browsing_result_ = SafeBrowsingService::URL_SAFE; + safe_browsing_result_ = SafeBrowsingService::SAFE; ResumeRequest(); } else { rdh_->CancelRequest(render_process_host_id_, deferred_request_id_, false); @@ -219,7 +219,7 @@ bool SafeBrowsingResourceHandler::CheckUrl(const GURL& url) { CHECK(state_ == STATE_NONE); bool succeeded_synchronously = safe_browsing_->CheckBrowseUrl(url, this); if (succeeded_synchronously) { - safe_browsing_result_ = SafeBrowsingService::URL_SAFE; + safe_browsing_result_ = SafeBrowsingService::SAFE; safe_browsing_->LogPauseDelay(base::TimeDelta()); // No delay. return true; } diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc index 2ff5f4c..5e61eca 100644 --- a/chrome/browser/safe_browsing/protocol_manager.cc +++ b/chrome/browser/safe_browsing/protocol_manager.cc @@ -126,9 +126,15 @@ SafeBrowsingProtocolManager::SafeBrowsingProtocolManager( } // static -void SafeBrowsingProtocolManager::RecordGetHashResult(ResultType result_type) { - UMA_HISTOGRAM_ENUMERATION("SB2.GetHashResult", result_type, - GET_HASH_RESULT_MAX); +void SafeBrowsingProtocolManager::RecordGetHashResult( + bool is_download, ResultType result_type) { + if (is_download) { + UMA_HISTOGRAM_ENUMERATION("SB2.GetHashResultDownload", result_type, + GET_HASH_RESULT_MAX); + } else { + UMA_HISTOGRAM_ENUMERATION("SB2.GetHashResult", result_type, + GET_HASH_RESULT_MAX); + } } SafeBrowsingProtocolManager::~SafeBrowsingProtocolManager() { @@ -231,9 +237,9 @@ void SafeBrowsingProtocolManager::OnURLFetchComplete( // For tracking our GetHash false positive (204) rate, compared to real // (200) responses. if (response_code == 200) - RecordGetHashResult(GET_HASH_STATUS_200); + RecordGetHashResult(check->is_download, GET_HASH_STATUS_200); else - RecordGetHashResult(GET_HASH_STATUS_204); + RecordGetHashResult(check->is_download, GET_HASH_STATUS_204); can_cache = true; gethash_error_count_ = 0; gethash_back_off_mult_ = 1; diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h index 7205b53..994849a 100644 --- a/chrome/browser/safe_browsing/protocol_manager.h +++ b/chrome/browser/safe_browsing/protocol_manager.h @@ -188,8 +188,10 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate { GET_HASH_RESULT_MAX }; - // Record a GetHash result. - static void RecordGetHashResult(ResultType result_type); + // Record a GetHash result. |is_download| indicates if the get + // hash is triggered by download related lookup. + static void RecordGetHashResult(bool is_download, + ResultType result_type); protected: // Constructs a SafeBrowsingProtocolManager for |sb_service| that issues diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index 318e6ac..0138224 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc @@ -35,21 +35,24 @@ class FakeSafeBrowsingService : public SafeBrowsingService { // can synchronously determine that the url is safe, CheckUrl returns true. // Otherwise it returns false, and "client" is called asynchronously with the // result when it is ready. - // Overrides SafeBrowsingService::CheckUrl. + // Overrides SafeBrowsingService::CheckBrowseUrl. virtual bool CheckBrowseUrl(const GURL& gurl, Client* client) { - const std::string& url = gurl.spec(); - if (badurls[url] == URL_SAFE) + if (badurls[gurl.spec()] == SAFE) return true; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(this, &FakeSafeBrowsingService::OnCheckDone, - url, client)); + NewRunnableMethod(this, &FakeSafeBrowsingService::OnCheckBrowseURLDone, + gurl, client)); return false; } - void OnCheckDone(std::string url, Client* client) { - client->OnSafeBrowsingResult(GURL(url), badurls[url]); + void OnCheckBrowseURLDone(const GURL& gurl, Client* client) { + SafeBrowsingService::SafeBrowsingCheck check; + check.url.reset(new GURL(gurl)); + check.client = client; + check.result = badurls[gurl.spec()]; + client->OnSafeBrowsingResult(check); } void AddURLResult(const GURL& url, UrlCheckResult checkresult) { @@ -114,8 +117,9 @@ class SafeBrowsingBlockingPageTest : public InProcessBrowserTest, // SafeBrowsingService::Client implementation. virtual void OnSafeBrowsingResult( - const GURL& url, SafeBrowsingService::UrlCheckResult result) { + const SafeBrowsingService::SafeBrowsingCheck& check) { } + virtual void OnBlockingPageComplete(bool proceed) { } diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc index 92ef562..c142907 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database.cc @@ -427,30 +427,49 @@ bool SafeBrowsingDatabaseNew::ContainsBrowseUrl( return true; } -bool SafeBrowsingDatabaseNew::ContainsDownloadUrl( - const GURL& url, std::vector<SBPrefix>* prefix_hits) { - DCHECK_EQ(creation_loop_, MessageLoop::current()); - prefix_hits->clear(); - - // Ignore this check when download checking is not enabled. - if (!download_store_.get()) return false; - - SBPrefix prefix; - GetDownloadUrlPrefix(url, &prefix); - +bool SafeBrowsingDatabaseNew::MatchDownloadAddPrefixes( + int list_bit, const SBPrefix& prefix, SBPrefix* prefix_hit) { std::vector<SBAddPrefix> add_prefixes; download_store_->GetAddPrefixes(&add_prefixes); for (size_t i = 0; i < add_prefixes.size(); ++i) { if (prefix == add_prefixes[i].prefix && - GetListIdBit(add_prefixes[i].chunk_id) == - safe_browsing_util::BINURL % 2) { - prefix_hits->push_back(prefix); + GetListIdBit(add_prefixes[i].chunk_id) == list_bit) { + *prefix_hit = prefix; return true; } } return false; } +bool SafeBrowsingDatabaseNew::ContainsDownloadUrl(const GURL& url, + SBPrefix* prefix_hit) { + DCHECK_EQ(creation_loop_, MessageLoop::current()); + + // Ignore this check when download checking is not enabled. + if (!download_store_.get()) + return false; + + SBPrefix prefix; + GetDownloadUrlPrefix(url, &prefix); + return MatchDownloadAddPrefixes(safe_browsing_util::BINURL % 2, + prefix, + prefix_hit); +} + +bool SafeBrowsingDatabaseNew::ContainsDownloadHashPrefix( + const SBPrefix& prefix) { + DCHECK_EQ(creation_loop_, MessageLoop::current()); + + // Ignore this check when download store is not available. + if (!download_store_.get()) + return false; + + SBPrefix prefix_hit; + return MatchDownloadAddPrefixes(safe_browsing_util::BINHASH % 2, + prefix, + &prefix_hit); +} + // Helper to insert entries for all of the prefixes or full hashes in // |entry| into the store. void SafeBrowsingDatabaseNew::InsertAdd(int chunk_id, SBPrefix host, diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h index d233ec6..b1712f0 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.h +++ b/chrome/browser/safe_browsing/safe_browsing_database.h @@ -85,10 +85,14 @@ class SafeBrowsingDatabase { base::Time last_update) = 0; // Returns false if |url| is not in Download database. If it returns true, - // |prefix_hits| should contain the prefix for |url|. + // |prefix_hit| should contain the prefix for |url|. // This function could ONLY be accessed from creation thread. virtual bool ContainsDownloadUrl(const GURL& url, - std::vector<SBPrefix>* prefix_hits) = 0; + SBPrefix* prefix_hit) = 0; + + // Returns false if |prefix| is not in Download database. + // This function could ONLY be accessed from creation thread. + virtual bool ContainsDownloadHashPrefix(const SBPrefix& prefix) = 0; // A database transaction should look like: // @@ -188,8 +192,8 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { std::vector<SBFullHashResult>* full_hits, base::Time last_update); virtual bool ContainsDownloadUrl(const GURL& url, - std::vector<SBPrefix>* prefix_hits); - + SBPrefix* prefix_hit); + virtual bool ContainsDownloadHashPrefix(const SBPrefix& prefix); virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists); virtual void InsertChunks(const std::string& list_name, const SBChunkList& chunks); @@ -233,6 +237,15 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { void UpdateDownloadStore(); void UpdateBrowseStore(); + // Helper function to compare addprefixes in download_store_ with prefix. + // The |list_bit| indicates which list (download url or download hash) + // to compare. + // Returns true if there is a match, |*prefix_hit| will contain the actual + // matching prefix. + bool MatchDownloadAddPrefixes(int list_bit, + const SBPrefix& prefix, + SBPrefix* prefix_hit); + // Used to verify that various calls are made from the thread the // object was created on. MessageLoop* creation_loop_; diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc index 8491212..a71a797 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc @@ -1131,32 +1131,27 @@ TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) { database_->UpdateFinished(true); const Time now = Time::Now(); - std::vector<SBPrefix> prefix_hits; + SBPrefix prefix_hit; std::string matching_list; EXPECT_TRUE(database_->ContainsDownloadUrl( - GURL(std::string("http://") + kEvil1Url1), &prefix_hits)); - EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); - EXPECT_EQ(prefix_hits.size(), 1U); + GURL(std::string("http://") + kEvil1Url1), &prefix_hit)); + EXPECT_EQ(prefix_hit, Sha256Prefix(kEvil1Url1)); EXPECT_TRUE(database_->ContainsDownloadUrl( - GURL(std::string("http://") + kEvil1Url2), &prefix_hits)); - EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); - EXPECT_EQ(prefix_hits.size(), 1U); + GURL(std::string("http://") + kEvil1Url2), &prefix_hit)); + EXPECT_EQ(prefix_hit, Sha256Prefix(kEvil1Url2)); EXPECT_TRUE(database_->ContainsDownloadUrl( - GURL(std::string("https://") + kEvil1Url2), &prefix_hits)); - EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); - EXPECT_EQ(prefix_hits.size(), 1U); + GURL(std::string("https://") + kEvil1Url2), &prefix_hit)); + EXPECT_EQ(prefix_hit, Sha256Prefix(kEvil1Url2)); EXPECT_TRUE(database_->ContainsDownloadUrl( - GURL(std::string("ftp://") + kEvil1Url2), &prefix_hits)); - EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); - EXPECT_EQ(prefix_hits.size(), 1U); + GURL(std::string("ftp://") + kEvil1Url2), &prefix_hit)); + EXPECT_EQ(prefix_hit, Sha256Prefix(kEvil1Url2)); EXPECT_FALSE(database_->ContainsDownloadUrl(GURL("http://www.randomevil.com"), - &prefix_hits)); - EXPECT_EQ(prefix_hits.size(), 0U); + &prefix_hit)); database_.reset(); } @@ -1259,7 +1254,10 @@ TEST_F(SafeBrowsingDatabaseTest, SameHostEntriesOkay) { &listname, &prefixes, &full_hashes, now)); } -TEST_F(SafeBrowsingDatabaseTest, BinHashEntries) { +TEST_F(SafeBrowsingDatabaseTest, BinHashInsertLookup) { + const SBPrefix kPrefix1 = 0x31313131; + const SBPrefix kPrefix2 = 0x32323232; + const SBPrefix kPrefix3 = 0x33333333; database_.reset(); MessageLoop loop(MessageLoop::TYPE_DEFAULT); SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); @@ -1270,9 +1268,9 @@ TEST_F(SafeBrowsingDatabaseTest, BinHashEntries) { SBChunkList chunks; SBChunk chunk; // Insert one host. - InsertAddChunkHostPrefixValue(&chunk, 1, 0, 0x31313131); + InsertAddChunkHostPrefixValue(&chunk, 1, 0, kPrefix1); // Insert a second host, which has the same host prefix as the first one. - InsertAddChunkHostPrefixValue(&chunk, 1, 0, 0x32323232); + InsertAddChunkHostPrefixValue(&chunk, 1, 0, kPrefix2); chunks.push_back(chunk); // Insert the testing chunks into database. @@ -1287,8 +1285,9 @@ TEST_F(SafeBrowsingDatabaseTest, BinHashEntries) { EXPECT_EQ("1", lists[3].adds); EXPECT_TRUE(lists[3].subs.empty()); - // TODO(lzheng): Query database and verifies the prefixes once that API - // database is available in database. + EXPECT_TRUE(database_->ContainsDownloadHashPrefix(kPrefix1)); + EXPECT_TRUE(database_->ContainsDownloadHashPrefix(kPrefix2)); + EXPECT_FALSE(database_->ContainsDownloadHashPrefix(kPrefix3)); database_.reset(); } diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 11d0657..e1e1efd 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc @@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/lazy_instance.h" #include "base/path_service.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/browser_process.h" @@ -59,7 +60,9 @@ Profile* GetDefaultProfile() { // Records disposition information about the check. |hit| should be // |true| if there were any prefix hits in |full_hashes|. void RecordGetHashCheckStatus( - bool hit, const std::vector<SBFullHashResult>& full_hashes) { + bool hit, + bool is_download, + const std::vector<SBFullHashResult>& full_hashes) { SafeBrowsingProtocolManager::ResultType result; if (full_hashes.empty()) { result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY; @@ -68,7 +71,7 @@ void RecordGetHashCheckStatus( } else { result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS; } - SafeBrowsingProtocolManager::RecordGetHashResult(result); + SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); } } // namespace @@ -104,7 +107,7 @@ struct SafeBrowsingService::WhiteListedEntry { SafeBrowsingService::UnsafeResource::UnsafeResource() : resource_type(ResourceType::MAIN_FRAME), - threat_type(URL_SAFE), + threat_type(SAFE), client(NULL), render_process_host_id(-1), render_view_id(-1) { @@ -113,13 +116,29 @@ SafeBrowsingService::UnsafeResource::UnsafeResource() SafeBrowsingService::UnsafeResource::~UnsafeResource() {} SafeBrowsingService::SafeBrowsingCheck::SafeBrowsingCheck() - : client(NULL), + : url(NULL), + full_hash(NULL), + client(NULL), need_get_hash(false), - result(URL_SAFE) { + result(SAFE), + is_download(false) { } SafeBrowsingService::SafeBrowsingCheck::~SafeBrowsingCheck() {} +void SafeBrowsingService::Client::OnSafeBrowsingResult( + const SafeBrowsingCheck& check) { + if (check.url.get()) { + DCHECK(!check.full_hash.get()); + OnBrowseUrlCheckResult(*(check.url), check.result); + OnDownloadUrlCheckResult(*(check.url), check.result); + } else if (check.full_hash.get()) { + OnDownloadHashCheckResult(*(check.full_hash), check.result); + } else { + NOTREACHED(); + } +} + /* static */ SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() { if (!factory_) @@ -170,36 +189,81 @@ bool SafeBrowsingService::DownloadBinHashNeeded() const { return enable_download_protection_ && CanReportStats(); } -void SafeBrowsingService::CheckDownloadUrlDone( - SafeBrowsingCheck* check, UrlCheckResult result) { +void SafeBrowsingService::CheckDownloadUrlDone(SafeBrowsingCheck* check) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(enable_download_protection_); - VLOG(1) << "CheckDownloadUrlDone: " << result; + DCHECK(check); - if (checks_.find(check) == checks_.end() || !check->client) + if (!enabled_) return; - check->client->OnSafeBrowsingResult(check->url, result); + + VLOG(1) << "CheckDownloadUrlDone: " << check->result; + DCHECK(checks_.find(check) != checks_.end()); + if (check->client) + check->client->OnSafeBrowsingResult(*check); checks_.erase(check); + delete check; } void SafeBrowsingService::CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check) { DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); DCHECK(enable_download_protection_); - std::vector<SBPrefix> prefix_hits; + SBPrefix prefix_hit; - if (!database_->ContainsDownloadUrl(check->url, &prefix_hits)) { + if (!database_->ContainsDownloadUrl(*(check->url), &prefix_hit)) { // Good, we don't have hash for this url prefix. + check->result = SAFE; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, &SafeBrowsingService::CheckDownloadUrlDone, - check, URL_SAFE)); + check)); return; } check->need_get_hash = true; - check->prefix_hits.swap(prefix_hits); + check->prefix_hits.clear(); + check->prefix_hits.push_back(prefix_hit); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check)); +} + +void SafeBrowsingService::CheckDownloadHashDone(SafeBrowsingCheck* check) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(enable_download_protection_); + DCHECK(check); + + if (!enabled_) + return; + + VLOG(1) << "CheckDownloadHashDone: " << check->result; + DCHECK(checks_.find(check) != checks_.end()); + if (check->client) + check->client->OnSafeBrowsingResult(*check); + checks_.erase(check); + delete check; +} + +void SafeBrowsingService::CheckDownloadHashOnSBThread( + SafeBrowsingCheck* check) { + DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop()); + DCHECK(enable_download_protection_); + + if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) { + // Good, we don't have hash for this url prefix. + check->result = SAFE; + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod(this, + &SafeBrowsingService::CheckDownloadHashDone, + check)); + return; + } + + check->need_get_hash = true; + check->prefix_hits.push_back(check->full_hash->prefix); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check)); @@ -215,9 +279,10 @@ bool SafeBrowsingService::CheckDownloadUrl(const GURL& url, // from the safebrowsing backends. These need to be asynchronous. SafeBrowsingCheck* check = new SafeBrowsingCheck(); - check->url = url; + check->url.reset(new GURL(url)); check->client = client; - check->result = URL_SAFE; + check->result = SAFE; + check->is_download = true; checks_.insert(check); safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( this, &SafeBrowsingService::CheckDownloadUrlOnSBThread, check)); @@ -225,6 +290,28 @@ bool SafeBrowsingService::CheckDownloadUrl(const GURL& url, return false; } +bool SafeBrowsingService::CheckDownloadHash(const std::string& full_hash, + Client* client) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (!enabled_ || !enable_download_protection_) + return true; + + // We need to check the database for url prefix, and later may fetch the url + // from the safebrowsing backends. These need to be asynchronous. + SafeBrowsingCheck* check = new SafeBrowsingCheck(); + + check->full_hash.reset(new SBFullHash); + safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get()); + check->client = client; + check->result = SAFE; + check->is_download = false; + checks_.insert(check); + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::CheckDownloadHashOnSBThread, check)); + + return false; +} + bool SafeBrowsingService::CheckBrowseUrl(const GURL& url, Client* client) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); @@ -259,9 +346,10 @@ bool SafeBrowsingService::CheckBrowseUrl(const GURL& url, // Needs to be asynchronous, since we could be in the constructor of a // ResourceDispatcherHost event handler which can't pause there. SafeBrowsingCheck* check = new SafeBrowsingCheck(); - check->url = url; + check->url.reset(new GURL(url)); check->client = client; - check->result = URL_SAFE; + check->result = SAFE; + check->is_download = false; check->need_get_hash = full_hits.empty(); check->prefix_hits.swap(prefix_hits); check->full_hits.swap(full_hits); @@ -558,12 +646,17 @@ void SafeBrowsingService::OnIOShutdown() { delete protocol_manager_; protocol_manager_ = NULL; - // Delete queued checks, calling back any clients with 'URL_SAFE'. + // Delete queued checks, calling back any clients with 'SAFE'. // If we don't do this here we may fail to close the database below. while (!queued_checks_.empty()) { - QueuedCheck check = queued_checks_.front(); - if (check.client) - check.client->OnSafeBrowsingResult(check.url, URL_SAFE); + QueuedCheck queued = queued_checks_.front(); + if (queued.client) { + SafeBrowsingCheck sb_check; + sb_check.url.reset(new GURL(queued.url)); + sb_check.client = queued.client; + sb_check.result = SAFE; + queued.client->OnSafeBrowsingResult(sb_check); + } queued_checks_.pop_front(); } @@ -586,16 +679,18 @@ void SafeBrowsingService::OnIOShutdown() { safe_browsing_thread_.reset(); } - // Delete pending checks, calling back any clients with 'URL_SAFE'. We have + // Delete pending checks, calling back any clients with 'SAFE'. We have // to do this after the db thread returns because methods on it can have // copies of these pointers, so deleting them might lead to accessing garbage. for (CurrentChecks::iterator it = checks_.begin(); it != checks_.end(); ++it) { - if ((*it)->client) - (*it)->client->OnSafeBrowsingResult((*it)->url, URL_SAFE); - delete *it; + SafeBrowsingCheck* check = *it; + if (check->client) { + check->result = SAFE; + check->client->OnSafeBrowsingResult(*check); + } } - checks_.clear(); + STLDeleteElements(&checks_); gethash_requests_.clear(); } @@ -741,8 +836,13 @@ void SafeBrowsingService::DatabaseLoadComplete() { // If CheckUrl() determines the URL is safe immediately, it doesn't call the // client's handler function (because normally it's being directly called by // the client). Since we're not the client, we have to convey this result. - if (check.client && CheckBrowseUrl(check.url, check.client)) - check.client->OnSafeBrowsingResult(check.url, URL_SAFE); + if (check.client && CheckBrowseUrl(check.url, check.client)) { + SafeBrowsingCheck sb_check; + sb_check.url.reset(new GURL(check.url)); + sb_check.client = check.client; + sb_check.result = SAFE; + check.client->OnSafeBrowsingResult(sb_check); + } queued_checks_.pop_front(); } } @@ -779,11 +879,15 @@ SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname( } if (safe_browsing_util::IsBadbinurlList(list_name)) { - return BINARY_MALWARE; + return BINARY_MALWARE_URL; + } + + if (safe_browsing_util::IsBadbinhashList(list_name)) { + return BINARY_MALWARE_HASH; } DVLOG(1) << "Unknown safe browsing list " << list_name; - return URL_SAFE; + return SAFE; } void SafeBrowsingService::NotifyClientBlockingComplete(Client* client, @@ -858,11 +962,12 @@ void SafeBrowsingService::OnHandleGetHashResults( SafeBrowsingCheck* check, const std::vector<SBFullHashResult>& full_hashes) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + bool is_download = check->is_download; SBPrefix prefix = check->prefix_hits[0]; GetHashRequests::iterator it = gethash_requests_.find(prefix); if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { const bool hit = HandleOneCheck(check, full_hashes); - RecordGetHashCheckStatus(hit, full_hashes); + RecordGetHashCheckStatus(hit, is_download, full_hashes); return; } @@ -874,7 +979,7 @@ void SafeBrowsingService::OnHandleGetHashResults( if (HandleOneCheck(*r, full_hashes)) hit = true; } - RecordGetHashCheckStatus(hit, full_hashes); + RecordGetHashCheckStatus(hit, is_download, full_hashes); gethash_requests_.erase(it); } @@ -883,18 +988,23 @@ bool SafeBrowsingService::HandleOneCheck( SafeBrowsingCheck* check, const std::vector<SBFullHashResult>& full_hashes) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(check); // Always calculate the index, for recording hits. - int index = safe_browsing_util::CompareFullHashes(check->url, full_hashes); + int index = -1; + if (check->url.get() != NULL) + index = safe_browsing_util::GetUrlHashIndex(*(check->url), full_hashes); + else + index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes); // |client| is NULL if the request was cancelled. if (check->client) { - UrlCheckResult result = URL_SAFE; + check->result = SAFE; if (index != -1) - result = GetResultFromListname(full_hashes[index].list_name); + check->result = GetResultFromListname(full_hashes[index].list_name); // Let the client continue handling the original request. - check->client->OnSafeBrowsingResult(check->url, result); + check->client->OnSafeBrowsingResult(*check); } checks_.erase(check); diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h index abebc32..ae4a7c3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.h +++ b/chrome/browser/safe_browsing/safe_browsing_service.h @@ -38,42 +38,15 @@ class Thread; class SafeBrowsingService : public base::RefCountedThreadSafe<SafeBrowsingService> { public: + class Client; // Users of this service implement this interface to be notified // asynchronously of the result. enum UrlCheckResult { - URL_SAFE, + SAFE, URL_PHISHING, URL_MALWARE, - BINARY_MALWARE, // This binary is a malware. - }; - - class Client { - public: - virtual ~Client() {} - - void OnSafeBrowsingResult(const GURL& url, UrlCheckResult result) { - OnBrowseUrlCheckResult(url, result); - OnDownloadUrlCheckResult(url, result); - // TODO(lzheng): This is not implemented yet. - // OnDownloadHashCheckResult(url, result); - } - - // Called when the user has made a decision about how to handle the - // SafeBrowsing interstitial page. - virtual void OnBlockingPageComplete(bool proceed) {} - - protected: - // Called when the result of checking a browse URL is known. - virtual void OnBrowseUrlCheckResult(const GURL& url, - UrlCheckResult result) {} - - // Called when the result of checking a download URL is known. - virtual void OnDownloadUrlCheckResult(const GURL& url, - UrlCheckResult result) {} - - // Called when the result of checking a download binary hash is known. - virtual void OnDownloadHashCheckResult(const GURL& url, - UrlCheckResult result) {} + BINARY_MALWARE_URL, // Binary url leads to a malware. + BINARY_MALWARE_HASH, // Binary hash indicates this is a malware. }; // Structure used to pass parameters between the IO and UI thread when @@ -92,16 +65,20 @@ class SafeBrowsingService int render_view_id; }; - // Bundle of SafeBrowsing state for one URL check. + // Bundle of SafeBrowsing state for one URL or hash prefix check. struct SafeBrowsingCheck { SafeBrowsingCheck(); ~SafeBrowsingCheck(); - GURL url; + // Either |url| or |prefix| is used to lookup database. + scoped_ptr<GURL> url; + scoped_ptr<SBFullHash> full_hash; + Client* client; bool need_get_hash; base::Time start; // Time that check was sent to SB service. UrlCheckResult result; + bool is_download; // If this check for download url or hash. std::vector<SBPrefix> prefix_hits; std::vector<SBFullHashResult> full_hits; @@ -109,6 +86,31 @@ class SafeBrowsingService DISALLOW_COPY_AND_ASSIGN(SafeBrowsingCheck); }; + class Client { + public: + virtual ~Client() {} + + void OnSafeBrowsingResult(const SafeBrowsingCheck& check); + + // Called when the user has made a decision about how to handle the + // SafeBrowsing interstitial page. + virtual void OnBlockingPageComplete(bool proceed) {} + + protected: + // Called when the result of checking a browse URL is known. + virtual void OnBrowseUrlCheckResult(const GURL& url, + UrlCheckResult result) {} + + // Called when the result of checking a download URL is known. + virtual void OnDownloadUrlCheckResult(const GURL& url, + UrlCheckResult result) {} + + // Called when the result of checking a download binary hash is known. + virtual void OnDownloadHashCheckResult(const SBFullHash& hash, + UrlCheckResult result) {} + }; + + // Makes the passed |factory| the factory used to instanciate // a SafeBrowsingService. Useful for tests. static void RegisterFactory(SafeBrowsingServiceFactory* factory) { @@ -145,6 +147,10 @@ class SafeBrowsingService // Result will be passed to callback in |client|. bool CheckDownloadUrl(const GURL& url, Client* client); + // Check if the prefix for |full_hash| is in safebrowsing binhash add lists. + // Result will be passed to callback in |client|. + virtual bool CheckDownloadHash(const std::string& full_hash, Client* client); + // Called on the IO thread to cancel a pending check if the result is no // longer needed. void CancelCheck(Client* client); @@ -333,12 +339,18 @@ class SafeBrowsingService bool is_subresource, UrlCheckResult threat_type); + // Checks the download hash on safe_browsing_thread_. + void CheckDownloadHashOnSBThread(SafeBrowsingCheck* check); + // Invoked by CheckDownloadUrl. It checks the download URL on // safe_browsing_thread_. void CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check); - // Call the Client's callback in IO thread after CheckDownloadUrl finishes. - void CheckDownloadUrlDone(SafeBrowsingCheck* check, UrlCheckResult result); + // Calls the Client's callback on IO thread after CheckDownloadUrl finishes. + void CheckDownloadUrlDone(SafeBrowsingCheck* check); + + // Calls the Client's callback on IO thread after CheckDownloadHash finishes. + void CheckDownloadHashDone(SafeBrowsingCheck* check); // The factory used to instanciate a SafeBrowsingService object. // Useful for tests, so they can provide their own implementation of diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index 0b44a250..4bff659 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc @@ -57,15 +57,22 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { safe_browsing_util::kPhishingList, url, prefix_hits, full_hits); } - virtual bool ContainsDownloadUrl(const GURL& url, - std::vector<SBPrefix>* prefix_hits) { + SBPrefix* prefix_hit) { std::vector<SBFullHashResult> full_hits; - return ContainsUrl(safe_browsing_util::kBinUrlList, - safe_browsing_util::kBinHashList, - url, prefix_hits, &full_hits); + std::vector<SBPrefix> prefix_hits; + bool found = ContainsUrl(safe_browsing_util::kBinUrlList, + safe_browsing_util::kBinHashList, + url, &prefix_hits, &full_hits); + if (!found) + return false; + DCHECK_EQ(1U, prefix_hits.size()); + *prefix_hit = prefix_hits[0]; + return true; + } + virtual bool ContainsDownloadHashPrefix(const SBPrefix& prefix) { + return download_digest_prefix_.count(prefix) > 0; } - virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists) { ADD_FAILURE() << "Not implemented."; return false; @@ -96,6 +103,11 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { badurls_[url.spec()].full_hits = full_hits; } + // Fill up the database with test hash digest. + void AddDownloadPrefix(SBPrefix prefix) { + download_digest_prefix_.insert(prefix); + } + private: struct Hits { std::string list_name; @@ -125,6 +137,7 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { } base::hash_map<std::string, Hits> badurls_; + base::hash_set<SBPrefix> download_digest_prefix_; }; // Factory that creates TestSafeBrowsingDatabase instances. @@ -172,25 +185,23 @@ class TestProtocolManager : public SafeBrowsingProtocolManager { // server's response. virtual void GetFullHash(SafeBrowsingService::SafeBrowsingCheck* check, const std::vector<SBPrefix>& prefixes) { - // The hash result should be inserted to the full_hashes_. - ASSERT_TRUE(full_hashes_.find(check->url.spec()) != full_hashes_.end()); // When we get a valid response, always cache the result. bool cancache = true; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod( sb_service_, &SafeBrowsingService::HandleGetHashResults, - check, full_hashes_[check->url.spec()], cancache)); + check, full_hashes_, cancache)); } - // Prepare the GetFullHash results for |url|. - void SetGetFullHashResponse(const GURL& url, - const SBFullHashResult& full_hash_result) { - full_hashes_[url.spec()].push_back(full_hash_result); + // Prepare the GetFullHash results for the next request. + void SetGetFullHashResponse(const SBFullHashResult& full_hash_result) { + full_hashes_.clear(); + full_hashes_.push_back(full_hash_result); } private: - base::hash_map<std::string, std::vector<SBFullHashResult> > full_hashes_; + std::vector<SBFullHashResult> full_hashes_; SafeBrowsingService* sb_service_; }; @@ -229,10 +240,10 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest { SafeBrowsingServiceTest() { } - static void GenerateFullhashResult(const GURL& url, - const std::string& list_name, - int add_chunk_id, - SBFullHashResult* full_hash) { + static void GenUrlFullhashResult(const GURL& url, + const std::string& list_name, + int add_chunk_id, + SBFullHashResult* full_hash) { std::string host; std::string path; safe_browsing_util::CanonicalizeUrl(url, &host, &path, NULL); @@ -242,6 +253,15 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest { full_hash->add_chunk_id = add_chunk_id; } + static void GenDigestFullhashResult(const std::string& full_digest, + const std::string& list_name, + int add_chunk_id, + SBFullHashResult* full_hash) { + safe_browsing_util::StringToSBFullHash(full_digest, &full_hash->hash); + full_hash->list_name = list_name; + full_hash->add_chunk_id = add_chunk_id; + } + virtual void SetUp() { // InProcessBrowserTest::SetUp() intantiates SafebrowsingService and // RegisterFactory has to be called before SafeBrowsingService is created. @@ -273,10 +293,9 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest { ASSERT_TRUE(test_server()->Start()); } - // This will setup the prefix in database and prepare protocol manager + // This will setup the "url" prefix in database and prepare protocol manager // to response with |full_hash| for get full hash request. - void SetupResponseForUrl(const GURL& url, - const SBFullHashResult& full_hash) { + void SetupResponseForUrl(const GURL& url, const SBFullHashResult& full_hash) { std::vector<SBPrefix> prefix_hits; prefix_hits.push_back(full_hash.hash.prefix); @@ -287,7 +306,20 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest { db->AddUrl(url, full_hash.list_name, prefix_hits, empty_full_hits); TestProtocolManager* pm = pm_factory_.GetProtocolManager(); - pm->SetGetFullHashResponse(url, full_hash); + pm->SetGetFullHashResponse(full_hash); + } + + // This will setup the binary digest prefix in database and prepare protocol + // manager to response with |full_hash| for get full hash request. + void SetupResponseForDigest(const std::string& digest, + const SBFullHashResult& hash_result) { + TestSafeBrowsingDatabase* db = db_factory_.GetDb(); + SBFullHash full_hash; + safe_browsing_util::StringToSBFullHash(digest, &full_hash); + db->AddDownloadPrefix(full_hash.prefix); + + TestProtocolManager* pm = pm_factory_.GetProtocolManager(); + pm->SetGetFullHashResponse(hash_result); } bool ShowingInterstitialPage() { @@ -316,8 +348,8 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, Malware) { // we should see the interstitial page. SBFullHashResult malware_full_hash; int chunk_id = 0; - GenerateFullhashResult(url, safe_browsing_util::kMalwareList, chunk_id, - &malware_full_hash); + GenUrlFullhashResult(url, safe_browsing_util::kMalwareList, chunk_id, + &malware_full_hash); SetupResponseForUrl(url, malware_full_hash); ui_test_utils::NavigateToURL(browser(), url); EXPECT_TRUE(ShowingInterstitialPage()); @@ -329,7 +361,7 @@ class TestSBClient : public base::RefCountedThreadSafe<TestSBClient>, public SafeBrowsingService::Client { public: - TestSBClient() : result_(SafeBrowsingService::URL_SAFE), + TestSBClient() : result_(SafeBrowsingService::SAFE), safe_browsing_service_(g_browser_process-> resource_dispatcher_host()-> safe_browsing_service()) { @@ -339,27 +371,50 @@ class TestSBClient return result_; } - void CheckUrl(const GURL& url) { + void CheckDownloadUrl(const GURL& url) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(this, &TestSBClient::CheckUrlOnIOThread, url)); + NewRunnableMethod(this, + &TestSBClient::CheckDownloadUrlOnIOThread, + url)); ui_test_utils::RunMessageLoop(); // Will stop in OnDownloadUrlCheckResult. } + void CheckDownloadHash(const std::string& full_hash) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod(this, + &TestSBClient::CheckDownloadHashOnIOThread, + full_hash)); + ui_test_utils::RunMessageLoop(); // Will stop in OnDownloadHashCheckResult. + } + private: - void CheckUrlOnIOThread(const GURL& url) { + void CheckDownloadUrlOnIOThread(const GURL& url) { safe_browsing_service_->CheckDownloadUrl(url, this); } + void CheckDownloadHashOnIOThread(const std::string& full_hash) { + safe_browsing_service_->CheckDownloadHash(full_hash, this); + } + // Called when the result of checking a download URL is known. void OnDownloadUrlCheckResult(const GURL& url, SafeBrowsingService::UrlCheckResult result) { result_ = result; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - NewRunnableMethod(this, &TestSBClient::DownloadUrlCheckDone)); + NewRunnableMethod(this, &TestSBClient::DownloadCheckDone)); } - void DownloadUrlCheckDone() { + // Called when the result of checking a download hash is known. + void OnDownloadHashCheckResult(const SBFullHash& hash, + SafeBrowsingService::UrlCheckResult result) { + result_ = result; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &TestSBClient::DownloadCheckDone)); + } + + void DownloadCheckDone() { MessageLoopForUI::current()->Quit(); } @@ -373,21 +428,41 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrl) { GURL badbin_url = test_server()->GetURL(kMalwareFile); scoped_refptr<TestSBClient> client(new TestSBClient); - client->CheckUrl(badbin_url); + client->CheckDownloadUrl(badbin_url); // Since badbin_url is not in database, it is considered to be safe. - EXPECT_EQ(SafeBrowsingService::URL_SAFE, client->GetResult()); + EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult()); - SBFullHashResult badbinurl_full_hash; + SBFullHashResult full_hash_result; int chunk_id = 0; - GenerateFullhashResult(badbin_url, safe_browsing_util::kBinUrlList, - chunk_id, &badbinurl_full_hash); - SetupResponseForUrl(badbin_url, badbinurl_full_hash); + GenUrlFullhashResult(badbin_url, safe_browsing_util::kBinUrlList, + chunk_id, &full_hash_result); + SetupResponseForUrl(badbin_url, full_hash_result); - client->CheckUrl(badbin_url); + client->CheckDownloadUrl(badbin_url); // Now, the badbin_url is not safe since it is added to download database. - EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE, client->GetResult()); + EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_URL, client->GetResult()); } +IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadHash) { + const std::string full_hash = "12345678902234567890323456789012"; + + scoped_refptr<TestSBClient> client(new TestSBClient); + client->CheckDownloadHash(full_hash); + + // Since badbin_url is not in database, it is considered to be safe. + EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult()); + + SBFullHashResult full_hash_result; + int chunk_id = 0; + GenDigestFullhashResult(full_hash, safe_browsing_util::kBinHashList, + chunk_id, &full_hash_result); + SetupResponseForDigest(full_hash, full_hash_result); + + client->CheckDownloadHash(full_hash); + + // Now, the badbin_url is not safe since it is added to download database. + EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_HASH, client->GetResult()); +} } // namespace diff --git a/chrome/browser/safe_browsing/safe_browsing_test.cc b/chrome/browser/safe_browsing/safe_browsing_test.cc index fb48e28..d921026 100644 --- a/chrome/browser/safe_browsing/safe_browsing_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_test.cc @@ -350,7 +350,7 @@ class SafeBrowsingServiceTestHelper EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); EXPECT_TRUE(safe_browsing_test_->is_checked_url_in_db()); safe_browsing_test_->set_is_checked_url_safe( - result == SafeBrowsingService::URL_SAFE); + result == SafeBrowsingService::SAFE); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &SafeBrowsingServiceTestHelper::OnCheckUrlDone)); diff --git a/chrome/browser/safe_browsing/safe_browsing_util.cc b/chrome/browser/safe_browsing/safe_browsing_util.cc index 3e449e0..06a18ca 100644 --- a/chrome/browser/safe_browsing/safe_browsing_util.cc +++ b/chrome/browser/safe_browsing/safe_browsing_util.cc @@ -162,12 +162,19 @@ void SBEntry::SetFullHashAt(int index, const SBFullHash& full_hash) { namespace safe_browsing_util { +// Listnames that browser can process. const char kMalwareList[] = "goog-malware-shavar"; const char kPhishingList[] = "goog-phish-shavar"; - const char kBinUrlList[] = "goog-badbinurl-shavar"; const char kBinHashList[] = "goog-badbinhash-shavar"; +// Keywords to identify a list type from listname. +// TODO(lzheng): check if this can be replaced by full listnames. +const char kMalwareListKey[] = "-malware-"; +const char kPhishingListKey[] = "-phish-"; +const char kBinUrlListKey[] = "-badbinurl-"; +const char kBinHashListKey[] = "-badbinhash-"; + int GetListId(const std::string& name) { int id; if (name == safe_browsing_util::kMalwareList) { @@ -409,8 +416,17 @@ void GeneratePathsToCheck(const GURL& url, std::vector<std::string>* paths) { paths->push_back(path + "?" + query); } -int CompareFullHashes(const GURL& url, - const std::vector<SBFullHashResult>& full_hashes) { +int GetHashIndex(const SBFullHash& hash, + const std::vector<SBFullHashResult>& full_hashes) { + for (size_t i = 0; i < full_hashes.size(); ++i) { + if (hash == full_hashes[i].hash) + return static_cast<int>(i); + } + return -1; +} + +int GetUrlHashIndex(const GURL& url, + const std::vector<SBFullHashResult>& full_hashes) { if (full_hashes.empty()) return -1; @@ -424,11 +440,8 @@ int CompareFullHashes(const GURL& url, base::SHA256HashString(hosts[h] + paths[p], key.full_hash, sizeof(SBFullHash)); - - for (size_t i = 0; i < full_hashes.size(); ++i) { - if (key == full_hashes[i].hash) - return static_cast<int>(i); - } + int index = GetHashIndex(key, full_hashes); + if (index != -1) return index; } } @@ -436,15 +449,19 @@ int CompareFullHashes(const GURL& url, } bool IsPhishingList(const std::string& list_name) { - return list_name.find("-phish-") != std::string::npos; + return list_name.find(kPhishingListKey) != std::string::npos; } bool IsMalwareList(const std::string& list_name) { - return list_name.find("-malware-") != std::string::npos; + return list_name.find(kMalwareListKey) != std::string::npos; } bool IsBadbinurlList(const std::string& list_name) { - return list_name.find("-badbinurl-") != std::string::npos; + return list_name.find(kBinUrlListKey) != std::string::npos; +} + +bool IsBadbinhashList(const std::string& list_name) { + return list_name.find(kBinHashListKey) != std::string::npos; } static void DecodeWebSafe(std::string* decoded) { @@ -503,4 +520,9 @@ GURL GeneratePhishingReportUrl(const std::string& report_page, return google_util::AppendGoogleLocaleParam(report_url); } +void StringToSBFullHash(const std::string& hash_in, SBFullHash* hash_out) { + DCHECK_EQ(static_cast<size_t>(base::SHA256_LENGTH), hash_in.size()); + memcpy(hash_out->full_hash, hash_in.data(), base::SHA256_LENGTH); +} + } // namespace safe_browsing_util diff --git a/chrome/browser/safe_browsing/safe_browsing_util.h b/chrome/browser/safe_browsing/safe_browsing_util.h index 85a79ef..5b01b44 100644 --- a/chrome/browser/safe_browsing/safe_browsing_util.h +++ b/chrome/browser/safe_browsing/safe_browsing_util.h @@ -289,15 +289,19 @@ void GenerateHostsToCheck(const GURL& url, std::vector<std::string>* hosts); // Given a URL, returns all the paths we need to check. void GeneratePathsToCheck(const GURL& url, std::vector<std::string>* paths); +int GetHashIndex(const SBFullHash& hash, + const std::vector<SBFullHashResult>& full_hashes); + // Given a URL, compare all the possible host + path full hashes to the set of // provided full hashes. Returns the index of the match if one is found, or -1 // otherwise. -int CompareFullHashes(const GURL& url, - const std::vector<SBFullHashResult>& full_hashes); +int GetUrlHashIndex(const GURL& url, + const std::vector<SBFullHashResult>& full_hashes); bool IsPhishingList(const std::string& list_name); bool IsMalwareList(const std::string& list_name); bool IsBadbinurlList(const std::string& list_name); +bool IsBadbinhashList(const std::string& list_name); // Returns 'true' if 'mac' can be verified using 'key' and 'data'. bool VerifyMAC(const std::string& key, @@ -308,6 +312,8 @@ bool VerifyMAC(const std::string& key, GURL GeneratePhishingReportUrl(const std::string& report_page, const std::string& url_to_report); +void StringToSBFullHash(const std::string& hash_in, SBFullHash* hash_out); + } // namespace safe_browsing_util #endif // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UTIL_H_ diff --git a/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc index 7bf7efc..a12c3ff 100644 --- a/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc @@ -280,7 +280,7 @@ TEST(SafeBrowsingUtilTest, CanonicalizeUrl) { } } -TEST(SafeBrowsingUtilTest, FullHashCompare) { +TEST(SafeBrowsingUtilTest, GetUrlHashIndex) { GURL url("http://www.evil.com/phish.html"); SBFullHashResult full_hash; base::SHA256HashString(url.host() + url.path(), @@ -289,10 +289,10 @@ TEST(SafeBrowsingUtilTest, FullHashCompare) { std::vector<SBFullHashResult> full_hashes; full_hashes.push_back(full_hash); - EXPECT_EQ(safe_browsing_util::CompareFullHashes(url, full_hashes), 0); + EXPECT_EQ(safe_browsing_util::GetUrlHashIndex(url, full_hashes), 0); url = GURL("http://www.evil.com/okay_path.html"); - EXPECT_EQ(safe_browsing_util::CompareFullHashes(url, full_hashes), -1); + EXPECT_EQ(safe_browsing_util::GetUrlHashIndex(url, full_hashes), -1); } TEST(SafeBrowsingUtilTest, ListIdListNameConversion) { @@ -334,3 +334,12 @@ TEST(SafeBrowsingUtilTest, ListIdVerification) { EXPECT_EQ(0, safe_browsing_util::BINURL %2); EXPECT_EQ(1, safe_browsing_util::BINHASH % 2); } + +TEST(SafeBrowsingUtilTest, StringToSBFullHash) { + // 31 chars plus the last \0 as full_hash. + const std::string hash_in = "12345678902234567890323456789012"; + SBFullHash hash_out; + safe_browsing_util::StringToSBFullHash(hash_in, &hash_out); + EXPECT_EQ(0x34333231, hash_out.prefix); + EXPECT_EQ(0, memcmp(hash_in.data(), hash_out.full_hash, sizeof(SBFullHash))); +} |