Commit 8c593acd authored by Natanael Copa's avatar Natanael Copa

main/libjpeg-turbo: backport fix for CVE-2019-2201

fixes #10948
parent da0d4ca4
......@@ -2,7 +2,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=libjpeg-turbo
pkgver=1.5.3
pkgrel=5
pkgrel=6
pkgdesc="accelerated baseline JPEG compression and decompression library"
url="https://libjpeg-turbo.org/"
arch="all"
......@@ -15,9 +15,12 @@ source="https://downloads.sourceforge.net/libjpeg-turbo/libjpeg-turbo-$pkgver.ta
0001-tjLoadImage-Fix-FPE-triggered-by-malformed-BMP.patch
CVE-2018-11813.patch
CVE-2018-14498.patch
CVE-2019-2201.patch
"
# secfixes:
# 1.5.3-r6:
# - CVE-2019-2201
# 1.5.3-r5:
# - CVE-2018-14498
# 1.5.3-r3:
......@@ -74,4 +77,5 @@ dev() {
sha512sums="b611b1cc3d1ddedddad871854b42449d053a5f910ed1bdfa45c98e0270f4ecc110fde3a10111d2b876d847a826fa634f09c0bb8c357056c9c3a91c9065eb5202 libjpeg-turbo-1.5.3.tar.gz
d6465d96427289d90c342e94316018565eb1711ea0028121ea0a962900b7c7599a7457e42201bcfd288da30019ae3b841ce319cfbe02705d49749d660ef04b74 0001-tjLoadImage-Fix-FPE-triggered-by-malformed-BMP.patch
d32234df784ebe1cad6af114f74d14995637e494a502c171e154e1abc5aa335930d3a256fda234a85842d5c1658d2fac6474e0bc959fdf04413f69a35e3bf39a CVE-2018-11813.patch
315aba552a2d66cdc8d83c5602a7e47c995f6709509afd07daf3ffacaf650404dc9f7a4beeb1373cabb5afc915a3d4c704b71dfdfcad3bc25ae5361ed16980d5 CVE-2018-14498.patch"
315aba552a2d66cdc8d83c5602a7e47c995f6709509afd07daf3ffacaf650404dc9f7a4beeb1373cabb5afc915a3d4c704b71dfdfcad3bc25ae5361ed16980d5 CVE-2018-14498.patch
28e0efd9227c3f6fe3d328f8ad6ae3f52875cdbb91934a93b516a0005bf4d22ac9e589e27472a17da8d8641cad10561cbd2de46e41d2b83378d6df969eed8848 CVE-2019-2201.patch"
From b5eb30229e9b9c4a09917e7f563317c380031a22 Mon Sep 17 00:00:00 2001
From: DRC <information@libjpeg-turbo.org>
Date: Thu, 11 Jul 2019 15:30:04 -0500
Subject: [PATCH 1/2] TurboJPEG: Properly handle gigapixel images
Prevent several integer overflow issues and subsequent segfaults that
occurred when attempting to compress or decompress gigapixel images with
the TurboJPEG API:
- Modify tjBufSize(), tjBufSizeYUV2(), and tjPlaneSizeYUV() to avoid
integer overflow when computing the return values and to return an
error if such an overflow is unavoidable.
- Modify tjunittest to validate the above.
- Modify tjCompress2(), tjEncodeYUVPlanes(), tjDecompress2(), and
tjDecodeYUVPlanes() to avoid integer overflow when computing the row
pointers in the 64-bit TurboJPEG C API.
- Modify TJBench (both C and Java versions) to avoid overflowing the
size argument to malloc()/new and to fail gracefully if such an
overflow is unavoidable.
In general, this allows gigapixel images to be accommodated by the
64-bit TurboJPEG C API when using automatic JPEG buffer (re)allocation.
Such images cannot currently be accommodated without automatic JPEG
buffer (re)allocation, due to the fact that tjAlloc() accepts a 32-bit
integer argument (oops.) Such images cannot be accommodated in the
TurboJPEG Java API due to the fact that Java always uses a signed 32-bit
integer as an array index.
Fixes #361
(cherry picked from commit 2a9e3bd7430cfda1bc812d139e0609c6aca0b884)
---
java/TJBench.java | 11 ++++++++++-
tjbench.c | 44 +++++++++++++++++++++++++++++------------
tjunittest.c | 38 +++++++++++++++++++++++++++++++++++
turbojpeg.c | 50 ++++++++++++++++++++++++++++-------------------
4 files changed, 109 insertions(+), 34 deletions(-)
diff --git a/java/TJBench.java b/java/TJBench.java
index ddc414c..9b1ff81 100644
--- a/java/TJBench.java
+++ b/java/TJBench.java
@@ -96,6 +96,8 @@ class TJBench {
int rindex = TJ.getRedOffset(pixelFormat);
int gindex = TJ.getGreenOffset(pixelFormat);
int bindex = TJ.getBlueOffset(pixelFormat);
+ if ((long)w[0] * (long)h[0] * (long)ps > (long)Integer.MAX_VALUE)
+ throw new Exception("Image is too large");
byte[] dstBuf = new byte[w[0] * h[0] * ps];
int pixels = w[0] * h[0], dstPtr = 0, rgbPtr = 0;
while (pixels-- > 0) {
@@ -147,8 +149,11 @@ class TJBench {
tjd = new TJDecompressor();
- if (dstBuf == null)
+ if (dstBuf == null) {
+ if ((long)pitch * (long)scaledh > (long)Integer.MAX_VALUE)
+ throw new Exception("Image is too large");
dstBuf = new byte[pitch * scaledh];
+ }
/* Set the destination buffer to gray so we know whether the decompressor
attempted to write to it */
@@ -287,6 +292,8 @@ class TJBench {
String pfStr = pixFormatStr[pf];
YUVImage yuvImage = null;
+ if ((long)pitch * (long)h > (long)Integer.MAX_VALUE)
+ throw new Exception("Image is too large");
tmpBuf = new byte[pitch * h];
if (quiet == 0)
@@ -435,6 +442,8 @@ class TJBench {
int ps = TJ.getPixelSize(pf), tile;
FileInputStream fis = new FileInputStream(fileName);
+ if (fis.getChannel().size() > (long)Integer.MAX_VALUE)
+ throw new Exception("Image is too large");
int srcSize = (int)fis.getChannel().size();
srcBuf = new byte[srcSize];
fis.read(srcBuf, 0, srcSize);
diff --git a/tjbench.c b/tjbench.c
index 0187b75..e90ba3d 100644
--- a/tjbench.c
+++ b/tjbench.c
@@ -32,6 +32,7 @@
#include <ctype.h>
#include <math.h>
#include <errno.h>
+#include <limits.h>
#include <cdjpeg.h>
#include "./bmp.h"
#include "./tjutil.h"
@@ -127,7 +128,10 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
if(dstbuf==NULL)
{
- if((dstbuf=(unsigned char *)malloc(pitch*scaledh))==NULL)
+ if ((unsigned long long)pitch * (unsigned long long)scaledh >
+ (unsigned long long)((size_t)-1))
+ _throw("allocating destination buffer", "Image is too large");
+ if ((dstbuf = (unsigned char *)malloc((size_t)pitch * scaledh)) == NULL)
_throwunix("allocating destination buffer");
dstbufalloc=1;
}
@@ -139,7 +143,10 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
{
int width=dotile? tilew:scaledw;
int height=dotile? tileh:scaledh;
- int yuvsize=tjBufSizeYUV2(width, yuvpad, height, subsamp);
+ unsigned long yuvsize=tjBufSizeYUV2(width, yuvpad, height, subsamp);
+
+ if (yuvsize == (unsigned long)-1)
+ _throwtj("allocating YUV buffer");
if((yuvbuf=(unsigned char *)malloc(yuvsize))==NULL)
_throwunix("allocating YUV buffer");
memset(yuvbuf, 127, yuvsize);
@@ -242,14 +249,14 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
if(!quiet) printf("Compression error written to %s.\n", tempstr);
if(subsamp==TJ_GRAYSCALE)
{
- int index, index2;
+ unsigned long index, index2;
for(row=0, index=0; row<h; row++, index+=pitch)
{
for(col=0, index2=index; col<w; col++, index2+=ps)
{
- int rindex=index2+tjRedOffset[pf];
- int gindex=index2+tjGreenOffset[pf];
- int bindex=index2+tjBlueOffset[pf];
+ unsigned long rindex=index2+tjRedOffset[pf];
+ unsigned long gindex=index2+tjGreenOffset[pf];
+ unsigned long bindex=index2+tjBlueOffset[pf];
int y=(int)((double)srcbuf[rindex]*0.299
+ (double)srcbuf[gindex]*0.587
+ (double)srcbuf[bindex]*0.114 + 0.5);
@@ -290,13 +297,16 @@ int fullTest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual,
unsigned char **jpegbuf=NULL, *yuvbuf=NULL, *tmpbuf=NULL, *srcptr, *srcptr2;
double start, elapsed, elapsedEncode;
int totaljpegsize=0, row, col, i, tilew=w, tileh=h, retval=0;
- int iter, yuvsize=0;
- unsigned long *jpegsize=NULL;
+ int iter;
+ unsigned long *jpegsize=NULL, yuvsize=0;
int ps=tjPixelSize[pf];
int ntilesw=1, ntilesh=1, pitch=w*ps;
const char *pfStr=pixFormatStr[pf];
- if((tmpbuf=(unsigned char *)malloc(pitch*h)) == NULL)
+ if((unsigned long long)pitch * (unsigned long long)h >
+ (unsigned long long)((size_t)-1))
+ _throw("allocating temporary image buffer", "Image is too large");
+ if((tmpbuf = (unsigned char *)malloc((size_t)pitch * h)) == NULL)
_throwunix("allocating temporary image buffer");
if(!quiet)
@@ -322,6 +332,8 @@ int fullTest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual,
if((flags&TJFLAG_NOREALLOC)!=0)
for(i=0; i<ntilesw*ntilesh; i++)
{
+ if(tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
+ _throw("getting buffer size", "Image is too large");
if((jpegbuf[i]=(unsigned char *)tjAlloc(tjBufSize(tilew, tileh,
subsamp)))==NULL)
_throwunix("allocating JPEG tiles");
@@ -339,6 +351,8 @@ int fullTest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual,
if(doyuv)
{
yuvsize=tjBufSizeYUV2(tilew, yuvpad, tileh, subsamp);
+ if(yuvsize == (unsigned long)-1)
+ _throwtj("allocating YUV buffer");
if((yuvbuf=(unsigned char *)malloc(yuvsize))==NULL)
_throwunix("allocating YUV buffer");
memset(yuvbuf, 127, yuvsize);
@@ -418,7 +432,7 @@ int fullTest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual,
{
printf("Encode YUV --> Frame rate: %f fps\n",
(double)iter/elapsedEncode);
- printf(" Output image size: %d bytes\n", yuvsize);
+ printf(" Output image size: %lu bytes\n", yuvsize);
printf(" Compression ratio: %f:1\n",
(double)(w*h*ps)/(double)yuvsize);
printf(" Throughput: %f Megapixels/sec\n",
@@ -561,9 +575,12 @@ int decompTest(char *filename)
_throwunix("allocating JPEG size array");
memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh);
- if((flags&TJFLAG_NOREALLOC)!=0 || !dotile)
+ if ((flags & TJFLAG_NOREALLOC) != 0 &&
+ (dotile || xformop != TJXOP_NONE || xformopt != 0 || customFilter))
for(i=0; i<ntilesw*ntilesh; i++)
{
+ if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
+ _throw("getting buffer size", "Image is too large");
if((jpegbuf[i]=(unsigned char *)tjAlloc(tjBufSize(tilew, tileh,
subsamp)))==NULL)
_throwunix("allocating JPEG tiles");
@@ -684,7 +701,7 @@ int decompTest(char *filename)
else
{
if(quiet==1) printf("N/A N/A ");
- tjFree(jpegbuf[0]);
+ if(jpegbuf[0]) tjFree(jpegbuf[0]);
jpegbuf[0]=NULL;
decompsrc=1;
}
@@ -701,7 +718,8 @@ int decompTest(char *filename)
for(i=0; i<ntilesw*ntilesh; i++)
{
- tjFree(jpegbuf[i]); jpegbuf[i]=NULL;
+ if(jpegbuf[i]) tjFree(jpegbuf[i]);
+ jpegbuf[i] = NULL;
}
free(jpegbuf); jpegbuf=NULL;
if(jpegsize) {free(jpegsize); jpegsize=NULL;}
diff --git a/tjunittest.c b/tjunittest.c
index f793796..a96440b 100644
--- a/tjunittest.c
+++ b/tjunittest.c
@@ -40,6 +40,7 @@
#include <time.h>
#define random() rand()
#endif
+#include "config.h" /* for SIZEOF_SIZE_T */
void usage(char *progName)
@@ -593,6 +594,42 @@ void doTest(int w, int h, const int *formats, int nformats, int subsamp,
}
+#if SIZEOF_SIZE_T == 8
+#define CHECKSIZE(function) { \
+ if ((unsigned long long)size < (unsigned long long)0xFFFFFFFF) \
+ _throw(#function " overflow"); \
+}
+#else
+#define CHECKSIZE(function) { \
+ if (size != (unsigned long)(-1) || \
+ !strcmp(tjGetErrorStr(), "No error")) \
+ _throw(#function " overflow"); \
+}
+#endif
+
+static void overflowTest(void)
+{
+ /* Ensure that the various buffer size functions don't overflow */
+ unsigned long size;
+
+ size = tjBufSize(26755, 26755, TJSAMP_444);
+ CHECKSIZE(tjBufSize());
+ size = TJBUFSIZE(26755, 26755);
+ CHECKSIZE(TJBUFSIZE());
+ size = tjBufSizeYUV2(37838, 1, 37838, TJSAMP_444);
+ CHECKSIZE(tjBufSizeYUV2());
+ size = TJBUFSIZEYUV(37838, 37838, TJSAMP_444);
+ CHECKSIZE(TJBUFSIZEYUV());
+ size = tjBufSizeYUV(37838, 37838, TJSAMP_444);
+ CHECKSIZE(tjBufSizeYUV());
+ size = tjPlaneSizeYUV(0, 65536, 0, 65536, TJSAMP_444);
+ CHECKSIZE(tjPlaneSizeYUV());
+
+bailout:
+ return;
+}
+
+
void bufSizeTest(void)
{
int w, h, i, subsamp;
@@ -704,6 +741,7 @@ int main(int argc, char *argv[])
}
if(alloc) printf("Testing automatic buffer allocation\n");
if(doyuv) num4bf=4;
+ overflowTest();
doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
diff --git a/turbojpeg.c b/turbojpeg.c
index 330a004..be03482 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -644,7 +644,8 @@ DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
int jpegSubsamp)
{
- unsigned long retval=0; int mcuw, mcuh, chromasf;
+ unsigned long long retval=0;
+ int mcuw, mcuh, chromasf;
if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
_throw("tjBufSize(): Invalid argument");
@@ -654,32 +655,37 @@ DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
mcuw=tjMCUWidth[jpegSubsamp];
mcuh=tjMCUHeight[jpegSubsamp];
chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
- retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
+ retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
+ if (retval > (unsigned long long)((unsigned long)-1))
+ _throw("tjBufSize(): Image is too large");
bailout:
- return retval;
+ return (unsigned long)retval;
}
DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
{
- unsigned long retval=0;
+ unsigned long long retval = 0;
if(width<1 || height<1)
_throw("TJBUFSIZE(): Invalid argument");
/* This allows for rare corner cases in which a JPEG image can actually be
larger than the uncompressed input (we wouldn't mention it if it hadn't
happened before.) */
- retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
+ retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
+ if (retval > (unsigned long long)((unsigned long)-1))
+ _throw("TJBUFSIZE(): Image is too large");
bailout:
- return retval;
+ return (unsigned long)retval;
}
DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
int subsamp)
{
- int retval=0, nc, i;
+ unsigned long long retval=0;
+ int nc, i;
if(subsamp<0 || subsamp>=NUMSUBOPT)
_throw("tjBufSizeYUV2(): Invalid argument");
@@ -691,11 +697,13 @@ DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
int stride=PAD(pw, pad);
int ph=tjPlaneHeight(i, height, subsamp);
if(pw<0 || ph<0) return -1;
- else retval+=stride*ph;
+ else retval+=(unsigned long long)stride*ph;
}
+ if (retval > (unsigned long long)((unsigned long)-1))
+ _throw("tjBufSizeYUV2(): Image is too large");
bailout:
- return retval;
+ return (unsigned long) retval;
}
DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
@@ -756,7 +764,7 @@ DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
int stride, int height, int subsamp)
{
- unsigned long retval=0;
+ unsigned long long retval=0;
int pw, ph;
if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
@@ -769,10 +777,12 @@ DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
if(stride==0) stride=pw;
else stride=abs(stride);
- retval=stride*(ph-1)+pw;
+ retval=(unsigned long long)stride*(ph-1)+pw;
+ if (retval > (unsigned long long)((unsigned long)-1))
+ _throw("tjPlaneSizeYUV(): Image is too large");
bailout:
- return retval;
+ return (unsigned long)retval;
}
@@ -836,8 +846,8 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
for(i=0; i<height; i++)
{
if(flags&TJFLAG_BOTTOMUP)
- row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
- else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
+ row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*(size_t)pitch];
+ else row_pointer[i]=(JSAMPROW)&srcBuf[i*(size_t)pitch];
}
while(cinfo->next_scanline<cinfo->image_height)
{
@@ -964,8 +974,8 @@ DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
for(i=0; i<height; i++)
{
if(flags&TJFLAG_BOTTOMUP)
- row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
- else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
+ row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*(size_t)pitch];
+ else row_pointer[i]=(JSAMPROW)&srcBuf[i*(size_t)pitch];
}
if(height<ph0)
for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
@@ -1485,8 +1495,8 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
for(i=0; i<(int)dinfo->output_height; i++)
{
if(flags&TJFLAG_BOTTOMUP)
- row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
- else row_pointer[i]=&dstBuf[i*pitch];
+ row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*(size_t)pitch];
+ else row_pointer[i]=&dstBuf[i*(size_t)pitch];
}
while(dinfo->output_scanline<dinfo->output_height)
{
@@ -1672,8 +1682,8 @@ DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
_throw("tjDecodeYUVPlanes(): Memory allocation failure");
for(i=0; i<height; i++)
{
- if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
- else row_pointer[i]=&dstBuf[i*pitch];
+ if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*(size_t)pitch];
+ else row_pointer[i]=&dstBuf[i*(size_t)pitch];
}
if(height<ph0)
for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
--
2.25.0
From c511336e5ead5f125647cc92174295d5d5c7d4bf Mon Sep 17 00:00:00 2001
From: DRC <information@libjpeg-turbo.org>
Date: Tue, 12 Nov 2019 12:27:22 -0600
Subject: [PATCH 2/2] 64-bit tjbench: Fix signed int overflow/segfault
... that occurred when attempting to decompress images with more than
715827882 (2048*1024*1024 / 3) pixels.
Fixes #388
(cherry picked from commit c30b1e72dac76343ef9029833d1561de07d29bad)
---
tjbench.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tjbench.c b/tjbench.c
index e90ba3d..858471c 100644
--- a/tjbench.c
+++ b/tjbench.c
@@ -137,7 +137,7 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
}
/* Set the destination buffer to gray so we know whether the decompressor
attempted to write to it */
- memset(dstbuf, 127, pitch*scaledh);
+ memset(dstbuf, 127, (size_t)pitch * scaledh);
if(doyuv)
{
@@ -159,7 +159,7 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
{
int tile=0;
double start=gettime();
- for(row=0, dstptr=dstbuf; row<ntilesh; row++, dstptr+=pitch*tileh)
+ for(row=0, dstptr=dstbuf; row<ntilesh; row++, dstptr+=(size_t)pitch*tileh)
{
for(col=0, dstptr2=dstptr; col<ntilesw; col++, tile++, dstptr2+=ps*tilew)
{
--
2.25.0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment