summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-02 00:47:47 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-02 00:47:47 +0000
commit3e72ed759ddc158877986c87cb8aeb7fb20a6fcb (patch)
tree43a45da6171450a4f741740074664185d1025609 /chrome
parentbc2a400794707a885c1c7247199d8ca1cd7be5ca (diff)
downloadchromium_src-3e72ed759ddc158877986c87cb8aeb7fb20a6fcb.zip
chromium_src-3e72ed759ddc158877986c87cb8aeb7fb20a6fcb.tar.gz
chromium_src-3e72ed759ddc158877986c87cb8aeb7fb20a6fcb.tar.bz2
Add an extension blacklist safebrowsing store and use it in
extensions::Blacklist. BUG=154149 TBR=ben@chromium.org Review URL: https://codereview.chromium.org/11943016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180219 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/blacklist.cc188
-rw-r--r--chrome/browser/extensions/blacklist.h45
-rw-r--r--chrome/browser/extensions/blacklist_unittest.cc60
-rw-r--r--chrome/browser/extensions/extension_blacklist_browsertest.cc9
-rw-r--r--chrome/browser/extensions/fake_safe_browsing_database_manager.cc70
-rw-r--r--chrome/browser/extensions/fake_safe_browsing_database_manager.h52
-rw-r--r--chrome/browser/extensions/test_blacklist.cc4
-rw-r--r--chrome/browser/safe_browsing/database_manager.cc88
-rw-r--r--chrome/browser/safe_browsing/database_manager.h16
-rw-r--r--chrome/browser/safe_browsing/protocol_parser.cc6
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database.cc129
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database.h37
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database_unittest.cc30
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc8
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_test.cc4
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util.cc10
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util.h9
-rw-r--r--chrome/chrome_tests_unit.gypi24
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
20 files changed, 731 insertions, 63 deletions
diff --git a/chrome/browser/extensions/blacklist.cc b/chrome/browser/extensions/blacklist.cc
index 3d745a6..12e5a7a 100644
--- a/chrome/browser/extensions/blacklist.cc
+++ b/chrome/browser/extensions/blacklist.cc
@@ -7,13 +7,112 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/safe_browsing/database_manager.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_util.h"
+#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+
+using content::BrowserThread;
namespace extensions {
+namespace {
+
+// The safe browsing database manager to use. Make this a global/static variable
+// rather than a member of Blacklist because Blacklist accesses the real
+// database manager before it has a chance to get a fake one.
+class LazySafeBrowsingDatabaseManager {
+ public:
+ LazySafeBrowsingDatabaseManager() {
+ if (g_browser_process && g_browser_process->safe_browsing_service()) {
+ instance_ =
+ g_browser_process->safe_browsing_service()->database_manager();
+ }
+ }
+
+ scoped_refptr<SafeBrowsingDatabaseManager> get() {
+ return instance_;
+ }
+
+ void set(scoped_refptr<SafeBrowsingDatabaseManager> instance) {
+ instance_ = instance;
+ }
+
+ private:
+ scoped_refptr<SafeBrowsingDatabaseManager> instance_;
+};
+
+static base::LazyInstance<LazySafeBrowsingDatabaseManager> g_database_manager =
+ LAZY_INSTANCE_INITIALIZER;
+
+// Implementation of SafeBrowsingDatabaseManager::Client, the class which is
+// called back from safebrowsing queries.
+//
+// Constructed on any thread but lives on the IO from then on.
+class SafeBrowsingClientImpl
+ : public SafeBrowsingDatabaseManager::Client,
+ public base::RefCountedThreadSafe<SafeBrowsingClientImpl> {
+ public:
+ typedef base::Callback<void(const std::set<std::string>&)> OnResultCallback;
+
+ // Constructs a client to query the database manager for |extension_ids| and
+ // run |callback| with the IDs of those which have been blacklisted.
+ SafeBrowsingClientImpl(
+ const std::set<std::string>& extension_ids,
+ const OnResultCallback& callback)
+ : callback_message_loop_(base::MessageLoopProxy::current()),
+ callback_(callback) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&SafeBrowsingClientImpl::StartCheck, this,
+ g_database_manager.Get().get(),
+ extension_ids));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<SafeBrowsingClientImpl>;
+ virtual ~SafeBrowsingClientImpl() {}
+
+ // Pass |database_manager| as a parameter to avoid touching
+ // SafeBrowsingService on the IO thread.
+ void StartCheck(scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+ const std::set<std::string>& extension_ids) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (database_manager->CheckExtensionIDs(extension_ids, this)) {
+ // Definitely not blacklisted. Callback immediately.
+ callback_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(callback_, std::set<std::string>()));
+ return;
+ }
+ // Something might be blacklisted, response will come in
+ // OnCheckExtensionsResult.
+ AddRef(); // Balanced in OnCheckExtensionsResult
+ }
+
+ void OnCheckExtensionsResult(const std::set<std::string>& hits) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ callback_message_loop_->PostTask(FROM_HERE, base::Bind(callback_, hits));
+ Release(); // Balanced in StartCheck.
+ }
+
+ scoped_refptr<base::MessageLoopProxy> callback_message_loop_;
+ OnResultCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SafeBrowsingClientImpl);
+};
+
+} // namespace
+
Blacklist::Observer::Observer(Blacklist* blacklist) : blacklist_(blacklist) {
blacklist_->AddObserver(this);
}
@@ -22,7 +121,32 @@ Blacklist::Observer::~Observer() {
blacklist_->RemoveObserver(this);
}
+Blacklist::ScopedDatabaseManagerForTest::ScopedDatabaseManagerForTest(
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager)
+ : original_(GetDatabaseManager()) {
+ SetDatabaseManager(database_manager);
+}
+
+Blacklist::ScopedDatabaseManagerForTest::~ScopedDatabaseManagerForTest() {
+ SetDatabaseManager(original_);
+}
+
Blacklist::Blacklist(ExtensionPrefs* prefs) : prefs_(prefs) {
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager =
+ g_database_manager.Get().get();
+ if (database_manager) {
+ registrar_.Add(this,
+ chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
+ content::Source<SafeBrowsingDatabaseManager>(
+ database_manager));
+ }
+
+ // TODO(kalman): Delete anything from the pref blacklist that is in the
+ // safebrowsing blacklist (of course, only entries for which the extension
+ // hasn't been installed).
+ //
+ // Or maybe just wait until we're able to delete the pref blacklist
+ // altogether (when we're sure it's a strict subset of the safebrowsing one).
}
Blacklist::~Blacklist() {
@@ -30,20 +154,37 @@ Blacklist::~Blacklist() {
void Blacklist::GetBlacklistedIDs(const std::set<std::string>& ids,
const GetBlacklistedIDsCallback& callback) {
- // TODO(kalman): Get the blacklisted IDs from the safebrowsing list.
- // This will require going to the IO thread and back.
- std::set<std::string> blacklisted_ids;
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // The blacklisted IDs are the union of those blacklisted in prefs and
+ // those blacklisted from safe browsing.
+ std::set<std::string> pref_blacklisted_ids;
for (std::set<std::string>::const_iterator it = ids.begin();
it != ids.end(); ++it) {
if (prefs_->IsExtensionBlacklisted(*it))
- blacklisted_ids.insert(*it);
+ pref_blacklisted_ids.insert(*it);
}
- MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(callback, blacklisted_ids));
+
+ if (!g_database_manager.Get().get()) {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, pref_blacklisted_ids));
+ return;
+ }
+
+ // Constructing the SafeBrowsingClientImpl begins the process of asking
+ // safebrowsing for the blacklisted extensions.
+ new SafeBrowsingClientImpl(
+ ids,
+ base::Bind(&Blacklist::OnSafeBrowsingResponse, AsWeakPtr(),
+ pref_blacklisted_ids,
+ callback));
}
void Blacklist::SetFromUpdater(const std::vector<std::string>& ids,
const std::string& version) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
std::set<std::string> ids_as_set;
for (std::vector<std::string>::const_iterator it = ids.begin();
it != ids.end(); ++it) {
@@ -82,11 +223,44 @@ void Blacklist::SetFromUpdater(const std::vector<std::string>& ids,
}
void Blacklist::AddObserver(Observer* observer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.AddObserver(observer);
}
void Blacklist::RemoveObserver(Observer* observer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.RemoveObserver(observer);
}
+// static
+void Blacklist::SetDatabaseManager(
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager) {
+ g_database_manager.Get().set(database_manager);
+}
+
+// static
+scoped_refptr<SafeBrowsingDatabaseManager> Blacklist::GetDatabaseManager() {
+ return g_database_manager.Get().get();
+}
+
+void Blacklist::OnSafeBrowsingResponse(
+ const std::set<std::string>& pref_blacklisted_ids,
+ const GetBlacklistedIDsCallback& callback,
+ const std::set<std::string>& safebrowsing_blacklisted_ids) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ std::set<std::string> blacklist = pref_blacklisted_ids;
+ blacklist.insert(safebrowsing_blacklisted_ids.begin(),
+ safebrowsing_blacklisted_ids.end());
+
+ callback.Run(blacklist);
+}
+
+void Blacklist::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, type);
+ FOR_EACH_OBSERVER(Observer, observers_, OnBlacklistUpdated());
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/blacklist.h b/chrome/browser/extensions/blacklist.h
index 89705a5..d5cdce5 100644
--- a/chrome/browser/extensions/blacklist.h
+++ b/chrome/browser/extensions/blacklist.h
@@ -10,7 +10,11 @@
#include <vector>
#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "chrome/browser/safe_browsing/database_manager.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
namespace extensions {
@@ -18,7 +22,8 @@ class Extension;
class ExtensionPrefs;
// A blacklist of extensions.
-class Blacklist {
+class Blacklist : public content::NotificationObserver,
+ public base::SupportsWeakPtr<Blacklist> {
public:
class Observer {
public:
@@ -34,17 +39,33 @@ class Blacklist {
Blacklist* blacklist_;
};
+ class ScopedDatabaseManagerForTest {
+ public:
+ explicit ScopedDatabaseManagerForTest(
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager);
+
+ ~ScopedDatabaseManagerForTest();
+
+ private:
+ scoped_refptr<SafeBrowsingDatabaseManager> original_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDatabaseManagerForTest);
+ };
+
typedef base::Callback<void(const std::set<std::string>&)>
GetBlacklistedIDsCallback;
// |prefs_| must outlive this.
explicit Blacklist(ExtensionPrefs* prefs);
- ~Blacklist();
+ virtual ~Blacklist();
// From the set of extension IDs passed in via |ids|, asynchronously checks
// which are blacklisted and includes them in the resulting set passed
// via |callback|, which will be sent on the caller's message loop.
+ //
+ // For a synchronous version which ONLY CHECKS CURRENTLY INSTALLED EXTENSIONS
+ // see ExtensionPrefs::IsExtensionBlacklisted.
void GetBlacklistedIDs(const std::set<std::string>& ids,
const GetBlacklistedIDsCallback& callback);
@@ -57,12 +78,32 @@ class Blacklist {
void RemoveObserver(Observer* observer);
private:
+ // Use via ScopedDatabaseManagerForTest.
+ static void SetDatabaseManager(
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager);
+ static scoped_refptr<SafeBrowsingDatabaseManager> GetDatabaseManager();
+
+ // Handles the |safebrowsing_blacklisted_ids| response from querying the
+ // safebrowsing blacklist, given that we know |pref_blacklisted_ids| are
+ // already blacklisted. Responds to |callback| with the union.
+ void OnSafeBrowsingResponse(
+ const std::set<std::string>& pref_blacklisted_ids,
+ const GetBlacklistedIDsCallback& callback,
+ const std::set<std::string>& safebrowsing_blacklisted_ids);
+
+ // content::NotificationObserver
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
ObserverList<Observer> observers_;
ExtensionPrefs* const prefs_;
std::set<std::string> prefs_blacklist_;
+ content::NotificationRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(Blacklist);
};
diff --git a/chrome/browser/extensions/blacklist_unittest.cc b/chrome/browser/extensions/blacklist_unittest.cc
index 9572a5c..31d20ba 100644
--- a/chrome/browser/extensions/blacklist_unittest.cc
+++ b/chrome/browser/extensions/blacklist_unittest.cc
@@ -7,8 +7,10 @@
#include "base/run_loop.h"
#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/fake_safe_browsing_database_manager.h"
#include "chrome/browser/extensions/test_blacklist.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
+#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
@@ -18,6 +20,11 @@ class BlacklistTest : public testing::Test {
public:
BlacklistTest()
: prefs_(message_loop_.message_loop_proxy()),
+ ui_thread_(content::BrowserThread::UI, &message_loop_),
+ io_thread_(content::BrowserThread::IO, &message_loop_),
+ safe_browsing_database_manager_(
+ new FakeSafeBrowsingDatabaseManager()),
+ scoped_blacklist_database_manager_(safe_browsing_database_manager_),
blacklist_(prefs_.prefs()) {
}
@@ -30,6 +37,13 @@ class BlacklistTest : public testing::Test {
TestExtensionPrefs prefs_;
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread io_thread_;
+
+ scoped_refptr<FakeSafeBrowsingDatabaseManager>
+ safe_browsing_database_manager_;
+ Blacklist::ScopedDatabaseManagerForTest scoped_blacklist_database_manager_;
+
Blacklist blacklist_;
};
@@ -141,5 +155,51 @@ TEST_F(BlacklistTest, OnlyIncludesRequestedIDs) {
EXPECT_EQ(blacklist_expected, blacklist_actual);
}
+TEST_F(BlacklistTest, PrefsVsSafeBrowsing) {
+ scoped_refptr<const Extension> extension_a = prefs_.AddExtension("a");
+ scoped_refptr<const Extension> extension_b = prefs_.AddExtension("b");
+ scoped_refptr<const Extension> extension_c = prefs_.AddExtension("c");
+
+ // Prefs have a and b blacklisted, safebrowsing has b and c.
+ prefs_.prefs()->SetExtensionBlacklisted(extension_a->id(), true);
+ prefs_.prefs()->SetExtensionBlacklisted(extension_b->id(), true);
+ {
+ std::set<std::string> bc;
+ bc.insert(extension_b->id());
+ bc.insert(extension_c->id());
+ safe_browsing_database_manager_->set_unsafe_ids(bc);
+ }
+
+ // The manager is still disabled at this point, so c won't be blacklisted.
+ EXPECT_TRUE(IsBlacklisted(extension_a));
+ EXPECT_TRUE(IsBlacklisted(extension_b));
+ EXPECT_FALSE(IsBlacklisted(extension_c));
+
+ // Now it should be.
+ safe_browsing_database_manager_->set_enabled(true);
+ EXPECT_TRUE(IsBlacklisted(extension_a));
+ EXPECT_TRUE(IsBlacklisted(extension_b));
+ EXPECT_TRUE(IsBlacklisted(extension_c));
+
+ // Corner case: nothing in safebrowsing (but still enabled).
+ safe_browsing_database_manager_->set_unsafe_ids(std::set<std::string>());
+ EXPECT_TRUE(IsBlacklisted(extension_a));
+ EXPECT_TRUE(IsBlacklisted(extension_b));
+ EXPECT_FALSE(IsBlacklisted(extension_c));
+
+ // Corner case: nothing in prefs.
+ prefs_.prefs()->SetExtensionBlacklisted(extension_a->id(), false);
+ prefs_.prefs()->SetExtensionBlacklisted(extension_b->id(), false);
+ {
+ std::set<std::string> bc;
+ bc.insert(extension_b->id());
+ bc.insert(extension_c->id());
+ safe_browsing_database_manager_->set_unsafe_ids(bc);
+ }
+ EXPECT_FALSE(IsBlacklisted(extension_a));
+ EXPECT_TRUE(IsBlacklisted(extension_b));
+ EXPECT_TRUE(IsBlacklisted(extension_c));
+}
+
} // namespace extensions
} // namespace
diff --git a/chrome/browser/extensions/extension_blacklist_browsertest.cc b/chrome/browser/extensions/extension_blacklist_browsertest.cc
index cc6bc24..a7307f1 100644
--- a/chrome/browser/extensions/extension_blacklist_browsertest.cc
+++ b/chrome/browser/extensions/extension_blacklist_browsertest.cc
@@ -169,7 +169,12 @@ class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest {
ExtensionBlacklistBrowserTest()
: info_a_("install/install.crx", "ogdbpbegnmindpdjfafpmpicikegejdj"),
info_b_("autoupdate/v1.crx", "ogjcoiohnmldgjemafoockdghcjciccf"),
- info_c_("hosted_app.crx", "kbmnembihfiondgfjekmnmcbddelicoi") {}
+ info_c_("hosted_app.crx", "kbmnembihfiondgfjekmnmcbddelicoi"),
+ // Just disable the safe browsing altogether.
+ // TODO(kalman): a different approach will be needed when the blacklist
+ // comes entirely from safe browsing.
+ scoped_blacklist_database_manager_(
+ scoped_refptr<SafeBrowsingDatabaseManager>(NULL)) {}
virtual ~ExtensionBlacklistBrowserTest() {}
@@ -230,6 +235,8 @@ class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest {
}
return testing::AssertionSuccess();
}
+
+ Blacklist::ScopedDatabaseManagerForTest scoped_blacklist_database_manager_;
};
// Stage 1: blacklisting when there weren't any extensions installed when the
diff --git a/chrome/browser/extensions/fake_safe_browsing_database_manager.cc b/chrome/browser/extensions/fake_safe_browsing_database_manager.cc
new file mode 100644
index 0000000..573c8d6
--- /dev/null
+++ b/chrome/browser/extensions/fake_safe_browsing_database_manager.cc
@@ -0,0 +1,70 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/fake_safe_browsing_database_manager.h"
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include "base/bind_helpers.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_util.h"
+
+namespace extensions {
+
+FakeSafeBrowsingDatabaseManager::FakeSafeBrowsingDatabaseManager()
+ : SafeBrowsingDatabaseManager(
+ make_scoped_refptr(SafeBrowsingService::CreateSafeBrowsingService())),
+ enabled_(false) {
+}
+
+FakeSafeBrowsingDatabaseManager::~FakeSafeBrowsingDatabaseManager() {
+}
+
+bool FakeSafeBrowsingDatabaseManager::CheckExtensionIDs(
+ const std::set<std::string>& extension_ids,
+ Client* client) {
+ if (!enabled_)
+ return true;
+
+ // Need to construct the full SafeBrowsingCheck rather than calling
+ // OnCheckExtensionsResult directly because it's protected. Grr!
+ std::vector<std::string> extension_ids_vector(extension_ids.begin(),
+ extension_ids.end());
+ std::vector<SBFullHash> extension_id_hashes;
+ std::transform(extension_ids_vector.begin(), extension_ids_vector.end(),
+ std::back_inserter(extension_id_hashes),
+ safe_browsing_util::StringToSBFullHash);
+
+ scoped_ptr<SafeBrowsingCheck> safe_browsing_check(
+ new SafeBrowsingCheck(std::vector<GURL>(),
+ extension_id_hashes,
+ client,
+ safe_browsing_util::EXTENSIONBLACKLIST));
+
+ for (size_t i = 0; i < extension_ids_vector.size(); ++i) {
+ const std::string& extension_id = extension_ids_vector[i];
+ if (unsafe_ids_.count(extension_id))
+ safe_browsing_check->full_hash_results[i] = SB_THREAT_TYPE_EXTENSION;
+ }
+
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeSafeBrowsingDatabaseManager::OnSafeBrowsingResult,
+ this,
+ base::Passed(&safe_browsing_check),
+ client));
+ return false;
+}
+
+void FakeSafeBrowsingDatabaseManager::OnSafeBrowsingResult(
+ scoped_ptr<SafeBrowsingCheck> result,
+ Client* client) {
+ client->OnSafeBrowsingResult(*result);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/fake_safe_browsing_database_manager.h b/chrome/browser/extensions/fake_safe_browsing_database_manager.h
new file mode 100644
index 0000000..2a91b73
--- /dev/null
+++ b/chrome/browser/extensions/fake_safe_browsing_database_manager.h
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_FAKE_SAFE_BROWSING_DATABASE_MANAGER_H_
+#define CHROME_BROWSER_EXTENSIONS_FAKE_SAFE_BROWSING_DATABASE_MANAGER_H_
+
+#include <set>
+#include <string>
+
+#include "chrome/browser/safe_browsing/database_manager.h"
+
+namespace extensions {
+
+// A fake safe browsing database manager for use with extensions tests.
+//
+// By default it is disabled (returning true and ignoring |unsafe_ids_|);
+// call set_enabled to enable it.
+class FakeSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
+ public:
+ FakeSafeBrowsingDatabaseManager();
+
+ // Returns true if synchronously safe, false if not in which case the unsafe
+ // IDs taken from |unsafe_ids_| are passed to to |client| on the current
+ // message loop.
+ virtual bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
+ Client* client) OVERRIDE;
+
+ void set_enabled(bool enabled) { enabled_ = enabled; }
+
+ void set_unsafe_ids(const std::set<std::string>& unsafe_ids) {
+ unsafe_ids_ = unsafe_ids;
+ }
+
+ private:
+ virtual ~FakeSafeBrowsingDatabaseManager();
+
+ // Runs client->SafeBrowsingResult(result).
+ void OnSafeBrowsingResult(scoped_ptr<SafeBrowsingCheck> result,
+ Client* client);
+
+ // Whether to respond to CheckExtensionIDs immediately with true (indicating
+ // that there is definitely no extension ID match).
+ bool enabled_;
+
+ // The extension IDs considered unsafe.
+ std::set<std::string> unsafe_ids_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_FAKE_SAFE_BROWSING_DATABASE_MANAGER_H_
diff --git a/chrome/browser/extensions/test_blacklist.cc b/chrome/browser/extensions/test_blacklist.cc
index 138804d..249d929 100644
--- a/chrome/browser/extensions/test_blacklist.cc
+++ b/chrome/browser/extensions/test_blacklist.cc
@@ -31,9 +31,7 @@ bool TestBlacklist::IsBlacklisted(const std::string& extension_id) {
std::set<std::string> blacklist_set;
blacklist_->GetBlacklistedIDs(id_set,
base::Bind(&Assign, &blacklist_set));
- base::RunLoop run_loop;
- MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
+ base::RunLoop().RunUntilIdle();
return blacklist_set.count(extension_id) > 0;
}
diff --git a/chrome/browser/safe_browsing/database_manager.cc b/chrome/browser/safe_browsing/database_manager.cc
index 1cbb761..fe37cbc 100644
--- a/chrome/browser/safe_browsing/database_manager.cc
+++ b/chrome/browser/safe_browsing/database_manager.cc
@@ -75,23 +75,22 @@ SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
need_get_hash(false),
check_type(check_type),
timeout_factory_(NULL) {
- DCHECK(urls.empty() || full_hashes.empty()) <<
- "There must be either urls or full_hashes to check";
- DCHECK(!urls.empty() || !full_hashes.empty()) <<
- "There cannot be both urls and full_hashes to check";
+ DCHECK_EQ(urls.empty(), !full_hashes.empty())
+ << "Exactly one of urls and full_hashes must be set";
}
SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
const SafeBrowsingCheck& check) {
+ DCHECK_EQ(check.urls.size(), check.url_results.size());
+ DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
if (!check.urls.empty()) {
DCHECK(check.full_hashes.empty());
switch (check.check_type) {
case safe_browsing_util::MALWARE:
case safe_browsing_util::PHISH:
DCHECK_EQ(1u, check.urls.size());
- DCHECK_EQ(1u, check.url_results.size());
OnCheckBrowseUrlResult(check.urls[0], check.url_results[0]);
break;
case safe_browsing_util::BINURL:
@@ -108,11 +107,21 @@ void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
switch (check.check_type) {
case safe_browsing_util::BINHASH:
DCHECK_EQ(1u, check.full_hashes.size());
- DCHECK_EQ(1u, check.full_hash_results.size());
OnCheckDownloadHashResult(
safe_browsing_util::SBFullHashToString(check.full_hashes[0]),
check.full_hash_results[0]);
break;
+ case safe_browsing_util::EXTENSIONBLACKLIST: {
+ std::set<std::string> unsafe_extension_ids;
+ for (size_t i = 0; i < check.full_hashes.size(); ++i) {
+ std::string extension_id =
+ safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
+ if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
+ unsafe_extension_ids.insert(extension_id);
+ }
+ OnCheckExtensionsResult(unsafe_extension_ids);
+ break;
+ }
default:
NOTREACHED();
}
@@ -129,6 +138,7 @@ SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
enable_download_protection_(false),
enable_csd_whitelist_(false),
enable_download_whitelist_(false),
+ enable_extension_blacklist_(false),
update_in_progress_(false),
database_update_in_progress_(false),
closing_database_(false),
@@ -149,6 +159,10 @@ SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
// list right now. This means that we need to be able to disable this list
// for the SafeBrowsing test to pass.
enable_download_whitelist_ = enable_csd_whitelist_;
+
+ // TODO(kalman): there really shouldn't be a flag for this.
+ enable_extension_blacklist_ =
+ !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
}
SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
@@ -206,6 +220,33 @@ bool SafeBrowsingDatabaseManager::CheckDownloadHash(
return false;
}
+bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
+ const std::set<std::string>& extension_ids,
+ Client* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (!enabled_ || !enable_extension_blacklist_)
+ return true;
+
+ std::vector<SBFullHash> extension_id_hashes;
+ std::transform(extension_ids.begin(), extension_ids.end(),
+ std::back_inserter(extension_id_hashes),
+ safe_browsing_util::StringToSBFullHash);
+
+ SafeBrowsingCheck* check = new SafeBrowsingCheck(
+ std::vector<GURL>(),
+ extension_id_hashes,
+ client,
+ safe_browsing_util::EXTENSIONBLACKLIST);
+
+ StartSafeBrowsingCheck(
+ check,
+ base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
+ this,
+ check));
+ return false;
+}
+
bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
@@ -533,7 +574,8 @@ SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
SafeBrowsingDatabase* database =
SafeBrowsingDatabase::Create(enable_download_protection_,
enable_csd_whitelist_,
- enable_download_whitelist_);
+ enable_download_whitelist_,
+ enable_extension_blacklist_);
database->Init(SafeBrowsingService::GetBaseFilename());
{
@@ -711,6 +753,10 @@ SBThreatType SafeBrowsingDatabaseManager::GetThreatTypeFromListname(
return SB_THREAT_TYPE_BINARY_MALWARE_HASH;
}
+ if (safe_browsing_util::IsExtensionList(list_name)) {
+ return SB_THREAT_TYPE_EXTENSION;
+ }
+
DVLOG(1) << "Unknown safe browsing list " << list_name;
return SB_THREAT_TYPE_SAFE;
}
@@ -880,6 +926,34 @@ void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
}
+void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
+ SafeBrowsingCheck* check) {
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
+
+ std::vector<SBPrefix> prefixes;
+ for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
+ it != check->full_hashes.end(); ++it) {
+ prefixes.push_back((*it).prefix);
+ }
+ database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
+
+ if (check->prefix_hits.empty()) {
+ // No matches for any extensions.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
+ check));
+ } else {
+ // Some prefixes matched, we need to ask Google whether they're legit.
+ check->need_get_hash = true;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
+ }
+}
+
void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(check);
diff --git a/chrome/browser/safe_browsing/database_manager.h b/chrome/browser/safe_browsing/database_manager.h
index 06669bb..922715a 100644
--- a/chrome/browser/safe_browsing/database_manager.h
+++ b/chrome/browser/safe_browsing/database_manager.h
@@ -107,6 +107,10 @@ class SafeBrowsingDatabaseManager
// Called when the result of checking a download binary hash is known.
virtual void OnCheckDownloadHashResult(const std::string& hash,
SBThreatType threat_type) {}
+
+ // Called when the result of checking a set of extensions is known.
+ virtual void OnCheckExtensionsResult(
+ const std::set<std::string>& threats) {}
};
// Creates the safe browsing service. Need to initialize before using.
@@ -136,6 +140,12 @@ class SafeBrowsingDatabaseManager
// Result will be passed to callback in |client|.
virtual bool CheckDownloadHash(const std::string& full_hash, Client* client);
+ // Check which prefixes in |extension_ids| are in the safebrowsing blacklist.
+ // Returns true if not, false if further checks need to be made in which case
+ // the result will be passed to |client|.
+ virtual bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
+ Client* client);
+
// Check if the |url| matches any of the full-length hashes from the
// client-side phishing detection whitelist. Returns true if there was a
// match and false otherwise. To make sure we are conservative we will return
@@ -304,6 +314,9 @@ class SafeBrowsingDatabaseManager
// Calls the Client's callback on IO thread after CheckDownloadHash finishes.
void CheckDownloadHashDone(SafeBrowsingCheck* check);
+ // Checks all extension ID hashes on safe_browsing_thread_.
+ void CheckExtensionIDsOnSBThread(SafeBrowsingCheck* check);
+
// Helper function that calls safe browsing client and cleans up |checks_|.
void SafeBrowsingCheckDone(SafeBrowsingCheck* check);
@@ -352,6 +365,9 @@ class SafeBrowsingDatabaseManager
// Indicate if the download whitelist should be enabled or not.
bool enable_download_whitelist_;
+ // Indicate if the extension blacklist should be enabled.
+ bool enable_extension_blacklist_;
+
// The SafeBrowsing thread that runs database operations.
//
// Note: Functions that run on this thread should run synchronously and return
diff --git a/chrome/browser/safe_browsing/protocol_parser.cc b/chrome/browser/safe_browsing/protocol_parser.cc
index 59a98db..7aac1d0 100644
--- a/chrome/browser/safe_browsing/protocol_parser.cc
+++ b/chrome/browser/safe_browsing/protocol_parser.cc
@@ -264,7 +264,8 @@ bool SafeBrowsingProtocolParser::ParseAddChunk(const std::string& list_name,
SBEntry::ADD_PREFIX : SBEntry::ADD_FULL_HASH;
if (list_name == safe_browsing_util::kBinHashList ||
- list_name == safe_browsing_util::kDownloadWhiteList) {
+ list_name == safe_browsing_util::kDownloadWhiteList ||
+ list_name == safe_browsing_util::kExtensionBlacklist) {
// These lists only contain prefixes, no HOSTKEY and COUNT.
DCHECK_EQ(0, remaining % hash_len);
prefix_count = remaining / hash_len;
@@ -309,7 +310,8 @@ bool SafeBrowsingProtocolParser::ParseSubChunk(const std::string& list_name,
SBEntry::SUB_PREFIX : SBEntry::SUB_FULL_HASH;
if (list_name == safe_browsing_util::kBinHashList ||
- list_name == safe_browsing_util::kDownloadWhiteList) {
+ list_name == safe_browsing_util::kDownloadWhiteList ||
+ list_name == safe_browsing_util::kExtensionBlacklist) {
SBChunkHost chunk_host;
// Set host to 0 and it won't be used for kBinHashList.
chunk_host.host = 0;
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc
index f2d95ca..e74528a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database.cc
@@ -40,6 +40,9 @@ const FilePath::CharType kCsdWhitelistDBFile[] =
// Filename suffix for the download whitelist store.
const FilePath::CharType kDownloadWhitelistDBFile[] =
FILE_PATH_LITERAL(" Download Whitelist");
+// Filename suffix for the extension blacklist store.
+const FilePath::CharType kExtensionBlacklistDBFile[] =
+ FILE_PATH_LITERAL(" Extension Blacklist");
// Filename suffix for browse store.
// TODO(shess): "Safe Browsing Bloom Prefix Set" is full of win.
// Unfortunately, to change the name implies lots of transition code
@@ -310,12 +313,14 @@ class SafeBrowsingDatabaseFactoryImpl : public SafeBrowsingDatabaseFactory {
virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
bool enable_download_protection,
bool enable_client_side_whitelist,
- bool enable_download_whitelist) {
+ bool enable_download_whitelist,
+ bool enable_extension_blacklist) {
return new SafeBrowsingDatabaseNew(
new SafeBrowsingStoreFile,
enable_download_protection ? new SafeBrowsingStoreFile : NULL,
enable_client_side_whitelist ? new SafeBrowsingStoreFile : NULL,
- enable_download_whitelist ? new SafeBrowsingStoreFile : NULL);
+ enable_download_whitelist ? new SafeBrowsingStoreFile : NULL,
+ enable_extension_blacklist ? new SafeBrowsingStoreFile : NULL);
}
SafeBrowsingDatabaseFactoryImpl() { }
@@ -335,12 +340,14 @@ SafeBrowsingDatabaseFactory* SafeBrowsingDatabase::factory_ = NULL;
SafeBrowsingDatabase* SafeBrowsingDatabase::Create(
bool enable_download_protection,
bool enable_client_side_whitelist,
- bool enable_download_whitelist) {
+ bool enable_download_whitelist,
+ bool enable_extension_blacklist) {
if (!factory_)
factory_ = new SafeBrowsingDatabaseFactoryImpl();
return factory_->CreateSafeBrowsingDatabase(enable_download_protection,
enable_client_side_whitelist,
- enable_download_whitelist);
+ enable_download_whitelist,
+ enable_extension_blacklist);
}
SafeBrowsingDatabase::~SafeBrowsingDatabase() {
@@ -382,6 +389,12 @@ FilePath SafeBrowsingDatabase::DownloadWhitelistDBFilename(
return FilePath(db_filename.value() + kDownloadWhitelistDBFile);
}
+// static
+FilePath SafeBrowsingDatabase::ExtensionBlacklistDBFilename(
+ const FilePath& db_filename) {
+ return FilePath(db_filename.value() + kExtensionBlacklistDBFile);
+}
+
SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) {
if (list_id == safe_browsing_util::PHISH ||
list_id == safe_browsing_util::MALWARE) {
@@ -393,6 +406,8 @@ SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) {
return csd_whitelist_store_.get();
} else if (list_id == safe_browsing_util::DOWNLOADWHITELIST) {
return download_whitelist_store_.get();
+ } else if (list_id == safe_browsing_util::EXTENSIONBLACKLIST) {
+ return extension_blacklist_store_.get();
}
return NULL;
}
@@ -416,18 +431,21 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew()
DCHECK(!download_store_.get());
DCHECK(!csd_whitelist_store_.get());
DCHECK(!download_whitelist_store_.get());
+ DCHECK(!extension_blacklist_store_.get());
}
SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew(
SafeBrowsingStore* browse_store,
SafeBrowsingStore* download_store,
SafeBrowsingStore* csd_whitelist_store,
- SafeBrowsingStore* download_whitelist_store)
+ SafeBrowsingStore* download_whitelist_store,
+ SafeBrowsingStore* extension_blacklist_store)
: creation_loop_(MessageLoop::current()),
browse_store_(browse_store),
download_store_(download_store),
csd_whitelist_store_(csd_whitelist_store),
download_whitelist_store_(download_whitelist_store),
+ extension_blacklist_store_(extension_blacklist_store),
ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)),
corruption_detected_(false) {
DCHECK(browse_store_.get());
@@ -444,6 +462,7 @@ void SafeBrowsingDatabaseNew::Init(const FilePath& filename_base) {
DCHECK(download_filename_.empty());
DCHECK(csd_whitelist_filename_.empty());
DCHECK(download_whitelist_filename_.empty());
+ DCHECK(extension_blacklist_filename_.empty());
browse_filename_ = BrowseDBFilename(filename_base);
prefix_set_filename_ = PrefixSetForFilename(browse_filename_);
@@ -508,6 +527,16 @@ void SafeBrowsingDatabaseNew::Init(const FilePath& filename_base) {
} else {
WhitelistEverything(&download_whitelist_); // Just to be safe.
}
+
+ if (extension_blacklist_store_.get()) {
+ extension_blacklist_filename_ = ExtensionBlacklistDBFilename(filename_base);
+ extension_blacklist_store_->Init(
+ extension_blacklist_filename_,
+ base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase,
+ base::Unretained(this)));
+ DVLOG(1) << "Init extension blacklist store: "
+ << extension_blacklist_filename_.value();
+ }
}
bool SafeBrowsingDatabaseNew::ResetDatabase() {
@@ -634,6 +663,19 @@ bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedUrl(const GURL& url) {
return ContainsWhitelistedHashes(download_whitelist_, full_hashes);
}
+bool SafeBrowsingDatabaseNew::ContainsExtensionPrefixes(
+ const std::vector<SBPrefix>& prefixes,
+ std::vector<SBPrefix>* prefix_hits) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+ if (!extension_blacklist_store_)
+ return false;
+
+ return MatchAddPrefixes(extension_blacklist_store_.get(),
+ safe_browsing_util::EXTENSIONBLACKLIST % 2,
+ prefixes,
+ prefix_hits);
+}
+
bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedString(
const std::string& str) {
SBFullHash hash;
@@ -925,6 +967,13 @@ bool SafeBrowsingDatabaseNew::UpdateStarted(
return false;
}
+ if (extension_blacklist_store_ &&
+ !extension_blacklist_store_->BeginUpdate()) {
+ RecordFailure(FAILURE_EXTENSION_BLACKLIST_UPDATE_BEGIN);
+ HandleCorruptDatabase();
+ return false;
+ }
+
std::vector<std::string> browse_listnames;
browse_listnames.push_back(safe_browsing_util::kMalwareList);
browse_listnames.push_back(safe_browsing_util::kPhishingList);
@@ -973,6 +1022,13 @@ bool SafeBrowsingDatabaseNew::UpdateStarted(
download_whitelist_listnames, lists);
}
+ if (extension_blacklist_store_) {
+ UpdateChunkRanges(
+ extension_blacklist_store_.get(),
+ std::vector<std::string>(1, safe_browsing_util::kExtensionBlacklist),
+ lists);
+ }
+
corruption_detected_ = false;
change_detected_ = false;
return true;
@@ -1001,6 +1057,11 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
!download_whitelist_store_->CheckValidity()) {
DLOG(ERROR) << "Safe-browsing download whitelist database corrupt.";
}
+
+ if (extension_blacklist_store_ &&
+ !extension_blacklist_store_->CheckValidity()) {
+ DLOG(ERROR) << "Safe-browsing extension blacklist database corrupt.";
+ }
}
if (corruption_detected_)
@@ -1020,10 +1081,20 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
csd_whitelist_store_->CancelUpdate();
if (download_whitelist_store_.get())
download_whitelist_store_->CancelUpdate();
+ if (extension_blacklist_store_)
+ extension_blacklist_store_->CancelUpdate();
return;
}
- UpdateDownloadStore();
+ if (download_store_) {
+ int64 size_bytes = UpdateHashPrefixStore(
+ download_filename_,
+ download_store_.get(),
+ FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH);
+ UMA_HISTOGRAM_COUNTS("SB2.DownloadDatabaseKilobytes",
+ static_cast<int>(size_bytes / 1024));
+ }
+
UpdateBrowseStore();
UpdateWhitelistStore(csd_whitelist_filename_,
csd_whitelist_store_.get(),
@@ -1031,6 +1102,15 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
UpdateWhitelistStore(download_whitelist_filename_,
download_whitelist_store_.get(),
&download_whitelist_);
+
+ if (extension_blacklist_store_) {
+ int64 size_bytes = UpdateHashPrefixStore(
+ extension_blacklist_filename_,
+ extension_blacklist_store_.get(),
+ FAILURE_EXTENSION_BLACKLIST_UPDATE_FINISH);
+ UMA_HISTOGRAM_COUNTS("SB2.ExtensionBlacklistKilobytes",
+ static_cast<int>(size_bytes / 1024));
+ }
}
void SafeBrowsingDatabaseNew::UpdateWhitelistStore(
@@ -1065,14 +1145,14 @@ void SafeBrowsingDatabaseNew::UpdateWhitelistStore(
LoadWhitelist(full_hashes, whitelist);
}
-void SafeBrowsingDatabaseNew::UpdateDownloadStore() {
- if (!download_store_.get())
- return;
-
- // For download, we don't cache and save full hashes.
+int64 SafeBrowsingDatabaseNew::UpdateHashPrefixStore(
+ const FilePath& store_filename,
+ SafeBrowsingStore* store,
+ FailureType failure_type) {
+ // We don't cache and save full hashes.
std::vector<SBAddFullHash> empty_add_hashes;
- // For download, backend lookup happens only if a prefix is in add list.
+ // Backend lookup happens only if a prefix is in add list.
std::set<SBPrefix> empty_miss_cache;
// These results are not used after this call. Simply ignore the
@@ -1080,19 +1160,18 @@ void SafeBrowsingDatabaseNew::UpdateDownloadStore() {
SBAddPrefixes add_prefixes_result;
std::vector<SBAddFullHash> add_full_hashes_result;
- if (!download_store_->FinishUpdate(empty_add_hashes,
- empty_miss_cache,
- &add_prefixes_result,
- &add_full_hashes_result))
- RecordFailure(FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH);
-
- int64 file_size = GetFileSizeOrZero(download_filename_);
- UMA_HISTOGRAM_COUNTS("SB2.DownloadDatabaseKilobytes",
- static_cast<int>(file_size / 1024));
+ if (!store->FinishUpdate(empty_add_hashes,
+ empty_miss_cache,
+ &add_prefixes_result,
+ &add_full_hashes_result)) {
+ RecordFailure(failure_type);
+ }
#if defined(OS_MACOSX)
- base::mac::SetFileBackupExclusion(download_filename_);
+ base::mac::SetFileBackupExclusion(store_filename);
#endif
+
+ return GetFileSizeOrZero(store_filename);
}
void SafeBrowsingDatabaseNew::UpdateBrowseStore() {
@@ -1278,7 +1357,11 @@ bool SafeBrowsingDatabaseNew::Delete() {
if (!r6)
RecordFailure(FAILURE_DATABASE_PREFIX_SET_DELETE);
- return r1 && r2 && r3 && r4 && r5 && r6;
+ const bool r7 = file_util::Delete(extension_blacklist_filename_, false);
+ if (!r7)
+ RecordFailure(FAILURE_EXTENSION_BLACKLIST_DELETE);
+
+ return r1 && r2 && r3 && r4 && r5 && r6 && r7;
}
void SafeBrowsingDatabaseNew::WritePrefixSet() {
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h
index 5abc97f..f24f37f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.h
+++ b/chrome/browser/safe_browsing/safe_browsing_database.h
@@ -36,7 +36,8 @@ class SafeBrowsingDatabaseFactory {
virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
bool enable_download_protection,
bool enable_client_side_whitelist,
- bool enable_download_whitelist) = 0;
+ bool enable_download_whitelist,
+ bool enable_extension_blacklist) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingDatabaseFactory);
};
@@ -66,7 +67,8 @@ class SafeBrowsingDatabase {
// database feature.
static SafeBrowsingDatabase* Create(bool enable_download_protection,
bool enable_client_side_whitelist,
- bool enable_download_whitelist);
+ bool enable_download_whitelist,
+ bool enable_extension_blacklist);
// Makes the passed |factory| the factory used to instantiate
// a SafeBrowsingDatabase. This is used for tests.
@@ -119,6 +121,14 @@ class SafeBrowsingDatabase {
virtual bool ContainsDownloadWhitelistedUrl(const GURL& url) = 0;
virtual bool ContainsDownloadWhitelistedString(const std::string& str) = 0;
+ // Populates |prefix_hits| with any prefixes in |prefixes| that have matches
+ // in the database.
+ //
+ // This function can ONLY be accessed from the creation thread.
+ virtual bool ContainsExtensionPrefixes(
+ const std::vector<SBPrefix>& prefixes,
+ std::vector<SBPrefix>* prefix_hits) = 0;
+
// A database transaction should look like:
//
// std::vector<SBListChunkRanges> lists;
@@ -175,6 +185,10 @@ class SafeBrowsingDatabase {
static FilePath DownloadWhitelistDBFilename(
const FilePath& download_whitelist_base_filename);
+ // Filename for extension blacklist database.
+ static FilePath ExtensionBlacklistDBFilename(
+ const FilePath& extension_blacklist_base_filename);
+
// Enumerate failures for histogramming purposes. DO NOT CHANGE THE
// ORDERING OF THESE VALUES.
enum FailureType {
@@ -196,6 +210,9 @@ class SafeBrowsingDatabase {
FAILURE_DATABASE_PREFIX_SET_READ,
FAILURE_DATABASE_PREFIX_SET_WRITE,
FAILURE_DATABASE_PREFIX_SET_DELETE,
+ FAILURE_EXTENSION_BLACKLIST_UPDATE_BEGIN,
+ FAILURE_EXTENSION_BLACKLIST_UPDATE_FINISH,
+ FAILURE_EXTENSION_BLACKLIST_DELETE,
// Memory space for histograms is determined by the max. ALWAYS
// ADD NEW VALUES BEFORE THIS ONE.
@@ -221,7 +238,8 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
SafeBrowsingDatabaseNew(SafeBrowsingStore* browse_store,
SafeBrowsingStore* download_store,
SafeBrowsingStore* csd_whitelist_store,
- SafeBrowsingStore* download_whitelist_store);
+ SafeBrowsingStore* download_whitelist_store,
+ SafeBrowsingStore* extension_blacklist_store);
// Create a database with a browse store. This is a legacy interface that
// useds Sqlite.
@@ -244,6 +262,9 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
virtual bool ContainsDownloadWhitelistedUrl(const GURL& url) OVERRIDE;
virtual bool ContainsDownloadWhitelistedString(
const std::string& str) OVERRIDE;
+ virtual bool ContainsExtensionPrefixes(
+ const std::vector<SBPrefix>& prefixes,
+ std::vector<SBPrefix>* prefix_hits) OVERRIDE;
virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists) OVERRIDE;
virtual void InsertChunks(const std::string& list_name,
const SBChunkList& chunks) OVERRIDE;
@@ -309,7 +330,10 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
void InsertSubChunks(safe_browsing_util::ListType list_id,
const SBChunkList& chunks);
- void UpdateDownloadStore();
+ // Returns the size in bytes of the store after the update.
+ int64 UpdateHashPrefixStore(const FilePath& store_filename,
+ SafeBrowsingStore* store,
+ FailureType failure_type);
void UpdateBrowseStore();
void UpdateWhitelistStore(const FilePath& store_filename,
SafeBrowsingStore* store,
@@ -344,8 +368,13 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
FilePath download_whitelist_filename_;
scoped_ptr<SafeBrowsingStore> download_whitelist_store_;
+ // For extension IDs.
+ FilePath extension_blacklist_filename_;
+ scoped_ptr<SafeBrowsingStore> extension_blacklist_store_;
+
SBWhitelist csd_whitelist_;
SBWhitelist download_whitelist_;
+ SBWhitelist extension_blacklist_;
// Cached browse store related full-hash items, ordered by prefix for
// efficient scanning.
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
index d53e6a1..d973ffb 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
@@ -368,10 +368,13 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) {
SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile();
+ SafeBrowsingStoreFile* extension_blacklist_store =
+ new SafeBrowsingStoreFile();
database_.reset(new SafeBrowsingDatabaseNew(browse_store,
download_store,
csd_whitelist_store,
- download_whitelist_store));
+ download_whitelist_store,
+ extension_blacklist_store));
database_->Init(database_filename_);
SBChunkList chunks;
@@ -421,10 +424,20 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) {
chunks.push_back(chunk);
database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, chunks);
+
+ chunk.hosts.clear();
+ InsertAddChunkHostFullHashes(&chunk, 8,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+
+ chunks.clear();
+ chunks.push_back(chunk);
+ database_->InsertChunks(safe_browsing_util::kExtensionBlacklist, chunks);
+
database_->UpdateFinished(true);
GetListsInfo(&lists);
- ASSERT_EQ(5U, lists.size());
+ ASSERT_EQ(6U, lists.size());
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].adds, "1");
EXPECT_TRUE(lists[0].subs.empty());
@@ -441,6 +454,9 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) {
EXPECT_TRUE(lists[4].name == safe_browsing_util::kDownloadWhiteList);
EXPECT_EQ(lists[4].adds, "6");
EXPECT_TRUE(lists[4].subs.empty());
+ EXPECT_TRUE(lists[5].name == safe_browsing_util::kExtensionBlacklist);
+ EXPECT_EQ(lists[5].adds, "8");
+ EXPECT_TRUE(lists[5].subs.empty());
database_.reset();
}
@@ -1064,7 +1080,7 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) {
database_.reset();
MessageLoop loop(MessageLoop::TYPE_DEFAULT);
SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile();
- database_.reset(new SafeBrowsingDatabaseNew(store, NULL, NULL, NULL));
+ database_.reset(new SafeBrowsingDatabaseNew(store, NULL, NULL, NULL, NULL));
database_->Init(database_filename_);
// This will cause an empty database to be created.
@@ -1137,6 +1153,7 @@ TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) {
database_.reset(new SafeBrowsingDatabaseNew(browse_store,
download_store,
csd_whitelist_store,
+ NULL,
NULL));
database_->Init(database_filename_);
@@ -1239,7 +1256,7 @@ TEST_F(SafeBrowsingDatabaseTest, Whitelists) {
// If the whitelist is disabled everything should match the whitelist.
database_.reset(new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile(),
- NULL, NULL, NULL));
+ NULL, NULL, NULL, NULL));
database_->Init(database_filename_);
EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
GURL(std::string("http://www.phishing.com/"))));
@@ -1250,9 +1267,12 @@ TEST_F(SafeBrowsingDatabaseTest, Whitelists) {
SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile();
+ SafeBrowsingStoreFile* extension_blacklist_store =
+ new SafeBrowsingStoreFile();
database_.reset(new SafeBrowsingDatabaseNew(browse_store, NULL,
csd_whitelist_store,
- download_whitelist_store));
+ download_whitelist_store,
+ extension_blacklist_store));
database_->Init(database_filename_);
const char kGood1Host[] = "www.good1.com/";
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 8fbd933..2a373e9 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -114,6 +114,11 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase {
virtual bool ContainsDownloadWhitelistedUrl(const GURL& url) {
return true;
}
+ virtual bool ContainsExtensionPrefixes(
+ const std::vector<SBPrefix>& prefixes,
+ std::vector<SBPrefix>* prefix_hits) OVERRIDE {
+ return true;
+ }
virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists) {
ADD_FAILURE() << "Not implemented.";
return false;
@@ -197,7 +202,8 @@ class TestSafeBrowsingDatabaseFactory : public SafeBrowsingDatabaseFactory {
virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
bool enable_download_protection,
bool enable_client_side_whitelist,
- bool enable_download_whitelist) {
+ bool enable_download_whitelist,
+ bool enable_extension_blacklist) {
db_ = new TestSafeBrowsingDatabase();
return db_;
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_test.cc b/chrome/browser/safe_browsing/safe_browsing_test.cc
index cad8262..d0d6d46 100644
--- a/chrome/browser/safe_browsing/safe_browsing_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_test.cc
@@ -247,6 +247,10 @@ class SafeBrowsingServerTest : public InProcessBrowserTest {
command_line->AppendSwitch(
switches::kDisableClientSidePhishingDetection);
+ // TODO(kalman): Generate new testing data that includes the extension
+ // blacklist.
+ command_line->AppendSwitch(switches::kSbDisableExtensionBlacklist);
+
// Point to the testing server for all SafeBrowsing requests.
std::string url_prefix = test_server_->GetURL("safebrowsing").spec();
command_line->AppendSwitchASCII(switches::kSbURLPrefix, url_prefix);
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.cc b/chrome/browser/safe_browsing/safe_browsing_util.cc
index 3951484..ef620a7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_util.cc
@@ -163,6 +163,7 @@ const char kBinUrlList[] = "goog-badbinurl-shavar";
const char kBinHashList[] = "goog-badbin-digestvar-disabled";
const char kCsdWhiteList[] = "goog-csdwhite-sha256";
const char kDownloadWhiteList[] = "goog-downloadwhite-digest256";
+const char kExtensionBlacklist[] = "goog-badcrxids-digestvar";
ListType GetListId(const std::string& name) {
ListType id;
@@ -178,6 +179,8 @@ ListType GetListId(const std::string& name) {
id = CSDWHITELIST;
} else if (name == safe_browsing_util::kDownloadWhiteList) {
id = DOWNLOADWHITELIST;
+ } else if (name == safe_browsing_util::kExtensionBlacklist) {
+ id = EXTENSIONBLACKLIST;
} else {
id = INVALID;
}
@@ -204,6 +207,9 @@ bool GetListName(ListType list_id, std::string* list) {
case DOWNLOADWHITELIST:
*list = safe_browsing_util::kDownloadWhiteList;
break;
+ case EXTENSIONBLACKLIST:
+ *list = safe_browsing_util::kExtensionBlacklist;
+ break;
default:
return false;
}
@@ -469,6 +475,10 @@ bool IsBadbinhashList(const std::string& list_name) {
return list_name.compare(kBinHashList) == 0;
}
+bool IsExtensionList(const std::string& list_name) {
+ return list_name.compare(kExtensionBlacklist) == 0;
+}
+
GURL GeneratePhishingReportUrl(const std::string& report_page,
const std::string& url_to_report,
bool is_client_side_detection) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.h b/chrome/browser/safe_browsing/safe_browsing_util.h
index 0ba14fa..4e0fd51 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.h
+++ b/chrome/browser/safe_browsing/safe_browsing_util.h
@@ -9,6 +9,7 @@
#include <cstring>
#include <deque>
+#include <set>
#include <string>
#include <vector>
@@ -147,6 +148,9 @@ enum SBThreatType {
// Url detected by the client-side phishing model. Note that unlike the
// above values, this does not correspond to a downloaded list.
SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL,
+
+ // The Chrome extension or app (given by its ID) is malware.
+ SB_THREAT_TYPE_EXTENSION,
};
// SBEntry ---------------------------------------------------------------------
@@ -287,6 +291,8 @@ extern const char kBinHashList[];
extern const char kCsdWhiteList[];
// SafeBrowsing download whitelist list name.
extern const char kDownloadWhiteList[];
+// SafeBrowsing extension list name.
+extern const char kExtensionBlacklist[];
enum ListType {
INVALID = -1,
@@ -299,6 +305,8 @@ enum ListType {
// available for a potential second list that we would store in the
// csd-whitelist store file.
DOWNLOADWHITELIST = 6,
+ // See above comment. Leave 7 available.
+ EXTENSIONBLACKLIST = 8,
};
// Maps a list name to ListType.
@@ -337,6 +345,7 @@ bool IsPhishingList(const std::string& list_name);
bool IsMalwareList(const std::string& list_name);
bool IsBadbinurlList(const std::string& list_name);
bool IsBadbinhashList(const std::string& list_name);
+bool IsExtensionList(const std::string& list_name);
GURL GeneratePhishingReportUrl(const std::string& report_page,
const std::string& url_to_report,
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 9bcaad8..4f579c5 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -106,6 +106,8 @@
'browser/download/download_test_file_activity_observer.h',
'browser/download/test_download_shelf.cc',
'browser/download/test_download_shelf.h',
+ 'browser/extensions/fake_safe_browsing_database_manager.cc',
+ 'browser/extensions/fake_safe_browsing_database_manager.h',
'browser/extensions/mock_extension_special_storage_policy.cc',
'browser/extensions/mock_extension_special_storage_policy.h',
'browser/extensions/test_blacklist.cc',
@@ -301,6 +303,13 @@
'../chromeos/chromeos.gyp:chromeos_test_support',
],
}],
+ ['safe_browsing!=1', {
+ 'sources/': [
+ ['exclude', '^browser/extensions/blacklist_unittest.cc'],
+ ['exclude', '^browser/extensions/fake_safe_browsing_database_manager.cc'],
+ ['exclude', '^browser/extensions/fake_safe_browsing_database_manager.h'],
+ ],
+ }],
['toolkit_uses_gtk == 1', {
'dependencies': [
'../build/linux/system.gyp:gtk',
@@ -1834,14 +1843,8 @@
'FULL_SAFE_BROWSING',
],
}],
- # TODO(sgurun): enable tests.
- ['safe_browsing==2', {
- 'sources/': [
- ['exclude', '^browser/safe_browsing/'],
- ['exclude', '^renderer/safe_browsing/'],
- ],
- }],
- ['safe_browsing==0', {
+ # TODO(sgurun): enable tests for safe_browsing==2.
+ ['safe_browsing!=1', {
'sources/': [
['exclude', '^browser/safe_browsing/'],
['exclude', '^renderer/safe_browsing/'],
@@ -2260,6 +2263,11 @@
['exclude', '^browser/managed_mode/'],
],
}],
+ ['safe_browsing!=1', {
+ 'sources/': [
+ ['exclude', '^browser/extensions/blacklist_unittest.cc'],
+ ],
+ }],
],
'target_conditions': [
['OS == "ios"', {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 024d66f..c2bf004 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1167,6 +1167,10 @@ const char kSbDisableAutoUpdate[] = "safebrowsing-disable-auto-update";
const char kSbDisableDownloadProtection[] =
"safebrowsing-disable-download-protection";
+// Disables safebrowsing feature that checks for blacklisted extensions.
+const char kSbDisableExtensionBlacklist[] =
+ "safebrowsing-disable-extension-blacklist";
+
// Enables or disables extension scripts badges in the location bar.
const char kScriptBadges[] = "script-badges";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 2f138e7..d8a1f3a 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -308,6 +308,7 @@ extern const char kSavePageAsMHTML[];
extern const char kSbURLPrefix[];
extern const char kSbDisableAutoUpdate[];
extern const char kSbDisableDownloadProtection[];
+extern const char kSbDisableExtensionBlacklist[];
extern const char kScriptBadges[];
extern const char kScriptBubble[];
extern const char kSearchInOmniboxHint[];