Index: chrome/browser/safe_browsing/download_protection_service.cc |
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc |
index 797ee20be4ee3de616db5cbefeab9734f22b588b..ad464cdc306753b57f564e0984ebac7160a0d17b 100644 |
--- a/chrome/browser/safe_browsing/download_protection_service.cc |
+++ b/chrome/browser/safe_browsing/download_protection_service.cc |
@@ -22,6 +22,7 @@ |
#include "chrome/browser/ui/browser_list.h" |
#include "chrome/common/safe_browsing/csd.pb.h" |
#include "chrome/common/url_constants.h" |
+#include "chrome/common/zip_reader.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/download_item.h" |
#include "content/public/browser/page_navigator.h" |
@@ -46,12 +47,19 @@ const char DownloadProtectionService::kDownloadRequestUrl[] = |
"https://sb-ssl.google.com/safebrowsing/clientreport/download"; |
namespace { |
+bool IsArchiveFile(const FilePath& file) { |
+ return file.MatchesExtension(FILE_PATH_LITERAL(".zip")); |
+} |
+ |
bool IsBinaryFile(const FilePath& file) { |
return (file.MatchesExtension(FILE_PATH_LITERAL(".exe")) || |
file.MatchesExtension(FILE_PATH_LITERAL(".cab")) || |
file.MatchesExtension(FILE_PATH_LITERAL(".msi")) || |
file.MatchesExtension(FILE_PATH_LITERAL(".crx")) || |
- file.MatchesExtension(FILE_PATH_LITERAL(".apk"))); |
+ file.MatchesExtension(FILE_PATH_LITERAL(".apk")) || |
+ // Archives _may_ contain binaries, we'll check in |
+ // ExtractFileFeatures. |
+ IsArchiveFile(file)); |
} |
ClientDownloadRequest::DownloadType GetDownloadType(const FilePath& file) { |
@@ -60,6 +68,8 @@ ClientDownloadRequest::DownloadType GetDownloadType(const FilePath& file) { |
return ClientDownloadRequest::ANDROID_APK; |
else if (file.MatchesExtension(FILE_PATH_LITERAL(".crx"))) |
return ClientDownloadRequest::CHROME_EXTENSION; |
+ else if (file.MatchesExtension(FILE_PATH_LITERAL(".zip"))) |
+ return ClientDownloadRequest::ZIPPED_WIN_EXECUTABLE; |
mattm
2012/05/11 22:42:06
Seems a little weird to say this since we haven't
Brian Ryner
2012/05/12 00:06:59
Yep, that's right. Added a comment to clarify.
|
return ClientDownloadRequest::WIN_EXECUTABLE; |
} |
@@ -137,7 +147,7 @@ enum SBStatsType { |
} // namespace |
DownloadProtectionService::DownloadInfo::DownloadInfo() |
- : total_bytes(0), user_initiated(false) {} |
+ : total_bytes(0), user_initiated(false), zipped_executable(false) {} |
DownloadProtectionService::DownloadInfo::~DownloadInfo() {} |
@@ -475,6 +485,31 @@ class DownloadProtectionService::CheckClientDownloadRequest |
} |
void ExtractFileFeatures() { |
+ // If we're checking an archive file, look to see if there are any |
+ // executables inside. If not, we will skip the pingback for this |
+ // download. |
+ if (info_.target_file.MatchesExtension(FILE_PATH_LITERAL(".zip"))) { |
+ ExtractZipFeatures(); |
+ if (!info_.zipped_executable) { |
+ RecordImprovedProtectionStats(REASON_NOT_BINARY_FILE); |
noelutz
2012/05/11 17:54:33
might be nice to have a separate reason for that.
Brian Ryner
2012/05/11 22:25:44
Done.
|
+ PostFinishTask(SAFE); |
+ return; |
+ } |
+ } else { |
+ DCHECK(!IsArchiveFile(info_.target_file)); |
+ ExtractSignatureFeatures(); |
+ } |
+ |
+ // TODO(noelutz): DownloadInfo should also contain the IP address of |
+ // every URL in the redirect chain. We also should check whether the |
+ // download URL is hosted on the internal network. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
+ } |
+ |
+ void ExtractSignatureFeatures() { |
signature_util_->CheckSignature(info_.local_file, &signature_info_); |
bool is_signed = (signature_info_.certificate_chain_size() > 0); |
if (is_signed) { |
@@ -483,14 +518,33 @@ class DownloadProtectionService::CheckClientDownloadRequest |
VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); |
} |
UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); |
+ } |
- // TODO(noelutz): DownloadInfo should also contain the IP address of every |
- // URL in the redirect chain. We also should check whether the download |
- // URL is hosted on the internal network. |
- BrowserThread::PostTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
+ void ExtractZipFeatures() { |
noelutz
2012/05/11 17:54:33
Would you mind adding a histogram for both this me
Brian Ryner
2012/05/11 22:25:44
Done.
|
+ zip::ZipReader reader; |
+ if (reader.Open(info_.local_file)) { |
+ for (; reader.HasMore(); reader.AdvanceToNextEntry()) { |
+ if (!reader.OpenCurrentEntryInZip()) { |
+ VLOG(1) << "Failed to open current entry in zip file: " |
+ << info_.local_file.value(); |
+ continue; |
+ } |
+ const FilePath& file = reader.current_entry_info()->file_path(); |
+ // Don't consider an archived archive to be executable. |
+ if (IsBinaryFile(file) && !IsArchiveFile(file)) { |
+ VLOG(2) << "Downloaded a zipped executable: " |
+ << info_.local_file.value(); |
+ info_.zipped_executable = true; |
+ break; |
+ } else { |
+ VLOG(3) << "Ignoring non-binary file: " << file.value(); |
+ } |
+ } |
+ } else { |
+ VLOG(1) << "Failed to open zip file: " << info_.local_file.value(); |
+ } |
+ UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable", |
+ info_.zipped_executable); |
} |
void CheckWhitelists() { |
@@ -750,7 +804,8 @@ bool DownloadProtectionService::IsSupportedDownload( |
return (CheckClientDownloadRequest::IsSupportedDownload(info, |
&reason, |
&type) && |
- ClientDownloadRequest::WIN_EXECUTABLE == type); |
+ ClientDownloadRequest::WIN_EXECUTABLE == type || |
+ ClientDownloadRequest::ZIPPED_WIN_EXECUTABLE == type); |
#else |
return false; |
#endif |