1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/safe_browsing/safe_browsing_store.h" 6 #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" 7 8 #include "testing/gtest/include/gtest/gtest.h" 9 10 namespace { 11 12 TEST(SafeBrowsingStoreTest, SBAddPrefixLess) { 13 // chunk_id then prefix. 14 EXPECT_TRUE(SBAddPrefixLess(SBAddPrefix(10, 1), SBAddPrefix(11, 1))); 15 EXPECT_FALSE(SBAddPrefixLess(SBAddPrefix(11, 1), SBAddPrefix(10, 1))); 16 EXPECT_TRUE(SBAddPrefixLess(SBAddPrefix(10, 1), SBAddPrefix(10, 2))); 17 EXPECT_FALSE(SBAddPrefixLess(SBAddPrefix(10, 2), SBAddPrefix(10, 1))); 18 19 // Equal is not less. 20 EXPECT_FALSE(SBAddPrefixLess(SBAddPrefix(10, 1), SBAddPrefix(10, 1))); 21 } 22 23 TEST(SafeBrowsingStoreTest, SBAddPrefixHashLess) { 24 // The first four bytes of SBFullHash can be read as an int32, which 25 // means that byte-ordering issues can come up. To test this, |one| 26 // and |two| differ in the prefix, while |one| and |onetwo| have the 27 // same prefix, but differ in the byte after the prefix. 28 SBFullHash one, onetwo, two; 29 memset(&one, 0, sizeof(one)); 30 memset(&onetwo, 0, sizeof(onetwo)); 31 memset(&two, 0, sizeof(two)); 32 one.prefix = 1; 33 one.full_hash[sizeof(int32)] = 1; 34 onetwo.prefix = 1; 35 onetwo.full_hash[sizeof(int32)] = 2; 36 two.prefix = 2; 37 38 const base::Time now = base::Time::Now(); 39 40 // add_id dominates. 41 EXPECT_TRUE(SBAddPrefixHashLess(SBAddFullHash(10, now, two), 42 SBAddFullHash(11, now, one))); 43 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(11, now, two), 44 SBAddFullHash(10, now, one))); 45 46 // After add_id, prefix. 47 EXPECT_TRUE(SBAddPrefixHashLess(SBAddFullHash(10, now, one), 48 SBAddFullHash(10, now, two))); 49 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(10, now, two), 50 SBAddFullHash(10, now, one))); 51 52 // After prefix, full hash. 53 EXPECT_TRUE(SBAddPrefixHashLess(SBAddFullHash(10, now, one), 54 SBAddFullHash(10, now, onetwo))); 55 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(10, now, onetwo), 56 SBAddFullHash(10, now, one))); 57 58 // Equal is not less-than. 59 EXPECT_FALSE(SBAddPrefixHashLess(SBAddFullHash(10, now, one), 60 SBAddFullHash(10, now, one))); 61 } 62 63 TEST(SafeBrowsingStoreTest, SBSubPrefixLess) { 64 // add_id dominates. 65 EXPECT_TRUE(SBAddPrefixLess(SBSubPrefix(12, 10, 2), SBSubPrefix(9, 11, 1))); 66 EXPECT_FALSE(SBAddPrefixLess(SBSubPrefix(12, 11, 2), SBSubPrefix(9, 10, 1))); 67 68 // After add_id, prefix. 69 EXPECT_TRUE(SBAddPrefixLess(SBSubPrefix(12, 10, 1), SBSubPrefix(9, 10, 2))); 70 EXPECT_FALSE(SBAddPrefixLess(SBSubPrefix(12, 10, 2), SBSubPrefix(9, 10, 1))); 71 72 // Equal is not less-than. 73 EXPECT_FALSE(SBAddPrefixLess(SBSubPrefix(12, 10, 1), SBSubPrefix(12, 10, 1))); 74 75 // chunk_id doesn't matter. 76 } 77 78 TEST(SafeBrowsingStoreTest, SBSubFullHashLess) { 79 SBFullHash one, onetwo, two; 80 memset(&one, 0, sizeof(one)); 81 memset(&onetwo, 0, sizeof(onetwo)); 82 memset(&two, 0, sizeof(two)); 83 one.prefix = 1; 84 one.full_hash[sizeof(int32)] = 1; 85 onetwo.prefix = 1; 86 onetwo.full_hash[sizeof(int32)] = 2; 87 two.prefix = 2; 88 89 // add_id dominates. 90 EXPECT_TRUE(SBAddPrefixHashLess(SBSubFullHash(12, 10, two), 91 SBSubFullHash(9, 11, one))); 92 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 11, two), 93 SBSubFullHash(9, 10, one))); 94 95 // After add_id, prefix. 96 EXPECT_TRUE(SBAddPrefixHashLess(SBSubFullHash(12, 10, one), 97 SBSubFullHash(9, 10, two))); 98 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 10, two), 99 SBSubFullHash(9, 10, one))); 100 101 // After prefix, full_hash. 102 EXPECT_TRUE(SBAddPrefixHashLess(SBSubFullHash(12, 10, one), 103 SBSubFullHash(9, 10, onetwo))); 104 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 10, onetwo), 105 SBSubFullHash(9, 10, one))); 106 107 // Equal is not less-than. 108 EXPECT_FALSE(SBAddPrefixHashLess(SBSubFullHash(12, 10, one), 109 SBSubFullHash(9, 10, one))); 110 } 111 112 // SBProcessSubs does a lot of iteration, run through empty just to 113 // make sure degenerate cases work. 114 TEST(SafeBrowsingStoreTest, SBProcessSubsEmpty) { 115 std::vector<SBAddPrefix> add_prefixes; 116 std::vector<SBAddFullHash> add_hashes; 117 std::vector<SBSubPrefix> sub_prefixes; 118 std::vector<SBSubFullHash> sub_hashes; 119 120 const base::hash_set<int32> no_deletions; 121 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes, 122 no_deletions, no_deletions); 123 EXPECT_TRUE(add_prefixes.empty()); 124 EXPECT_TRUE(sub_prefixes.empty()); 125 EXPECT_TRUE(add_hashes.empty()); 126 EXPECT_TRUE(sub_hashes.empty()); 127 } 128 129 // Test that subs knock out adds. 130 TEST(SafeBrowsingStoreTest, SBProcessSubsKnockout) { 131 const base::Time kNow = base::Time::Now(); 132 const SBFullHash kHash1(SBFullHashFromString("one")); 133 const SBFullHash kHash2(SBFullHashFromString("two")); 134 const SBFullHash kHash3(SBFullHashFromString("three")); 135 const int kAddChunk1 = 1; // Use different chunk numbers just in case. 136 const int kSubChunk1 = 2; 137 138 // Construct some full hashes which share prefix with another. 139 SBFullHash kHash1mod1 = kHash1; 140 kHash1mod1.full_hash[sizeof(kHash1mod1.full_hash) - 1] ++; 141 SBFullHash kHash1mod2 = kHash1mod1; 142 kHash1mod2.full_hash[sizeof(kHash1mod2.full_hash) - 1] ++; 143 SBFullHash kHash1mod3 = kHash1mod2; 144 kHash1mod3.full_hash[sizeof(kHash1mod3.full_hash) - 1] ++; 145 146 std::vector<SBAddPrefix> add_prefixes; 147 std::vector<SBAddFullHash> add_hashes; 148 std::vector<SBSubPrefix> sub_prefixes; 149 std::vector<SBSubFullHash> sub_hashes; 150 151 // An add with prefix and a couple hashes, plus a sub for the prefix 152 // and a couple sub hashes. The sub should knock all of them out. 153 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash1.prefix)); 154 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1)); 155 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1mod1)); 156 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash1.prefix)); 157 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod2)); 158 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod3)); 159 160 // An add with no corresponding sub. Both items should be retained. 161 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash2)); 162 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash2.prefix)); 163 164 // A sub with no corresponding add. Both items should be retained. 165 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash3)); 166 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash3.prefix)); 167 168 const base::hash_set<int32> no_deletions; 169 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes, 170 no_deletions, no_deletions); 171 172 EXPECT_EQ(1U, add_prefixes.size()); 173 EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id); 174 EXPECT_EQ(kHash2.prefix, add_prefixes[0].prefix); 175 176 EXPECT_EQ(1U, add_hashes.size()); 177 EXPECT_EQ(kAddChunk1, add_hashes[0].chunk_id); 178 EXPECT_TRUE(SBFullHashEq(kHash2, add_hashes[0].full_hash)); 179 180 EXPECT_EQ(1U, sub_prefixes.size()); 181 EXPECT_EQ(kSubChunk1, sub_prefixes[0].chunk_id); 182 EXPECT_EQ(kAddChunk1, sub_prefixes[0].add_chunk_id); 183 EXPECT_EQ(kHash3.prefix, sub_prefixes[0].add_prefix); 184 185 EXPECT_EQ(1U, sub_hashes.size()); 186 EXPECT_EQ(kSubChunk1, sub_hashes[0].chunk_id); 187 EXPECT_EQ(kAddChunk1, sub_hashes[0].add_chunk_id); 188 EXPECT_TRUE(SBFullHashEq(kHash3, sub_hashes[0].full_hash)); 189 } 190 191 // Test chunk deletions, and ordering of deletions WRT subs knocking 192 // out adds. 193 TEST(SafeBrowsingStoreTest, SBProcessSubsDeleteChunk) { 194 const base::Time kNow = base::Time::Now(); 195 const SBFullHash kHash1(SBFullHashFromString("one")); 196 const SBFullHash kHash2(SBFullHashFromString("two")); 197 const SBFullHash kHash3(SBFullHashFromString("three")); 198 const int kAddChunk1 = 1; // Use different chunk numbers just in case. 199 const int kSubChunk1 = 2; 200 201 // Construct some full hashes which share prefix with another. 202 SBFullHash kHash1mod1 = kHash1; 203 kHash1mod1.full_hash[sizeof(kHash1mod1.full_hash) - 1] ++; 204 SBFullHash kHash1mod2 = kHash1mod1; 205 kHash1mod2.full_hash[sizeof(kHash1mod2.full_hash) - 1] ++; 206 SBFullHash kHash1mod3 = kHash1mod2; 207 kHash1mod3.full_hash[sizeof(kHash1mod3.full_hash) - 1] ++; 208 209 std::vector<SBAddPrefix> add_prefixes; 210 std::vector<SBAddFullHash> add_hashes; 211 std::vector<SBSubPrefix> sub_prefixes; 212 std::vector<SBSubFullHash> sub_hashes; 213 214 // An add with prefix and a couple hashes, plus a sub for the prefix 215 // and a couple sub hashes. The sub should knock all of them out. 216 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash1.prefix)); 217 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1)); 218 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1mod1)); 219 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash1.prefix)); 220 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod2)); 221 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod3)); 222 223 // An add with no corresponding sub. Both items should be retained. 224 add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash2)); 225 add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash2.prefix)); 226 227 // A sub with no corresponding add. Both items should be retained. 228 sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash3)); 229 sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash3.prefix)); 230 231 const base::hash_set<int32> no_deletions; 232 base::hash_set<int32> add_deletions; 233 add_deletions.insert(kAddChunk1); 234 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes, 235 add_deletions, no_deletions); 236 237 EXPECT_TRUE(add_prefixes.empty()); 238 EXPECT_TRUE(add_hashes.empty()); 239 240 EXPECT_EQ(1U, sub_prefixes.size()); 241 EXPECT_EQ(kSubChunk1, sub_prefixes[0].chunk_id); 242 EXPECT_EQ(kAddChunk1, sub_prefixes[0].add_chunk_id); 243 EXPECT_EQ(kHash3.prefix, sub_prefixes[0].add_prefix); 244 245 EXPECT_EQ(1U, sub_hashes.size()); 246 EXPECT_EQ(kSubChunk1, sub_hashes[0].chunk_id); 247 EXPECT_EQ(kAddChunk1, sub_hashes[0].add_chunk_id); 248 EXPECT_TRUE(SBFullHashEq(kHash3, sub_hashes[0].full_hash)); 249 250 base::hash_set<int32> sub_deletions; 251 sub_deletions.insert(kSubChunk1); 252 SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes, 253 no_deletions, sub_deletions); 254 255 EXPECT_TRUE(add_prefixes.empty()); 256 EXPECT_TRUE(add_hashes.empty()); 257 EXPECT_TRUE(sub_prefixes.empty()); 258 EXPECT_TRUE(sub_hashes.empty()); 259 } 260 261 TEST(SafeBrowsingStoreTest, Y2K38) { 262 const base::Time now = base::Time::Now(); 263 const base::Time future = now + base::TimeDelta::FromDays(3*365); 264 265 // TODO: Fix file format before 2035. 266 EXPECT_GT(static_cast<int32>(future.ToTimeT()), 0) 267 << " (int32)time_t is running out."; 268 } 269 270 } // namespace 271