| 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 |