Skip to content

Commit

Permalink
Merge pull request #6819 from brave/mpilgrim_webgl2_farbling
Browse files Browse the repository at this point in the history
Implement WebGL2 farbling
  • Loading branch information
pilgrim-brave authored Oct 14, 2020
2 parents 2b2bf78 + 3e491a4 commit 54fdb85
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 24 deletions.
94 changes: 72 additions & 22 deletions browser/farbling/brave_webgl_farbling_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/test/thread_test_helper.h"
Expand Down Expand Up @@ -52,36 +53,33 @@ class BraveWebGLFarblingBrowserTest : public InProcessBrowserTest {
embedded_test_server()->ServeFilesFromDirectory(test_data_dir);

ASSERT_TRUE(embedded_test_server()->Start());

top_level_page_url_ = embedded_test_server()->GetURL("a.com", "/");
get_parameter_url_ =
embedded_test_server()->GetURL("a.com", "/getParameter.html");
}

void TearDown() override {
browser_content_client_.reset();
content_client_.reset();
}

const GURL& get_parameter_url() { return get_parameter_url_; }

HostContentSettingsMap* content_settings() {
return HostContentSettingsMapFactory::GetForProfile(browser()->profile());
}

void AllowFingerprinting() {
void AllowFingerprinting(std::string domain) {
brave_shields::SetFingerprintingControlType(
content_settings(), ControlType::ALLOW, top_level_page_url_);
content_settings(), ControlType::ALLOW,
embedded_test_server()->GetURL(domain, "/"));
}

void BlockFingerprinting() {
void BlockFingerprinting(std::string domain) {
brave_shields::SetFingerprintingControlType(
content_settings(), ControlType::BLOCK, top_level_page_url_);
content_settings(), ControlType::BLOCK,
embedded_test_server()->GetURL(domain, "/"));
}

void SetFingerprintingDefault() {
void SetFingerprintingDefault(std::string domain) {
brave_shields::SetFingerprintingControlType(
content_settings(), ControlType::DEFAULT, top_level_page_url_);
content_settings(), ControlType::DEFAULT,
embedded_test_server()->GetURL(domain, "/"));
}

template <typename T>
Expand All @@ -100,41 +98,93 @@ class BraveWebGLFarblingBrowserTest : public InProcessBrowserTest {
return WaitForLoadStop(contents());
}

std::vector<int64_t> SplitStringAsInts(std::string raw_values) {
std::vector<int64_t> results;
for (const auto& cur : base::SplitStringPiece(
raw_values, base::kWhitespaceASCII, base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
int64_t value;
base::StringToInt64(cur, &value);
results.push_back(value);
}
return results;
}

std::string DiffsAsString(std::vector<int64_t> real_values,
std::vector<int64_t> farbled_values) {
std::string diffs;
for (uint64_t i = 0; i < real_values.size(); i++) {
diffs = diffs + base::NumberToString(real_values[i] - farbled_values[i]);
}
return diffs;
}

private:
GURL top_level_page_url_;
GURL get_parameter_url_;
std::unique_ptr<ChromeContentClient> content_client_;
std::unique_ptr<BraveContentBrowserClient> browser_content_client_;
};

IN_PROC_BROWSER_TEST_F(BraveWebGLFarblingBrowserTest, FarbleGetParameter) {
IN_PROC_BROWSER_TEST_F(BraveWebGLFarblingBrowserTest, FarbleGetParameterWebGL) {
std::string domain = "a.com";
GURL url = embedded_test_server()->GetURL(domain, "/getParameter.html");
const std::string kExpectedRandomString = "UKlSpUqV,TJEix48e";
// Farbling level: maximum
// WebGL getParameter of restricted values: pseudo-random data with no
// relation to original data
BlockFingerprinting();
NavigateToURLUntilLoadStop(get_parameter_url());
BlockFingerprinting(domain);
NavigateToURLUntilLoadStop(url);
EXPECT_EQ(ExecScriptGetStr(kTitleScript, contents()), kExpectedRandomString);
// second time, same as the first (tests that results are consistent for the
// lifetime of a session, and that the PRNG properly resets itself at the
// beginning of each calculation)
NavigateToURLUntilLoadStop(get_parameter_url());
NavigateToURLUntilLoadStop(url);
EXPECT_EQ(ExecScriptGetStr(kTitleScript, contents()), kExpectedRandomString);

std::string actual;
// Farbling level: balanced (default)
// WebGL getParameter of restricted values: original data
SetFingerprintingDefault();
NavigateToURLUntilLoadStop(get_parameter_url());
SetFingerprintingDefault(domain);
NavigateToURLUntilLoadStop(url);
actual = ExecScriptGetStr(kTitleScript, contents());

// Farbling level: off
// WebGL getParameter of restricted values: original data
AllowFingerprinting();
NavigateToURLUntilLoadStop(get_parameter_url());
AllowFingerprinting(domain);
NavigateToURLUntilLoadStop(url);
// Since this value depends on the underlying hardware, we just test that the
// results for "off" are the same as the results for "balanced", and that
// they're different than the results for "maximum".
EXPECT_EQ(ExecScriptGetStr(kTitleScript, contents()), actual);
EXPECT_NE(kExpectedRandomString, actual);
}

IN_PROC_BROWSER_TEST_F(BraveWebGLFarblingBrowserTest,
FarbleGetParameterWebGL2) {
const std::map<std::string, std::string> tests = {{"a.com", "101111101011"},
{"b.com", "111011111011"},
{"c.com", "101111000110"}};
for (const auto& pair : tests) {
std::string domain = pair.first;
std::string expected_diff = pair.second;
GURL url =
embedded_test_server()->GetURL(pair.first, "/webgl2-parameters.html");

// Farbling level: off
// Get the actual WebGL2 parameter values.
AllowFingerprinting(domain);
NavigateToURLUntilLoadStop(url);
std::vector<int64_t> real_values =
SplitStringAsInts(ExecScriptGetStr(kTitleScript, contents()));
ASSERT_EQ(real_values.size(), 12UL);

// Farbling level: default
// WebGL2 parameter values will be farbled based on session+domain keys,
// so we get the farbled values and look at the differences.
SetFingerprintingDefault(domain);
NavigateToURLUntilLoadStop(url);
std::vector<int64_t> farbled_values =
SplitStringAsInts(ExecScriptGetStr(kTitleScript, contents()));
ASSERT_EQ(farbled_values.size(), 12UL);
ASSERT_EQ(DiffsAsString(real_values, farbled_values), expected_diff);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,121 @@
* 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 "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
#include "brave/components/content_settings/renderer/brave_content_settings_agent_impl_helper.h"
#include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"

#include <algorithm>

using blink::ScriptState;
using blink::ScriptValue;
using blink::WebGL2RenderingContextBase;
using blink::WebGLAny;

namespace {

ScriptValue FarbleGLIntParameter(WebGL2RenderingContextBase* owner,
ScriptState* script_state,
GLenum pname,
int discard) {
GLint value = 0;
if (!owner->isContextLost())
owner->ContextGL()->GetIntegerv(pname, &value);
if (value > 0) {
std::mt19937_64 prng =
brave::BraveSessionCache::From(*ExecutionContext::From(script_state))
.MakePseudoRandomGenerator();
prng.discard(discard);
if (prng() % 2 != 0) {
value = value - 1;
}
}
return WebGLAny(script_state, value);
}

ScriptValue FarbleGLInt64Parameter(WebGL2RenderingContextBase* owner,
ScriptState* script_state,
GLenum pname,
int discard) {
GLint64 value = 0;
if (!owner->isContextLost())
owner->ContextGL()->GetInteger64v(pname, &value);
if (value > 0) {
std::mt19937_64 prng =
brave::BraveSessionCache::From(*ExecutionContext::From(script_state))
.MakePseudoRandomGenerator();
prng.discard(discard);
if (prng() % 2 != 0) {
value = value - 1;
}
}
return WebGLAny(script_state, value);
}

} // namespace

#define BRAVE_WEBGL2_RENDERING_CONTEXT_BASE \
if (canvas() && !AllowFingerprinting(canvas()->GetDocument().GetFrame())) \
return ScriptValue::CreateNull(script_state->GetIsolate());

#define BRAVE_WEBGL2_RENDERING_CONTEXT_BASE_GETPARAMETER \
if (ExecutionContext* context = ExecutionContext::From(script_state)) { \
if (WebContentSettingsClient* settings = \
brave::GetContentSettingsClientFor(context)) { \
if (settings->GetBraveFarblingLevel() == BraveFarblingLevel::MAXIMUM) { \
switch (pname) { \
case GL_SHADING_LANGUAGE_VERSION: \
case GL_VERSION: \
case GL_COPY_READ_BUFFER_BINDING: \
case GL_COPY_WRITE_BUFFER_BINDING: \
case GL_DRAW_FRAMEBUFFER_BINDING: \
case GL_MAX_VERTEX_UNIFORM_COMPONENTS: \
case GL_MAX_VERTEX_UNIFORM_BLOCKS: \
case GL_MAX_VERTEX_OUTPUT_COMPONENTS: \
case GL_MAX_VARYING_COMPONENTS: \
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: \
case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: \
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: \
case GL_MAX_FRAGMENT_INPUT_COMPONENTS: \
case GL_MAX_UNIFORM_BUFFER_BINDINGS: \
case GL_MAX_COMBINED_UNIFORM_BLOCKS: \
case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: \
case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: \
return ScriptValue::CreateNull(script_state->GetIsolate()); \
} \
} else if (settings->GetBraveFarblingLevel() == \
BraveFarblingLevel::BALANCED) { \
switch (pname) { \
case GL_MAX_VERTEX_UNIFORM_COMPONENTS: \
return FarbleGLIntParameter(this, script_state, pname, 1); \
case GL_MAX_VERTEX_UNIFORM_BLOCKS: \
return FarbleGLIntParameter(this, script_state, pname, 2); \
case GL_MAX_VERTEX_OUTPUT_COMPONENTS: \
return FarbleGLIntParameter(this, script_state, pname, 3); \
case GL_MAX_VARYING_COMPONENTS: \
return FarbleGLIntParameter(this, script_state, pname, 4); \
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: \
return FarbleGLIntParameter(this, script_state, pname, 5); \
case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: \
return FarbleGLIntParameter(this, script_state, pname, 6); \
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: \
return FarbleGLIntParameter(this, script_state, pname, 7); \
case GL_MAX_FRAGMENT_INPUT_COMPONENTS: \
return FarbleGLIntParameter(this, script_state, pname, 8); \
case GL_MAX_UNIFORM_BUFFER_BINDINGS: \
return FarbleGLIntParameter(this, script_state, pname, 9); \
case GL_MAX_COMBINED_UNIFORM_BLOCKS: \
return FarbleGLIntParameter(this, script_state, pname, 10); \
case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: \
return FarbleGLInt64Parameter(this, script_state, pname, 11); \
case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: \
return FarbleGLInt64Parameter(this, script_state, pname, 12); \
} \
} \
} \
}

#include "../../../../../../../third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc"
#undef BRAVE_WEBGL2_RENDERING_CONTEXT_BASE
#undef BRAVE_WEBGL2_RENDERING_CONTEXT_BASE_GETPARAMETER
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 2d8068bf9f28ed7c5e33e7dee7003963aca89a0e..5d7d75d6ff5085f21fe40f79411e82fa01570617 100644
index 2d8068bf9f28ed7c5e33e7dee7003963aca89a0e..f71dd39a2070fdcb111be4a61087a9ff95f4d68a 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -5062,6 +5062,7 @@ ScriptValue WebGL2RenderingContextBase::getParameter(ScriptState* script_state,
GLenum pname) {
if (isContextLost())
return ScriptValue::CreateNull(script_state->GetIsolate());
+ BRAVE_WEBGL2_RENDERING_CONTEXT_BASE
+ BRAVE_WEBGL2_RENDERING_CONTEXT_BASE_GETPARAMETER
switch (pname) {
case GL_SHADING_LANGUAGE_VERSION: {
return WebGLAny(
Expand Down
31 changes: 31 additions & 0 deletions test/data/webgl/webgl2-parameters.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>WebGL2 getParameter() test</title>
<meta charset="utf-8">
</head>
<body>
<canvas id="test" width="8" height="8"></canvas>
<script>
var canvas = document.getElementById("test");
var gl = canvas.getContext("webgl2");
params = ["MAX_VERTEX_UNIFORM_COMPONENTS",
"MAX_VERTEX_UNIFORM_BLOCKS",
"MAX_VERTEX_OUTPUT_COMPONENTS",
"MAX_VARYING_COMPONENTS",
"MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS",
"MAX_FRAGMENT_UNIFORM_COMPONENTS",
"MAX_FRAGMENT_UNIFORM_BLOCKS",
"MAX_FRAGMENT_INPUT_COMPONENTS",
"MAX_UNIFORM_BUFFER_BINDINGS",
"MAX_COMBINED_UNIFORM_BLOCKS",
"MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS",
"MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS"];
var result = [];
for (i in params) {
result.push(gl.getParameter(gl[params[i]]));
}
document.title = result.join(" ");
</script>
</body>
</html>

0 comments on commit 54fdb85

Please sign in to comment.