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