OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/safe_browsing_database.h" | 5 #include "chrome/browser/safe_browsing/safe_browsing_database.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 for (size_t i = 0; i < decoded_chunks.size(); ++i) { | 257 for (size_t i = 0; i < decoded_chunks.size(); ++i) { |
258 ChunksToRangeString(decoded_chunks[i], &((*list_ranges)[i])); | 258 ChunksToRangeString(decoded_chunks[i], &((*list_ranges)[i])); |
259 } | 259 } |
260 } | 260 } |
261 | 261 |
262 // Helper function to create chunk range lists for Browse related | 262 // Helper function to create chunk range lists for Browse related |
263 // lists. | 263 // lists. |
264 void UpdateChunkRanges(SafeBrowsingStore* store, | 264 void UpdateChunkRanges(SafeBrowsingStore* store, |
265 const std::vector<std::string>& listnames, | 265 const std::vector<std::string>& listnames, |
266 std::vector<SBListChunkRanges>* lists) { | 266 std::vector<SBListChunkRanges>* lists) { |
| 267 if (!store) |
| 268 return; |
| 269 |
267 DCHECK_GT(listnames.size(), 0U); | 270 DCHECK_GT(listnames.size(), 0U); |
268 DCHECK_LE(listnames.size(), 2U); | 271 DCHECK_LE(listnames.size(), 2U); |
269 std::vector<int> add_chunks; | 272 std::vector<int> add_chunks; |
270 std::vector<int> sub_chunks; | 273 std::vector<int> sub_chunks; |
271 store->GetAddChunks(&add_chunks); | 274 store->GetAddChunks(&add_chunks); |
272 store->GetSubChunks(&sub_chunks); | 275 store->GetSubChunks(&sub_chunks); |
273 | 276 |
274 // Always decode 2 ranges, even if only the first one is expected. | 277 // Always decode 2 ranges, even if only the first one is expected. |
275 // The loop below will only load as many into |lists| as |listnames| | 278 // The loop below will only load as many into |lists| as |listnames| |
276 // indicates. | 279 // indicates. |
277 std::vector<std::string> adds(2); | 280 std::vector<std::string> adds(2); |
278 std::vector<std::string> subs(2); | 281 std::vector<std::string> subs(2); |
279 GetChunkRanges(add_chunks, &adds); | 282 GetChunkRanges(add_chunks, &adds); |
280 GetChunkRanges(sub_chunks, &subs); | 283 GetChunkRanges(sub_chunks, &subs); |
281 | 284 |
282 for (size_t i = 0; i < listnames.size(); ++i) { | 285 for (size_t i = 0; i < listnames.size(); ++i) { |
283 const std::string& listname = listnames[i]; | 286 const std::string& listname = listnames[i]; |
284 DCHECK_EQ(safe_browsing_util::GetListId(listname) % 2, | 287 DCHECK_EQ(safe_browsing_util::GetListId(listname) % 2, |
285 static_cast<int>(i % 2)); | 288 static_cast<int>(i % 2)); |
286 DCHECK_NE(safe_browsing_util::GetListId(listname), | 289 DCHECK_NE(safe_browsing_util::GetListId(listname), |
287 safe_browsing_util::INVALID); | 290 safe_browsing_util::INVALID); |
288 lists->push_back(SBListChunkRanges(listname)); | 291 lists->push_back(SBListChunkRanges(listname)); |
289 lists->back().adds.swap(adds[i]); | 292 lists->back().adds.swap(adds[i]); |
290 lists->back().subs.swap(subs[i]); | 293 lists->back().subs.swap(subs[i]); |
291 } | 294 } |
292 } | 295 } |
293 | 296 |
294 // Helper for deleting chunks left over from obsolete lists. | 297 void UpdateChunkRangesForLists(SafeBrowsingStore* store, |
295 void DeleteChunksFromStore(SafeBrowsingStore* store, int listid){ | 298 const std::string& listname0, |
296 std::vector<int> add_chunks; | 299 const std::string& listname1, |
297 size_t adds_deleted = 0; | 300 std::vector<SBListChunkRanges>* lists) { |
298 store->GetAddChunks(&add_chunks); | 301 std::vector<std::string> listnames; |
299 for (std::vector<int>::const_iterator iter = add_chunks.begin(); | 302 listnames.push_back(listname0); |
300 iter != add_chunks.end(); ++iter) { | 303 listnames.push_back(listname1); |
301 if (GetListIdBit(*iter) == GetListIdBit(listid)) { | 304 UpdateChunkRanges(store, listnames, lists); |
302 adds_deleted++; | 305 } |
303 store->DeleteAddChunk(*iter); | |
304 } | |
305 } | |
306 if (adds_deleted > 0) | |
307 UMA_HISTOGRAM_COUNTS("SB2.DownloadBinhashAddsDeleted", adds_deleted); | |
308 | 306 |
309 std::vector<int> sub_chunks; | 307 void UpdateChunkRangesForList(SafeBrowsingStore* store, |
310 size_t subs_deleted = 0; | 308 const std::string& listname, |
311 store->GetSubChunks(&sub_chunks); | 309 std::vector<SBListChunkRanges>* lists) { |
312 for (std::vector<int>::const_iterator iter = sub_chunks.begin(); | 310 UpdateChunkRanges(store, std::vector<std::string>(1, listname), lists); |
313 iter != sub_chunks.end(); ++iter) { | |
314 if (GetListIdBit(*iter) == GetListIdBit(listid)) { | |
315 subs_deleted++; | |
316 store->DeleteSubChunk(*iter); | |
317 } | |
318 } | |
319 if (subs_deleted > 0) | |
320 UMA_HISTOGRAM_COUNTS("SB2.DownloadBinhashSubsDeleted", subs_deleted); | |
321 } | 311 } |
322 | 312 |
323 // Order |SBAddFullHash| on the prefix part. |SBAddPrefixLess()| from | 313 // Order |SBAddFullHash| on the prefix part. |SBAddPrefixLess()| from |
324 // safe_browsing_store.h orders on both chunk-id and prefix. | 314 // safe_browsing_store.h orders on both chunk-id and prefix. |
325 bool SBAddFullHashPrefixLess(const SBAddFullHash& a, const SBAddFullHash& b) { | 315 bool SBAddFullHashPrefixLess(const SBAddFullHash& a, const SBAddFullHash& b) { |
326 return a.full_hash.prefix < b.full_hash.prefix; | 316 return a.full_hash.prefix < b.full_hash.prefix; |
327 } | 317 } |
328 | 318 |
329 // This code always checks for non-zero file size. This helper makes | 319 // This code always checks for non-zero file size. This helper makes |
330 // that less verbose. | 320 // that less verbose. |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 // static | 433 // static |
444 base::FilePath SafeBrowsingDatabase::IpBlacklistDBFilename( | 434 base::FilePath SafeBrowsingDatabase::IpBlacklistDBFilename( |
445 const base::FilePath& db_filename) { | 435 const base::FilePath& db_filename) { |
446 return base::FilePath(db_filename.value() + kIPBlacklistDBFile); | 436 return base::FilePath(db_filename.value() + kIPBlacklistDBFile); |
447 } | 437 } |
448 | 438 |
449 SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { | 439 SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { |
450 if (list_id == safe_browsing_util::PHISH || | 440 if (list_id == safe_browsing_util::PHISH || |
451 list_id == safe_browsing_util::MALWARE) { | 441 list_id == safe_browsing_util::MALWARE) { |
452 return browse_store_.get(); | 442 return browse_store_.get(); |
453 } else if (list_id == safe_browsing_util::BINURL || | 443 } else if (list_id == safe_browsing_util::BINURL) { |
454 list_id == safe_browsing_util::BINHASH) { | |
455 return download_store_.get(); | 444 return download_store_.get(); |
456 } else if (list_id == safe_browsing_util::CSDWHITELIST) { | 445 } else if (list_id == safe_browsing_util::CSDWHITELIST) { |
457 return csd_whitelist_store_.get(); | 446 return csd_whitelist_store_.get(); |
458 } else if (list_id == safe_browsing_util::DOWNLOADWHITELIST) { | 447 } else if (list_id == safe_browsing_util::DOWNLOADWHITELIST) { |
459 return download_whitelist_store_.get(); | 448 return download_whitelist_store_.get(); |
460 } else if (list_id == safe_browsing_util::EXTENSIONBLACKLIST) { | 449 } else if (list_id == safe_browsing_util::EXTENSIONBLACKLIST) { |
461 return extension_blacklist_store_.get(); | 450 return extension_blacklist_store_.get(); |
462 } else if (list_id == safe_browsing_util::SIDEEFFECTFREEWHITELIST) { | 451 } else if (list_id == safe_browsing_util::SIDEEFFECTFREEWHITELIST) { |
463 return side_effect_free_whitelist_store_.get(); | 452 return side_effect_free_whitelist_store_.get(); |
464 } else if (list_id == safe_browsing_util::IPBLACKLIST) { | 453 } else if (list_id == safe_browsing_util::IPBLACKLIST) { |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 return false; | 729 return false; |
741 | 730 |
742 std::vector<SBPrefix> prefixes; | 731 std::vector<SBPrefix> prefixes; |
743 GetDownloadUrlPrefixes(urls, &prefixes); | 732 GetDownloadUrlPrefixes(urls, &prefixes); |
744 return MatchAddPrefixes(download_store_.get(), | 733 return MatchAddPrefixes(download_store_.get(), |
745 safe_browsing_util::BINURL % 2, | 734 safe_browsing_util::BINURL % 2, |
746 prefixes, | 735 prefixes, |
747 prefix_hits); | 736 prefix_hits); |
748 } | 737 } |
749 | 738 |
750 bool SafeBrowsingDatabaseNew::ContainsDownloadHashPrefix( | |
751 const SBPrefix& prefix) { | |
752 DCHECK_EQ(creation_loop_, base::MessageLoop::current()); | |
753 | |
754 // Ignore this check when download store is not available. | |
755 if (!download_store_.get()) | |
756 return false; | |
757 | |
758 std::vector<SBPrefix> prefix_hits; | |
759 return MatchAddPrefixes(download_store_.get(), | |
760 safe_browsing_util::BINHASH % 2, | |
761 std::vector<SBPrefix>(1, prefix), | |
762 &prefix_hits); | |
763 } | |
764 | |
765 bool SafeBrowsingDatabaseNew::ContainsCsdWhitelistedUrl(const GURL& url) { | 739 bool SafeBrowsingDatabaseNew::ContainsCsdWhitelistedUrl(const GURL& url) { |
766 // This method is theoretically thread-safe but we expect all calls to | 740 // This method is theoretically thread-safe but we expect all calls to |
767 // originate from the IO thread. | 741 // originate from the IO thread. |
768 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 742 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
769 std::vector<SBFullHash> full_hashes; | 743 std::vector<SBFullHash> full_hashes; |
770 BrowseFullHashesToCheck(url, true, &full_hashes); | 744 BrowseFullHashesToCheck(url, true, &full_hashes); |
771 return ContainsWhitelistedHashes(csd_whitelist_, full_hashes); | 745 return ContainsWhitelistedHashes(csd_whitelist_, full_hashes); |
772 } | 746 } |
773 | 747 |
774 bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedUrl(const GURL& url) { | 748 bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedUrl(const GURL& url) { |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 HandleCorruptDatabase(); | 1130 HandleCorruptDatabase(); |
1157 return false; | 1131 return false; |
1158 } | 1132 } |
1159 | 1133 |
1160 if (ip_blacklist_store_ && !ip_blacklist_store_->BeginUpdate()) { | 1134 if (ip_blacklist_store_ && !ip_blacklist_store_->BeginUpdate()) { |
1161 RecordFailure(FAILURE_IP_BLACKLIST_UPDATE_BEGIN); | 1135 RecordFailure(FAILURE_IP_BLACKLIST_UPDATE_BEGIN); |
1162 HandleCorruptDatabase(); | 1136 HandleCorruptDatabase(); |
1163 return false; | 1137 return false; |
1164 } | 1138 } |
1165 | 1139 |
1166 std::vector<std::string> browse_listnames; | 1140 UpdateChunkRangesForLists(browse_store_.get(), |
1167 browse_listnames.push_back(safe_browsing_util::kMalwareList); | 1141 safe_browsing_util::kMalwareList, |
1168 browse_listnames.push_back(safe_browsing_util::kPhishingList); | 1142 safe_browsing_util::kPhishingList, |
1169 UpdateChunkRanges(browse_store_.get(), browse_listnames, lists); | 1143 lists); |
1170 | 1144 |
1171 if (download_store_.get()) { | 1145 // NOTE(shess): |download_store_| used to contain kBinHashList, which has been |
1172 // This store used to contain kBinHashList in addition to | 1146 // deprecated. Code to delete the list from the store shows ~15k hits/day as |
1173 // kBinUrlList. Strip the stale data before generating the chunk | 1147 // of Feb 2014, so it has been removed. Everything _should_ be resilient to |
1174 // ranges to request. UpdateChunkRanges() will traverse the chunk | 1148 // extra data of that sort. |
1175 // list, so this is very cheap if there are no kBinHashList chunks. | 1149 UpdateChunkRangesForList(download_store_.get(), |
1176 const int listid = | 1150 safe_browsing_util::kBinUrlList, lists); |
1177 safe_browsing_util::GetListId(safe_browsing_util::kBinHashList); | |
1178 DeleteChunksFromStore(download_store_.get(), listid); | |
1179 | 1151 |
1180 // The above marks the chunks for deletion, but they are not | 1152 UpdateChunkRangesForList(csd_whitelist_store_.get(), |
1181 // actually deleted until the database is rewritten. The | 1153 safe_browsing_util::kCsdWhiteList, lists); |
1182 // following code removes the kBinHashList part of the request | |
1183 // before continuing so that UpdateChunkRanges() doesn't break. | |
1184 std::vector<std::string> download_listnames; | |
1185 download_listnames.push_back(safe_browsing_util::kBinUrlList); | |
1186 download_listnames.push_back(safe_browsing_util::kBinHashList); | |
1187 UpdateChunkRanges(download_store_.get(), download_listnames, lists); | |
1188 DCHECK_EQ(lists->back().name, | |
1189 std::string(safe_browsing_util::kBinHashList)); | |
1190 lists->pop_back(); | |
1191 | 1154 |
1192 // TODO(shess): This problem could also be handled in | 1155 UpdateChunkRangesForList(download_whitelist_store_.get(), |
1193 // BeginUpdate() by detecting the chunks to delete and rewriting | 1156 safe_browsing_util::kDownloadWhiteList, lists); |
1194 // the database before it's used. When I implemented that, it | |
1195 // felt brittle, it might be easier to just wait for some future | |
1196 // format change. | |
1197 } | |
1198 | 1157 |
1199 if (csd_whitelist_store_.get()) { | 1158 UpdateChunkRangesForList(extension_blacklist_store_.get(), |
1200 std::vector<std::string> csd_whitelist_listnames; | 1159 safe_browsing_util::kExtensionBlacklist, lists); |
1201 csd_whitelist_listnames.push_back(safe_browsing_util::kCsdWhiteList); | |
1202 UpdateChunkRanges(csd_whitelist_store_.get(), | |
1203 csd_whitelist_listnames, lists); | |
1204 } | |
1205 | 1160 |
1206 if (download_whitelist_store_.get()) { | 1161 UpdateChunkRangesForList(side_effect_free_whitelist_store_.get(), |
1207 std::vector<std::string> download_whitelist_listnames; | 1162 safe_browsing_util::kSideEffectFreeWhitelist, lists); |
1208 download_whitelist_listnames.push_back( | |
1209 safe_browsing_util::kDownloadWhiteList); | |
1210 UpdateChunkRanges(download_whitelist_store_.get(), | |
1211 download_whitelist_listnames, lists); | |
1212 } | |
1213 | 1163 |
1214 if (extension_blacklist_store_) { | 1164 UpdateChunkRangesForList(ip_blacklist_store_.get(), |
1215 UpdateChunkRanges( | 1165 safe_browsing_util::kIPBlacklist, lists); |
1216 extension_blacklist_store_.get(), | |
1217 std::vector<std::string>(1, safe_browsing_util::kExtensionBlacklist), | |
1218 lists); | |
1219 } | |
1220 | |
1221 if (side_effect_free_whitelist_store_) { | |
1222 UpdateChunkRanges( | |
1223 side_effect_free_whitelist_store_.get(), | |
1224 std::vector<std::string>( | |
1225 1, safe_browsing_util::kSideEffectFreeWhitelist), | |
1226 lists); | |
1227 } | |
1228 | |
1229 if (ip_blacklist_store_) { | |
1230 UpdateChunkRanges( | |
1231 ip_blacklist_store_.get(), | |
1232 std::vector<std::string>(1, safe_browsing_util::kIPBlacklist), | |
1233 lists); | |
1234 } | |
1235 | 1166 |
1236 corruption_detected_ = false; | 1167 corruption_detected_ = false; |
1237 change_detected_ = false; | 1168 change_detected_ = false; |
1238 return true; | 1169 return true; |
1239 } | 1170 } |
1240 | 1171 |
1241 void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { | 1172 void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { |
1242 DCHECK_EQ(creation_loop_, base::MessageLoop::current()); | 1173 DCHECK_EQ(creation_loop_, base::MessageLoop::current()); |
1243 | 1174 |
1244 // The update may have failed due to corrupt storage (for instance, | 1175 // The update may have failed due to corrupt storage (for instance, |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1784 } | 1715 } |
1785 | 1716 |
1786 bool SafeBrowsingDatabaseNew::IsMalwareIPMatchKillSwitchOn() { | 1717 bool SafeBrowsingDatabaseNew::IsMalwareIPMatchKillSwitchOn() { |
1787 SBFullHash malware_kill_switch; | 1718 SBFullHash malware_kill_switch; |
1788 crypto::SHA256HashString(kMalwareIPKillSwitchUrl, &malware_kill_switch, | 1719 crypto::SHA256HashString(kMalwareIPKillSwitchUrl, &malware_kill_switch, |
1789 sizeof(malware_kill_switch)); | 1720 sizeof(malware_kill_switch)); |
1790 std::vector<SBFullHash> full_hashes; | 1721 std::vector<SBFullHash> full_hashes; |
1791 full_hashes.push_back(malware_kill_switch); | 1722 full_hashes.push_back(malware_kill_switch); |
1792 return ContainsWhitelistedHashes(csd_whitelist_, full_hashes); | 1723 return ContainsWhitelistedHashes(csd_whitelist_, full_hashes); |
1793 } | 1724 } |
OLD | NEW |