From 9f6dedae26617efd8c57a42eeb669a60a304619b Mon Sep 17 00:00:00 2001 From: Mark Pilgrim Date: Tue, 21 Jul 2020 18:27:09 -0400 Subject: [PATCH] Implement navigator.hardwareConcurrency farbling lint . tests patch IDL instead . lint . . --- ...ardwareconcurrency_farbling_browsertest.cc | 145 ++++++++++++++++++ .../frame/navigator_concurrent_hardware.cc | 62 ++++++++ .../frame/navigator_concurrent_hardware.h | 22 +++ ...me-navigator_concurrent_hardware.idl.patch | 11 ++ test/BUILD.gn | 1 + 5 files changed, 241 insertions(+) create mode 100644 browser/farbling/brave_navigator_hardwareconcurrency_farbling_browsertest.cc create mode 100644 chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.cc create mode 100644 chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h create mode 100644 patches/third_party-blink-renderer-core-frame-navigator_concurrent_hardware.idl.patch diff --git a/browser/farbling/brave_navigator_hardwareconcurrency_farbling_browsertest.cc b/browser/farbling/brave_navigator_hardwareconcurrency_farbling_browsertest.cc new file mode 100644 index 000000000000..047ee53320b1 --- /dev/null +++ b/browser/farbling/brave_navigator_hardwareconcurrency_farbling_browsertest.cc @@ -0,0 +1,145 @@ +/* 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 kHardwareConcurrencyScript[] = + "domAutomationController.send(navigator.hardwareConcurrency);"; + +class BraveNavigatorHardwareConcurrencyFarblingBrowserTest + : 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 + int ExecScriptGetInt(const std::string& script, T* frame) { + int value; + EXPECT_TRUE(ExecuteScriptAndExtractInt(frame, script, &value)); + return value; + } + + template + 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 content_client_; + std::unique_ptr browser_content_client_; +}; + +// Tests results of farbling known values +IN_PROC_BROWSER_TEST_F(BraveNavigatorHardwareConcurrencyFarblingBrowserTest, + FarbleNavigatorHardwareConcurrency) { + // Farbling level: off + // get real navigator.hardwareConcurrency + AllowFingerprinting(); + NavigateToURLUntilLoadStop(farbling_url()); + int real_value = ExecScriptGetInt(kHardwareConcurrencyScript, contents()); + ASSERT_GE(real_value, 2); + + // Farbling level: balanced (default) + // navigator.hardwareConcurrency should be greater than or equal to 2 + // and less than or equal to the real value + SetFingerprintingDefault(); + NavigateToURLUntilLoadStop(farbling_url()); + int fake_value = ExecScriptGetInt(kHardwareConcurrencyScript, contents()); + EXPECT_GE(fake_value, 2); + EXPECT_LE(fake_value, real_value); + + // Farbling level: maximum + // navigator.hardwareConcurrency should be greater than or equal to 2 + // and less than or equal to 8 + BlockFingerprinting(); + NavigateToURLUntilLoadStop(farbling_url()); + int completely_fake_value = + ExecScriptGetInt(kHardwareConcurrencyScript, contents()); + // For this domain (a.com) + the random seed (constant for browser tests), + // the value will always be the same. + EXPECT_EQ(completely_fake_value, 7); +} diff --git a/chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.cc b/chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.cc new file mode 100644 index 000000000000..6aaa0bd2d4cd --- /dev/null +++ b/chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.cc @@ -0,0 +1,62 @@ +/* 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 + +#include "base/system/sys_info.h" +#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_dom_window.h" +#include "third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h" + +namespace brave { + +using blink::LocalFrame; + +const unsigned kFakeMinProcessors = 2; +const unsigned kFakeMaxProcessors = 8; + +unsigned FarbleNumberOfProcessors(LocalFrame* frame) { + unsigned true_value = + static_cast(base::SysInfo::NumberOfProcessors()); + if ((true_value <= 2) || !frame || !frame->GetContentSettingsClient()) + return true_value; + unsigned farbled_value = true_value; + switch (frame->GetContentSettingsClient()->GetBraveFarblingLevel()) { + case BraveFarblingLevel::OFF: { + break; + } + case BraveFarblingLevel::MAXIMUM: { + true_value = kFakeMaxProcessors; + // "Maximum" behavior is "balanced" behavior but with a fake maximum, + // so fall through here. + U_FALLTHROUGH; + } + case BraveFarblingLevel::BALANCED: { + std::mt19937_64 prng = BraveSessionCache::From(*(frame->GetDocument())) + .MakePseudoRandomGenerator(); + farbled_value = + kFakeMinProcessors + (prng() % (true_value + 1 - kFakeMinProcessors)); + break; + } + default: + NOTREACHED(); + } + return farbled_value; +} + +} // namespace brave + +namespace blink { + +unsigned NavigatorConcurrentHardware::hardwareConcurrency( + ScriptState* script_state) const { + LocalFrame* frame = nullptr; + if (LocalDOMWindow* window = LocalDOMWindow::From(script_state)) + frame = window->GetFrame(); + return brave::FarbleNumberOfProcessors(frame); +} + +} // namespace blink diff --git a/chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h b/chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h new file mode 100644 index 000000000000..3877c5e0a519 --- /dev/null +++ b/chromium_src/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h @@ -0,0 +1,22 @@ +/* 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/. */ + +#ifndef BRAVE_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATOR_CONCURRENT_HARDWARE_H_ +#define BRAVE_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATOR_CONCURRENT_HARDWARE_H_ + +#include "third_party/blink/renderer/core/core_export.h" + +namespace blink { + +class ScriptState; + +class CORE_EXPORT NavigatorConcurrentHardware { + public: + unsigned hardwareConcurrency(ScriptState*) const; +}; + +} // namespace blink + +#endif // BRAVE_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATOR_CONCURRENT_HARDWARE_H_ diff --git a/patches/third_party-blink-renderer-core-frame-navigator_concurrent_hardware.idl.patch b/patches/third_party-blink-renderer-core-frame-navigator_concurrent_hardware.idl.patch new file mode 100644 index 000000000000..5402ad0d12b6 --- /dev/null +++ b/patches/third_party-blink-renderer-core-frame-navigator_concurrent_hardware.idl.patch @@ -0,0 +1,11 @@ +diff --git a/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl b/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl +index 3bb78d4b00c651a9edef3639a125736dc55d6be7..8bc1b636ba5423c443137aa7cb344261340de477 100644 +--- a/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl ++++ b/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl +@@ -5,5 +5,5 @@ + // https://html.spec.whatwg.org/C/#navigator.hardwareconcurrency + + interface mixin NavigatorConcurrentHardware { +- [HighEntropy, MeasureAs=NavigatorHardwareConcurrency] readonly attribute unsigned long long hardwareConcurrency; ++ [CallWith=ScriptState, HighEntropy, MeasureAs=NavigatorHardwareConcurrency] readonly attribute unsigned long long hardwareConcurrency; + }; diff --git a/test/BUILD.gn b/test/BUILD.gn index 2435e4f53335..0534cd844541 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -543,6 +543,7 @@ test("brave_browser_tests") { "//brave/browser/extensions/brave_extension_functional_test.h", "//brave/browser/extensions/brave_extension_provider_browsertest.cc", "//brave/browser/extensions/brave_theme_event_router_browsertest.cc", + "//brave/browser/farbling/brave_navigator_hardwareconcurrency_farbling_browsertest.cc", "//brave/browser/farbling/brave_navigator_plugins_farbling_browsertest.cc", "//brave/browser/farbling/brave_offscreencanvas_farbling_browsertest.cc", "//brave/browser/farbling/brave_webaudio_farbling_browsertest.cc",