-
Notifications
You must be signed in to change notification settings - Fork 883
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement navigator.plugins farbling
feedback and known-value tests fix WebGL farbling test
- Loading branch information
1 parent
ad3b5bd
commit 2794b2b
Showing
7 changed files
with
291 additions
and
3 deletions.
There are no files selected for viewing
171 changes: 171 additions & 0 deletions
171
browser/farbling/brave_navigator_plugins_farbling_browsertest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/* Copyright (c) 2020 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "base/path_service.h" | ||
#include "base/strings/stringprintf.h" | ||
#include "base/task/post_task.h" | ||
#include "base/test/thread_test_helper.h" | ||
#include "brave/browser/brave_browser_process_impl.h" | ||
#include "brave/browser/brave_content_browser_client.h" | ||
#include "brave/browser/extensions/brave_base_local_data_files_browsertest.h" | ||
#include "brave/common/brave_paths.h" | ||
#include "brave/common/pref_names.h" | ||
#include "brave/components/brave_component_updater/browser/local_data_files_service.h" | ||
#include "brave/components/brave_shields/browser/brave_shields_util.h" | ||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" | ||
#include "chrome/browser/extensions/extension_browsertest.h" | ||
#include "chrome/browser/ui/browser.h" | ||
#include "chrome/common/chrome_content_client.h" | ||
#include "chrome/test/base/in_process_browser_test.h" | ||
#include "chrome/test/base/ui_test_utils.h" | ||
#include "components/permissions/permission_request.h" | ||
#include "components/prefs/pref_service.h" | ||
#include "content/public/browser/render_frame_host.h" | ||
#include "content/public/test/browser_test.h" | ||
#include "content/public/test/browser_test_utils.h" | ||
#include "net/dns/mock_host_resolver.h" | ||
|
||
using brave_shields::ControlType; | ||
|
||
const char kPluginsLengthScript[] = | ||
"domAutomationController.send(navigator.plugins.length);"; | ||
|
||
class BraveNavigatorPluginsFarblingBrowserTest : public InProcessBrowserTest { | ||
public: | ||
void SetUpOnMainThread() override { | ||
InProcessBrowserTest::SetUpOnMainThread(); | ||
|
||
content_client_.reset(new ChromeContentClient); | ||
content::SetContentClient(content_client_.get()); | ||
browser_content_client_.reset(new BraveContentBrowserClient()); | ||
content::SetBrowserClientForTesting(browser_content_client_.get()); | ||
|
||
host_resolver()->AddRule("*", "127.0.0.1"); | ||
content::SetupCrossSiteRedirector(embedded_test_server()); | ||
|
||
brave::RegisterPathProvider(); | ||
base::FilePath test_data_dir; | ||
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir); | ||
embedded_test_server()->ServeFilesFromDirectory(test_data_dir); | ||
|
||
ASSERT_TRUE(embedded_test_server()->Start()); | ||
|
||
top_level_page_url_ = embedded_test_server()->GetURL("a.com", "/"); | ||
farbling_url_ = embedded_test_server()->GetURL("a.com", "/simple.html"); | ||
} | ||
|
||
void TearDown() override { | ||
browser_content_client_.reset(); | ||
content_client_.reset(); | ||
} | ||
|
||
const GURL& farbling_url() { return farbling_url_; } | ||
|
||
HostContentSettingsMap* content_settings() { | ||
return HostContentSettingsMapFactory::GetForProfile(browser()->profile()); | ||
} | ||
|
||
void AllowFingerprinting() { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::ALLOW, top_level_page_url_); | ||
} | ||
|
||
void BlockFingerprinting() { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::BLOCK, top_level_page_url_); | ||
} | ||
|
||
void SetFingerprintingDefault() { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::DEFAULT, top_level_page_url_); | ||
} | ||
|
||
template <typename T> | ||
int ExecScriptGetInt(const std::string& script, T* frame) { | ||
int value; | ||
EXPECT_TRUE(ExecuteScriptAndExtractInt(frame, script, &value)); | ||
return value; | ||
} | ||
|
||
template <typename T> | ||
std::string ExecScriptGetStr(const std::string& script, T* frame) { | ||
std::string value; | ||
EXPECT_TRUE(ExecuteScriptAndExtractString(frame, script, &value)); | ||
return value; | ||
} | ||
|
||
content::WebContents* contents() { | ||
return browser()->tab_strip_model()->GetActiveWebContents(); | ||
} | ||
|
||
bool NavigateToURLUntilLoadStop(const GURL& url) { | ||
ui_test_utils::NavigateToURL(browser(), url); | ||
return WaitForLoadStop(contents()); | ||
} | ||
|
||
private: | ||
GURL top_level_page_url_; | ||
GURL farbling_url_; | ||
std::unique_ptr<ChromeContentClient> content_client_; | ||
std::unique_ptr<BraveContentBrowserClient> browser_content_client_; | ||
}; | ||
|
||
// Tests results of farbling known values | ||
IN_PROC_BROWSER_TEST_F(BraveNavigatorPluginsFarblingBrowserTest, | ||
FarbleNavigatorPlugins) { | ||
// Farbling level: off | ||
// get real length of navigator.plugins | ||
AllowFingerprinting(); | ||
NavigateToURLUntilLoadStop(farbling_url()); | ||
int off_length = ExecScriptGetInt(kPluginsLengthScript, contents()); | ||
|
||
// Farbling level: balanced (default) | ||
// navigator.plugins should contain all real plugins + 2 fake ones | ||
SetFingerprintingDefault(); | ||
NavigateToURLUntilLoadStop(farbling_url()); | ||
int balanced_length = ExecScriptGetInt(kPluginsLengthScript, contents()); | ||
EXPECT_EQ(balanced_length, off_length + 2); | ||
|
||
// Farbling level: maximum | ||
// navigator.plugins should contain no real plugins, only 2 fake ones | ||
BlockFingerprinting(); | ||
NavigateToURLUntilLoadStop(farbling_url()); | ||
int maximum_length = ExecScriptGetInt(kPluginsLengthScript, contents()); | ||
EXPECT_EQ(maximum_length, 2); | ||
EXPECT_EQ(ExecScriptGetStr( | ||
"domAutomationController.send(navigator.plugins[0].name);", | ||
contents()), | ||
"Xr1at27"); | ||
EXPECT_EQ(ExecScriptGetStr( | ||
"domAutomationController.send(navigator.plugins[0].filename);", | ||
contents()), | ||
"SJEChw48ev3bNGD"); | ||
EXPECT_EQ( | ||
ExecScriptGetStr( | ||
"domAutomationController.send(navigator.plugins[0].description);", | ||
contents()), | ||
"rVqVqVqVqVKlSpUqVqVKlSJEChQIECh"); | ||
EXPECT_EQ(ExecScriptGetInt( | ||
"domAutomationController.send(navigator.plugins[0].length);", | ||
contents()), | ||
0); | ||
EXPECT_EQ(ExecScriptGetStr( | ||
"domAutomationController.send(navigator.plugins[1].name);", | ||
contents()), | ||
"8.fPHDhw"); | ||
EXPECT_EQ(ExecScriptGetStr( | ||
"domAutomationController.send(navigator.plugins[1].filename);", | ||
contents()), | ||
"06du37du3bt2bNmT"); | ||
EXPECT_EQ( | ||
ExecScriptGetStr( | ||
"domAutomationController.send(navigator.plugins[1].description);", | ||
contents()), | ||
"BgwYMmTpUq1aNmTJky5cOnTp069ePnTp"); | ||
EXPECT_EQ(ExecScriptGetInt( | ||
"domAutomationController.send(navigator.plugins[1].length);", | ||
contents()), | ||
0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
chromium_src/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* Copyright (c) 2020 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include <random> | ||
|
||
#include "brave/third_party/blink/renderer/brave_farbling_constants.h" | ||
#include "third_party/blink/public/platform/web_content_settings_client.h" | ||
#include "third_party/blink/renderer/core/frame/local_frame.h" | ||
#include "third_party/blink/renderer/core/page/plugin_data.h" | ||
#include "third_party/blink/renderer/modules/plugins/dom_plugin.h" | ||
#include "third_party/blink/renderer/modules/plugins/dom_plugin_array.h" | ||
#include "third_party/blink/renderer/platform/heap/heap.h" | ||
#include "third_party/blink/renderer/platform/wtf/vector.h" | ||
|
||
using blink::DOMPlugin; | ||
using blink::DOMPluginArray; | ||
using blink::HeapVector; | ||
using blink::LocalFrame; | ||
using blink::MakeGarbageCollected; | ||
using blink::Member; | ||
using blink::PluginInfo; | ||
|
||
namespace brave { | ||
|
||
void FarblePlugins(DOMPluginArray* owner, | ||
HeapVector<Member<DOMPlugin>>* dom_plugins) { | ||
LocalFrame* frame = owner->GetFrame(); | ||
if (!frame || !frame->GetContentSettingsClient()) | ||
return; | ||
switch (frame->GetContentSettingsClient()->GetBraveFarblingLevel()) { | ||
case BraveFarblingLevel::OFF: { | ||
break; | ||
} | ||
case BraveFarblingLevel::MAXIMUM: { | ||
dom_plugins->clear(); | ||
// "Maximum" behavior is clear existing plugins + "balanced" behavior, | ||
// so fall through here. | ||
U_FALLTHROUGH; | ||
} | ||
case BraveFarblingLevel::BALANCED: { | ||
// The item() method will populate plugin info if any item of | ||
// |dom_plugins_| is null, but when it tries, it assumes the | ||
// length of |dom_plugins_| == the length of the underlying | ||
// GetPluginData()->Plugins(). Once we add our fake plugins, that | ||
// assumption will break and the item() method will crash with an | ||
// out-of-bounds array access. Rather than patch the item() method, we | ||
// ensure that the cache is fully populated now while the assumptions | ||
// still hold, so the problematic code is never executed later. | ||
for (unsigned index = 0; index < dom_plugins->size(); index++) { | ||
(*dom_plugins)[index] = owner->item(index); | ||
} | ||
// Add fake plugin #1. | ||
auto* fake_plugin_info_1 = MakeGarbageCollected<PluginInfo>( | ||
BraveSessionCache::From(*(frame->GetDocument())) | ||
.GenerateRandomString("PLUGIN_1_NAME", 8), | ||
BraveSessionCache::From(*(frame->GetDocument())) | ||
.GenerateRandomString("PLUGIN_1_FILENAME", 16), | ||
BraveSessionCache::From(*(frame->GetDocument())) | ||
.GenerateRandomString("PLUGIN_1_DESCRIPTION", 32), | ||
0, false); | ||
auto* fake_dom_plugin_1 = | ||
MakeGarbageCollected<DOMPlugin>(frame, *fake_plugin_info_1); | ||
dom_plugins->push_back(fake_dom_plugin_1); | ||
// Add fake plugin #2. | ||
auto* fake_plugin_info_2 = MakeGarbageCollected<PluginInfo>( | ||
BraveSessionCache::From(*(frame->GetDocument())) | ||
.GenerateRandomString("PLUGIN_2_NAME", 7), | ||
BraveSessionCache::From(*(frame->GetDocument())) | ||
.GenerateRandomString("PLUGIN_2_FILENAME", 15), | ||
BraveSessionCache::From(*(frame->GetDocument())) | ||
.GenerateRandomString("PLUGIN_2_DESCRIPTION", 31), | ||
0, false); | ||
auto* fake_dom_plugin_2 = | ||
MakeGarbageCollected<DOMPlugin>(frame, *fake_plugin_info_2); | ||
dom_plugins->push_back(fake_dom_plugin_2); | ||
// Shuffle the list of plugins pseudo-randomly, based on the domain key. | ||
std::mt19937_64 prng = BraveSessionCache::From(*(frame->GetDocument())) | ||
.MakePseudoRandomGenerator(); | ||
std::shuffle(dom_plugins->begin(), dom_plugins->end(), prng); | ||
break; | ||
} | ||
default: | ||
NOTREACHED(); | ||
} | ||
} | ||
|
||
} // namespace brave | ||
|
||
#define BRAVE_DOM_PLUGINS_UPDATE_PLUGIN_DATA \ | ||
brave::FarblePlugins(this, &dom_plugins_); | ||
|
||
#include "../../../../../../third_party/blink/renderer/modules/plugins/dom_plugin_array.cc" | ||
|
||
#undef BRAVE_DOM_PLUGIN_ARRAY_GET_PLUGIN_DATA |
12 changes: 12 additions & 0 deletions
12
patches/third_party-blink-renderer-modules-plugins-dom_plugin_array.cc.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
diff --git a/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc b/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc | ||
index 322e74880ddaa6c6c54f80f4f5f7ab0264631ffd..0c13152cb2f9ebd5bbf86955f50eab6909f05443 100644 | ||
--- a/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc | ||
+++ b/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc | ||
@@ -146,6 +146,7 @@ void DOMPluginArray::UpdatePluginData() { | ||
} | ||
} | ||
} | ||
+ BRAVE_DOM_PLUGINS_UPDATE_PLUGIN_DATA | ||
} | ||
|
||
void DOMPluginArray::ContextDestroyed() { |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters