1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
Description: Check buffer length in vrle.
Should fix CVE-2021-31315 related issues.
Origin: https://github.com/desktop-app/rlottie/commit/0ee2e9c5843257ccd11672611829b9bb5d02aa98
https://github.com/desktop-app/rlottie/commit/75b31e49b3c69355c4971ee2029eff23a22fcb75
https://github.com/desktop-app/rlottie/commit/839dcab7f083a51b8130061ea5ec245195af6c58
Author: John Preston <johnprestonmail@gmail.com>
Acked-By: Nicholas Guriev <guriev-ns@ya.ru>
Last-Update: Sat, 22 May 2021 19:07:06 +0300
--- a/src/vector/vrle.cpp
+++ b/src/vector/vrle.cpp
@@ -497,11 +497,14 @@ static void rleIntersectWithRect(const V
result->size = result->alloc - available;
}
-void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX)
+void blitXor(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX)
{
while (count--) {
int x = spans->x + offsetX;
int l = spans->len;
+ if (x < 0 || x + l > bufferLen) {
+ return;
+ }
uchar *ptr = buffer + x;
while (l--) {
int da = *ptr;
@@ -513,12 +516,15 @@ void blitXor(VRle::Span *spans, int coun
}
}
-void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer,
+void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, int bufferLen,
int offsetX)
{
while (count--) {
int x = spans->x + offsetX;
int l = spans->len;
+ if (x < 0 || x + l > bufferLen) {
+ return;
+ }
uchar *ptr = buffer + x;
while (l--) {
*ptr = divBy255((255 - spans->coverage) * (*ptr));
@@ -528,11 +534,14 @@ void blitDestinationOut(VRle::Span *span
}
}
-void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX)
+void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX)
{
while (count--) {
int x = spans->x + offsetX;
int l = spans->len;
+ if (x < 0 || x + l > bufferLen) {
+ return;
+ }
uchar *ptr = buffer + x;
while (l--) {
*ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr));
@@ -542,11 +551,14 @@ void blitSrcOver(VRle::Span *spans, int
}
}
-void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX)
+void blit(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX)
{
while (count--) {
int x = spans->x + offsetX;
int l = spans->len;
+ if (x < 0 || x + l > bufferLen) {
+ return;
+ }
uchar *ptr = buffer + x;
while (l--) {
*ptr = std::max(spans->coverage, *ptr);
@@ -556,13 +568,16 @@ void blit(VRle::Span *spans, int count,
}
}
-size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out)
+size_t bufferToRle(uchar *buffer, int bufferLen, int size, int offsetX, int y, VRle::Span *out)
{
size_t count = 0;
uchar value = buffer[0];
int curIndex = 0;
size = offsetX < 0 ? size + offsetX : size;
+ if (size > bufferLen) {
+ return count;
+ }
for (int i = 0; i < size; i++) {
uchar curValue = buffer[0];
if (value != curValue) {
@@ -620,14 +635,15 @@ static void rleOpGeneric(VRleHelper *a,
int bLength = (bPtr - 1)->x + (bPtr - 1)->len;
int offset = std::min(aStart->x, bStart->x);
- std::array<uchar, 1024> array = {{0}};
- blit(aStart, (aPtr - aStart), array.data(), -offset);
+ constexpr auto kBufferSize = 1024;
+ std::array<uchar, kBufferSize> array = {{0}};
+ blit(aStart, (aPtr - aStart), array.data(), kBufferSize, -offset);
if (op == Operation::Add)
- blitSrcOver(bStart, (bPtr - bStart), array.data(), -offset);
+ blitSrcOver(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset);
else if (op == Operation::Xor)
- blitXor(bStart, (bPtr - bStart), array.data(), -offset);
+ blitXor(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset);
VRle::Span *tResult = temp.data();
- size_t size = bufferToRle(array.data(), std::max(aLength, bLength),
+ size_t size = bufferToRle(array.data(), kBufferSize, std::max(aLength, bLength),
offset, y, tResult);
if (available >= size) {
while (size--) {
@@ -683,11 +699,12 @@ static void rleSubstractWithRle(VRleHelp
int bLength = (bPtr - 1)->x + (bPtr - 1)->len;
int offset = std::min(aStart->x, bStart->x);
- std::array<uchar, 1024> array = {{0}};
- blit(aStart, (aPtr - aStart), array.data(), -offset);
- blitDestinationOut(bStart, (bPtr - bStart), array.data(), -offset);
+ constexpr auto kBufferSize = 1024;
+ std::array<uchar, kBufferSize> array = {{0}};
+ blit(aStart, (aPtr - aStart), array.data(), kBufferSize, -offset);
+ blitDestinationOut(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset);
VRle::Span *tResult = temp.data();
- size_t size = bufferToRle(array.data(), std::max(aLength, bLength),
+ size_t size = bufferToRle(array.data(), kBufferSize, std::max(aLength, bLength),
offset, y, tResult);
if (available >= size) {
while (size--) {
|