diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/download/download_file_manager.cc | 9 | ||||
-rw-r--r-- | chrome/browser/download/download_manager.cc | 39 | ||||
-rw-r--r-- | chrome/browser/download/download_manager.h | 8 | ||||
-rw-r--r-- | chrome/browser/download/download_manager_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/browser/download/download_safe_browsing_client.cc | 116 | ||||
-rw-r--r-- | chrome/browser/download/download_safe_browsing_client.h | 63 |
6 files changed, 190 insertions, 49 deletions
diff --git a/chrome/browser/download/download_file_manager.cc b/chrome/browser/download/download_file_manager.cc index 619e28a..4b7e860 100644 --- a/chrome/browser/download/download_file_manager.cc +++ b/chrome/browser/download/download_file_manager.cc @@ -217,11 +217,15 @@ void DownloadFileManager::OnResponseCompleted(int id, DownloadBuffer* buffer) { DownloadManager* download_manager = download->GetDownloadManager(); if (download_manager) { + std::string hash; + if (!download->GetSha256Hash(&hash)) + hash.clear(); + BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod( download_manager, &DownloadManager::OnAllDataSaved, - id, download->bytes_so_far())); + id, download->bytes_so_far(), hash)); } // We need to keep the download around until the UI thread has finalized @@ -283,8 +287,7 @@ void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) { // The DownloadManager in the UI thread has provided an intermediate .crdownload // name for the download specified by 'id'. Rename the in progress download. void DownloadFileManager::OnIntermediateDownloadName( - int id, const FilePath& full_path, DownloadManager* download_manager) -{ + int id, const FilePath& full_path, DownloadManager* download_manager) { VLOG(20) << __FUNCTION__ << "()" << " id = " << id << " full_path = \"" << full_path.value() << "\""; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc index f9afd47..4087ce5 100644 --- a/chrome/browser/download/download_manager.cc +++ b/chrome/browser/download/download_manager.cc @@ -250,9 +250,10 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) { // Create a client to verify download URL with safebrowsing. // It deletes itself after the callback. - scoped_refptr<DownloadSBClient> sb_client = new DownloadSBClient(info); + scoped_refptr<DownloadSBClient> sb_client = new DownloadSBClient( + info->download_id, info->url, info->original_url, info->referrer_url); sb_client->CheckDownloadUrl( - NewCallback(this, &DownloadManager::CheckDownloadUrlDone)); + info, NewCallback(this, &DownloadManager::CheckDownloadUrlDone)); } void DownloadManager::CheckDownloadUrlDone(DownloadCreateInfo* info, @@ -525,7 +526,9 @@ void DownloadManager::UpdateDownload(int32 download_id, int64 size) { } } -void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) { +void DownloadManager::OnAllDataSaved(int32 download_id, + int64 size, + const std::string& hash) { VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id << " size = " << size; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -538,9 +541,39 @@ void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) { DownloadItem* download = active_downloads_[download_id]; download->OnAllDataSaved(size); + // When hash is not available, it means either it is not calculated + // or there is error while it is calculated. We will skip the download hash + // check in that case. + if (!hash.empty()) { + scoped_refptr<DownloadSBClient> sb_client = + new DownloadSBClient(download_id, + download->url(), + download->original_url(), + download->referrer_url()); + sb_client->CheckDownloadHash( + hash, NewCallback(this, &DownloadManager::CheckDownloadHashDone)); + } MaybeCompleteDownload(download); } +// TODO(lzheng): This function currently works as a callback place holder. +// Once we decide the hash check is reliable, we could move the +// MaybeCompleteDownload in OnAllDataSaved to this function. +void DownloadManager::CheckDownloadHashDone(int32 download_id, + bool is_dangerous_hash) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DVLOG(1) << "CheckDownloadHashDone, download_id: " << download_id + << " is dangerous_hash: " << is_dangerous_hash; + + // If it's not in active_downloads_, that means it was cancelled or + // the download already finished. + if (active_downloads_.count(download_id) == 0) + return; + + DVLOG(1) << "CheckDownloadHashDone, url: " + << active_downloads_[download_id]->url().spec(); +} + bool DownloadManager::IsDownloadReadyForCompletion(DownloadItem* download) { // If we don't have all the data, the download is not ready for // completion. diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h index b7fc417..807b9a9 100644 --- a/chrome/browser/download/download_manager.h +++ b/chrome/browser/download/download_manager.h @@ -114,7 +114,9 @@ class DownloadManager // Notifications sent from the download thread to the UI thread void StartDownload(DownloadCreateInfo* info); void UpdateDownload(int32 download_id, int64 size); - void OnAllDataSaved(int32 download_id, int64 size); + // |hash| is sha256 hash for the downloaded file. It is empty when the hash + // is not available. + void OnAllDataSaved(int32 download_id, int64 size, const std::string& hash); // Called from a view when a user clicks a UI button or link. void DownloadCancelled(int32 download_id); @@ -228,6 +230,10 @@ class DownloadManager // Callback function after url is checked with safebrowsing service. void CheckDownloadUrlDone(DownloadCreateInfo* info, bool is_dangerous_url); + // Callback function after download file hash is checked with safebrowsing + // service. + void CheckDownloadHashDone(int32 download_id, bool is_dangerous_hash); + private: // For testing. friend class DownloadManagerTest; diff --git a/chrome/browser/download/download_manager_unittest.cc b/chrome/browser/download/download_manager_unittest.cc index e1dca2e..683a993 100644 --- a/chrome/browser/download/download_manager_unittest.cc +++ b/chrome/browser/download/download_manager_unittest.cc @@ -252,11 +252,11 @@ TEST_F(DownloadManagerTest, DownloadRenameTest) { download_manager_->CreateDownloadItem(info); if (kDownloadRenameCases[i].finish_before_rename) { - download_manager_->OnAllDataSaved(i, 1024); + download_manager_->OnAllDataSaved(i, 1024, std::string("fake_hash")); download_manager_->FileSelected(new_path, i, info); } else { download_manager_->FileSelected(new_path, i, info); - download_manager_->OnAllDataSaved(i, 1024); + download_manager_->OnAllDataSaved(i, 1024, std::string("fake_hash")); } message_loop_.RunAllPending(); diff --git a/chrome/browser/download/download_safe_browsing_client.cc b/chrome/browser/download/download_safe_browsing_client.cc index bbce50f..c2877e9 100644 --- a/chrome/browser/download/download_safe_browsing_client.cc +++ b/chrome/browser/download/download_safe_browsing_client.cc @@ -12,6 +12,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/history/download_create_info.h" +#include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "chrome/common/chrome_switches.h" #include "content/browser/browser_thread.h" #include "content/browser/renderer_host/resource_dispatcher_host.h" @@ -19,9 +20,16 @@ // TODO(lzheng): Get rid of the AddRef and Release after // SafeBrowsingService::Client is changed to RefCountedThreadSafe<>. -DownloadSBClient::DownloadSBClient(DownloadCreateInfo* info) : info_(info) { +DownloadSBClient::DownloadSBClient(int32 download_id, + const GURL& download_url, + const GURL& page_url, + const GURL& referrer_url) + : info_(NULL), + download_id_(download_id), + download_url_(download_url), + page_url_(page_url), + referrer_url_(referrer_url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - CHECK(info_); ResourceDispatcherHost* rdh = g_browser_process->resource_dispatcher_host(); if (rdh) sb_service_ = rdh->safe_browsing_service(); @@ -29,31 +37,52 @@ DownloadSBClient::DownloadSBClient(DownloadCreateInfo* info) : info_(info) { DownloadSBClient::~DownloadSBClient() {} -void DownloadSBClient::CheckDownloadUrl(DoneCallback* callback) { +void DownloadSBClient::CheckDownloadUrl(DownloadCreateInfo* info, + UrlDoneCallback* callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // It is not allowed to call this method twice. - CHECK(!done_callback_.get()); + CHECK(!url_done_callback_.get() && !hash_done_callback_.get()); CHECK(callback); + CHECK(info); + info_ = info; start_time_ = base::TimeTicks::Now(); - done_callback_.reset(callback); + url_done_callback_.reset(callback); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, - &DownloadSBClient::CheckDownloadUrlOnIOThread)); - UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_TOTAL); + &DownloadSBClient::CheckDownloadUrlOnIOThread, + info->url)); + UpdateDownloadCheckStats(DOWNLOAD_URL_CHECKS_TOTAL); } -void DownloadSBClient::CheckDownloadUrlOnIOThread() { +void DownloadSBClient::CheckDownloadHash(const std::string& hash, + HashDoneCallback* callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // It is not allowed to call this method twice. + CHECK(!url_done_callback_.get() && !hash_done_callback_.get()); + CHECK(callback); + + start_time_ = base::TimeTicks::Now(); + hash_done_callback_.reset(callback); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod(this, + &DownloadSBClient::CheckDownloadHashOnIOThread, + hash)); + UpdateDownloadCheckStats(DOWNLOAD_HASH_CHECKS_TOTAL); +} + +void DownloadSBClient::CheckDownloadUrlOnIOThread(const GURL& url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // Will be released in OnDownloadUrlCheckResult. AddRef(); - if (sb_service_.get() && !sb_service_->CheckDownloadUrl(info_->url, this)) { + if (sb_service_.get() && !sb_service_->CheckDownloadUrl(url, this)) { // Wait for SafeBrowsingService to call back OnDownloadUrlCheckResult. return; } - OnDownloadUrlCheckResult(info_->url, SafeBrowsingService::SAFE); + OnDownloadUrlCheckResult(url, SafeBrowsingService::SAFE); } // The callback interface for SafeBrowsingService::Client. @@ -68,6 +97,29 @@ void DownloadSBClient::OnDownloadUrlCheckResult( Release(); } +void DownloadSBClient::CheckDownloadHashOnIOThread(const std::string& hash) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + // Will be released in OnDownloadUrlCheckResult. + AddRef(); + if (sb_service_.get() && !sb_service_->CheckDownloadHash(hash, this)) { + // Wait for SafeBrowsingService to call back OnDownloadUrlCheckResult. + return; + } + OnDownloadHashCheckResult(hash, SafeBrowsingService::SAFE); +} + +// The callback interface for SafeBrowsingService::Client. +// Called when the result of checking a download URL is known. +void DownloadSBClient::OnDownloadHashCheckResult( + const std::string& hash, SafeBrowsingService::UrlCheckResult result) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &DownloadSBClient::SafeBrowsingCheckHashDone, + result)); + Release(); +} + void DownloadSBClient::SafeBrowsingCheckUrlDone( SafeBrowsingService::UrlCheckResult result) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -77,27 +129,45 @@ void DownloadSBClient::SafeBrowsingCheckUrlDone( CommandLine* cmdline = CommandLine::ForCurrentProcess(); if (!cmdline->HasSwitch(switches::kSbEnableDownloadWarningUI)) { // Always ignore the safebrowsing result without the flag. - done_callback_->Run(info_, false); + url_done_callback_->Run(info_, false); } else { - done_callback_->Run(info_, is_dangerous); + url_done_callback_->Run(info_, is_dangerous); } UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration", base::TimeTicks::Now() - start_time_); if (is_dangerous) { - UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_MALWARE); - - // TODO(lzheng): we need to collect page_url and referrer_url to report. - sb_service_->ReportSafeBrowsingHit(info_->url, - info_->url /* page_url */, - info_->url /* referrer_url */, - true, - result); + UpdateDownloadCheckStats(DOWNLOAD_URL_CHECKS_MALWARE); + ReportMalware(result); } } -void DownloadSBClient::UpdateDownloadUrlCheckStats(SBStatsType stat_type) { - UMA_HISTOGRAM_ENUMERATION("SB2.DownloadUrlChecks", +void DownloadSBClient::SafeBrowsingCheckHashDone( + SafeBrowsingService::UrlCheckResult result) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DVLOG(1) << "SafeBrowsingCheckHashDone with result: " << result; + + bool is_dangerous = result != SafeBrowsingService::SAFE; + hash_done_callback_->Run(download_id_, is_dangerous); + UMA_HISTOGRAM_TIMES("SB2.DownloadHashCheckDuration", + base::TimeTicks::Now() - start_time_); + if (is_dangerous) { + UpdateDownloadCheckStats(DOWNLOAD_HASH_CHECKS_MALWARE); + ReportMalware(result); + } +} + +void DownloadSBClient::ReportMalware( + SafeBrowsingService::UrlCheckResult result) { + sb_service_->ReportSafeBrowsingHit(download_url_, // malicious_url + page_url_, + referrer_url_, + true, + result); +} + +void DownloadSBClient::UpdateDownloadCheckStats(SBStatsType stat_type) { + UMA_HISTOGRAM_ENUMERATION("SB2.DownloadChecks", stat_type, - DOWNLOAD_URL_CHECKS_MAX); + DOWNLOAD_CHECKS_MAX); } diff --git a/chrome/browser/download/download_safe_browsing_client.h b/chrome/browser/download/download_safe_browsing_client.h index ef1b1a8..71eac69d 100644 --- a/chrome/browser/download/download_safe_browsing_client.h +++ b/chrome/browser/download/download_safe_browsing_client.h @@ -19,32 +19,46 @@ struct DownloadCreateInfo; // Usage: // { // scoped_refptr<DownloadSBClient> client_ = new DownloadSBClient(...); -// client_->CheckDownloadUrl(NewCallback(this, &DownloadManager::CallBack)); +// client_->CheckDownloadUrl(..., NewCallback(this, +// &DownloadManager::UrlCallBack)); +// or +// client_->CheckDownloadHash(..., NewCallback(this, +// &DownloadManager::HashCallBack)); // } -// DownloadManager::CallBack(...) { +// DownloadManager::UrlCallBack(...) or HashCallCall { // // After this, the |client_| is gone. // } class DownloadSBClient : public SafeBrowsingService::Client, public base::RefCountedThreadSafe<DownloadSBClient> { public: - typedef Callback2<DownloadCreateInfo*, bool>::Type DoneCallback; + typedef Callback2<DownloadCreateInfo*, bool>::Type UrlDoneCallback; + typedef Callback2<int32, bool>::Type HashDoneCallback; - explicit DownloadSBClient(DownloadCreateInfo* info); + DownloadSBClient(int32 download_id, + const GURL& download_url, + const GURL& page_url, + const GURL& referrer_url); - // Note: This method can only be called once per DownloadSBClient instance. - void CheckDownloadUrl(DoneCallback* callback); + // Call safebrowsing service to verifiy the download. + // For each DownloadSBClient instance, either CheckDownloadUrl or + // CheckDownloadHash can be called, and be called only once. + // DownloadSBClient instance. + void CheckDownloadUrl(DownloadCreateInfo* info, UrlDoneCallback* callback); + void CheckDownloadHash(const std::string& hash, HashDoneCallback* callback); - protected: - // Call SafeBrowsingService on IO thread to verify the download URL. - void CheckDownloadUrlOnIOThread(); + private: + // Call SafeBrowsingService on IO thread to verify the download URL or + // hash of downloaded file. + void CheckDownloadUrlOnIOThread(const GURL& url); + void CheckDownloadHashOnIOThread(const std::string& hash); - // The callback interface for SafeBrowsingService::Client. - // Called when the result of checking a download URL is known. + // Callback interfaces for SafeBrowsingService::Client. virtual void OnDownloadUrlCheckResult( const GURL& url, SafeBrowsingService::UrlCheckResult result); + virtual void OnDownloadHashCheckResult( + const std::string& hash, SafeBrowsingService::UrlCheckResult result); - private: // Enumerate for histogramming purposes. // DO NOT CHANGE THE ORDERING OF THESE VALUES (different histogram data will // be mixed together based on their values). @@ -53,27 +67,42 @@ class DownloadSBClient DOWNLOAD_URL_CHECKS_CANCELED, DOWNLOAD_URL_CHECKS_MALWARE, + DOWNLOAD_HASH_CHECKS_TOTAL, + DOWNLOAD_HASH_CHECKS_MALWARE, + // Memory space for histograms is determined by the max. // ALWAYS ADD NEW VALUES BEFORE THIS ONE. - DOWNLOAD_URL_CHECKS_MAX + DOWNLOAD_CHECKS_MAX }; friend class base::RefCountedThreadSafe<DownloadSBClient>; virtual ~DownloadSBClient(); - // Call DownloadManager on UI thread. + // Call DownloadManager on UI thread for download URL or hash check. void SafeBrowsingCheckUrlDone(SafeBrowsingService::UrlCheckResult result); + void SafeBrowsingCheckHashDone(SafeBrowsingService::UrlCheckResult result); + + // Report malware hits to safebrowsing service. + void ReportMalware(SafeBrowsingService::UrlCheckResult result); // Update the UMA stats. - void UpdateDownloadUrlCheckStats(SBStatsType stat_type); + void UpdateDownloadCheckStats(SBStatsType stat_type); - scoped_ptr<DoneCallback> done_callback_; + scoped_ptr<UrlDoneCallback> url_done_callback_; + scoped_ptr<HashDoneCallback> hash_done_callback_; // Not owned by this class. DownloadCreateInfo* info_; + + int32 download_id_; scoped_refptr<SafeBrowsingService> sb_service_; - // When a safebrowsing URL check starts, for stats purpose. + // These URLs are used to report malware to safe browsing service. + GURL download_url_; + GURL page_url_; + GURL referrer_url_; + + // When a safebrowsing check starts, for stats purpose. base::TimeTicks start_time_; DISALLOW_COPY_AND_ASSIGN(DownloadSBClient); |