diff --git a/patches/playwright/1-leak-fixes.patch b/patches/playwright/1-leak-fixes.patch index 9ce029e1..98295c55 100644 --- a/patches/playwright/1-leak-fixes.patch +++ b/patches/playwright/1-leak-fixes.patch @@ -2,8 +2,9 @@ diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index e0cbb3f1f8..d7868e7ae0 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp -@@ -2318,26 +2318,6 @@ dom::PrivateAttribution* Navigator::PrivateAttribution() { - +@@ -2316,26 +2316,6 @@ dom::PrivateAttribution* Navigator::PrivateAttribution() { + } + /* static */ bool Navigator::Webdriver() { -#ifdef ENABLE_WEBDRIVER diff --git a/patches/webgl-spoofing.patch.bak b/patches/webgl-spoofing.patch.bak new file mode 100644 index 00000000..951a33c2 --- /dev/null +++ b/patches/webgl-spoofing.patch.bak @@ -0,0 +1,398 @@ +diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp +index a1e5c4792d..be99491bf8 100644 +--- a/dom/canvas/ClientWebGLContext.cpp ++++ b/dom/canvas/ClientWebGLContext.cpp +@@ -4,6 +4,9 @@ + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + #include "ClientWebGLContext.h" ++#include "MaskConfig.hpp" ++#include ++#include + + #include + +@@ -750,6 +753,13 @@ void ClientWebGLContext::SetUnpackColorSpace( + Run(*mUnpackColorSpace); + } + ++bool ClientWebGLContext::MBoolVal(const std::string& key, bool defaultValue) { ++ if (auto value = MaskConfig::GetAttribute(key, mIsWebGL2); ++ value.has_value()) ++ return value.value(); ++ return defaultValue; ++} ++ + void ClientWebGLContext::GetContextAttributes( + dom::Nullable& retval) { + retval.SetNull(); +@@ -760,15 +770,40 @@ void ClientWebGLContext::GetContextAttributes( + + const auto& options = mNotLost->info.options; + +- result.mAlpha.Construct(options.alpha); +- result.mDepth = options.depth; +- result.mStencil = options.stencil; +- result.mAntialias.Construct(options.antialias); +- result.mPremultipliedAlpha = options.premultipliedAlpha; +- result.mPreserveDrawingBuffer = options.preserveDrawingBuffer; +- result.mFailIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat; +- result.mPowerPreference = options.powerPreference; +- result.mForceSoftwareRendering = options.forceSoftwareRendering; ++ result.mAlpha.Construct(MBoolVal("alpha", options.alpha)); ++ result.mDepth = MBoolVal("depth", options.depth); ++ result.mStencil = MBoolVal("stencil", options.stencil); ++ result.mAntialias.Construct(MBoolVal("antialias", options.antialias)); ++ result.mPremultipliedAlpha = MBoolVal( ++ "webGl:contextAttributes.premultipliedAlpha", options.premultipliedAlpha); ++ result.mPreserveDrawingBuffer = ++ MBoolVal("preserveDrawingBuffer", options.preserveDrawingBuffer); ++ result.mFailIfMajorPerformanceCaveat = MBoolVal( ++ "failIfMajorPerformanceCaveat", options.failIfMajorPerformanceCaveat); ++ if (auto value = ++ MaskConfig::GetAttribute("powerPreference", mIsWebGL2); ++ value.has_value()) { ++ // Convert to enum ++ switch (value.value()[0]) { ++ case 'd': ++ result.mPowerPreference = dom::WebGLPowerPreference::Default; ++ break; ++ case 'l': ++ result.mPowerPreference = dom::WebGLPowerPreference::Low_power; ++ break; ++ case 'h': ++ result.mPowerPreference = dom::WebGLPowerPreference::High_performance; ++ break; ++ default: ++ // Invalid value ++ result.mPowerPreference = options.powerPreference; ++ break; ++ } ++ } else { ++ result.mPowerPreference = options.powerPreference; ++ } ++ result.mForceSoftwareRendering = MBoolVal( ++ "forceSoftwareRendering", options.forceSoftwareRendering); + } + + // ----------------------- +@@ -986,18 +1021,28 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) { + std::unordered_map webgl::MakeIsEnabledMap(const bool webgl2) { + auto ret = std::unordered_map{}; + +- ret[LOCAL_GL_BLEND] = false; +- ret[LOCAL_GL_CULL_FACE] = false; +- ret[LOCAL_GL_DEPTH_TEST] = false; +- ret[LOCAL_GL_DITHER] = true; +- ret[LOCAL_GL_POLYGON_OFFSET_FILL] = false; +- ret[LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE] = false; +- ret[LOCAL_GL_SAMPLE_COVERAGE] = false; +- ret[LOCAL_GL_SCISSOR_TEST] = false; +- ret[LOCAL_GL_STENCIL_TEST] = false; ++ ret[LOCAL_GL_BLEND] = ++ MaskConfig::MParamGL(LOCAL_GL_BLEND, false, webgl2); ++ ret[LOCAL_GL_CULL_FACE] = ++ MaskConfig::MParamGL(LOCAL_GL_CULL_FACE, false, webgl2); ++ ret[LOCAL_GL_DEPTH_TEST] = ++ MaskConfig::MParamGL(LOCAL_GL_DEPTH_TEST, false, webgl2); ++ ret[LOCAL_GL_DITHER] = ++ MaskConfig::MParamGL(LOCAL_GL_DITHER, true, webgl2); ++ ret[LOCAL_GL_POLYGON_OFFSET_FILL] = ++ MaskConfig::MParamGL(LOCAL_GL_POLYGON_OFFSET_FILL, false, webgl2); ++ ret[LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE] = MaskConfig::MParamGL( ++ LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false, webgl2); ++ ret[LOCAL_GL_SAMPLE_COVERAGE] = ++ MaskConfig::MParamGL(LOCAL_GL_SAMPLE_COVERAGE, false, webgl2); ++ ret[LOCAL_GL_SCISSOR_TEST] = ++ MaskConfig::MParamGL(LOCAL_GL_SCISSOR_TEST, false, webgl2); ++ ret[LOCAL_GL_STENCIL_TEST] = ++ MaskConfig::MParamGL(LOCAL_GL_STENCIL_TEST, false, webgl2); + + if (webgl2) { +- ret[LOCAL_GL_RASTERIZER_DISCARD] = false; ++ ret[LOCAL_GL_RASTERIZER_DISCARD] = ++ MaskConfig::MParamGL(LOCAL_GL_RASTERIZER_DISCARD, false, webgl2); + } + + return ret; +@@ -2066,6 +2111,57 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + const auto& state = State(); + + // - ++ std::optional< ++ std::variant> ++ data; ++ data = MaskConfig::GLParam(pname, mIsWebGL2); ++ ++ if (data.has_value()) { ++ const auto& value = data.value(); ++ if (std::holds_alternative(value)) { ++ retval.set(JS::NumberValue(double(std::get(value)))); ++ return; ++ } ++ if (std::holds_alternative(value)) { ++ retval.set(JS::NumberValue(std::get(value))); ++ return; ++ } ++ if (std::holds_alternative(value)) { ++ retval.set(JS::BooleanValue(std::get(value))); ++ return; ++ } ++ if (std::holds_alternative(value)) { ++ retval.set(StringValue(cx, std::get(value), rv)); ++ return; ++ } ++ if (std::holds_alternative(value)) { ++ retval.set(JS::NullValue()); ++ return; ++ } ++ } ++ // If the value is not array (we will handle those later), ++ // then check if it should be blocked. ++ switch (pname) { ++ case LOCAL_GL_DEPTH_RANGE: ++ case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: ++ case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: ++ case LOCAL_GL_COLOR_CLEAR_VALUE: ++ case LOCAL_GL_BLEND_COLOR: ++ case LOCAL_GL_MAX_VIEWPORT_DIMS: ++ case LOCAL_GL_SCISSOR_BOX: ++ case LOCAL_GL_VIEWPORT: ++ case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: ++ case LOCAL_GL_COLOR_WRITEMASK: ++ case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_RENDERER_WEBGL: ++ case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_VENDOR_WEBGL: ++ break; ++ default: ++ if (MaskConfig::CheckBool(mIsWebGL2 ? "webGl2:parameters:blockIfNotDefined" ++ : "webGl:parameters:blockIfNotDefined")) { ++ retval.set(JS::NullValue()); ++ return; ++ } ++ } + + const auto fnSetRetval_Buffer = [&](const GLenum target) { + const auto buffer = *MaybeFind(state.mBoundBufferByTarget, target); +@@ -2171,49 +2267,84 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + + // 2 floats + case LOCAL_GL_DEPTH_RANGE: +- retval.set(Create(cx, this, state.mDepthRange, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>(pname, state.mDepthRange, ++ mIsWebGL2), ++ rv)); + return; + + case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: +- retval.set( +- Create(cx, this, limits.pointSizeRange, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>( ++ pname, limits.pointSizeRange, mIsWebGL2), ++ rv)); + return; + + case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: +- retval.set( +- Create(cx, this, limits.lineWidthRange, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>( ++ pname, limits.lineWidthRange, mIsWebGL2), ++ rv)); + return; + + // 4 floats + case LOCAL_GL_COLOR_CLEAR_VALUE: +- retval.set(Create(cx, this, state.mClearColor, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>(pname, state.mClearColor, ++ mIsWebGL2), ++ rv)); + return; + + case LOCAL_GL_BLEND_COLOR: +- retval.set(Create(cx, this, state.mBlendColor, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>(pname, state.mBlendColor, ++ mIsWebGL2), ++ rv)); + return; + + // 2 ints + case LOCAL_GL_MAX_VIEWPORT_DIMS: { + auto maxViewportDim = BitwiseCast(limits.maxViewportDim); + const auto dims = std::array{maxViewportDim, maxViewportDim}; +- retval.set(Create(cx, this, dims, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>(pname, dims, ++ mIsWebGL2), ++ rv)); + return; + } + + // 4 ints + case LOCAL_GL_SCISSOR_BOX: +- retval.set(Create(cx, this, state.mScissor, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>(pname, state.mScissor, ++ mIsWebGL2), ++ rv)); + return; + + case LOCAL_GL_VIEWPORT: +- retval.set(Create(cx, this, state.mViewport, rv)); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGL>(pname, state.mViewport, ++ mIsWebGL2), ++ rv)); + return; + +- // any + case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: +- retval.set(Create(cx, this, +- state.mCompressedTextureFormats, rv)); ++ std::vector compressedTextureUint32( ++ state.mCompressedTextureFormats.begin(), ++ state.mCompressedTextureFormats.end()); ++ retval.set(Create( ++ cx, this, ++ MaskConfig::MParamGLVector(pname, compressedTextureUint32, ++ mIsWebGL2), ++ rv)); + return; + } + +@@ -2574,8 +2576,12 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + switch (pname) { + case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_RENDERER_WEBGL: ++ if (auto value = MaskConfig::GetString("webGl:renderer")) { ++ ret = Some(value.value()); ++ break; ++ } + if (ShouldResistFingerprinting(RFPTarget::WebGLRenderInfo)) { + ret = Some("Mozilla"_ns); + } else { + ret = GetUnmaskedRenderer(); + if (ret && StaticPrefs::webgl_sanitize_unmasked_renderer()) { + ret = Some(webgl::SanitizeRenderer(*ret)); +@@ -2585,8 +2591,12 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + break; + + case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_VENDOR_WEBGL: ++ if (auto value = MaskConfig::GetString("webGl:vendor")) { ++ ret = Some(value.value()); ++ break; ++ } + ret = ShouldResistFingerprinting(RFPTarget::WebGLRenderInfo) + ? Some("Mozilla"_ns) + : GetUnmaskedVendor(); + break; + +@@ -2676,7 +2686,9 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + case LOCAL_GL_COLOR_WRITEMASK: { + const auto mask = uint8_t(*maybe); + const auto bs = std::bitset<4>(mask); +- const auto src = std::array{bs[0], bs[1], bs[2], bs[3]}; ++ const auto src = MaskConfig::MParamGL>( ++ pname, std::array{bs[0], bs[1], bs[2], bs[3]}, ++ mIsWebGL2); + JS::Rooted arr(cx); + if (!dom::ToJSValue(cx, src.data(), src.size(), &arr)) { + rv = NS_ERROR_OUT_OF_MEMORY; +@@ -3092,6 +3104,24 @@ + const FuncScope funcScope(*this, "getShaderPrecisionFormat"); + if (IsContextLost()) return nullptr; + ++ // Check for spoofed value ++ if (auto value = ++ MaskConfig::MShaderData(shadertype, precisiontype, mIsWebGL2)) { ++ const auto& format = value.value(); ++ const auto spoofed = webgl::ShaderPrecisionFormat{ ++ format[0], // rangeMin ++ format[1], // rangeMax ++ format[2] // precision ++ }; ++ return AsAddRefed(new WebGLShaderPrecisionFormatJS(spoofed)); ++ } ++ // Check if block if not defined is on ++ if (MaskConfig::CheckBool( ++ mIsWebGL2 ? "webGl2:shaderPrecisionFormats:blockIfNotDefined" ++ : "webGl:shaderPrecisionFormats:blockIfNotDefined")) { ++ return nullptr; ++ } ++ + const auto& shaderPrecisions = *notLost->info.shaderPrecisions; + const auto args = + webgl::GetShaderPrecisionFormatArgs{shadertype, precisiontype}; +@@ -6233,6 +6267,17 @@ bool ClientWebGLContext::IsSupported(const WebGLExtensionID ext, + return false; + } + ++ if (std::vector maskValues = ++ MaskConfig::GetStringList(mIsWebGL2 ? "webGl2:supportedExtensions" ++ : "webGl:supportedExtensions"); ++ !maskValues.empty()) { ++ if (std::find(maskValues.begin(), maskValues.end(), ++ GetExtensionName(ext)) != maskValues.end()) { ++ return true; ++ } ++ return false; ++ } ++ + const auto& limits = Limits(); + return limits.supportedExtensions[ext]; + } +@@ -6244,6 +6290,18 @@ void ClientWebGLContext::GetSupportedExtensions( + if (IsContextLost()) return; + + auto& retarr = retval.SetValue(); ++ ++ // Implement separately to prevent O(n^2) timing ++ if (std::vector maskValues = ++ MaskConfig::GetStringList(mIsWebGL2 ? "webGl2:supportedExtensions" ++ : "webGl:supportedExtensions"); ++ !maskValues.empty()) { ++ for (const auto& ext : maskValues) { ++ retarr.AppendElement(NS_ConvertUTF8toUTF16(ext)); ++ } ++ return; ++ } ++ + for (const auto i : MakeEnumeratedRange(WebGLExtensionID::Max)) { + if (!IsSupported(i, callerType)) continue; + +diff --git a/dom/canvas/ClientWebGLContext.h b/dom/canvas/ClientWebGLContext.h +index 62957ee445..dfb2b8ff53 100644 +--- a/dom/canvas/ClientWebGLContext.h ++++ b/dom/canvas/ClientWebGLContext.h +@@ -1074,6 +1074,9 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, + + // - + ++ // Helper to get booleans set in MaskConfig ++ bool MBoolVal(const std::string& key, bool defaultValue); ++ + void GetContextAttributes(dom::Nullable& retval); + + private: +diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build +index 3a533d36d1..41d74d9b3f 100644 +--- a/dom/canvas/moz.build ++++ b/dom/canvas/moz.build +@@ -221,3 +221,6 @@ if CONFIG["CC_TYPE"] == "gcc": + + # Add libFuzzer configuration directives + include("/tools/fuzzing/libfuzzer-config.mozbuild") ++ ++# DOM Mask ++LOCAL_INCLUDES += ["/camoucfg"] +\ No newline at end of file