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 f9c62c3c0a1fa2b4131c2ad8e107b999fae9e3a3..93f81e30f4cb1131d210ca29909e60dee5637ec5 100644 |
--- a/chrome/browser/safe_browsing/download_protection_service.cc |
+++ b/chrome/browser/safe_browsing/download_protection_service.cc |
@@ -278,6 +278,7 @@ class DownloadProtectionService::CheckClientDownloadRequest |
tab_url_(item->GetTabUrl()), |
tab_referrer_url_(item->GetTabReferrerUrl()), |
archived_executable_(false), |
+ archive_is_valid_(ArchiveValid::UNSET), |
callback_(callback), |
service_(service), |
binary_feature_extractor_(binary_feature_extractor), |
@@ -485,6 +486,20 @@ class DownloadProtectionService::CheckClientDownloadRequest |
DCHECK(item_ == NULL); |
} |
+ // .zip files that look invalid to Chrome can often be successfully unpacked |
+ // by other archive tools, so they may be a real threat. For that reason, |
+ // we send pings for them if !in_incognito && is_extended_reporting. |
+ bool CanReportInvalidArchives() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ Profile* profile = Profile::FromBrowserContext(item_->GetBrowserContext()); |
+ if (!profile || |
+ !profile->GetPrefs()->GetBoolean( |
+ prefs::kSafeBrowsingExtendedReportingEnabled)) |
+ return false; |
+ |
+ return !item_->GetBrowserContext()->IsOffTheRecord(); |
+ } |
+ |
void OnFileFeatureExtractionDone() { |
// This can run in any thread, since it just posts more messages. |
@@ -564,15 +579,19 @@ class DownloadProtectionService::CheckClientDownloadRequest |
DCHECK_EQ(ClientDownloadRequest::ZIPPED_EXECUTABLE, type_); |
if (!service_) |
return; |
- if (results.success) { |
- archived_executable_ = results.has_executable; |
- archived_binary_.CopyFrom(results.archived_binary); |
- DVLOG(1) << "Zip analysis finished for " << item_->GetFullPath().value() |
- << ", has_executable=" << results.has_executable |
- << " has_archive=" << results.has_archive; |
- } else { |
- DVLOG(1) << "Zip analysis failed for " << item_->GetFullPath().value(); |
- } |
+ |
+ // Even if !results.success, some of the zip may have been parsed. |
+ // Some unzippers will successfully unpack archives that we cannot, |
+ // so we're lenient here. |
+ archive_is_valid_ = |
+ (results.success ? ArchiveValid::VALID : ArchiveValid::INVALID); |
+ archived_executable_ = results.has_executable; |
+ archived_binary_.CopyFrom(results.archived_binary); |
+ DVLOG(1) << "Zip analysis finished for " << item_->GetFullPath().value() |
+ << ", has_executable=" << results.has_executable |
+ << ", has_archive=" << results.has_archive |
+ << ", success=" << results.success; |
+ |
UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileSuccess", results.success); |
UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable", |
archived_executable_); |
@@ -583,13 +602,18 @@ class DownloadProtectionService::CheckClientDownloadRequest |
for (const auto& file_name : results.archived_archive_filenames) |
RecordArchivedArchiveFileExtensionType(file_name); |
- if (!archived_executable_ && !results.has_archive) { |
- PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); |
- return; |
+ if (!archived_executable_) { |
+ if (results.has_archive) { |
+ type_ = ClientDownloadRequest::ZIPPED_ARCHIVE; |
+ } else if (!results.success && CanReportInvalidArchives()) { |
+ type_ = ClientDownloadRequest::INVALID_ZIP; |
+ } else { |
+ // Normal zip w/o EXEs, or invalid zip and not extended-reporting. |
+ PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); |
+ return; |
+ } |
} |
- if (!archived_executable_ && results.has_archive) |
- type_ = ClientDownloadRequest::ZIPPED_ARCHIVE; |
OnFileFeatureExtractionDone(); |
} |
@@ -611,15 +635,14 @@ class DownloadProtectionService::CheckClientDownloadRequest |
if (!service_) |
return; |
- if (results.success) { |
- archived_executable_ = results.has_executable; |
- archived_binary_.CopyFrom(results.archived_binary); |
- DVLOG(1) << "DMG analysis has finished for " |
- << item_->GetFullPath().value() << ", has_executable=" |
- << results.has_executable; |
- } else { |
- DVLOG(1) << "DMG analysis failed for "<< item_->GetFullPath().value(); |
- } |
+ // Even if !results.success, some of the DMG may have been parsed. |
+ archive_is_valid_ = |
+ (results.success ? ArchiveValid::VALID : ArchiveValid::INVALID); |
+ archived_executable_ = results.has_executable; |
+ archived_binary_.CopyFrom(results.archived_binary); |
+ DVLOG(1) << "DMG analysis has finished for " << item_->GetFullPath().value() |
+ << ", has_executable=" << results.has_executable |
+ << ", success=" << results.success; |
UMA_HISTOGRAM_BOOLEAN("SBClientDownload.DmgFileSuccess", results.success); |
UMA_HISTOGRAM_BOOLEAN("SBClientDownload.DmgFileHasExecutable", |
@@ -628,8 +651,12 @@ class DownloadProtectionService::CheckClientDownloadRequest |
base::TimeTicks::Now() - dmg_analysis_start_time_); |
if (!archived_executable_) { |
- PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); |
- return; |
+ if (!results.success && CanReportInvalidArchives()) { |
+ type_ = ClientDownloadRequest::INVALID_MAC_ARCHIVE; |
+ } else { |
+ PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); |
+ return; |
+ } |
} |
OnFileFeatureExtractionDone(); |
@@ -812,6 +839,8 @@ class DownloadProtectionService::CheckClientDownloadRequest |
request.set_file_basename( |
item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); |
request.set_download_type(type_); |
+ if (archive_is_valid_ != ArchiveValid::UNSET) |
+ request.set_archive_valid(archive_is_valid_ == ArchiveValid::VALID); |
request.mutable_signature()->CopyFrom(signature_info_); |
if (image_headers_) |
request.set_allocated_image_headers(image_headers_.release()); |
@@ -936,6 +965,8 @@ class DownloadProtectionService::CheckClientDownloadRequest |
return false; |
} |
+ enum class ArchiveValid { UNSET, VALID, INVALID }; |
+ |
// The DownloadItem we are checking. Will be NULL if the request has been |
// canceled. Must be accessed only on UI thread. |
content::DownloadItem* item_; |
@@ -949,6 +980,8 @@ class DownloadProtectionService::CheckClientDownloadRequest |
GURL tab_referrer_url_; |
bool archived_executable_; |
+ ArchiveValid archive_is_valid_; |
+ |
ClientDownloadRequest_SignatureInfo signature_info_; |
scoped_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; |
google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary> |