OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/download_protection_service.h" | 5 #include "chrome/browser/safe_browsing/download_protection_service.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 const CheckDownloadCallback& callback, | 271 const CheckDownloadCallback& callback, |
272 DownloadProtectionService* service, | 272 DownloadProtectionService* service, |
273 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, | 273 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, |
274 BinaryFeatureExtractor* binary_feature_extractor) | 274 BinaryFeatureExtractor* binary_feature_extractor) |
275 : item_(item), | 275 : item_(item), |
276 url_chain_(item->GetUrlChain()), | 276 url_chain_(item->GetUrlChain()), |
277 referrer_url_(item->GetReferrerUrl()), | 277 referrer_url_(item->GetReferrerUrl()), |
278 tab_url_(item->GetTabUrl()), | 278 tab_url_(item->GetTabUrl()), |
279 tab_referrer_url_(item->GetTabReferrerUrl()), | 279 tab_referrer_url_(item->GetTabReferrerUrl()), |
280 archived_executable_(false), | 280 archived_executable_(false), |
| 281 archive_is_valid_(ArchiveValid::UNSET), |
281 callback_(callback), | 282 callback_(callback), |
282 service_(service), | 283 service_(service), |
283 binary_feature_extractor_(binary_feature_extractor), | 284 binary_feature_extractor_(binary_feature_extractor), |
284 database_manager_(database_manager), | 285 database_manager_(database_manager), |
285 pingback_enabled_(service_->enabled()), | 286 pingback_enabled_(service_->enabled()), |
286 finished_(false), | 287 finished_(false), |
287 type_(ClientDownloadRequest::WIN_EXECUTABLE), | 288 type_(ClientDownloadRequest::WIN_EXECUTABLE), |
288 start_time_(base::TimeTicks::Now()), | 289 start_time_(base::TimeTicks::Now()), |
289 weakptr_factory_(this) { | 290 weakptr_factory_(this) { |
290 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 291 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 | 479 |
479 private: | 480 private: |
480 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | 481 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
481 friend class base::DeleteHelper<CheckClientDownloadRequest>; | 482 friend class base::DeleteHelper<CheckClientDownloadRequest>; |
482 | 483 |
483 ~CheckClientDownloadRequest() override { | 484 ~CheckClientDownloadRequest() override { |
484 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 485 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
485 DCHECK(item_ == NULL); | 486 DCHECK(item_ == NULL); |
486 } | 487 } |
487 | 488 |
| 489 // .zip files that look invalid to Chrome can often be successfully unpacked |
| 490 // by other archive tools, so they may be a real threat. For that reason, |
| 491 // we send pings for them if !in_incognito && is_extended_reporting. |
| 492 bool CanReportInvalidArchives() { |
| 493 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 494 Profile* profile = Profile::FromBrowserContext(item_->GetBrowserContext()); |
| 495 if (!profile || |
| 496 !profile->GetPrefs()->GetBoolean( |
| 497 prefs::kSafeBrowsingExtendedReportingEnabled)) |
| 498 return false; |
| 499 |
| 500 return !item_->GetBrowserContext()->IsOffTheRecord(); |
| 501 } |
| 502 |
488 void OnFileFeatureExtractionDone() { | 503 void OnFileFeatureExtractionDone() { |
489 // This can run in any thread, since it just posts more messages. | 504 // This can run in any thread, since it just posts more messages. |
490 | 505 |
491 // TODO(noelutz): DownloadInfo should also contain the IP address of | 506 // TODO(noelutz): DownloadInfo should also contain the IP address of |
492 // every URL in the redirect chain. We also should check whether the | 507 // every URL in the redirect chain. We also should check whether the |
493 // download URL is hosted on the internal network. | 508 // download URL is hosted on the internal network. |
494 BrowserThread::PostTask( | 509 BrowserThread::PostTask( |
495 BrowserThread::IO, | 510 BrowserThread::IO, |
496 FROM_HERE, | 511 FROM_HERE, |
497 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); | 512 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 base::Bind(&CheckClientDownloadRequest::OnZipAnalysisFinished, | 572 base::Bind(&CheckClientDownloadRequest::OnZipAnalysisFinished, |
558 weakptr_factory_.GetWeakPtr())); | 573 weakptr_factory_.GetWeakPtr())); |
559 analyzer_->Start(); | 574 analyzer_->Start(); |
560 } | 575 } |
561 | 576 |
562 void OnZipAnalysisFinished(const zip_analyzer::Results& results) { | 577 void OnZipAnalysisFinished(const zip_analyzer::Results& results) { |
563 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 578 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
564 DCHECK_EQ(ClientDownloadRequest::ZIPPED_EXECUTABLE, type_); | 579 DCHECK_EQ(ClientDownloadRequest::ZIPPED_EXECUTABLE, type_); |
565 if (!service_) | 580 if (!service_) |
566 return; | 581 return; |
567 if (results.success) { | 582 |
568 archived_executable_ = results.has_executable; | 583 // Even if !results.success, some of the zip may have been parsed. |
569 archived_binary_.CopyFrom(results.archived_binary); | 584 // Some unzippers will successfully unpack archives that we cannot, |
570 DVLOG(1) << "Zip analysis finished for " << item_->GetFullPath().value() | 585 // so we're lenient here. |
571 << ", has_executable=" << results.has_executable | 586 archive_is_valid_ = |
572 << " has_archive=" << results.has_archive; | 587 (results.success ? ArchiveValid::VALID : ArchiveValid::INVALID); |
573 } else { | 588 archived_executable_ = results.has_executable; |
574 DVLOG(1) << "Zip analysis failed for " << item_->GetFullPath().value(); | 589 archived_binary_.CopyFrom(results.archived_binary); |
575 } | 590 DVLOG(1) << "Zip analysis finished for " << item_->GetFullPath().value() |
| 591 << ", has_executable=" << results.has_executable |
| 592 << ", has_archive=" << results.has_archive |
| 593 << ", success=" << results.success; |
| 594 |
576 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileSuccess", results.success); | 595 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileSuccess", results.success); |
577 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable", | 596 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable", |
578 archived_executable_); | 597 archived_executable_); |
579 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable", | 598 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable", |
580 results.has_archive && !archived_executable_); | 599 results.has_archive && !archived_executable_); |
581 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime", | 600 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime", |
582 base::TimeTicks::Now() - zip_analysis_start_time_); | 601 base::TimeTicks::Now() - zip_analysis_start_time_); |
583 for (const auto& file_name : results.archived_archive_filenames) | 602 for (const auto& file_name : results.archived_archive_filenames) |
584 RecordArchivedArchiveFileExtensionType(file_name); | 603 RecordArchivedArchiveFileExtensionType(file_name); |
585 | 604 |
586 if (!archived_executable_ && !results.has_archive) { | 605 if (!archived_executable_) { |
587 PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); | 606 if (results.has_archive) { |
588 return; | 607 type_ = ClientDownloadRequest::ZIPPED_ARCHIVE; |
| 608 } else if (!results.success && CanReportInvalidArchives()) { |
| 609 type_ = ClientDownloadRequest::INVALID_ZIP; |
| 610 } else { |
| 611 // Normal zip w/o EXEs, or invalid zip and not extended-reporting. |
| 612 PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); |
| 613 return; |
| 614 } |
589 } | 615 } |
590 | 616 |
591 if (!archived_executable_ && results.has_archive) | |
592 type_ = ClientDownloadRequest::ZIPPED_ARCHIVE; | |
593 OnFileFeatureExtractionDone(); | 617 OnFileFeatureExtractionDone(); |
594 } | 618 } |
595 | 619 |
596 #if defined(OS_MACOSX) | 620 #if defined(OS_MACOSX) |
597 void StartExtractDmgFeatures() { | 621 void StartExtractDmgFeatures() { |
598 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 622 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
599 DCHECK(item_); | 623 DCHECK(item_); |
600 dmg_analyzer_ = new SandboxedDMGAnalyzer( | 624 dmg_analyzer_ = new SandboxedDMGAnalyzer( |
601 item_->GetFullPath(), | 625 item_->GetFullPath(), |
602 base::Bind(&CheckClientDownloadRequest::OnDmgAnalysisFinished, | 626 base::Bind(&CheckClientDownloadRequest::OnDmgAnalysisFinished, |
603 weakptr_factory_.GetWeakPtr())); | 627 weakptr_factory_.GetWeakPtr())); |
604 dmg_analyzer_->Start(); | 628 dmg_analyzer_->Start(); |
605 dmg_analysis_start_time_ = base::TimeTicks::Now(); | 629 dmg_analysis_start_time_ = base::TimeTicks::Now(); |
606 } | 630 } |
607 | 631 |
608 void OnDmgAnalysisFinished(const zip_analyzer::Results& results) { | 632 void OnDmgAnalysisFinished(const zip_analyzer::Results& results) { |
609 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 633 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
610 DCHECK_EQ(ClientDownloadRequest::MAC_EXECUTABLE, type_); | 634 DCHECK_EQ(ClientDownloadRequest::MAC_EXECUTABLE, type_); |
611 if (!service_) | 635 if (!service_) |
612 return; | 636 return; |
613 | 637 |
614 if (results.success) { | 638 // Even if !results.success, some of the DMG may have been parsed. |
615 archived_executable_ = results.has_executable; | 639 archive_is_valid_ = |
616 archived_binary_.CopyFrom(results.archived_binary); | 640 (results.success ? ArchiveValid::VALID : ArchiveValid::INVALID); |
617 DVLOG(1) << "DMG analysis has finished for " | 641 archived_executable_ = results.has_executable; |
618 << item_->GetFullPath().value() << ", has_executable=" | 642 archived_binary_.CopyFrom(results.archived_binary); |
619 << results.has_executable; | 643 DVLOG(1) << "DMG analysis has finished for " << item_->GetFullPath().value() |
620 } else { | 644 << ", has_executable=" << results.has_executable |
621 DVLOG(1) << "DMG analysis failed for "<< item_->GetFullPath().value(); | 645 << ", success=" << results.success; |
622 } | |
623 | 646 |
624 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.DmgFileSuccess", results.success); | 647 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.DmgFileSuccess", results.success); |
625 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.DmgFileHasExecutable", | 648 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.DmgFileHasExecutable", |
626 archived_executable_); | 649 archived_executable_); |
627 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractDmgFeaturesTime", | 650 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractDmgFeaturesTime", |
628 base::TimeTicks::Now() - dmg_analysis_start_time_); | 651 base::TimeTicks::Now() - dmg_analysis_start_time_); |
629 | 652 |
630 if (!archived_executable_) { | 653 if (!archived_executable_) { |
631 PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); | 654 if (!results.success && CanReportInvalidArchives()) { |
632 return; | 655 type_ = ClientDownloadRequest::INVALID_MAC_ARCHIVE; |
| 656 } else { |
| 657 PostFinishTask(UNKNOWN, REASON_ARCHIVE_WITHOUT_BINARIES); |
| 658 return; |
| 659 } |
633 } | 660 } |
634 | 661 |
635 OnFileFeatureExtractionDone(); | 662 OnFileFeatureExtractionDone(); |
636 } | 663 } |
637 #endif // defined(OS_MACOSX) | 664 #endif // defined(OS_MACOSX) |
638 | 665 |
639 static void RecordCountOfSignedOrWhitelistedDownload() { | 666 static void RecordCountOfSignedOrWhitelistedDownload() { |
640 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); | 667 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); |
641 } | 668 } |
642 | 669 |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 if (tab_referrer_url_.is_valid()) { | 832 if (tab_referrer_url_.is_valid()) { |
806 resource->set_referrer(SanitizeUrl(tab_referrer_url_)); | 833 resource->set_referrer(SanitizeUrl(tab_referrer_url_)); |
807 DVLOG(2) << "tab referrer " << resource->referrer(); | 834 DVLOG(2) << "tab referrer " << resource->referrer(); |
808 } | 835 } |
809 } | 836 } |
810 | 837 |
811 request.set_user_initiated(item_->HasUserGesture()); | 838 request.set_user_initiated(item_->HasUserGesture()); |
812 request.set_file_basename( | 839 request.set_file_basename( |
813 item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); | 840 item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); |
814 request.set_download_type(type_); | 841 request.set_download_type(type_); |
| 842 if (archive_is_valid_ != ArchiveValid::UNSET) |
| 843 request.set_archive_valid(archive_is_valid_ == ArchiveValid::VALID); |
815 request.mutable_signature()->CopyFrom(signature_info_); | 844 request.mutable_signature()->CopyFrom(signature_info_); |
816 if (image_headers_) | 845 if (image_headers_) |
817 request.set_allocated_image_headers(image_headers_.release()); | 846 request.set_allocated_image_headers(image_headers_.release()); |
818 if (archived_executable_) | 847 if (archived_executable_) |
819 request.mutable_archived_binary()->Swap(&archived_binary_); | 848 request.mutable_archived_binary()->Swap(&archived_binary_); |
820 if (!request.SerializeToString(&client_download_request_data_)) { | 849 if (!request.SerializeToString(&client_download_request_data_)) { |
821 FinishRequest(UNKNOWN, REASON_INVALID_REQUEST_PROTO); | 850 FinishRequest(UNKNOWN, REASON_INVALID_REQUEST_PROTO); |
822 return; | 851 return; |
823 } | 852 } |
824 service_->client_download_request_callbacks_.Notify(item_, &request); | 853 service_->client_download_request_callbacks_.Notify(item_, &request); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
929 << cert->subject().GetDisplayName() | 958 << cert->subject().GetDisplayName() |
930 << " issuer=" << issuer->subject().GetDisplayName(); | 959 << " issuer=" << issuer->subject().GetDisplayName(); |
931 return true; | 960 return true; |
932 } | 961 } |
933 } | 962 } |
934 cert = issuer; | 963 cert = issuer; |
935 } | 964 } |
936 return false; | 965 return false; |
937 } | 966 } |
938 | 967 |
| 968 enum class ArchiveValid { UNSET, VALID, INVALID }; |
| 969 |
939 // The DownloadItem we are checking. Will be NULL if the request has been | 970 // The DownloadItem we are checking. Will be NULL if the request has been |
940 // canceled. Must be accessed only on UI thread. | 971 // canceled. Must be accessed only on UI thread. |
941 content::DownloadItem* item_; | 972 content::DownloadItem* item_; |
942 // Copies of data from |item_| for access on other threads. | 973 // Copies of data from |item_| for access on other threads. |
943 std::vector<GURL> url_chain_; | 974 std::vector<GURL> url_chain_; |
944 GURL referrer_url_; | 975 GURL referrer_url_; |
945 // URL chain of redirects leading to (but not including) |tab_url|. | 976 // URL chain of redirects leading to (but not including) |tab_url|. |
946 std::vector<GURL> tab_redirects_; | 977 std::vector<GURL> tab_redirects_; |
947 // URL and referrer of the window the download was started from. | 978 // URL and referrer of the window the download was started from. |
948 GURL tab_url_; | 979 GURL tab_url_; |
949 GURL tab_referrer_url_; | 980 GURL tab_referrer_url_; |
950 | 981 |
951 bool archived_executable_; | 982 bool archived_executable_; |
| 983 ArchiveValid archive_is_valid_; |
| 984 |
952 ClientDownloadRequest_SignatureInfo signature_info_; | 985 ClientDownloadRequest_SignatureInfo signature_info_; |
953 scoped_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; | 986 scoped_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; |
954 google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary> | 987 google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary> |
955 archived_binary_; | 988 archived_binary_; |
956 CheckDownloadCallback callback_; | 989 CheckDownloadCallback callback_; |
957 // Will be NULL if the request has been canceled. | 990 // Will be NULL if the request has been canceled. |
958 DownloadProtectionService* service_; | 991 DownloadProtectionService* service_; |
959 scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_; | 992 scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_; |
960 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; | 993 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; |
961 const bool pingback_enabled_; | 994 const bool pingback_enabled_; |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1203 GURL DownloadProtectionService::GetDownloadRequestUrl() { | 1236 GURL DownloadProtectionService::GetDownloadRequestUrl() { |
1204 GURL url(kDownloadRequestUrl); | 1237 GURL url(kDownloadRequestUrl); |
1205 std::string api_key = google_apis::GetAPIKey(); | 1238 std::string api_key = google_apis::GetAPIKey(); |
1206 if (!api_key.empty()) | 1239 if (!api_key.empty()) |
1207 url = url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); | 1240 url = url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); |
1208 | 1241 |
1209 return url; | 1242 return url; |
1210 } | 1243 } |
1211 | 1244 |
1212 } // namespace safe_browsing | 1245 } // namespace safe_browsing |
OLD | NEW |