Fix CVE-2020-26971

This commit is contained in:
lvfei 2024-05-08 14:25:55 +08:00
parent d4cf889c2f
commit 6170c4fb7f
2 changed files with 318 additions and 2 deletions

311
CVE-2020-26971.patch Normal file
View File

@ -0,0 +1,311 @@
From f3b438abf346c7f49b16f800a3af7ff9d1a4edcc Mon Sep 17 00:00:00 2001
From: Jeff Gilbert <jgilbert@mozilla.com>
Date: Mon, 23 Nov 2020 19:54:41 +0000 (2020-11-24)
Subject: [PATCH] CVE-2020-26971
---
dom/canvas/WebGLFramebuffer.cpp | 129 ++++++++++++++----
dom/canvas/WebGLTypes.h | 51 ++++++-
.../test/webgl-conf/generated-mochitest.ini | 1 -
.../test/webgl-conf/mochitest-errata.ini | 2 -
4 files changed, 154 insertions(+), 29 deletions(-)
diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp
index 155ef0277e..53be7b4570 100644
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -1263,11 +1263,16 @@ static void GetBackbufferFormats(const WebGLContext* webgl,
}
/*static*/
-void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint srcX0,
- GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1,
- GLint dstY1, GLbitfield mask,
- GLenum filter) {
+void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint _srcX0,
+ GLint _srcY0, GLint _srcX1, GLint _srcY1,
+ GLint _dstX0, GLint _dstY0, GLint _dstX1,
+ GLint _dstY1, GLbitfield mask,
+ GLenum filter) {
+ auto srcP0 = ivec2{_srcX0, _srcY0};
+ auto srcP1 = ivec2{_srcX1, _srcY1};
+ auto dstP0 = ivec2{_dstX0, _dstY0};
+ auto dstP1 = ivec2{_dstX1, _dstY1};
+
const GLbitfield depthAndStencilBits =
LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT;
if (bool(mask & depthAndStencilBits) && filter == LOCAL_GL_LINEAR) {
@@ -1420,8 +1425,8 @@ void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint srcX0,
return;
}
- if (dstX0 != srcX0 || dstX1 != srcX1 || dstY0 != srcY0 || dstY1 != srcY1) {
- webgl->ErrorInvalidOperation(
+ if (srcP0 != dstP0 || srcP1 != dstP1) {
+ webgl->ErrorInvalidOperation(
"If the source is multisampled, then the"
" source and dest regions must match exactly.");
return;
@@ -1510,11 +1515,83 @@ void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint srcX0,
}
// -
+ // Mutually constrain src and dst rects for eldritch blits.
+
+ [&]{
+ using fvec2 = avec2<float>; // Switch to float, because there's no perfect solution anyway.
+
+ const auto zero2f = fvec2{0, 0};
+ const auto srcSizef = AsVec(srcSize).StaticCast<fvec2>();
+ const auto dstSizef = AsVec(dstSize).StaticCast<fvec2>();
+
+ const auto srcP0f = srcP0.StaticCast<fvec2>();
+ const auto srcP1f = srcP1.StaticCast<fvec2>();
+ const auto dstP0f = dstP0.StaticCast<fvec2>();
+ const auto dstP1f = dstP1.StaticCast<fvec2>();
+
+ const auto srcRectDiff = srcP1f - srcP0f;
+ const auto dstRectDiff = dstP1f - dstP0f;
+
+ // Skip if zero-sized.
+ if (!srcRectDiff.x || !srcRectDiff.y || !dstRectDiff.x || !dstRectDiff.y) {
+ srcP0 = srcP1 = dstP0 = dstP1 = {0,0};
+ return;
+ }
+
+ // Clamp the rect points
+ const auto srcQ0 = srcP0f.ClampMinMax(zero2f, srcSizef);
+ const auto srcQ1 = srcP1f.ClampMinMax(zero2f, srcSizef);
+
+ // Normalized to the [0,1] abstact copy rect
+ const auto srcQ0Norm = (srcQ0 - srcP0f) / srcRectDiff;
+ const auto srcQ1Norm = (srcQ1 - srcP0f) / srcRectDiff;
+
+ // Map into dst
+ const auto srcQ0InDst = dstP0f + srcQ0Norm * dstRectDiff;
+ const auto srcQ1InDst = dstP0f + srcQ1Norm * dstRectDiff;
+
+ // Clamp the rect points
+ const auto dstQ0 = srcQ0InDst.ClampMinMax(zero2f, dstSizef);
+ const auto dstQ1 = srcQ1InDst.ClampMinMax(zero2f, dstSizef);
+
+ // Alright, time to go back to src!
+ // Normalized to the [0,1] abstact copy rect
+ const auto dstQ0Norm = (dstQ0 - dstP0f) / dstRectDiff;
+ const auto dstQ1Norm = (dstQ1 - dstP0f) / dstRectDiff;
+
+ // Map into src
+ const auto dstQ0InSrc = srcP0f + dstQ0Norm * srcRectDiff;
+ const auto dstQ1InSrc = srcP0f + dstQ1Norm * srcRectDiff;
+
+ const auto srcQ0Constrained = dstQ0InSrc.ClampMinMax(zero2f, srcSizef);
+ const auto srcQ1Constrained = dstQ1InSrc.ClampMinMax(zero2f, srcSizef);
+
+ // Round, don't floor:
+ srcP0 = (srcQ0Constrained + 0.5).StaticCast<ivec2>();
+ srcP1 = (srcQ1Constrained + 0.5).StaticCast<ivec2>();
+ dstP0 = (dstQ0 + 0.5).StaticCast<ivec2>();
+ dstP1 = (dstQ1 + 0.5).StaticCast<ivec2>();
+ }();
+
+ bool inBounds = true;
+ inBounds &= ( srcP0 == srcP0.Clamp({0,0}, AsVec(srcSize)) );
+ inBounds &= ( srcP1 == srcP1.Clamp({0,0}, AsVec(srcSize)) );
+ inBounds &= ( dstP0 == dstP0.Clamp({0,0}, AsVec(dstSize)) );
+ inBounds &= ( dstP1 == dstP1.Clamp({0,0}, AsVec(dstSize)) );
+ if (!inBounds) {
+ webgl->ErrorImplementationBug("Subrects still not within src and dst after constraining.");
+ return;
+ }
+
+ // -
+ // Execute as constrained
+
const auto& gl = webgl->gl;
const ScopedDrawCallWrapper wrapper(*webgl);
- gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
- mask, filter);
+
+ gl->fBlitFramebuffer(srcP0.x, srcP0.y, srcP1.x, srcP1.y, dstP0.x, dstP0.y,
+ dstP1.x, dstP1.y, mask, filter);
// -
@@ -1557,13 +1634,14 @@ void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint srcX0,
if (srcColorFormat->isSRGB) {
// srgb -> linear
- gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, srcX0, srcY0, srcX1,
- srcY1, LOCAL_GL_COLOR_BUFFER_BIT,
- LOCAL_GL_NEAREST);
+ gl->fBlitFramebuffer(srcP0.x, srcP0.y, srcP1.x, srcP1.y, srcP0.x,
+ srcP0.y, srcP1.x, srcP1.y,
+ LOCAL_GL_COLOR_BUFFER_BIT, LOCAL_GL_NEAREST);
} else {
// linear -> srgb
- gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
- dstY1, LOCAL_GL_COLOR_BUFFER_BIT, filter);
+ gl->fBlitFramebuffer(srcP0.x, srcP0.y, srcP1.x, srcP1.y, dstP0.x,
+ dstP0.y, dstP1.x, dstP1.y,
+ LOCAL_GL_COLOR_BUFFER_BIT, filter);
}
const auto& blitHelper = *gl->BlitHelper();
@@ -1577,13 +1655,14 @@ void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint srcX0,
if (srcColorFormat->isSRGB) {
// srgb -> linear
- gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
- dstY1, LOCAL_GL_COLOR_BUFFER_BIT, filter);
+ gl->fBlitFramebuffer(srcP0.x, srcP0.y, srcP1.x, srcP1.y, dstP0.x,
+ dstP0.y, dstP1.x, dstP1.y,
+ LOCAL_GL_COLOR_BUFFER_BIT, filter);
} else {
// linear -> srgb
- gl->fBlitFramebuffer(dstX0, dstY0, dstX1, dstY1, dstX0, dstY0, dstX1,
- dstY1, LOCAL_GL_COLOR_BUFFER_BIT,
- LOCAL_GL_NEAREST);
+ gl->fBlitFramebuffer(dstP0.x, dstP0.y, dstP1.x, dstP1.y, dstP0.x,
+ dstP0.y, dstP1.x, dstP1.y,
+ LOCAL_GL_COLOR_BUFFER_BIT, LOCAL_GL_NEAREST);
}
}
}
@@ -1598,13 +1677,15 @@ void WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, GLint srcX0,
if (webgl->mRasterizerDiscardEnabled) {
gl->fDisable(LOCAL_GL_RASTERIZER_DISCARD);
}
- const WebGLContext::ScissorRect dstRect = {
- std::min(dstX0, dstX1), std::min(dstY0, dstY1), abs(dstX1 - dstX0),
- abs(dstY1 - dstY0)};
+ const auto dstRectMin = MinExtents(dstP0, dstP1);
+ const auto dstRectMax = MaxExtents(dstP0, dstP1);
+ const auto dstRectSize = dstRectMax - dstRectMin;
+ const WebGLContext::ScissorRect dstRect = {dstRectMin.x, dstRectMin.y,
+ dstRectSize.x, dstRectSize.y};
+
dstRect.Apply(*gl);
gl->fClearColor(0, 0, 0, 1);
-
- webgl->DoColorMask(0x8);
+ webgl->DoColorMask(1 << 3);
gl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
if (!webgl->mScissorTestEnabled) {
diff --git a/dom/canvas/WebGLTypes.h b/dom/canvas/WebGLTypes.h
index f04184e289..38006ab37a 100644
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -15,6 +15,7 @@
#include "GLDefs.h"
#include "mozilla/Casting.h"
#include "mozilla/CheckedInt.h"
+#include "mozilla/MathAlgorithms.h"
#include "mozilla/Range.h"
#include "mozilla/RefCounted.h"
#include "mozilla/gfx/Point.h"
@@ -391,8 +392,9 @@ struct WebGLContextOptions {
// -
-template <typename T>
+template <typename _T>
struct avec2 {
+ using T = _T;
T x = T();
T y = T();
@@ -418,10 +420,54 @@ struct avec2 {
bool operator==(const avec2& rhs) const { return x == rhs.x && y == rhs.y; }
bool operator!=(const avec2& rhs) const { return !(*this == rhs); }
+
+#define _(OP) \
+ avec2 operator OP(const avec2& rhs) const { \
+ return {x OP rhs.x, y OP rhs.y}; \
+ } \
+ avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
+
+ _(+)
+ _(-)
+ _(*)
+ _(/)
+
+#undef _
+
+ avec2 Clamp(const avec2& min, const avec2& max) const {
+ return {mozilla::Clamp(x, min.x, max.x), mozilla::Clamp(y, min.y, max.y)};
+ }
+
+ // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
+ // helper.
+ avec2 ClampMinMax(const avec2& min, const avec2& max) const {
+ const auto ClampScalar = [](const T v, const T min, const T max) {
+ return std::max(min, std::min(v, max));
+ };
+ return {ClampScalar(x, min.x, max.x), ClampScalar(y, min.y, max.y)};
+ }
+
+ template <typename U>
+ U StaticCast() const {
+ return {static_cast<typename U::T>(x), static_cast<typename U::T>(y)};
+ }
};
-template <typename T>
+template<typename T>
+avec2<T> MinExtents(const avec2<T>& a, const avec2<T>& b) {
+ return {std::min(a.x, b.x), std::min(a.y, b.y)};
+}
+
+template<typename T>
+avec2<T> MaxExtents(const avec2<T>& a, const avec2<T>& b) {
+ return {std::max(a.x, b.x), std::max(a.y, b.y)};
+}
+
+// -
+
+template <typename _T>
struct avec3 {
+ using T = _T;
T x = T();
T y = T();
T z = T();
@@ -454,6 +500,7 @@ typedef avec3<int32_t> ivec3;
typedef avec2<uint32_t> uvec2;
typedef avec3<uint32_t> uvec3;
+inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }
// -
namespace webgl {
diff --git a/dom/canvas/test/webgl-conf/generated-mochitest.ini b/dom/canvas/test/webgl-conf/generated-mochitest.ini
index 0d47a180bd..246f83c465 100644
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -5328,7 +5328,6 @@ subsuite = webgl2-core
fail-if = (os == 'linux')
[generated/test_2_conformance2__rendering__blitframebuffer-outside-readbuffer.html]
subsuite = webgl2-core
-fail-if = (os == 'linux') || (os == 'mac')
[generated/test_2_conformance2__rendering__blitframebuffer-r11f-g11f-b10f.html]
subsuite = webgl2-core
[generated/test_2_conformance2__rendering__blitframebuffer-resolve-to-back-buffer.html]
diff --git a/dom/canvas/test/webgl-conf/mochitest-errata.ini b/dom/canvas/test/webgl-conf/mochitest-errata.ini
index 2ef5365c9e..903e721b02 100644
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -335,8 +335,6 @@ skip-if = (os == 'android')
skip-if = (os == 'win') || (os == 'mac')
[generated/test_2_conformance2__glsl3__tricky-loop-conditions.html]
fail-if = (os == 'win')
-[generated/test_2_conformance2__rendering__blitframebuffer-outside-readbuffer.html]
-fail-if = (os == 'linux') || (os == 'mac')
[generated/test_2_conformance2__textures__misc__tex-srgb-mipmap.html]
fail-if = (os == 'mac')
[generated/test_2_conformance2__textures__video__tex-3d-r11f_g11f_b10f-rgb-float.html]
--
2.27.0

View File

@ -88,7 +88,7 @@
Summary: Mozilla Firefox Web browser
Name: firefox
Version: 79.0
Release: 19
Release: 20
URL: https://www.mozilla.org/firefox/
License: MPLv1.1 or GPLv2+ or LGPLv2+
Source0: https://archive.mozilla.org/pub/firefox/releases/%{version}/source/firefox-%{version}.source.tar.xz
@ -198,6 +198,7 @@ Patch654: CVE-2022-22755.patch
Patch655: CVE-2022-1802.patch
Patch656: CVE-2023-44488.patch
Patch657: CVE-2020-26950.patch
Patch658: CVE-2020-26971.patch
%if %{?system_nss}
BuildRequires: pkgconfig(nspr) >= %{nspr_version} pkgconfig(nss) >= %{nss_version}
@ -390,6 +391,7 @@ tar -xf %{SOURCE3}
%patch655 -p1
%patch656 -p1
%patch657 -p1
%patch658 -p1
%{__rm} -f .mozconfig
%{__cp} %{SOURCE10} .mozconfig
@ -838,8 +840,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%endif
%changelog
* Tue May 07 2024 lvfei <lvfei@kylinos.cn> - 79.0-20
- Fix CVE-2020-26971
* Wed Apr 24 2024 lvfei <lvfei@kylinos.cn> - 79.0-19
- Fif CVE-2020-26950
- Fix CVE-2020-26950
* Fri Apr 19 2024 lvfei <lvfei@kylinos.cn> - 79.0-18
- Fix CVE-2023-44488