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..7d24f33a954fe7b926411bcdcb136cdec83ed7b0 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,22 @@ 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 for some users. |
+ bool CanReportInvalidArchives() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ const bool in_incognito = item_->GetBrowserContext()->IsOffTheRecord(); |
asanka
2015/11/18 21:37:55
Nit: Maybe return early if in_incognito is true.
Nathan Parker
2015/11/20 06:22:16
We're sending pings here that weren't sent before,
asanka
2015/11/20 15:55:40
It does. I was just curious.
|
+ |
+ Profile* profile = Profile::FromBrowserContext(item_->GetBrowserContext()); |
+ const bool is_extended_reporting = |
+ profile && |
+ profile->GetPrefs()->GetBoolean( |
+ prefs::kSafeBrowsingExtendedReportingEnabled); |
+ |
+ return !in_incognito && is_extended_reporting; |
+ } |
+ |
void OnFileFeatureExtractionDone() { |
// This can run in any thread, since it just posts more messages. |
@@ -564,15 +581,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_ = |
asanka
2015/11/18 21:37:55
By the way, what happens if our utility process cr
Nathan Parker
2015/11/20 06:22:16
I suspect the download would never complete, since
asanka
2015/11/20 15:55:40
I pointed out one crash bug, though I didn't look
|
+ (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 +604,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 +637,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 +653,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 +841,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 +967,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 +982,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> |