| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/safe_browsing_db/v4_local_database_manager.h" |
| 6 #include "base/base64.h" |
| 5 #include "base/files/scoped_temp_dir.h" | 7 #include "base/files/scoped_temp_dir.h" |
| 6 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 7 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
| 8 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
| 9 #include "base/test/test_simple_task_runner.h" | 11 #include "base/test/test_simple_task_runner.h" |
| 10 #include "base/threading/thread_task_runner_handle.h" | 12 #include "base/threading/thread_task_runner_handle.h" |
| 11 #include "components/safe_browsing_db/v4_database.h" | 13 #include "components/safe_browsing_db/v4_database.h" |
| 12 #include "components/safe_browsing_db/v4_local_database_manager.h" | |
| 13 #include "components/safe_browsing_db/v4_test_util.h" | 14 #include "components/safe_browsing_db/v4_test_util.h" |
| 14 #include "content/public/test/test_browser_thread_bundle.h" | 15 #include "content/public/test/test_browser_thread_bundle.h" |
| 15 #include "crypto/sha2.h" | 16 #include "crypto/sha2.h" |
| 16 #include "net/url_request/test_url_fetcher_factory.h" | 17 #include "net/url_request/test_url_fetcher_factory.h" |
| 17 #include "testing/platform_test.h" | 18 #include "testing/platform_test.h" |
| 18 | 19 |
| 19 namespace safe_browsing { | 20 namespace safe_browsing { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 24 typedef std::vector<FullHashInfo> FullHashInfos; |
| 25 |
| 23 // Utility function for populating hashes. | 26 // Utility function for populating hashes. |
| 24 FullHash HashForUrl(const GURL& url) { | 27 FullHash HashForUrl(const GURL& url) { |
| 25 std::vector<FullHash> full_hashes; | 28 std::vector<FullHash> full_hashes; |
| 26 V4ProtocolManagerUtil::UrlToFullHashes(url, &full_hashes); | 29 V4ProtocolManagerUtil::UrlToFullHashes(url, &full_hashes); |
| 27 // ASSERT_GE(full_hashes.size(), 1u); | 30 // ASSERT_GE(full_hashes.size(), 1u); |
| 28 return full_hashes[0]; | 31 return full_hashes[0]; |
| 29 } | 32 } |
| 30 | 33 |
| 31 // Always returns misses from GetFullHashes(). | 34 // Always returns misses from GetFullHashes(). |
| 32 class FakeGetHashProtocolManager : public V4GetHashProtocolManager { | 35 class FakeGetHashProtocolManager : public V4GetHashProtocolManager { |
| 33 public: | 36 public: |
| 34 FakeGetHashProtocolManager( | 37 FakeGetHashProtocolManager( |
| 35 net::URLRequestContextGetter* request_context_getter, | 38 net::URLRequestContextGetter* request_context_getter, |
| 36 const StoresToCheck& stores_to_check, | 39 const StoresToCheck& stores_to_check, |
| 37 const V4ProtocolConfig& config) | 40 const V4ProtocolConfig& config, |
| 41 const FullHashInfos& full_hash_infos) |
| 38 : V4GetHashProtocolManager(request_context_getter, | 42 : V4GetHashProtocolManager(request_context_getter, |
| 39 stores_to_check, | 43 stores_to_check, |
| 40 config) {} | 44 config), |
| 45 full_hash_infos_(full_hash_infos) {} |
| 41 | 46 |
| 42 void GetFullHashes(const FullHashToStoreAndHashPrefixesMap&, | 47 void GetFullHashes(const FullHashToStoreAndHashPrefixesMap&, |
| 43 FullHashCallback callback) override { | 48 FullHashCallback callback) override { |
| 44 std::vector<FullHashInfo> full_hash_infos; | |
| 45 | |
| 46 // Async, since the real manager might use a fetcher. | 49 // Async, since the real manager might use a fetcher. |
| 47 base::ThreadTaskRunnerHandle::Get()->PostTask( | 50 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 48 FROM_HERE, base::Bind(callback, full_hash_infos)); | 51 FROM_HERE, base::Bind(callback, full_hash_infos_)); |
| 49 } | 52 } |
| 53 |
| 54 private: |
| 55 FullHashInfos full_hash_infos_; |
| 50 }; | 56 }; |
| 51 | 57 |
| 52 class FakeGetHashProtocolManagerFactory | 58 class FakeGetHashProtocolManagerFactory |
| 53 : public V4GetHashProtocolManagerFactory { | 59 : public V4GetHashProtocolManagerFactory { |
| 54 public: | 60 public: |
| 61 FakeGetHashProtocolManagerFactory(const FullHashInfos& full_hash_infos) |
| 62 : full_hash_infos_(full_hash_infos) {} |
| 63 |
| 55 std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager( | 64 std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager( |
| 56 net::URLRequestContextGetter* request_context_getter, | 65 net::URLRequestContextGetter* request_context_getter, |
| 57 const StoresToCheck& stores_to_check, | 66 const StoresToCheck& stores_to_check, |
| 58 const V4ProtocolConfig& config) override { | 67 const V4ProtocolConfig& config) override { |
| 59 return base::MakeUnique<FakeGetHashProtocolManager>( | 68 return base::MakeUnique<FakeGetHashProtocolManager>( |
| 60 request_context_getter, stores_to_check, config); | 69 request_context_getter, stores_to_check, config, full_hash_infos_); |
| 61 } | 70 } |
| 71 |
| 72 private: |
| 73 FullHashInfos full_hash_infos_; |
| 62 }; | 74 }; |
| 63 | 75 |
| 64 // Use FakeGetHashProtocolManagerFactory in scope, then reset. | 76 // Use FakeGetHashProtocolManagerFactory in scope, then reset. |
| 65 class ScopedFakeGetHashProtocolManagerFactory { | 77 class ScopedFakeGetHashProtocolManagerFactory { |
| 66 public: | 78 public: |
| 67 ScopedFakeGetHashProtocolManagerFactory() { | 79 ScopedFakeGetHashProtocolManagerFactory( |
| 80 const FullHashInfos& full_hash_infos) { |
| 68 V4GetHashProtocolManager::RegisterFactory( | 81 V4GetHashProtocolManager::RegisterFactory( |
| 69 base::MakeUnique<FakeGetHashProtocolManagerFactory>()); | 82 base::MakeUnique<FakeGetHashProtocolManagerFactory>(full_hash_infos)); |
| 70 } | 83 } |
| 71 ~ScopedFakeGetHashProtocolManagerFactory() { | 84 ~ScopedFakeGetHashProtocolManagerFactory() { |
| 72 V4GetHashProtocolManager::RegisterFactory(nullptr); | 85 V4GetHashProtocolManager::RegisterFactory(nullptr); |
| 73 } | 86 } |
| 74 }; | 87 }; |
| 75 | 88 |
| 76 } // namespace | 89 } // namespace |
| 77 | 90 |
| 78 class FakeV4Database : public V4Database { | 91 class FakeV4Database : public V4Database { |
| 79 public: | 92 public: |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 if (manager_to_cancel_) { | 173 if (manager_to_cancel_) { |
| 161 manager_to_cancel_->CancelCheck(this); | 174 manager_to_cancel_->CancelCheck(this); |
| 162 } | 175 } |
| 163 } | 176 } |
| 164 | 177 |
| 165 void OnCheckResourceUrlResult(const GURL& url, | 178 void OnCheckResourceUrlResult(const GURL& url, |
| 166 SBThreatType threat_type, | 179 SBThreatType threat_type, |
| 167 const std::string& threat_hash) override { | 180 const std::string& threat_hash) override { |
| 168 DCHECK_EQ(expected_url, url); | 181 DCHECK_EQ(expected_url, url); |
| 169 DCHECK_EQ(expected_sb_threat_type, threat_type); | 182 DCHECK_EQ(expected_sb_threat_type, threat_type); |
| 170 // |threat_hash| is empty because GetFullHashes calls back with empty | 183 DCHECK_EQ(threat_type == SB_THREAT_TYPE_SAFE, threat_hash.empty()); |
| 171 // |full_hash_infos|. | |
| 172 DCHECK(threat_hash.empty()); | |
| 173 on_check_resource_url_result_called_ = true; | 184 on_check_resource_url_result_called_ = true; |
| 174 } | 185 } |
| 175 | 186 |
| 176 SBThreatType expected_sb_threat_type; | 187 SBThreatType expected_sb_threat_type; |
| 177 GURL expected_url; | 188 GURL expected_url; |
| 178 bool on_check_browse_url_result_called_; | 189 bool on_check_browse_url_result_called_; |
| 179 bool on_check_resource_url_result_called_; | 190 bool on_check_resource_url_result_called_; |
| 180 V4LocalDatabaseManager* manager_to_cancel_; | 191 V4LocalDatabaseManager* manager_to_cancel_; |
| 181 }; | 192 }; |
| 182 | 193 |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 // The database is unavailable so the check should get queued. | 449 // The database is unavailable so the check should get queued. |
| 439 EXPECT_EQ(1ul, GetQueuedChecks().size()); | 450 EXPECT_EQ(1ul, GetQueuedChecks().size()); |
| 440 | 451 |
| 441 StopLocalDatabaseManager(); | 452 StopLocalDatabaseManager(); |
| 442 EXPECT_TRUE(GetQueuedChecks().empty()); | 453 EXPECT_TRUE(GetQueuedChecks().empty()); |
| 443 } | 454 } |
| 444 | 455 |
| 445 // Verify that a window where checks cannot be cancelled is closed. | 456 // Verify that a window where checks cannot be cancelled is closed. |
| 446 TEST_F(V4LocalDatabaseManagerTest, CancelPending) { | 457 TEST_F(V4LocalDatabaseManagerTest, CancelPending) { |
| 447 // Setup to receive full-hash misses. | 458 // Setup to receive full-hash misses. |
| 448 ScopedFakeGetHashProtocolManagerFactory pin; | 459 ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); |
| 449 | 460 |
| 450 // Reset the database manager so it picks up the replacement protocol manager. | 461 // Reset the database manager so it picks up the replacement protocol manager. |
| 451 ResetLocalDatabaseManager(); | 462 ResetLocalDatabaseManager(); |
| 452 WaitForTasksOnTaskRunner(); | 463 WaitForTasksOnTaskRunner(); |
| 453 | 464 |
| 454 // An URL and matching prefix. | 465 // An URL and matching prefix. |
| 455 const GURL url("http://example.com/a/"); | 466 const GURL url("http://example.com/a/"); |
| 456 const HashPrefix hash_prefix("eW\x1A\xF\xA9"); | 467 const HashPrefix hash_prefix("eW\x1A\xF\xA9"); |
| 457 | 468 |
| 458 // Put a match in the db that will cause a protocol-manager request. | 469 // Put a match in the db that will cause a protocol-manager request. |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 // Whitelisted. | 676 // Whitelisted. |
| 666 EXPECT_TRUE( | 677 EXPECT_TRUE( |
| 667 v4_local_database_manager_->MatchModuleWhitelistString("chrome.dll")); | 678 v4_local_database_manager_->MatchModuleWhitelistString("chrome.dll")); |
| 668 | 679 |
| 669 EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled( | 680 EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled( |
| 670 v4_local_database_manager_)); | 681 v4_local_database_manager_)); |
| 671 } | 682 } |
| 672 | 683 |
| 673 // This verifies the fix for race in http://crbug.com/660293 | 684 // This verifies the fix for race in http://crbug.com/660293 |
| 674 TEST_F(V4LocalDatabaseManagerTest, TestCheckBrowseUrlWithSameClientAndCancel) { | 685 TEST_F(V4LocalDatabaseManagerTest, TestCheckBrowseUrlWithSameClientAndCancel) { |
| 675 ScopedFakeGetHashProtocolManagerFactory pin; | 686 ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); |
| 676 // Reset the database manager so it picks up the replacement protocol manager. | 687 // Reset the database manager so it picks up the replacement protocol manager. |
| 677 ResetLocalDatabaseManager(); | 688 ResetLocalDatabaseManager(); |
| 678 WaitForTasksOnTaskRunner(); | 689 WaitForTasksOnTaskRunner(); |
| 679 | 690 |
| 680 StoreAndHashPrefixes store_and_hash_prefixes; | 691 StoreAndHashPrefixes store_and_hash_prefixes; |
| 681 store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), | 692 store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), |
| 682 HashPrefix("sن\340\t\006_")); | 693 HashPrefix("sن\340\t\006_")); |
| 683 ReplaceV4Database(store_and_hash_prefixes); | 694 ReplaceV4Database(store_and_hash_prefixes); |
| 684 | 695 |
| 685 GURL first_url("http://example.com/a"); | 696 GURL first_url("http://example.com/a"); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 700 WaitForTasksOnTaskRunner(); | 711 WaitForTasksOnTaskRunner(); |
| 701 // |on_check_browse_url_result_called_| is true only if OnCheckBrowseUrlResult | 712 // |on_check_browse_url_result_called_| is true only if OnCheckBrowseUrlResult |
| 702 // gets called with the |url| equal to |expected_url|, which is |second_url| | 713 // gets called with the |url| equal to |expected_url|, which is |second_url| |
| 703 // in | 714 // in |
| 704 // this test. | 715 // this test. |
| 705 EXPECT_TRUE(client.on_check_browse_url_result_called_); | 716 EXPECT_TRUE(client.on_check_browse_url_result_called_); |
| 706 } | 717 } |
| 707 | 718 |
| 708 TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrl) { | 719 TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrl) { |
| 709 // Setup to receive full-hash misses. | 720 // Setup to receive full-hash misses. |
| 710 ScopedFakeGetHashProtocolManagerFactory pin; | 721 ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); |
| 711 | 722 |
| 712 // Reset the database manager so it picks up the replacement protocol manager. | 723 // Reset the database manager so it picks up the replacement protocol manager. |
| 713 ResetLocalDatabaseManager(); | 724 ResetLocalDatabaseManager(); |
| 714 WaitForTasksOnTaskRunner(); | 725 WaitForTasksOnTaskRunner(); |
| 715 | 726 |
| 716 // An URL and matching prefix. | 727 // An URL and matching prefix. |
| 717 const GURL url("http://example.com/a/"); | 728 const GURL url("http://example.com/a/"); |
| 718 const HashPrefix hash_prefix("eW\x1A\xF\xA9"); | 729 const HashPrefix hash_prefix("eW\x1A\xF\xA9"); |
| 719 | 730 |
| 720 // Put a match in the db that will cause a protocol-manager request. | 731 // Put a match in the db that will cause a protocol-manager request. |
| 721 StoreAndHashPrefixes store_and_hash_prefixes; | 732 StoreAndHashPrefixes store_and_hash_prefixes; |
| 722 store_and_hash_prefixes.emplace_back(GetChromeUrlClientIncidentId(), | 733 store_and_hash_prefixes.emplace_back(GetChromeUrlClientIncidentId(), |
| 723 hash_prefix); | 734 hash_prefix); |
| 724 ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */); | 735 ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */); |
| 725 | 736 |
| 726 TestClient client(SB_THREAT_TYPE_SAFE, url); | 737 TestClient client(SB_THREAT_TYPE_SAFE, url); |
| 727 EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url, &client)); | 738 EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url, &client)); |
| 728 EXPECT_FALSE(client.on_check_resource_url_result_called_); | 739 EXPECT_FALSE(client.on_check_resource_url_result_called_); |
| 729 WaitForTasksOnTaskRunner(); | 740 WaitForTasksOnTaskRunner(); |
| 730 EXPECT_TRUE(client.on_check_resource_url_result_called_); | 741 EXPECT_TRUE(client.on_check_resource_url_result_called_); |
| 731 } | 742 } |
| 732 | 743 |
| 744 TEST_F(V4LocalDatabaseManagerTest, TestSubresourceFilterCallback) { |
| 745 // Setup to receive full-hash misses. |
| 746 ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); |
| 747 |
| 748 // Reset the database manager so it picks up the replacement protocol manager. |
| 749 ResetLocalDatabaseManager(); |
| 750 WaitForTasksOnTaskRunner(); |
| 751 |
| 752 // An URL and matching prefix. |
| 753 const GURL url("http://example.com/a/"); |
| 754 const HashPrefix hash_prefix("eW\x1A\xF\xA9"); |
| 755 |
| 756 // Put a match in the db that will cause a protocol-manager request. |
| 757 StoreAndHashPrefixes store_and_hash_prefixes; |
| 758 store_and_hash_prefixes.emplace_back(GetUrlSubresourceFilterId(), |
| 759 hash_prefix); |
| 760 ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */); |
| 761 |
| 762 // Test that a request flows through to the callback. |
| 763 { |
| 764 TestClient client(SB_THREAT_TYPE_SAFE, url); |
| 765 EXPECT_FALSE( |
| 766 v4_local_database_manager_->CheckUrlForSubresourceFilter(url, &client)); |
| 767 EXPECT_FALSE(client.on_check_browse_url_result_called_); |
| 768 WaitForTasksOnTaskRunner(); |
| 769 EXPECT_TRUE(client.on_check_browse_url_result_called_); |
| 770 } |
| 771 } |
| 772 |
| 773 TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrlReturnsBad) { |
| 774 std::string base64_encoded = "ZVcaD6lke9GaaZEf07X3CpuEgMAqbpAyPw3sX/7eK9M="; |
| 775 std::string base64_decoded; |
| 776 base::Base64Decode(base64_encoded, &base64_decoded); |
| 777 FullHashInfo fhi(base64_decoded, GetChromeUrlClientIncidentId(), |
| 778 base::Time()); |
| 779 |
| 780 // Setup to receive full-hash hit. |
| 781 ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({fhi})); |
| 782 |
| 783 // Reset the database manager so it picks up the replacement protocol manager. |
| 784 ResetLocalDatabaseManager(); |
| 785 WaitForTasksOnTaskRunner(); |
| 786 |
| 787 // An URL and matching prefix. |
| 788 const GURL url("http://example.com/a/"); |
| 789 const HashPrefix hash_prefix("eW\x1A\xF\xA9"); |
| 790 |
| 791 // Put a match in the db that will cause a protocol-manager request. |
| 792 StoreAndHashPrefixes store_and_hash_prefixes; |
| 793 store_and_hash_prefixes.emplace_back(GetChromeUrlClientIncidentId(), |
| 794 hash_prefix); |
| 795 ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */); |
| 796 |
| 797 TestClient client(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, url); |
| 798 EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url, &client)); |
| 799 EXPECT_FALSE(client.on_check_resource_url_result_called_); |
| 800 WaitForTasksOnTaskRunner(); |
| 801 EXPECT_TRUE(client.on_check_resource_url_result_called_); |
| 802 } |
| 803 |
| 733 // TODO(nparker): Add tests for | 804 // TODO(nparker): Add tests for |
| 734 // CheckDownloadUrl() | 805 // CheckDownloadUrl() |
| 735 // CheckExtensionIDs() | 806 // CheckExtensionIDs() |
| 736 | 807 |
| 737 } // namespace safe_browsing | 808 } // namespace safe_browsing |
| OLD | NEW |