summaryrefslogtreecommitdiffstats
path: root/chrome/browser/download
diff options
context:
space:
mode:
authorlzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-09 00:21:22 +0000
committerlzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-09 00:21:22 +0000
commit26711738350a67f6db9f3d408badfa5882790b1e (patch)
treeb8b2f0a7666d9b7142476aa303928814cb319234 /chrome/browser/download
parentf3fdcc774f633efe8a66dcdf95b2e123153502c4 (diff)
downloadchromium_src-26711738350a67f6db9f3d408badfa5882790b1e.zip
chromium_src-26711738350a67f6db9f3d408badfa5882790b1e.tar.gz
chromium_src-26711738350a67f6db9f3d408badfa5882790b1e.tar.bz2
Check the download file's hash against safebrowsing database. Report the malware hit when needed.
TEST=safe_browsing tests stay green. BUG=60822 Review URL: http://codereview.chromium.org/6611005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77382 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/download')
-rw-r--r--chrome/browser/download/download_file_manager.cc9
-rw-r--r--chrome/browser/download/download_manager.cc39
-rw-r--r--chrome/browser/download/download_manager.h8
-rw-r--r--chrome/browser/download/download_manager_unittest.cc4
-rw-r--r--chrome/browser/download/download_safe_browsing_client.cc116
-rw-r--r--chrome/browser/download/download_safe_browsing_client.h63
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);