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 3 // found in the LICENSE file. 4 // 5 // Unit tests for the SafeBrowsing storage system. 6 7 #include "base/file_util.h" 8 #include "base/files/scoped_temp_dir.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/sha1.h" 12 #include "base/time/time.h" 13 #include "chrome/browser/safe_browsing/safe_browsing_database.h" 14 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" 15 #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" 16 #include "content/public/test/test_browser_thread_bundle.h" 17 #include "crypto/sha2.h" 18 #include "net/base/net_util.h" 19 #include "sql/connection.h" 20 #include "sql/statement.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/platform_test.h" 23 #include "url/gurl.h" 24 25 using base::Time; 26 27 namespace { 28 29 SBPrefix Sha256Prefix(const std::string& str) { 30 SBPrefix prefix; 31 crypto::SHA256HashString(str, &prefix, sizeof(prefix)); 32 return prefix; 33 } 34 35 SBFullHash Sha256Hash(const std::string& str) { 36 SBFullHash hash; 37 crypto::SHA256HashString(str, &hash, sizeof(hash)); 38 return hash; 39 } 40 41 std::string HashedIpPrefix(const std::string& ip_prefix, size_t prefix_size) { 42 net::IPAddressNumber ip_number; 43 EXPECT_TRUE(net::ParseIPLiteralToNumber(ip_prefix, &ip_number)); 44 EXPECT_EQ(net::kIPv6AddressSize, ip_number.size()); 45 const std::string hashed_ip_prefix = base::SHA1HashString( 46 net::IPAddressToPackedString(ip_number)); 47 std::string hash(crypto::kSHA256Length, '\0'); 48 hash.replace(0, hashed_ip_prefix.size(), hashed_ip_prefix); 49 hash[base::kSHA1Length] = static_cast<char>(prefix_size); 50 return hash; 51 } 52 53 // Same as InsertAddChunkHostPrefixUrl, but with pre-computed 54 // prefix values. 55 void InsertAddChunkHostPrefixValue(SBChunk* chunk, 56 int chunk_number, 57 const SBPrefix& host_prefix, 58 const SBPrefix& url_prefix) { 59 chunk->chunk_number = chunk_number; 60 chunk->is_add = true; 61 SBChunkHost host; 62 host.host = host_prefix; 63 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 64 host.entry->set_chunk_id(chunk->chunk_number); 65 host.entry->SetPrefixAt(0, url_prefix); 66 chunk->hosts.push_back(host); 67 } 68 69 // A helper function that appends one AddChunkHost to chunk with 70 // one url for prefix. 71 void InsertAddChunkHostPrefixUrl(SBChunk* chunk, 72 int chunk_number, 73 const std::string& host_name, 74 const std::string& url) { 75 InsertAddChunkHostPrefixValue(chunk, chunk_number, 76 Sha256Prefix(host_name), 77 Sha256Prefix(url)); 78 } 79 80 // Same as InsertAddChunkHostPrefixUrl, but with full hashes. 81 void InsertAddChunkHostFullHashes(SBChunk* chunk, 82 int chunk_number, 83 const std::string& host_name, 84 const std::string& url) { 85 chunk->chunk_number = chunk_number; 86 chunk->is_add = true; 87 SBChunkHost host; 88 host.host = Sha256Prefix(host_name); 89 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 1); 90 host.entry->set_chunk_id(chunk->chunk_number); 91 host.entry->SetFullHashAt(0, Sha256Hash(url)); 92 chunk->hosts.push_back(host); 93 } 94 95 void InsertAddChunkFullHash(SBChunk* chunk, 96 int chunk_number, 97 const std::string& ip_str, 98 size_t prefix_size) { 99 const std::string full_hash_str = HashedIpPrefix(ip_str, prefix_size); 100 EXPECT_EQ(sizeof(SBFullHash), full_hash_str.size()); 101 SBFullHash full_hash; 102 std::memcpy(&(full_hash.full_hash), full_hash_str.data(), sizeof(SBFullHash)); 103 104 chunk->chunk_number = chunk_number; 105 chunk->is_add = true; 106 SBChunkHost host; 107 host.host = full_hash.prefix; 108 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 1); 109 host.entry->set_chunk_id(chunk->chunk_number); 110 host.entry->SetFullHashAt(0, full_hash); 111 chunk->hosts.push_back(host); 112 } 113 114 // Same as InsertAddChunkHostPrefixUrl, but with two urls for prefixes. 115 void InsertAddChunkHost2PrefixUrls(SBChunk* chunk, 116 int chunk_number, 117 const std::string& host_name, 118 const std::string& url1, 119 const std::string& url2) { 120 chunk->chunk_number = chunk_number; 121 chunk->is_add = true; 122 SBChunkHost host; 123 host.host = Sha256Prefix(host_name); 124 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 125 host.entry->set_chunk_id(chunk->chunk_number); 126 host.entry->SetPrefixAt(0, Sha256Prefix(url1)); 127 host.entry->SetPrefixAt(1, Sha256Prefix(url2)); 128 chunk->hosts.push_back(host); 129 } 130 131 // Same as InsertAddChunkHost2PrefixUrls, but with full hashes. 132 void InsertAddChunkHost2FullHashes(SBChunk* chunk, 133 int chunk_number, 134 const std::string& host_name, 135 const std::string& url1, 136 const std::string& url2) { 137 chunk->chunk_number = chunk_number; 138 chunk->is_add = true; 139 SBChunkHost host; 140 host.host = Sha256Prefix(host_name); 141 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 2); 142 host.entry->set_chunk_id(chunk->chunk_number); 143 host.entry->SetFullHashAt(0, Sha256Hash(url1)); 144 host.entry->SetFullHashAt(1, Sha256Hash(url2)); 145 chunk->hosts.push_back(host); 146 } 147 148 // Same as InsertSubChunkHostPrefixUrl, but with pre-computed 149 // prefix values. 150 void InsertSubChunkHostPrefixValue(SBChunk* chunk, 151 int chunk_number, 152 int chunk_id_to_sub, 153 const SBPrefix& host_prefix, 154 const SBPrefix& url_prefix) { 155 chunk->chunk_number = chunk_number; 156 chunk->is_add = false; 157 SBChunkHost host; 158 host.host = host_prefix; 159 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 160 host.entry->set_chunk_id(chunk->chunk_number); 161 host.entry->SetChunkIdAtPrefix(0, chunk_id_to_sub); 162 host.entry->SetPrefixAt(0, url_prefix); 163 chunk->hosts.push_back(host); 164 } 165 166 // A helper function that adds one SubChunkHost to chunk with 167 // one url for prefix. 168 void InsertSubChunkHostPrefixUrl(SBChunk* chunk, 169 int chunk_number, 170 int chunk_id_to_sub, 171 const std::string& host_name, 172 const std::string& url) { 173 InsertSubChunkHostPrefixValue(chunk, chunk_number, 174 chunk_id_to_sub, 175 Sha256Prefix(host_name), 176 Sha256Prefix(url)); 177 } 178 179 // Same as InsertSubChunkHostPrefixUrl, but with two urls for prefixes. 180 void InsertSubChunkHost2PrefixUrls(SBChunk* chunk, 181 int chunk_number, 182 int chunk_id_to_sub, 183 const std::string& host_name, 184 const std::string& url1, 185 const std::string& url2) { 186 chunk->chunk_number = chunk_number; 187 chunk->is_add = false; 188 SBChunkHost host; 189 host.host = Sha256Prefix(host_name); 190 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 2); 191 host.entry->set_chunk_id(chunk->chunk_number); 192 host.entry->SetPrefixAt(0, Sha256Prefix(url1)); 193 host.entry->SetChunkIdAtPrefix(0, chunk_id_to_sub); 194 host.entry->SetPrefixAt(1, Sha256Prefix(url2)); 195 host.entry->SetChunkIdAtPrefix(1, chunk_id_to_sub); 196 chunk->hosts.push_back(host); 197 } 198 199 // Same as InsertSubChunkHost2PrefixUrls, but with full hashes. 200 void InsertSubChunkHostFullHash(SBChunk* chunk, 201 int chunk_number, 202 int chunk_id_to_sub, 203 const std::string& host_name, 204 const std::string& url) { 205 chunk->chunk_number = chunk_number; 206 chunk->is_add = false; 207 SBChunkHost host; 208 host.host = Sha256Prefix(host_name); 209 host.entry = SBEntry::Create(SBEntry::SUB_FULL_HASH, 2); 210 host.entry->set_chunk_id(chunk->chunk_number); 211 host.entry->SetFullHashAt(0, Sha256Hash(url)); 212 host.entry->SetChunkIdAtPrefix(0, chunk_id_to_sub); 213 chunk->hosts.push_back(host); 214 } 215 216 // Prevent DCHECK from killing tests. 217 // TODO(shess): Pawel disputes the use of this, so the test which uses 218 // it is DISABLED. http://crbug.com/56448 219 class ScopedLogMessageIgnorer { 220 public: 221 ScopedLogMessageIgnorer() { 222 logging::SetLogMessageHandler(&LogMessageIgnorer); 223 } 224 ~ScopedLogMessageIgnorer() { 225 // TODO(shess): Would be better to verify whether anyone else 226 // changed it, and then restore it to the previous value. 227 logging::SetLogMessageHandler(NULL); 228 } 229 230 private: 231 static bool LogMessageIgnorer(int severity, const char* file, int line, 232 size_t message_start, const std::string& str) { 233 // Intercept FATAL, strip the stack backtrace, and log it without 234 // the crash part. 235 if (severity == logging::LOG_FATAL) { 236 size_t newline = str.find('\n'); 237 if (newline != std::string::npos) { 238 const std::string msg = str.substr(0, newline + 1); 239 fprintf(stderr, "%s", msg.c_str()); 240 fflush(stderr); 241 } 242 return true; 243 } 244 245 return false; 246 } 247 }; 248 249 } // namespace 250 251 class SafeBrowsingDatabaseTest : public PlatformTest { 252 public: 253 virtual void SetUp() { 254 PlatformTest::SetUp(); 255 256 // Setup a database in a temporary directory. 257 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 258 database_.reset(new SafeBrowsingDatabaseNew); 259 database_filename_ = 260 temp_dir_.path().AppendASCII("SafeBrowsingTestDatabase"); 261 database_->Init(database_filename_); 262 } 263 264 virtual void TearDown() { 265 database_.reset(); 266 267 PlatformTest::TearDown(); 268 } 269 270 void GetListsInfo(std::vector<SBListChunkRanges>* lists) { 271 lists->clear(); 272 EXPECT_TRUE(database_->UpdateStarted(lists)); 273 database_->UpdateFinished(true); 274 } 275 276 // Helper function to do an AddDel or SubDel command. 277 void DelChunk(const std::string& list, 278 int chunk_id, 279 bool is_sub_del) { 280 std::vector<SBChunkDelete> deletes; 281 SBChunkDelete chunk_delete; 282 chunk_delete.list_name = list; 283 chunk_delete.is_sub_del = is_sub_del; 284 chunk_delete.chunk_del.push_back(ChunkRange(chunk_id)); 285 deletes.push_back(chunk_delete); 286 database_->DeleteChunks(deletes); 287 } 288 289 void AddDelChunk(const std::string& list, int chunk_id) { 290 DelChunk(list, chunk_id, false); 291 } 292 293 void SubDelChunk(const std::string& list, int chunk_id) { 294 DelChunk(list, chunk_id, true); 295 } 296 297 // Utility function for setting up the database for the caching test. 298 void PopulateDatabaseForCacheTest(); 299 300 scoped_ptr<SafeBrowsingDatabaseNew> database_; 301 base::FilePath database_filename_; 302 base::ScopedTempDir temp_dir_; 303 }; 304 305 // Tests retrieving list name information. 306 TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowse) { 307 SBChunkList chunks; 308 SBChunk chunk; 309 310 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", 311 "www.evil.com/malware.html"); 312 chunks.clear(); 313 chunks.push_back(chunk); 314 std::vector<SBListChunkRanges> lists; 315 EXPECT_TRUE(database_->UpdateStarted(&lists)); 316 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 317 318 chunk.hosts.clear(); 319 InsertAddChunkHostPrefixUrl(&chunk, 2, "www.foo.com/", 320 "www.foo.com/malware.html"); 321 chunks.clear(); 322 chunks.push_back(chunk); 323 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 324 325 chunk.hosts.clear(); 326 InsertAddChunkHostPrefixUrl(&chunk, 3, "www.whatever.com/", 327 "www.whatever.com/malware.html"); 328 chunks.clear(); 329 chunks.push_back(chunk); 330 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 331 database_->UpdateFinished(true); 332 333 GetListsInfo(&lists); 334 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 335 EXPECT_EQ(lists[0].adds, "1-3"); 336 EXPECT_TRUE(lists[0].subs.empty()); 337 338 // Insert a malware sub chunk. 339 chunk.hosts.clear(); 340 InsertSubChunkHostPrefixUrl(&chunk, 7, 19, "www.subbed.com/", 341 "www.subbed.com/noteveil1.html"); 342 chunks.clear(); 343 chunks.push_back(chunk); 344 345 EXPECT_TRUE(database_->UpdateStarted(&lists)); 346 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 347 database_->UpdateFinished(true); 348 349 GetListsInfo(&lists); 350 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 351 EXPECT_EQ(lists[0].adds, "1-3"); 352 EXPECT_EQ(lists[0].subs, "7"); 353 if (lists.size() == 2) { 354 // Old style database won't have the second entry since it creates the lists 355 // when it receives an update containing that list. The filter-based 356 // database has these values hard coded. 357 EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList); 358 EXPECT_TRUE(lists[1].adds.empty()); 359 EXPECT_TRUE(lists[1].subs.empty()); 360 } 361 362 // Add a phishing add chunk. 363 chunk.hosts.clear(); 364 InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/", 365 "www.evil.com/phishing.html"); 366 chunks.clear(); 367 chunks.push_back(chunk); 368 EXPECT_TRUE(database_->UpdateStarted(&lists)); 369 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 370 371 // Insert some phishing sub chunks. 372 chunk.hosts.clear(); 373 InsertSubChunkHostPrefixUrl(&chunk, 200, 1999, "www.phishy.com/", 374 "www.phishy.com/notevil1.html"); 375 chunks.clear(); 376 chunks.push_back(chunk); 377 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 378 379 chunk.hosts.clear(); 380 InsertSubChunkHostPrefixUrl(&chunk, 201, 1999, "www.phishy2.com/", 381 "www.phishy2.com/notevil1.html"); 382 chunks.clear(); 383 chunks.push_back(chunk); 384 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 385 database_->UpdateFinished(true); 386 387 GetListsInfo(&lists); 388 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 389 EXPECT_EQ(lists[0].adds, "1-3"); 390 EXPECT_EQ(lists[0].subs, "7"); 391 EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList); 392 EXPECT_EQ(lists[1].adds, "47"); 393 EXPECT_EQ(lists[1].subs, "200-201"); 394 } 395 396 TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) { 397 database_.reset(); 398 base::MessageLoop loop(base::MessageLoop::TYPE_DEFAULT); 399 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); 400 SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile(); 401 SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); 402 SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile(); 403 SafeBrowsingStoreFile* extension_blacklist_store = 404 new SafeBrowsingStoreFile(); 405 SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile(); 406 database_.reset(new SafeBrowsingDatabaseNew(browse_store, 407 download_store, 408 csd_whitelist_store, 409 download_whitelist_store, 410 extension_blacklist_store, 411 NULL, 412 ip_blacklist_store)); 413 database_->Init(database_filename_); 414 415 SBChunkList chunks; 416 SBChunk chunk; 417 418 // Insert malware, phish, binurl and bindownload add chunks. 419 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", 420 "www.evil.com/malware.html"); 421 chunks.push_back(chunk); 422 std::vector<SBListChunkRanges> lists; 423 EXPECT_TRUE(database_->UpdateStarted(&lists)); 424 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 425 426 chunk.hosts.clear(); 427 InsertAddChunkHostPrefixUrl(&chunk, 2, "www.foo.com/", 428 "www.foo.com/malware.html"); 429 chunks.clear(); 430 chunks.push_back(chunk); 431 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 432 433 chunk.hosts.clear(); 434 InsertAddChunkHostPrefixUrl(&chunk, 3, "www.whatever.com/", 435 "www.whatever.com/download.html"); 436 chunks.clear(); 437 chunks.push_back(chunk); 438 database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks); 439 440 chunk.hosts.clear(); 441 InsertAddChunkHostPrefixUrl(&chunk, 4, "www.forhash.com/", 442 "www.forhash.com/download.html"); 443 chunks.clear(); 444 chunks.push_back(chunk); 445 database_->InsertChunks(safe_browsing_util::kBinHashList, chunks); 446 447 chunk.hosts.clear(); 448 InsertAddChunkHostFullHashes(&chunk, 5, "www.forwhitelist.com/", 449 "www.forwhitelist.com/a.html"); 450 chunks.clear(); 451 chunks.push_back(chunk); 452 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, chunks); 453 454 chunk.hosts.clear(); 455 InsertAddChunkHostFullHashes(&chunk, 6, "www.download.com/", 456 "www.download.com/"); 457 458 chunks.clear(); 459 chunks.push_back(chunk); 460 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, chunks); 461 462 chunk.hosts.clear(); 463 InsertAddChunkHostFullHashes(&chunk, 8, 464 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 465 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); 466 467 chunks.clear(); 468 chunks.push_back(chunk); 469 database_->InsertChunks(safe_browsing_util::kExtensionBlacklist, chunks); 470 471 chunk.hosts.clear(); 472 InsertAddChunkFullHash(&chunk, 9, "::ffff:192.168.1.0", 120); 473 474 chunks.clear(); 475 chunks.push_back(chunk); 476 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 477 478 database_->UpdateFinished(true); 479 480 GetListsInfo(&lists); 481 ASSERT_EQ(7U, lists.size()); 482 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 483 EXPECT_EQ(lists[0].adds, "1"); 484 EXPECT_TRUE(lists[0].subs.empty()); 485 EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList); 486 EXPECT_EQ(lists[1].adds, "2"); 487 EXPECT_TRUE(lists[1].subs.empty()); 488 EXPECT_TRUE(lists[2].name == safe_browsing_util::kBinUrlList); 489 EXPECT_EQ(lists[2].adds, "3"); 490 EXPECT_TRUE(lists[2].subs.empty()); 491 // kBinHashList is ignored. (http://crbug.com/108130) 492 EXPECT_TRUE(lists[3].name == safe_browsing_util::kCsdWhiteList); 493 EXPECT_EQ(lists[3].adds, "5"); 494 EXPECT_TRUE(lists[3].subs.empty()); 495 EXPECT_TRUE(lists[4].name == safe_browsing_util::kDownloadWhiteList); 496 EXPECT_EQ(lists[4].adds, "6"); 497 EXPECT_TRUE(lists[4].subs.empty()); 498 EXPECT_TRUE(lists[5].name == safe_browsing_util::kExtensionBlacklist); 499 EXPECT_EQ(lists[5].adds, "8"); 500 EXPECT_TRUE(lists[5].subs.empty()); 501 EXPECT_TRUE(lists[6].name == safe_browsing_util::kIPBlacklist); 502 EXPECT_EQ(lists[6].adds, "9"); 503 EXPECT_TRUE(lists[6].subs.empty()); 504 505 database_.reset(); 506 } 507 508 // Checks database reading and writing for browse. 509 TEST_F(SafeBrowsingDatabaseTest, BrowseDatabase) { 510 SBChunkList chunks; 511 SBChunk chunk; 512 513 // Add a simple chunk with one hostkey. 514 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.evil.com/", 515 "www.evil.com/phishing.html", 516 "www.evil.com/malware.html"); 517 chunks.push_back(chunk); 518 std::vector<SBListChunkRanges> lists; 519 EXPECT_TRUE(database_->UpdateStarted(&lists)); 520 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 521 522 chunk.hosts.clear(); 523 InsertAddChunkHost2PrefixUrls(&chunk, 2, "www.evil.com/", 524 "www.evil.com/notevil1.html", 525 "www.evil.com/notevil2.html"); 526 InsertAddChunkHost2PrefixUrls(&chunk, 2, "www.good.com/", 527 "www.good.com/good1.html", 528 "www.good.com/good2.html"); 529 chunks.clear(); 530 chunks.push_back(chunk); 531 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 532 533 // and a chunk with an IP-based host 534 chunk.hosts.clear(); 535 InsertAddChunkHostPrefixUrl(&chunk, 3, "192.168.0.1/", 536 "192.168.0.1/malware.html"); 537 chunks.clear(); 538 chunks.push_back(chunk); 539 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 540 database_->UpdateFinished(true); 541 542 // Make sure they were added correctly. 543 GetListsInfo(&lists); 544 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 545 EXPECT_EQ(lists[0].adds, "1-3"); 546 EXPECT_TRUE(lists[0].subs.empty()); 547 548 const Time now = Time::Now(); 549 std::vector<SBFullHashResult> full_hashes; 550 std::vector<SBPrefix> prefix_hits; 551 std::string matching_list; 552 EXPECT_TRUE(database_->ContainsBrowseUrl( 553 GURL("http://www.evil.com/phishing.html"), 554 &matching_list, &prefix_hits, 555 &full_hashes, now)); 556 EXPECT_EQ(prefix_hits[0], Sha256Prefix("www.evil.com/phishing.html")); 557 EXPECT_EQ(prefix_hits.size(), 1U); 558 559 EXPECT_TRUE(database_->ContainsBrowseUrl( 560 GURL("http://www.evil.com/malware.html"), 561 &matching_list, &prefix_hits, 562 &full_hashes, now)); 563 564 EXPECT_TRUE(database_->ContainsBrowseUrl( 565 GURL("http://www.evil.com/notevil1.html"), 566 &matching_list, &prefix_hits, 567 &full_hashes, now)); 568 569 EXPECT_TRUE(database_->ContainsBrowseUrl( 570 GURL("http://www.evil.com/notevil2.html"), 571 &matching_list, &prefix_hits, 572 &full_hashes, now)); 573 574 EXPECT_TRUE(database_->ContainsBrowseUrl( 575 GURL("http://www.good.com/good1.html"), 576 &matching_list, &prefix_hits, 577 &full_hashes, now)); 578 579 EXPECT_TRUE(database_->ContainsBrowseUrl( 580 GURL("http://www.good.com/good2.html"), 581 &matching_list, &prefix_hits, 582 &full_hashes, now)); 583 584 EXPECT_TRUE(database_->ContainsBrowseUrl( 585 GURL("http://192.168.0.1/malware.html"), 586 &matching_list, &prefix_hits, 587 &full_hashes, now)); 588 589 EXPECT_FALSE(database_->ContainsBrowseUrl( 590 GURL("http://www.evil.com/"), 591 &matching_list, &prefix_hits, 592 &full_hashes, now)); 593 EXPECT_TRUE(prefix_hits.empty()); 594 595 EXPECT_FALSE(database_->ContainsBrowseUrl( 596 GURL("http://www.evil.com/robots.txt"), 597 &matching_list, &prefix_hits, 598 &full_hashes, now)); 599 600 // Attempt to re-add the first chunk (should be a no-op). 601 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 602 chunk.hosts.clear(); 603 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.evil.com/", 604 "www.evil.com/phishing.html", 605 "www.evil.com/malware.html"); 606 chunks.clear(); 607 chunks.push_back(chunk); 608 EXPECT_TRUE(database_->UpdateStarted(&lists)); 609 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 610 database_->UpdateFinished(true); 611 612 GetListsInfo(&lists); 613 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 614 EXPECT_EQ(lists[0].adds, "1-3"); 615 EXPECT_TRUE(lists[0].subs.empty()); 616 617 // Test removing a single prefix from the add chunk. 618 chunk.hosts.clear(); 619 InsertSubChunkHostPrefixUrl(&chunk, 4, 2, "www.evil.com/", 620 "www.evil.com/notevil1.html"); 621 chunks.clear(); 622 chunks.push_back(chunk); 623 EXPECT_TRUE(database_->UpdateStarted(&lists)); 624 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 625 626 database_->UpdateFinished(true); 627 628 EXPECT_TRUE(database_->ContainsBrowseUrl( 629 GURL("http://www.evil.com/phishing.html"), 630 &matching_list, &prefix_hits, 631 &full_hashes, now)); 632 EXPECT_EQ(prefix_hits[0], Sha256Prefix("www.evil.com/phishing.html")); 633 EXPECT_EQ(prefix_hits.size(), 1U); 634 635 EXPECT_FALSE(database_->ContainsBrowseUrl( 636 GURL("http://www.evil.com/notevil1.html"), 637 &matching_list, &prefix_hits, 638 &full_hashes, now)); 639 EXPECT_TRUE(prefix_hits.empty()); 640 641 EXPECT_TRUE(database_->ContainsBrowseUrl( 642 GURL("http://www.evil.com/notevil2.html"), 643 &matching_list, &prefix_hits, 644 &full_hashes, now)); 645 646 EXPECT_TRUE(database_->ContainsBrowseUrl( 647 GURL("http://www.good.com/good1.html"), 648 &matching_list, &prefix_hits, 649 &full_hashes, now)); 650 651 EXPECT_TRUE(database_->ContainsBrowseUrl( 652 GURL("http://www.good.com/good2.html"), 653 &matching_list, &prefix_hits, 654 &full_hashes, now)); 655 656 GetListsInfo(&lists); 657 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 658 EXPECT_EQ(lists[0].subs, "4"); 659 660 // Test the same sub chunk again. This should be a no-op. 661 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 662 chunk.hosts.clear(); 663 InsertSubChunkHostPrefixUrl(&chunk, 4, 2, "www.evil.com/", 664 "www.evil.com/notevil1.html"); 665 chunks.clear(); 666 chunks.push_back(chunk); 667 668 EXPECT_TRUE(database_->UpdateStarted(&lists)); 669 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 670 database_->UpdateFinished(true); 671 672 GetListsInfo(&lists); 673 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 674 EXPECT_EQ(lists[0].subs, "4"); 675 676 // Test removing all the prefixes from an add chunk. 677 EXPECT_TRUE(database_->UpdateStarted(&lists)); 678 AddDelChunk(safe_browsing_util::kMalwareList, 2); 679 database_->UpdateFinished(true); 680 681 EXPECT_FALSE(database_->ContainsBrowseUrl( 682 GURL("http://www.evil.com/notevil2.html"), 683 &matching_list, &prefix_hits, 684 &full_hashes, now)); 685 686 EXPECT_FALSE(database_->ContainsBrowseUrl( 687 GURL("http://www.good.com/good1.html"), 688 &matching_list, &prefix_hits, 689 &full_hashes, now)); 690 691 EXPECT_FALSE(database_->ContainsBrowseUrl( 692 GURL("http://www.good.com/good2.html"), 693 &matching_list, &prefix_hits, 694 &full_hashes, now)); 695 696 GetListsInfo(&lists); 697 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 698 EXPECT_EQ(lists[0].adds, "1,3"); 699 EXPECT_EQ(lists[0].subs, "4"); 700 701 // The adddel command exposed a bug in the transaction code where any 702 // transaction after it would fail. Add a dummy entry and remove it to 703 // make sure the transcation works fine. 704 chunk.hosts.clear(); 705 InsertAddChunkHostPrefixUrl(&chunk, 44, "www.redherring.com/", 706 "www.redherring.com/index.html"); 707 chunks.clear(); 708 chunks.push_back(chunk); 709 EXPECT_TRUE(database_->UpdateStarted(&lists)); 710 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 711 712 // Now remove the dummy entry. If there are any problems with the 713 // transactions, asserts will fire. 714 AddDelChunk(safe_browsing_util::kMalwareList, 44); 715 716 // Test the subdel command. 717 SubDelChunk(safe_browsing_util::kMalwareList, 4); 718 database_->UpdateFinished(true); 719 720 GetListsInfo(&lists); 721 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 722 EXPECT_EQ(lists[0].adds, "1,3"); 723 EXPECT_EQ(lists[0].subs, ""); 724 725 // Test a sub command coming in before the add. 726 chunk.hosts.clear(); 727 InsertSubChunkHost2PrefixUrls(&chunk, 5, 10, 728 "www.notevilanymore.com/", 729 "www.notevilanymore.com/index.html", 730 "www.notevilanymore.com/good.html"); 731 chunks.clear(); 732 chunks.push_back(chunk); 733 EXPECT_TRUE(database_->UpdateStarted(&lists)); 734 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 735 database_->UpdateFinished(true); 736 737 EXPECT_FALSE(database_->ContainsBrowseUrl( 738 GURL("http://www.notevilanymore.com/index.html"), 739 &matching_list, &prefix_hits, &full_hashes, now)); 740 741 // Now insert the tardy add chunk and we don't expect them to appear 742 // in database because of the previous sub chunk. 743 chunk.hosts.clear(); 744 InsertAddChunkHost2PrefixUrls(&chunk, 10, "www.notevilanymore.com/", 745 "www.notevilanymore.com/index.html", 746 "www.notevilanymore.com/good.html"); 747 chunks.clear(); 748 chunks.push_back(chunk); 749 EXPECT_TRUE(database_->UpdateStarted(&lists)); 750 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 751 database_->UpdateFinished(true); 752 753 EXPECT_FALSE(database_->ContainsBrowseUrl( 754 GURL("http://www.notevilanymore.com/index.html"), 755 &matching_list, &prefix_hits, &full_hashes, now)); 756 757 EXPECT_FALSE(database_->ContainsBrowseUrl( 758 GURL("http://www.notevilanymore.com/good.html"), 759 &matching_list, &prefix_hits, &full_hashes, now)); 760 } 761 762 763 // Test adding zero length chunks to the database. 764 TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) { 765 SBChunkList chunks; 766 SBChunk chunk; 767 768 // Populate with a couple of normal chunks. 769 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.test.com/", 770 "www.test.com/test1.html", 771 "www.test.com/test2.html"); 772 chunks.clear(); 773 chunks.push_back(chunk); 774 775 chunk.hosts.clear(); 776 InsertAddChunkHost2PrefixUrls(&chunk, 10, "www.random.com/", 777 "www.random.com/random1.html", 778 "www.random.com/random2.html"); 779 chunks.push_back(chunk); 780 781 std::vector<SBListChunkRanges> lists; 782 EXPECT_TRUE(database_->UpdateStarted(&lists)); 783 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 784 database_->UpdateFinished(true); 785 786 // Add an empty ADD and SUB chunk. 787 GetListsInfo(&lists); 788 EXPECT_EQ(lists[0].adds, "1,10"); 789 790 SBChunk empty_chunk; 791 empty_chunk.chunk_number = 19; 792 empty_chunk.is_add = true; 793 chunks.clear(); 794 chunks.push_back(empty_chunk); 795 EXPECT_TRUE(database_->UpdateStarted(&lists)); 796 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 797 chunks.clear(); 798 empty_chunk.chunk_number = 7; 799 empty_chunk.is_add = false; 800 chunks.push_back(empty_chunk); 801 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 802 database_->UpdateFinished(true); 803 804 GetListsInfo(&lists); 805 EXPECT_EQ(lists[0].adds, "1,10,19"); 806 EXPECT_EQ(lists[0].subs, "7"); 807 808 // Add an empty chunk along with a couple that contain data. This should 809 // result in the chunk range being reduced in size. 810 empty_chunk.hosts.clear(); 811 InsertAddChunkHostPrefixUrl(&empty_chunk, 20, "www.notempy.com/", 812 "www.notempty.com/full1.html"); 813 chunks.clear(); 814 chunks.push_back(empty_chunk); 815 816 empty_chunk.chunk_number = 21; 817 empty_chunk.is_add = true; 818 empty_chunk.hosts.clear(); 819 chunks.push_back(empty_chunk); 820 821 empty_chunk.hosts.clear(); 822 InsertAddChunkHostPrefixUrl(&empty_chunk, 22, "www.notempy.com/", 823 "www.notempty.com/full2.html"); 824 chunks.push_back(empty_chunk); 825 826 EXPECT_TRUE(database_->UpdateStarted(&lists)); 827 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 828 database_->UpdateFinished(true); 829 830 const Time now = Time::Now(); 831 std::vector<SBFullHashResult> full_hashes; 832 std::vector<SBPrefix> prefix_hits; 833 std::string matching_list; 834 EXPECT_TRUE(database_->ContainsBrowseUrl( 835 GURL("http://www.notempty.com/full1.html"), 836 &matching_list, &prefix_hits, 837 &full_hashes, now)); 838 EXPECT_TRUE(database_->ContainsBrowseUrl( 839 GURL("http://www.notempty.com/full2.html"), 840 &matching_list, &prefix_hits, 841 &full_hashes, now)); 842 843 GetListsInfo(&lists); 844 EXPECT_EQ(lists[0].adds, "1,10,19-22"); 845 EXPECT_EQ(lists[0].subs, "7"); 846 847 // Handle AddDel and SubDel commands for empty chunks. 848 EXPECT_TRUE(database_->UpdateStarted(&lists)); 849 AddDelChunk(safe_browsing_util::kMalwareList, 21); 850 database_->UpdateFinished(true); 851 852 GetListsInfo(&lists); 853 EXPECT_EQ(lists[0].adds, "1,10,19-20,22"); 854 EXPECT_EQ(lists[0].subs, "7"); 855 856 EXPECT_TRUE(database_->UpdateStarted(&lists)); 857 SubDelChunk(safe_browsing_util::kMalwareList, 7); 858 database_->UpdateFinished(true); 859 860 GetListsInfo(&lists); 861 EXPECT_EQ(lists[0].adds, "1,10,19-20,22"); 862 EXPECT_EQ(lists[0].subs, ""); 863 } 864 865 // Utility function for setting up the database for the caching test. 866 void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() { 867 SBChunkList chunks; 868 SBChunk chunk; 869 // Add a simple chunk with one hostkey and cache it. 870 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.evil.com/", 871 "www.evil.com/phishing.html", 872 "www.evil.com/malware.html"); 873 chunks.push_back(chunk); 874 875 std::vector<SBListChunkRanges> lists; 876 EXPECT_TRUE(database_->UpdateStarted(&lists)); 877 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 878 database_->UpdateFinished(true); 879 880 // Add the GetHash results to the cache. 881 SBFullHashResult full_hash; 882 full_hash.hash = Sha256Hash("www.evil.com/phishing.html"); 883 full_hash.list_name = safe_browsing_util::kMalwareList; 884 full_hash.add_chunk_id = 1; 885 886 std::vector<SBFullHashResult> results; 887 results.push_back(full_hash); 888 889 full_hash.hash = Sha256Hash("www.evil.com/malware.html"); 890 results.push_back(full_hash); 891 892 std::vector<SBPrefix> prefixes; 893 database_->CacheHashResults(prefixes, results); 894 } 895 896 TEST_F(SafeBrowsingDatabaseTest, HashCaching) { 897 PopulateDatabaseForCacheTest(); 898 899 // We should have both full hashes in the cache. 900 EXPECT_EQ(database_->pending_browse_hashes_.size(), 2U); 901 902 // Test the cache lookup for the first prefix. 903 std::string listname; 904 std::vector<SBPrefix> prefixes; 905 std::vector<SBFullHashResult> full_hashes; 906 database_->ContainsBrowseUrl( 907 GURL("http://www.evil.com/phishing.html"), 908 &listname, &prefixes, &full_hashes, Time::Now()); 909 EXPECT_EQ(full_hashes.size(), 1U); 910 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 911 Sha256Hash("www.evil.com/phishing.html"))); 912 913 prefixes.clear(); 914 full_hashes.clear(); 915 916 // Test the cache lookup for the second prefix. 917 database_->ContainsBrowseUrl( 918 GURL("http://www.evil.com/malware.html"), 919 &listname, &prefixes, &full_hashes, Time::Now()); 920 EXPECT_EQ(full_hashes.size(), 1U); 921 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 922 Sha256Hash("www.evil.com/malware.html"))); 923 924 prefixes.clear(); 925 full_hashes.clear(); 926 927 // Test removing a prefix via a sub chunk. 928 SBChunk chunk; 929 SBChunkList chunks; 930 InsertSubChunkHostPrefixUrl(&chunk, 2, 1, "www.evil.com/", 931 "www.evil.com/phishing.html"); 932 chunks.push_back(chunk); 933 934 std::vector<SBListChunkRanges> lists; 935 EXPECT_TRUE(database_->UpdateStarted(&lists)); 936 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 937 database_->UpdateFinished(true); 938 939 // This prefix should still be there. 940 database_->ContainsBrowseUrl( 941 GURL("http://www.evil.com/malware.html"), 942 &listname, &prefixes, &full_hashes, Time::Now()); 943 EXPECT_EQ(full_hashes.size(), 1U); 944 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 945 Sha256Hash("www.evil.com/malware.html"))); 946 prefixes.clear(); 947 full_hashes.clear(); 948 949 // This prefix should be gone. 950 database_->ContainsBrowseUrl( 951 GURL("http://www.evil.com/phishing.html"), 952 &listname, &prefixes, &full_hashes, Time::Now()); 953 EXPECT_TRUE(full_hashes.empty()); 954 955 prefixes.clear(); 956 full_hashes.clear(); 957 958 // Test that an AddDel for the original chunk removes the last cached entry. 959 EXPECT_TRUE(database_->UpdateStarted(&lists)); 960 AddDelChunk(safe_browsing_util::kMalwareList, 1); 961 database_->UpdateFinished(true); 962 database_->ContainsBrowseUrl( 963 GURL("http://www.evil.com/malware.html"), 964 &listname, &prefixes, &full_hashes, Time::Now()); 965 EXPECT_TRUE(full_hashes.empty()); 966 EXPECT_TRUE(database_->full_browse_hashes_.empty()); 967 EXPECT_TRUE(database_->pending_browse_hashes_.empty()); 968 969 prefixes.clear(); 970 full_hashes.clear(); 971 972 // Test that the cache won't return expired values. First we have to adjust 973 // the cached entries' received time to make them older, since the database 974 // cache insert uses Time::Now(). First, store some entries. 975 PopulateDatabaseForCacheTest(); 976 977 std::vector<SBAddFullHash>* hash_cache = &database_->pending_browse_hashes_; 978 EXPECT_EQ(hash_cache->size(), 2U); 979 980 // Now adjust one of the entries times to be in the past. 981 base::Time expired = base::Time::Now() - base::TimeDelta::FromMinutes(60); 982 const SBPrefix key = Sha256Prefix("www.evil.com/malware.html"); 983 std::vector<SBAddFullHash>::iterator iter; 984 for (iter = hash_cache->begin(); iter != hash_cache->end(); ++iter) { 985 if (iter->full_hash.prefix == key) { 986 iter->received = static_cast<int32>(expired.ToTimeT()); 987 break; 988 } 989 } 990 EXPECT_TRUE(iter != hash_cache->end()); 991 992 database_->ContainsBrowseUrl( 993 GURL("http://www.evil.com/malware.html"), 994 &listname, &prefixes, &full_hashes, expired); 995 EXPECT_TRUE(full_hashes.empty()); 996 997 // This entry should still exist. 998 database_->ContainsBrowseUrl( 999 GURL("http://www.evil.com/phishing.html"), 1000 &listname, &prefixes, &full_hashes, expired); 1001 EXPECT_EQ(full_hashes.size(), 1U); 1002 1003 1004 // Testing prefix miss caching. First, we clear out the existing database, 1005 // Since PopulateDatabaseForCacheTest() doesn't handle adding duplicate 1006 // chunks. 1007 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1008 AddDelChunk(safe_browsing_util::kMalwareList, 1); 1009 database_->UpdateFinished(true); 1010 1011 std::vector<SBPrefix> prefix_misses; 1012 std::vector<SBFullHashResult> empty_full_hash; 1013 prefix_misses.push_back(Sha256Prefix("http://www.bad.com/malware.html")); 1014 prefix_misses.push_back(Sha256Prefix("http://www.bad.com/phishing.html")); 1015 database_->CacheHashResults(prefix_misses, empty_full_hash); 1016 1017 // Prefixes with no full results are misses. 1018 EXPECT_EQ(database_->prefix_miss_cache_.size(), 2U); 1019 1020 // Update the database. 1021 PopulateDatabaseForCacheTest(); 1022 1023 // Prefix miss cache should be cleared. 1024 EXPECT_TRUE(database_->prefix_miss_cache_.empty()); 1025 1026 // Cache a GetHash miss for a particular prefix, and even though the prefix is 1027 // in the database, it is flagged as a miss so looking up the associated URL 1028 // will not succeed. 1029 prefixes.clear(); 1030 full_hashes.clear(); 1031 prefix_misses.clear(); 1032 empty_full_hash.clear(); 1033 prefix_misses.push_back(Sha256Prefix("www.evil.com/phishing.html")); 1034 database_->CacheHashResults(prefix_misses, empty_full_hash); 1035 EXPECT_FALSE(database_->ContainsBrowseUrl( 1036 GURL("http://www.evil.com/phishing.html"), 1037 &listname, &prefixes, 1038 &full_hashes, Time::Now())); 1039 1040 prefixes.clear(); 1041 full_hashes.clear(); 1042 1043 // Test receiving a full add chunk. 1044 chunk.hosts.clear(); 1045 InsertAddChunkHost2FullHashes(&chunk, 20, "www.fullevil.com/", 1046 "www.fullevil.com/bad1.html", 1047 "www.fullevil.com/bad2.html"); 1048 chunks.clear(); 1049 chunks.push_back(chunk); 1050 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1051 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1052 database_->UpdateFinished(true); 1053 1054 EXPECT_TRUE(database_->ContainsBrowseUrl( 1055 GURL("http://www.fullevil.com/bad1.html"), 1056 &listname, &prefixes, &full_hashes, 1057 Time::Now())); 1058 EXPECT_EQ(full_hashes.size(), 1U); 1059 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 1060 Sha256Hash("www.fullevil.com/bad1.html"))); 1061 prefixes.clear(); 1062 full_hashes.clear(); 1063 1064 EXPECT_TRUE(database_->ContainsBrowseUrl( 1065 GURL("http://www.fullevil.com/bad2.html"), 1066 &listname, &prefixes, &full_hashes, 1067 Time::Now())); 1068 EXPECT_EQ(full_hashes.size(), 1U); 1069 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 1070 Sha256Hash("www.fullevil.com/bad2.html"))); 1071 prefixes.clear(); 1072 full_hashes.clear(); 1073 1074 // Test receiving a full sub chunk, which will remove one of the full adds. 1075 chunk.hosts.clear(); 1076 InsertSubChunkHostFullHash(&chunk, 200, 20, 1077 "www.fullevil.com/", 1078 "www.fullevil.com/bad1.html"); 1079 chunks.clear(); 1080 chunks.push_back(chunk); 1081 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1082 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1083 database_->UpdateFinished(true); 1084 1085 EXPECT_FALSE(database_->ContainsBrowseUrl( 1086 GURL("http://www.fullevil.com/bad1.html"), 1087 &listname, &prefixes, &full_hashes, 1088 Time::Now())); 1089 EXPECT_TRUE(full_hashes.empty()); 1090 1091 // There should be one remaining full add. 1092 EXPECT_TRUE(database_->ContainsBrowseUrl( 1093 GURL("http://www.fullevil.com/bad2.html"), 1094 &listname, &prefixes, &full_hashes, 1095 Time::Now())); 1096 EXPECT_EQ(full_hashes.size(), 1U); 1097 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 1098 Sha256Hash("www.fullevil.com/bad2.html"))); 1099 prefixes.clear(); 1100 full_hashes.clear(); 1101 1102 // Now test an AddDel for the remaining full add. 1103 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1104 AddDelChunk(safe_browsing_util::kMalwareList, 20); 1105 database_->UpdateFinished(true); 1106 1107 EXPECT_FALSE(database_->ContainsBrowseUrl( 1108 GURL("http://www.fullevil.com/bad1.html"), 1109 &listname, &prefixes, &full_hashes, 1110 Time::Now())); 1111 EXPECT_FALSE(database_->ContainsBrowseUrl( 1112 GURL("http://www.fullevil.com/bad2.html"), 1113 &listname, &prefixes, &full_hashes, 1114 Time::Now())); 1115 } 1116 1117 // Test that corrupt databases are appropriately handled, even if the 1118 // corruption is detected in the midst of the update. 1119 // TODO(shess): Disabled until ScopedLogMessageIgnorer resolved. 1120 // http://crbug.com/56448 1121 TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) { 1122 // Re-create the database in a captive message loop so that we can 1123 // influence task-posting. Database specifically needs to the 1124 // file-backed. 1125 database_.reset(); 1126 base::MessageLoop loop(base::MessageLoop::TYPE_DEFAULT); 1127 SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile(); 1128 database_.reset(new SafeBrowsingDatabaseNew(store, NULL, NULL, NULL, NULL, 1129 NULL, NULL)); 1130 database_->Init(database_filename_); 1131 1132 // This will cause an empty database to be created. 1133 std::vector<SBListChunkRanges> lists; 1134 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1135 database_->UpdateFinished(true); 1136 1137 // Create a sub chunk to insert. 1138 SBChunkList chunks; 1139 SBChunk chunk; 1140 SBChunkHost host; 1141 host.host = Sha256Prefix("www.subbed.com/"); 1142 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 1143 host.entry->set_chunk_id(7); 1144 host.entry->SetChunkIdAtPrefix(0, 19); 1145 host.entry->SetPrefixAt(0, Sha256Prefix("www.subbed.com/notevil1.html")); 1146 chunk.chunk_number = 7; 1147 chunk.is_add = false; 1148 chunk.hosts.clear(); 1149 chunk.hosts.push_back(host); 1150 chunks.clear(); 1151 chunks.push_back(chunk); 1152 1153 // Corrupt the file by corrupting the checksum, which is not checked 1154 // until the entire table is read in |UpdateFinished()|. 1155 FILE* fp = base::OpenFile(database_filename_, "r+"); 1156 ASSERT_TRUE(fp); 1157 ASSERT_NE(-1, fseek(fp, -8, SEEK_END)); 1158 for (size_t i = 0; i < 8; ++i) { 1159 fputc('!', fp); 1160 } 1161 fclose(fp); 1162 1163 { 1164 // The following code will cause DCHECKs, so suppress the crashes. 1165 ScopedLogMessageIgnorer ignorer; 1166 1167 // Start an update. The insert will fail due to corruption. 1168 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1169 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1170 database_->UpdateFinished(true); 1171 1172 // Database file still exists until the corruption handler has run. 1173 EXPECT_TRUE(base::PathExists(database_filename_)); 1174 1175 // Flush through the corruption-handler task. 1176 VLOG(1) << "Expect failed check on: SafeBrowsing database reset"; 1177 base::MessageLoop::current()->RunUntilIdle(); 1178 } 1179 1180 // Database file should not exist. 1181 EXPECT_FALSE(base::PathExists(database_filename_)); 1182 1183 // Run the update again successfully. 1184 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1185 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1186 database_->UpdateFinished(true); 1187 EXPECT_TRUE(base::PathExists(database_filename_)); 1188 1189 database_.reset(); 1190 } 1191 1192 // Checks database reading and writing. 1193 TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) { 1194 database_.reset(); 1195 base::MessageLoop loop(base::MessageLoop::TYPE_DEFAULT); 1196 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); 1197 SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile(); 1198 SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); 1199 database_.reset(new SafeBrowsingDatabaseNew(browse_store, 1200 download_store, 1201 csd_whitelist_store, 1202 NULL, 1203 NULL, 1204 NULL, 1205 NULL)); 1206 database_->Init(database_filename_); 1207 1208 const char kEvil1Host[] = "www.evil1.com/"; 1209 const char kEvil1Url1[] = "www.evil1.com/download1/"; 1210 const char kEvil1Url2[] = "www.evil1.com/download2.html"; 1211 1212 SBChunkList chunks; 1213 SBChunk chunk; 1214 // Add a simple chunk with one hostkey for download url list. 1215 InsertAddChunkHost2PrefixUrls(&chunk, 1, kEvil1Host, 1216 kEvil1Url1, kEvil1Url2); 1217 chunks.push_back(chunk); 1218 std::vector<SBListChunkRanges> lists; 1219 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1220 database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks); 1221 database_->UpdateFinished(true); 1222 1223 std::vector<SBPrefix> prefix_hits; 1224 std::vector<GURL> urls(1); 1225 1226 urls[0] = GURL(std::string("http://") + kEvil1Url1); 1227 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1228 ASSERT_EQ(prefix_hits.size(), 1U); 1229 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); 1230 1231 urls[0] = GURL(std::string("http://") + kEvil1Url2); 1232 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1233 ASSERT_EQ(prefix_hits.size(), 1U); 1234 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); 1235 1236 urls[0] = GURL(std::string("https://") + kEvil1Url2); 1237 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1238 ASSERT_EQ(prefix_hits.size(), 1U); 1239 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); 1240 1241 urls[0] = GURL(std::string("ftp://") + kEvil1Url2); 1242 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1243 ASSERT_EQ(prefix_hits.size(), 1U); 1244 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); 1245 1246 urls[0] = GURL("http://www.randomevil.com"); 1247 EXPECT_FALSE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1248 1249 // Should match with query args stripped. 1250 urls[0] = GURL(std::string("http://") + kEvil1Url2 + "?blah"); 1251 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1252 ASSERT_EQ(prefix_hits.size(), 1U); 1253 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2)); 1254 1255 // Should match with extra path stuff and query args stripped. 1256 urls[0] = GURL(std::string("http://") + kEvil1Url1 + "foo/bar?blah"); 1257 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1258 ASSERT_EQ(prefix_hits.size(), 1U); 1259 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); 1260 1261 // First hit in redirect chain is malware. 1262 urls.clear(); 1263 urls.push_back(GURL(std::string("http://") + kEvil1Url1)); 1264 urls.push_back(GURL("http://www.randomevil.com")); 1265 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1266 ASSERT_EQ(prefix_hits.size(), 1U); 1267 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); 1268 1269 // Middle hit in redirect chain is malware. 1270 urls.clear(); 1271 urls.push_back(GURL("http://www.randomevil.com")); 1272 urls.push_back(GURL(std::string("http://") + kEvil1Url1)); 1273 urls.push_back(GURL("http://www.randomevil2.com")); 1274 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1275 ASSERT_EQ(prefix_hits.size(), 1U); 1276 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); 1277 1278 // Final hit in redirect chain is malware. 1279 urls.clear(); 1280 urls.push_back(GURL("http://www.randomevil.com")); 1281 urls.push_back(GURL(std::string("http://") + kEvil1Url1)); 1282 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1283 ASSERT_EQ(prefix_hits.size(), 1U); 1284 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); 1285 1286 // Multiple hits in redirect chain are in malware list. 1287 urls.clear(); 1288 urls.push_back(GURL(std::string("http://") + kEvil1Url1)); 1289 urls.push_back(GURL(std::string("https://") + kEvil1Url2)); 1290 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits)); 1291 ASSERT_EQ(prefix_hits.size(), 2U); 1292 EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1)); 1293 EXPECT_EQ(prefix_hits[1], Sha256Prefix(kEvil1Url2)); 1294 database_.reset(); 1295 } 1296 1297 // Checks that the whitelists are handled properly. 1298 TEST_F(SafeBrowsingDatabaseTest, Whitelists) { 1299 database_.reset(); 1300 // We expect all calls to ContainsCsdWhitelistedUrl in particular to be made 1301 // from the IO thread. In general the whitelist lookups are thread-safe. 1302 content::TestBrowserThreadBundle thread_bundle_; 1303 1304 // If the whitelist is disabled everything should match the whitelist. 1305 database_.reset(new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile(), 1306 NULL, NULL, NULL, NULL, NULL, 1307 NULL)); 1308 database_->Init(database_filename_); 1309 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1310 GURL(std::string("http://www.phishing.com/")))); 1311 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1312 GURL(std::string("http://www.phishing.com/")))); 1313 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf")); 1314 1315 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); 1316 SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); 1317 SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile(); 1318 SafeBrowsingStoreFile* extension_blacklist_store = 1319 new SafeBrowsingStoreFile(); 1320 database_.reset(new SafeBrowsingDatabaseNew(browse_store, NULL, 1321 csd_whitelist_store, 1322 download_whitelist_store, 1323 extension_blacklist_store, 1324 NULL, NULL)); 1325 database_->Init(database_filename_); 1326 1327 const char kGood1Host[] = "www.good1.com/"; 1328 const char kGood1Url1[] = "www.good1.com/a/b.html"; 1329 const char kGood1Url2[] = "www.good1.com/b/"; 1330 1331 const char kGood2Host[] = "www.good2.com/"; 1332 const char kGood2Url1[] = "www.good2.com/c"; // Should match '/c/bla'. 1333 1334 // good3.com/a/b/c/d/e/f/g/ should match because it's a whitelist. 1335 const char kGood3Host[] = "good3.com/"; 1336 const char kGood3Url1[] = "good3.com/"; 1337 1338 const char kGoodString[] = "good_string"; 1339 1340 SBChunkList download_chunks, csd_chunks; 1341 SBChunk chunk; 1342 // Add two simple chunks to the csd whitelist. 1343 InsertAddChunkHost2FullHashes(&chunk, 1, kGood1Host, 1344 kGood1Url1, kGood1Url2); 1345 csd_chunks.push_back(chunk); 1346 1347 chunk.hosts.clear(); 1348 InsertAddChunkHostFullHashes(&chunk, 2, kGood2Host, kGood2Url1); 1349 csd_chunks.push_back(chunk); 1350 1351 chunk.hosts.clear(); 1352 InsertAddChunkHostFullHashes(&chunk, 2, kGood2Host, kGood2Url1); 1353 download_chunks.push_back(chunk); 1354 1355 chunk.hosts.clear(); 1356 InsertAddChunkHostFullHashes(&chunk, 3, kGoodString, kGoodString); 1357 download_chunks.push_back(chunk); 1358 1359 chunk.hosts.clear(); 1360 InsertAddChunkHostFullHashes(&chunk, 4, kGood3Host, kGood3Url1); 1361 download_chunks.push_back(chunk); 1362 1363 std::vector<SBListChunkRanges> lists; 1364 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1365 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, 1366 csd_chunks); 1367 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, 1368 download_chunks); 1369 database_->UpdateFinished(true); 1370 1371 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl( 1372 GURL(std::string("http://") + kGood1Host))); 1373 1374 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1375 GURL(std::string("http://") + kGood1Url1))); 1376 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1377 GURL(std::string("http://") + kGood1Url1 + "?a=b"))); 1378 1379 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1380 GURL(std::string("http://") + kGood1Url2))); 1381 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1382 GURL(std::string("http://") + kGood1Url2 + "/c.html"))); 1383 1384 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1385 GURL(std::string("https://") + kGood1Url2 + "/c.html"))); 1386 1387 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1388 GURL(std::string("http://") + kGood2Url1 + "/c"))); 1389 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1390 GURL(std::string("http://") + kGood2Url1 + "/c?bla"))); 1391 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1392 GURL(std::string("http://") + kGood2Url1 + "/c/bla"))); 1393 1394 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl( 1395 GURL(std::string("http://www.google.com/")))); 1396 1397 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1398 GURL(std::string("http://") + kGood2Url1 + "/c"))); 1399 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1400 GURL(std::string("http://") + kGood2Url1 + "/c?bla"))); 1401 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1402 GURL(std::string("http://") + kGood2Url1 + "/c/bla"))); 1403 1404 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1405 GURL(std::string("http://good3.com/a/b/c/d/e/f/g/")))); 1406 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1407 GURL(std::string("http://a.b.good3.com/")))); 1408 1409 EXPECT_FALSE(database_->ContainsDownloadWhitelistedString("asdf")); 1410 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString)); 1411 1412 EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl( 1413 GURL(std::string("http://www.google.com/")))); 1414 1415 // Test only add the malware IP killswitch 1416 csd_chunks.clear(); 1417 chunk.hosts.clear(); 1418 InsertAddChunkHostFullHashes( 1419 &chunk, 15, "sb-ssl.google.com/", 1420 "sb-ssl.google.com/safebrowsing/csd/killswitch_malware"); 1421 csd_chunks.push_back(chunk); 1422 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1423 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks); 1424 database_->UpdateFinished(true); 1425 1426 EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn()); 1427 1428 // Test that the kill-switch works as intended. 1429 csd_chunks.clear(); 1430 download_chunks.clear(); 1431 lists.clear(); 1432 chunk.hosts.clear(); 1433 InsertAddChunkHostFullHashes(&chunk, 5, "sb-ssl.google.com/", 1434 "sb-ssl.google.com/safebrowsing/csd/killswitch"); 1435 csd_chunks.push_back(chunk); 1436 chunk.hosts.clear(); 1437 InsertAddChunkHostFullHashes(&chunk, 5, "sb-ssl.google.com/", 1438 "sb-ssl.google.com/safebrowsing/csd/killswitch"); 1439 download_chunks.push_back(chunk); 1440 1441 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1442 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks); 1443 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, 1444 download_chunks); 1445 database_->UpdateFinished(true); 1446 1447 EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn()); 1448 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1449 GURL(std::string("https://") + kGood1Url2 + "/c.html"))); 1450 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1451 GURL(std::string("http://www.google.com/")))); 1452 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1453 GURL(std::string("http://www.phishing_url.com/")))); 1454 1455 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1456 GURL(std::string("https://") + kGood1Url2 + "/c.html"))); 1457 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1458 GURL(std::string("http://www.google.com/")))); 1459 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1460 GURL(std::string("http://www.phishing_url.com/")))); 1461 1462 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf")); 1463 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString)); 1464 1465 // Remove the kill-switch and verify that we can recover. 1466 csd_chunks.clear(); 1467 download_chunks.clear(); 1468 lists.clear(); 1469 SBChunk sub_chunk; 1470 InsertSubChunkHostFullHash(&sub_chunk, 1, 5, 1471 "sb-ssl.google.com/", 1472 "sb-ssl.google.com/safebrowsing/csd/killswitch"); 1473 csd_chunks.push_back(sub_chunk); 1474 1475 sub_chunk.hosts.clear(); 1476 InsertSubChunkHostFullHash( 1477 &sub_chunk, 10, 15, "sb-ssl.google.com/", 1478 "sb-ssl.google.com/safebrowsing/csd/killswitch_malware"); 1479 csd_chunks.push_back(sub_chunk); 1480 1481 sub_chunk.hosts.clear(); 1482 InsertSubChunkHostFullHash(&sub_chunk, 1, 5, 1483 "sb-ssl.google.com/", 1484 "sb-ssl.google.com/safebrowsing/csd/killswitch"); 1485 download_chunks.push_back(sub_chunk); 1486 1487 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1488 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks); 1489 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, 1490 download_chunks); 1491 database_->UpdateFinished(true); 1492 1493 EXPECT_FALSE(database_->IsMalwareIPMatchKillSwitchOn()); 1494 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1495 GURL(std::string("https://") + kGood1Url2 + "/c.html"))); 1496 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl( 1497 GURL(std::string("https://") + kGood2Url1 + "/c/bla"))); 1498 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl( 1499 GURL(std::string("http://www.google.com/")))); 1500 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl( 1501 GURL(std::string("http://www.phishing_url.com/")))); 1502 1503 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1504 GURL(std::string("https://") + kGood2Url1 + "/c/bla"))); 1505 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( 1506 GURL(std::string("https://good3.com/")))); 1507 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString)); 1508 EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl( 1509 GURL(std::string("http://www.google.com/")))); 1510 EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl( 1511 GURL(std::string("http://www.phishing_url.com/")))); 1512 EXPECT_FALSE(database_->ContainsDownloadWhitelistedString("asdf")); 1513 1514 database_.reset(); 1515 } 1516 1517 // Test to make sure we could insert chunk list that 1518 // contains entries for the same host. 1519 TEST_F(SafeBrowsingDatabaseTest, SameHostEntriesOkay) { 1520 SBChunk chunk; 1521 1522 // Add a malware add chunk with two entries of the same host. 1523 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", 1524 "www.evil.com/malware1.html"); 1525 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", 1526 "www.evil.com/malware2.html"); 1527 SBChunkList chunks; 1528 chunks.push_back(chunk); 1529 1530 // Insert the testing chunks into database. 1531 std::vector<SBListChunkRanges> lists; 1532 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1533 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1534 database_->UpdateFinished(true); 1535 1536 GetListsInfo(&lists); 1537 EXPECT_EQ(std::string(safe_browsing_util::kMalwareList), lists[0].name); 1538 EXPECT_EQ("1", lists[0].adds); 1539 EXPECT_TRUE(lists[0].subs.empty()); 1540 1541 // Add a phishing add chunk with two entries of the same host. 1542 chunk.hosts.clear(); 1543 InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/", 1544 "www.evil.com/phishing1.html"); 1545 InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/", 1546 "www.evil.com/phishing2.html"); 1547 chunks.clear(); 1548 chunks.push_back(chunk); 1549 1550 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1551 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 1552 database_->UpdateFinished(true); 1553 1554 GetListsInfo(&lists); 1555 EXPECT_EQ(std::string(safe_browsing_util::kMalwareList), lists[0].name); 1556 EXPECT_EQ("1", lists[0].adds); 1557 EXPECT_EQ(std::string(safe_browsing_util::kPhishingList), lists[1].name); 1558 EXPECT_EQ("47", lists[1].adds); 1559 1560 const Time now = Time::Now(); 1561 std::vector<SBPrefix> prefixes; 1562 std::vector<SBFullHashResult> full_hashes; 1563 std::vector<SBPrefix> prefix_hits; 1564 std::string matching_list; 1565 std::string listname; 1566 1567 EXPECT_TRUE(database_->ContainsBrowseUrl( 1568 GURL("http://www.evil.com/malware1.html"), 1569 &listname, &prefixes, &full_hashes, now)); 1570 EXPECT_TRUE(database_->ContainsBrowseUrl( 1571 GURL("http://www.evil.com/malware2.html"), 1572 &listname, &prefixes, &full_hashes, now)); 1573 EXPECT_TRUE(database_->ContainsBrowseUrl( 1574 GURL("http://www.evil.com/phishing1.html"), 1575 &listname, &prefixes, &full_hashes, now)); 1576 EXPECT_TRUE(database_->ContainsBrowseUrl( 1577 GURL("http://www.evil.com/phishing2.html"), 1578 &listname, &prefixes, &full_hashes, now)); 1579 1580 // Test removing a single prefix from the add chunk. 1581 // Remove the prefix that added first. 1582 chunk.hosts.clear(); 1583 InsertSubChunkHostPrefixUrl(&chunk, 4, 1, "www.evil.com/", 1584 "www.evil.com/malware1.html"); 1585 chunks.clear(); 1586 chunks.push_back(chunk); 1587 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1588 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1589 database_->UpdateFinished(true); 1590 1591 // Remove the prefix that added last. 1592 chunk.hosts.clear(); 1593 InsertSubChunkHostPrefixUrl(&chunk, 5, 47, "www.evil.com/", 1594 "www.evil.com/phishing2.html"); 1595 chunks.clear(); 1596 chunks.push_back(chunk); 1597 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1598 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 1599 database_->UpdateFinished(true); 1600 1601 // Verify that the database contains urls expected. 1602 EXPECT_FALSE(database_->ContainsBrowseUrl( 1603 GURL("http://www.evil.com/malware1.html"), 1604 &listname, &prefixes, &full_hashes, now)); 1605 EXPECT_TRUE(database_->ContainsBrowseUrl( 1606 GURL("http://www.evil.com/malware2.html"), 1607 &listname, &prefixes, &full_hashes, now)); 1608 EXPECT_TRUE(database_->ContainsBrowseUrl( 1609 GURL("http://www.evil.com/phishing1.html"), 1610 &listname, &prefixes, &full_hashes, now)); 1611 EXPECT_FALSE(database_->ContainsBrowseUrl( 1612 GURL("http://www.evil.com/phishing2.html"), 1613 &listname, &prefixes, &full_hashes, now)); 1614 } 1615 1616 // Test that an empty update doesn't actually update the database. 1617 // This isn't a functionality requirement, but it is a useful 1618 // optimization. 1619 TEST_F(SafeBrowsingDatabaseTest, EmptyUpdate) { 1620 SBChunkList chunks; 1621 SBChunk chunk; 1622 1623 base::FilePath filename = database_->BrowseDBFilename(database_filename_); 1624 1625 // Prime the database. 1626 std::vector<SBListChunkRanges> lists; 1627 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1628 1629 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", 1630 "www.evil.com/malware.html"); 1631 chunks.clear(); 1632 chunks.push_back(chunk); 1633 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1634 database_->UpdateFinished(true); 1635 1636 // Get an older time to reset the lastmod time for detecting whether 1637 // the file has been updated. 1638 base::PlatformFileInfo before_info, after_info; 1639 ASSERT_TRUE(base::GetFileInfo(filename, &before_info)); 1640 const base::Time old_last_modified = 1641 before_info.last_modified - base::TimeDelta::FromSeconds(10); 1642 1643 // Inserting another chunk updates the database file. The sleep is 1644 // needed because otherwise the entire test can finish w/in the 1645 // resolution of the lastmod time. 1646 ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified)); 1647 ASSERT_TRUE(base::GetFileInfo(filename, &before_info)); 1648 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1649 chunk.hosts.clear(); 1650 InsertAddChunkHostPrefixUrl(&chunk, 2, "www.foo.com/", 1651 "www.foo.com/malware.html"); 1652 chunks.clear(); 1653 chunks.push_back(chunk); 1654 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1655 database_->UpdateFinished(true); 1656 ASSERT_TRUE(base::GetFileInfo(filename, &after_info)); 1657 EXPECT_LT(before_info.last_modified, after_info.last_modified); 1658 1659 // Deleting a chunk updates the database file. 1660 ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified)); 1661 ASSERT_TRUE(base::GetFileInfo(filename, &before_info)); 1662 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1663 AddDelChunk(safe_browsing_util::kMalwareList, chunk.chunk_number); 1664 database_->UpdateFinished(true); 1665 ASSERT_TRUE(base::GetFileInfo(filename, &after_info)); 1666 EXPECT_LT(before_info.last_modified, after_info.last_modified); 1667 1668 // Simply calling |UpdateStarted()| then |UpdateFinished()| does not 1669 // update the database file. 1670 ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified)); 1671 ASSERT_TRUE(base::GetFileInfo(filename, &before_info)); 1672 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1673 database_->UpdateFinished(true); 1674 ASSERT_TRUE(base::GetFileInfo(filename, &after_info)); 1675 EXPECT_EQ(before_info.last_modified, after_info.last_modified); 1676 } 1677 1678 // Test that a filter file is written out during update and read back 1679 // in during setup. 1680 TEST_F(SafeBrowsingDatabaseTest, FilterFile) { 1681 // Create a database with trivial example data and write it out. 1682 { 1683 SBChunkList chunks; 1684 SBChunk chunk; 1685 1686 // Prime the database. 1687 std::vector<SBListChunkRanges> lists; 1688 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1689 1690 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", 1691 "www.evil.com/malware.html"); 1692 chunks.clear(); 1693 chunks.push_back(chunk); 1694 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 1695 database_->UpdateFinished(true); 1696 } 1697 1698 // Find the malware url in the database, don't find a good url. 1699 const Time now = Time::Now(); 1700 std::vector<SBFullHashResult> full_hashes; 1701 std::vector<SBPrefix> prefix_hits; 1702 std::string matching_list; 1703 EXPECT_TRUE(database_->ContainsBrowseUrl( 1704 GURL("http://www.evil.com/malware.html"), 1705 &matching_list, &prefix_hits, &full_hashes, now)); 1706 EXPECT_FALSE(database_->ContainsBrowseUrl( 1707 GURL("http://www.good.com/goodware.html"), 1708 &matching_list, &prefix_hits, &full_hashes, now)); 1709 1710 base::FilePath filter_file = database_->PrefixSetForFilename( 1711 database_->BrowseDBFilename(database_filename_)); 1712 1713 // After re-creating the database, it should have a filter read from 1714 // a file, so it should find the same results. 1715 ASSERT_TRUE(base::PathExists(filter_file)); 1716 database_.reset(new SafeBrowsingDatabaseNew); 1717 database_->Init(database_filename_); 1718 EXPECT_TRUE(database_->ContainsBrowseUrl( 1719 GURL("http://www.evil.com/malware.html"), 1720 &matching_list, &prefix_hits, &full_hashes, now)); 1721 EXPECT_FALSE(database_->ContainsBrowseUrl( 1722 GURL("http://www.good.com/goodware.html"), 1723 &matching_list, &prefix_hits, &full_hashes, now)); 1724 1725 // If there is no filter file, the database cannot find malware urls. 1726 base::DeleteFile(filter_file, false); 1727 ASSERT_FALSE(base::PathExists(filter_file)); 1728 database_.reset(new SafeBrowsingDatabaseNew); 1729 database_->Init(database_filename_); 1730 EXPECT_FALSE(database_->ContainsBrowseUrl( 1731 GURL("http://www.evil.com/malware.html"), 1732 &matching_list, &prefix_hits, &full_hashes, now)); 1733 EXPECT_FALSE(database_->ContainsBrowseUrl( 1734 GURL("http://www.good.com/goodware.html"), 1735 &matching_list, &prefix_hits, &full_hashes, now)); 1736 } 1737 1738 TEST_F(SafeBrowsingDatabaseTest, MalwareIpBlacklist) { 1739 database_.reset(); 1740 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); 1741 SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile(); 1742 database_.reset(new SafeBrowsingDatabaseNew(browse_store, 1743 NULL, 1744 NULL, 1745 NULL, 1746 NULL, 1747 NULL, 1748 ip_blacklist_store)); 1749 database_->Init(database_filename_); 1750 std::vector<SBListChunkRanges> lists; 1751 EXPECT_TRUE(database_->UpdateStarted(&lists)); 1752 1753 // IPv4 prefix match for ::ffff:192.168.1.0/120. 1754 SBChunkList chunks; 1755 SBChunk chunk; 1756 InsertAddChunkFullHash(&chunk, 1, "::ffff:192.168.1.0", 120); 1757 chunks.push_back(chunk); 1758 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 1759 1760 // IPv4 exact match for ::ffff:192.1.1.1. 1761 chunks.clear(); 1762 chunk.hosts.clear(); 1763 InsertAddChunkFullHash(&chunk, 2, "::ffff:192.1.1.1", 128); 1764 chunks.push_back(chunk); 1765 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 1766 1767 // IPv6 exact match for: fe80::31a:a0ff:fe10:786e/128. 1768 chunks.clear(); 1769 chunk.hosts.clear(); 1770 InsertAddChunkFullHash(&chunk, 3, "fe80::31a:a0ff:fe10:786e", 128); 1771 chunks.push_back(chunk); 1772 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 1773 1774 // IPv6 prefix match for: 2620:0:1000:3103::/64. 1775 chunks.clear(); 1776 chunk.hosts.clear(); 1777 InsertAddChunkFullHash(&chunk, 4, "2620:0:1000:3103::", 64); 1778 chunks.push_back(chunk); 1779 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 1780 1781 // IPv4 prefix match for ::ffff:192.1.122.0/119. 1782 chunks.clear(); 1783 chunk.hosts.clear(); 1784 InsertAddChunkFullHash(&chunk, 5, "::ffff:192.1.122.0", 119); 1785 chunks.push_back(chunk); 1786 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 1787 1788 // IPv4 prefix match for ::ffff:192.1.128.0/113. 1789 chunks.clear(); 1790 chunk.hosts.clear(); 1791 InsertAddChunkFullHash(&chunk, 6, "::ffff:192.1.128.0", 113); 1792 chunks.push_back(chunk); 1793 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks); 1794 1795 database_->UpdateFinished(true); 1796 1797 EXPECT_FALSE(database_->ContainsMalwareIP("192.168.0.255")); 1798 EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.0")); 1799 EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.255")); 1800 EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.10")); 1801 EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.168.1.2")); 1802 EXPECT_FALSE(database_->ContainsMalwareIP("192.168.2.0")); 1803 1804 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.1.0")); 1805 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.1.1")); 1806 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.1.2")); 1807 1808 EXPECT_FALSE(database_->ContainsMalwareIP( 1809 "2620:0:1000:3102:ffff:ffff:ffff:ffff")); 1810 EXPECT_TRUE(database_->ContainsMalwareIP("2620:0:1000:3103::")); 1811 EXPECT_TRUE(database_->ContainsMalwareIP( 1812 "2620:0:1000:3103:ffff:ffff:ffff:ffff")); 1813 EXPECT_FALSE(database_->ContainsMalwareIP("2620:0:1000:3104::")); 1814 1815 EXPECT_FALSE(database_->ContainsMalwareIP("fe80::21a:a0ff:fe10:786d")); 1816 EXPECT_TRUE(database_->ContainsMalwareIP("fe80::31a:a0ff:fe10:786e")); 1817 EXPECT_FALSE(database_->ContainsMalwareIP("fe80::21a:a0ff:fe10:786f")); 1818 1819 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.121.255")); 1820 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.122.0")); 1821 EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.1.122.1")); 1822 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.122.255")); 1823 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.123.0")); 1824 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.123.255")); 1825 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.124.0")); 1826 1827 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.127.255")); 1828 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.128.0")); 1829 EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.1.128.1")); 1830 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.128.255")); 1831 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.255.0")); 1832 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.255.255")); 1833 EXPECT_FALSE(database_->ContainsMalwareIP("192.2.0.0")); 1834 } 1835