Compare commits

...

No commits in common. 'i9' and 'epel9' have entirely different histories.
i9 ... epel9

72
.gitignore vendored

@ -1 +1,71 @@
SOURCES/Pillow-9.5.0.tar.gz
/python-imaging-Pillow-1.7.8-137-g7866759.tar.gz
/python-imaging-Pillow-2.0.0-11-g2f4207c.tar.gz
/python-imaging-Pillow-2.0.0-26-g2e88848.tar.gz
/python-imaging-Pillow-2.0.0-28-gde210a2.tar.gz
/python-imaging-Pillow-2.0.0-58-g93a488e.tar.gz
/python-imaging-Pillow-2.0.0-105-gd1c6db8.tar.gz
/python-imaging-Pillow-2.1.0-0-g75af7e0.tar.gz
/python-imaging-Pillow-2.2.1-0-g3c2496e.tar.gz
/python-imaging-Pillow-2.3.0-0-gb1b88cf.tar.gz
/python-imaging-Pillow-2.3.1-0-gb8d4895.tar.gz
/python-imaging-Pillow-2.4.0-0-g72de37c.tar.gz
/python-pillow-Pillow-2.5.0-0-g80d6137.tar.gz
/python-pillow-Pillow-2.5.1-0-g1ab78b8.tar.gz
/python-pillow-Pillow-2.5.2-0-g4081f9f.tar.gz
/python-pillow-Pillow-2.5.3-0-g68c6904.tar.gz
/python-pillow-Pillow-2.6.0-0-g9634e43.tar.gz
/python-pillow-Pillow-2.6.1-0-g4a8471d.tar.gz
/python-pillow-Pillow-2.7.0-0-g0f05eb2.tar.gz
/python-pillow-Pillow-2.8.0-0-gd754598.tar.gz
/python-pillow-Pillow-2.8.1-0-g3f09b8f.tar.gz
/python-pillow-Pillow-2.8.2-0-g0222a05.tar.gz
/python-pillow-Pillow-2.9.0-0-g80672b6.tar.gz
/python-pillow-Pillow-3.0.0-0-g0177cce.tar.gz
/python-pillow-Pillow-3.1.0-0-gfff5536.tar.gz
/python-pillow-Pillow-3.1.1-0-geb72bf8.tar.gz
/python-pillow-Pillow-3.2.0-0-g344cb70.tar.gz
/Pillow-3.3.0.tar.gz
/Pillow-3.3.1.tar.gz
/Pillow-3.4.0.tar.gz
/Pillow-3.4.1.tar.gz
/Pillow-3.4.2.tar.gz
/Pillow-4.0.0.tar.gz
/Pillow-4.1.0.tar.gz
/Pillow-4.1.1.tar.gz
/Pillow-4.2.0.tar.gz
/Pillow-4.2.1.tar.gz
/Pillow-4.3.0.tar.gz
/Pillow-5.0.0.tar.gz
/Pillow-5.1.0.tar.gz
/Pillow-5.1.1.tar.gz
/Pillow-5.2.0.tar.gz
/Pillow-5.3.0.tar.gz
/Pillow-5.4.1.tar.gz
/Pillow-6.0.0.tar.gz
/Pillow-6.1.0.tar.gz
/Pillow-6.2.0.tar.gz
/python-pillow-6.2.1-1.fc32.src.rpm
/Pillow-6.2.1.tar.gz
/Pillow-7.0.0.tar.gz
/Pillow-7.1.1.tar.gz
/Pillow-7.1.2.tar.gz
/Pillow-7.2.0.tar.gz
/Pillow-8.0.0.tar.gz
/Pillow-8.0.1.tar.gz
/Pillow-8.1.0.tar.gz
/Pillow-8.1.1.tar.gz
/Pillow-8.1.2.tar.gz
/Pillow-8.2.0.tar.gz
/Pillow-8.3.1.tar.gz
/Pillow-8.3.2.tar.gz
/Pillow-8.4.0.tar.gz
/Pillow-9.0.0.tar.gz
/Pillow-9.0.1.tar.gz
/Pillow-9.1.0.tar.gz
/Pillow-9.1.1.tar.gz
/Pillow-9.2.0.tar.gz
/Pillow-9.3.0.tar.gz
/Pillow-9.4.0.tar.gz
/Pillow-9.5.0.tar.gz
/Pillow-10.0.0.tar.gz
/Pillow-10.0.1.tar.gz

@ -1 +0,0 @@
2eecd1b48ae358de352e1116b9ae3bbb53be3869 SOURCES/Pillow-9.5.0.tar.gz

@ -1,42 +0,0 @@
From b78ede45a294b567d27d7198ff3354df86a5b7f1 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Tue, 11 Sep 2018 15:58:31 +0200
Subject: [PATCH 1/2] Fix potential un-terminated buffer problem (CWE-120)
---
src/libImaging/Histo.c | 4 +++-
src/libImaging/Palette.c | 3 ++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/libImaging/Histo.c b/src/libImaging/Histo.c
index 0bfc8dfe..2b35873e 100644
--- a/src/libImaging/Histo.c
+++ b/src/libImaging/Histo.c
@@ -41,7 +41,9 @@ ImagingHistogramNew(Imaging im)
/* Create histogram descriptor */
h = calloc(1, sizeof(struct ImagingHistogramInstance));
- strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH);
+ strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH-1);
+ h->mode[IMAGING_MODE_LENGTH-1] = 0;
+
h->bands = im->bands;
h->histogram = calloc(im->pixelsize, 256 * sizeof(long));
diff --git a/src/libImaging/Palette.c b/src/libImaging/Palette.c
index 31c2c024..7aee6e8e 100644
--- a/src/libImaging/Palette.c
+++ b/src/libImaging/Palette.c
@@ -37,7 +37,8 @@ ImagingPaletteNew(const char* mode)
if (!palette)
return (ImagingPalette) ImagingError_MemoryError();
- strncpy(palette->mode, mode, IMAGING_MODE_LENGTH);
+ strncpy(palette->mode, mode, IMAGING_MODE_LENGTH-1);
+ palette->mode[IMAGING_MODE_LENGTH-1] = 0;
/* Initialize to ramp */
for (i = 0; i < 256; i++) {
--
2.17.1

@ -1,258 +0,0 @@
From 6adac809e96c8bfeb50a3bd14570a8118bcd5d65 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Thu, 13 Sep 2018 12:22:11 +0200
Subject: [PATCH 2/2] Fix potential leaked storage issues (CWE-772)
---
src/Tk/tkImaging.c | 2 ++
src/_imaging.c | 15 +++++++++++++--
src/encode.c | 12 +++++++++---
src/libImaging/Histo.c | 12 +++++++++---
src/libImaging/Quant.c | 2 ++
src/libImaging/QuantOctree.c | 1 +
src/libImaging/Resample.c | 2 ++
src/path.c | 8 ++++++--
8 files changed, 44 insertions(+), 10 deletions(-)
diff --git a/src/Tk/tkImaging.c b/src/Tk/tkImaging.c
index f448be16..10090b0e 100644
--- a/src/Tk/tkImaging.c
+++ b/src/Tk/tkImaging.c
@@ -442,6 +442,7 @@ int load_tkinter_funcs(void)
/* Try loading from the main program namespace first */
main_program = dlopen(NULL, RTLD_LAZY);
if (_func_loader(main_program) == 0) {
+ dlclose(main_program);
return 0;
}
/* Clear exception triggered when we didn't find symbols above */
@@ -470,6 +471,7 @@ int load_tkinter_funcs(void)
/* dlclose probably safe because tkinter has been imported. */
dlclose(tkinter_lib);
exit:
+ dlclose(main_program);
Py_XDECREF(pModule);
Py_XDECREF(pString);
return ret;
diff --git a/src/_imaging.c b/src/_imaging.c
index 11f5f6ea..445470bf 100644
--- a/src/_imaging.c
+++ b/src/_imaging.c
@@ -856,8 +856,10 @@ _gaussian_blur(ImagingObject* self, PyObject* args)
if (!imOut)
return NULL;
- if (!ImagingGaussianBlur(imOut, imIn, radius, passes))
+ if (!ImagingGaussianBlur(imOut, imIn, radius, passes)) {
+ ImagingDelete(imOut);
return NULL;
+ }
return PyImagingNew(imOut);
}
@@ -1745,8 +1747,10 @@ _box_blur(ImagingObject* self, PyObject* args)
if (!imOut)
return NULL;
- if (!ImagingBoxBlur(imOut, imIn, radius, n))
+ if (!ImagingBoxBlur(imOut, imIn, radius, n)) {
+ ImagingDelete(imOut);
return NULL;
+ }
return PyImagingNew(imOut);
}
@@ -2386,6 +2390,7 @@ _draw_arc(ImagingDrawObject* self, PyObject* args)
return NULL;
if (n != 2) {
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
return NULL;
}
@@ -2423,6 +2428,7 @@ _draw_bitmap(ImagingDrawObject* self, PyObject* args)
PyErr_SetString(PyExc_TypeError,
"coordinate list must contain exactly 1 coordinate"
);
+ free(xy);
return NULL;
}
@@ -2458,6 +2464,7 @@ _draw_chord(ImagingDrawObject* self, PyObject* args)
return NULL;
if (n != 2) {
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
return NULL;
}
@@ -2493,6 +2500,7 @@ _draw_ellipse(ImagingDrawObject* self, PyObject* args)
return NULL;
if (n != 2) {
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
return NULL;
}
@@ -2674,6 +2682,7 @@ _draw_pieslice(ImagingDrawObject* self, PyObject* args)
return NULL;
if (n != 2) {
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
return NULL;
}
@@ -2712,6 +2721,7 @@ _draw_polygon(ImagingDrawObject* self, PyObject* args)
PyErr_SetString(PyExc_TypeError,
"coordinate list must contain at least 2 coordinates"
);
+ free(xy);
return NULL;
}
@@ -2754,6 +2764,7 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args)
return NULL;
if (n != 2) {
PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
return NULL;
}
diff --git a/src/encode.c b/src/encode.c
index ae4277c0..9f7c6592 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -552,11 +552,15 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
dictionary = NULL;
encoder = PyImaging_EncoderNew(sizeof(ZIPSTATE));
- if (encoder == NULL)
+ if (encoder == NULL) {
+ free(dictionary);
return NULL;
+ }
- if (get_packer(encoder, mode, rawmode) < 0)
+ if (get_packer(encoder, mode, rawmode) < 0) {
+ free(dictionary);
return NULL;
+ }
encoder->encode = ImagingZipEncode;
encoder->cleanup = ImagingZipEncodeCleanup;
@@ -717,8 +721,10 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
if (rawExif && rawExifLen > 0) {
/* malloc check ok, length is from python parsearg */
char* pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5
- if (!pp)
+ if (!pp) {
+ if (extra) free(extra);
return PyErr_NoMemory();
+ }
memcpy(pp, rawExif, rawExifLen);
rawExif = pp;
} else
diff --git a/src/libImaging/Histo.c b/src/libImaging/Histo.c
index 2b35873e..b7c1a983 100644
--- a/src/libImaging/Histo.c
+++ b/src/libImaging/Histo.c
@@ -82,8 +82,10 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
h->histogram[im->image8[y][x]]++;
ImagingSectionLeave(&cookie);
} else { /* yes, we need the braces. C isn't Python! */
- if (im->type != IMAGING_TYPE_UINT8)
+ if (im->type != IMAGING_TYPE_UINT8) {
+ ImagingHistogramDelete(h);
return ImagingError_ModeError();
+ }
ImagingSectionEnter(&cookie);
for (y = 0; y < im->ysize; y++) {
UINT8* in = (UINT8*) im->image32[y];
@@ -122,8 +124,10 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
ImagingSectionLeave(&cookie);
break;
case IMAGING_TYPE_INT32:
- if (!minmax)
+ if (!minmax) {
+ ImagingHistogramDelete(h);
return ImagingError_ValueError("min/max not given");
+ }
if (!im->xsize || !im->ysize)
break;
imin = ((INT32*) minmax)[0];
@@ -143,8 +147,10 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
ImagingSectionLeave(&cookie);
break;
case IMAGING_TYPE_FLOAT32:
- if (!minmax)
+ if (!minmax) {
+ ImagingHistogramDelete(h);
return ImagingError_ValueError("min/max not given");
+ }
if (!im->xsize || !im->ysize)
break;
fmin = ((FLOAT32*) minmax)[0];
diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c
index df313816..b94dc6e1 100644
--- a/src/libImaging/Quant.c
+++ b/src/libImaging/Quant.c
@@ -568,6 +568,8 @@ split(BoxNode *node)
left=malloc(sizeof(BoxNode));
right=malloc(sizeof(BoxNode));
if (!left||!right) {
+ free(left);
+ free(right);
return 0;
}
for(i=0;i<3;i++) {
diff --git a/src/libImaging/QuantOctree.c b/src/libImaging/QuantOctree.c
index e18ab3c6..d778c942 100644
--- a/src/libImaging/QuantOctree.c
+++ b/src/libImaging/QuantOctree.c
@@ -470,6 +470,7 @@ error:
free(qp);
free_color_cube(lookupCube);
free_color_cube(coarseLookupCube);
+ free(paletteBuckets);
free(paletteBucketsCoarse);
free(paletteBucketsFine);
free_color_cube(coarseCube);
diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c
index cda005d9..b90395e8 100644
--- a/src/libImaging/Resample.c
+++ b/src/libImaging/Resample.c
@@ -538,6 +538,8 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize,
if ( ! ksize_vert) {
free(bounds_horiz);
free(kk_horiz);
+ free(bounds_vert);
+ free(kk_vert);
return NULL;
}
diff --git a/src/path.c b/src/path.c
index b56ea838..5984a3d1 100644
--- a/src/path.c
+++ b/src/path.c
@@ -82,12 +82,16 @@ path_new(Py_ssize_t count, double* xy, int duplicate)
xy = p;
}
- if (PyType_Ready(&PyPathType) < 0)
+ if (PyType_Ready(&PyPathType) < 0) {
+ free(xy);
return NULL;
+ }
path = PyObject_New(PyPathObject, &PyPathType);
- if (path == NULL)
+ if (path == NULL) {
+ free(xy);
return NULL;
+ }
path->count = count;
path->xy = xy;
--
2.17.1

@ -1,50 +0,0 @@
From e705cd1476f04a918aae34f638b502116cb12eba Mon Sep 17 00:00:00 2001
From: Jon Dufresne <jon.dufresne@gmail.com>
Date: Tue, 3 Apr 2018 20:36:09 -0700
Subject: [PATCH] Fix dereferencing type-punned pointer will break
strict-aliasing
Compiler warning appeared as:
src/path.c:574:22: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
Py_TYPE(&item)->tp_name);
^~~~~~~
As item is already of type PyObject*, and the Py_TYPE macro is
equivalent to (((PyObject*)(o))->ob_type), no need for the dereference.
https://docs.python.org/3/c-api/structures.html#c.Py_TYPE
---
Tests/test_imagepath.py | 5 +++++
src/path.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py
index 14cc4d14b..98a6d3416 100644
--- a/Tests/test_imagepath.py
+++ b/Tests/test_imagepath.py
@@ -17,6 +17,11 @@ def test_path(self):
self.assertEqual(p[0], (0.0, 1.0))
self.assertEqual(p[-1], (8.0, 9.0))
self.assertEqual(list(p[:1]), [(0.0, 1.0)])
+ with self.assertRaises(TypeError) as cm:
+ p['foo']
+ self.assertEqual(
+ str(cm.exception),
+ "Path indices must be integers, not str")
self.assertEqual(
list(p),
[(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)])
diff --git a/src/path.c b/src/path.c
index b56ea838e..d1c18c8ed 100644
--- a/src/path.c
+++ b/src/path.c
@@ -571,7 +571,7 @@ path_subscript(PyPathObject* self, PyObject* item) {
else {
PyErr_Format(PyExc_TypeError,
"Path indices must be integers, not %.200s",
- Py_TYPE(&item)->tp_name);
+ Py_TYPE(item)->tp_name);
return NULL;
}
}

@ -1,56 +0,0 @@
From f91c78960495efa04c7f12eeb916158d4bfbabc4 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 13 Jul 2020 15:40:11 +0200
Subject: [PATCH] CVE-2020-11538
---
src/libImaging/SgiRleDecode.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index 6367ae7..eb8fc84 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -28,6 +28,7 @@ static void read4B(UINT32* dest, UINT8* buf)
static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
{
UINT8 pixel, count;
+ int x = 0;
for (;n > 0; n--)
{
@@ -37,9 +38,10 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
count = pixel & RLE_MAX_RUN;
if (!count)
return count;
- if (count > xsize) {
+ if (x + count > xsize) {
return -1;
}
+ x += count;
if (pixel & RLE_COPY_FLAG) {
while(count--) {
*dest = *src++;
@@ -63,6 +65,7 @@ static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize)
{
UINT8 pixel, count;
+ int x = 0;
for (;n > 0; n--)
{
@@ -73,9 +76,10 @@ static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize)
count = pixel & RLE_MAX_RUN;
if (!count)
return count;
- if (count > xsize) {
+ if (x + count > xsize) {
return -1;
}
+ x += count;
if (pixel & RLE_COPY_FLAG) {
while(count--) {
*dest = *src++;
--
2.26.2

@ -1,41 +0,0 @@
From 7a0aea5806d57e0e7c5187fbc9c2937a16e0bca1 Mon Sep 17 00:00:00 2001
From: Eric Soroos <eric-github@soroos.net>
Date: Thu, 17 Dec 2020 00:17:53 +0100
Subject: [PATCH] Fix for CVE CVE-2020-35655 - Read Overflow in PCX Decoding.
* Don't trust the image to specify a buffer size
---
src/PIL/PcxImagePlugin.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py
index 564713a..17bbd18 100644
--- a/src/PIL/PcxImagePlugin.py
+++ b/src/PIL/PcxImagePlugin.py
@@ -63,9 +63,9 @@ class PcxImageFile(ImageFile.ImageFile):
version = i8(s[1])
bits = i8(s[3])
planes = i8(s[65])
- stride = i16(s, 66)
+ ignored_stride = i16(s, 66)
logger.debug("PCX version %s, bits %s, planes %s, stride %s",
- version, bits, planes, stride)
+ version, bits, planes, ignored_stride)
self.info["dpi"] = i16(s, 12), i16(s, 14)
@@ -102,6 +102,11 @@ class PcxImageFile(ImageFile.ImageFile):
self.mode = mode
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
+ # don't trust the passed in stride. Calculate for ourselves.
+ # CVE-2020-35653
+ stride = (self.size[0] * bits + 7) // 8
+ stride += stride % 2
+
bbox = (0, 0) + self.size
logger.debug("size: %sx%s", *self.size)
--
2.29.2

@ -1,136 +0,0 @@
From f276de1139ec16395dc8b382860fb58e331fbd53 Mon Sep 17 00:00:00 2001
From: Eric Soroos <eric-github@soroos.net>
Date: Thu, 29 Oct 2020 23:07:15 +0000
Subject: [PATCH 1/2] Fix for SGI Decode buffer overrun CVE-2020-35655
* Independently found by a contributor and sent to Tidelift, and by Google's OSS Fuzz.
---
src/libImaging/SgiRleDecode.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index eb8fc84..c256169 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -107,11 +107,27 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
int err = 0;
int status;
+ /* size check */
+ if (im->xsize > INT_MAX / im->bands ||
+ im->ysize > INT_MAX / im->bands) {
+ return IMAGING_CODEC_MEMORY;
+ }
+
/* Get all data from File descriptor */
c = (SGISTATE*)state->context;
_imaging_seek_pyFd(state->fd, 0L, SEEK_END);
c->bufsize = _imaging_tell_pyFd(state->fd);
c->bufsize -= SGI_HEADER_SIZE;
+
+ c->tablen = im->bands * im->ysize;
+ /* below, we populate the starttab and lentab into the bufsize,
+ each with 4 bytes per element of tablen
+ Check here before we allocate any memory
+ */
+ if (c->bufsize < 8*c->tablen) {
+ return IMAGING_CODEC_MEMORY;
+ }
+
ptr = malloc(sizeof(UINT8) * c->bufsize);
if (!ptr) {
return IMAGING_CODEC_MEMORY;
@@ -129,18 +145,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
state->ystep = 1;
}
- if (im->xsize > INT_MAX / im->bands ||
- im->ysize > INT_MAX / im->bands) {
- err = IMAGING_CODEC_MEMORY;
- goto sgi_finish_decode;
- }
-
/* Allocate memory for RLE tables and rows */
free(state->buffer);
state->buffer = NULL;
/* malloc overflow check above */
state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2);
- c->tablen = im->bands * im->ysize;
c->starttab = calloc(c->tablen, sizeof(UINT32));
c->lengthtab = calloc(c->tablen, sizeof(UINT32));
if (!state->buffer ||
--
2.29.2
From 18aa14484fa63dabcafea63cf0b7bfb4066e979c Mon Sep 17 00:00:00 2001
From: Eric Soroos <eric-github@soroos.net>
Date: Fri, 30 Oct 2020 09:57:23 +0000
Subject: [PATCH 2/2] Make the SGI code return -1 as an error flag, error in
state
---
src/libImaging/SgiRleDecode.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index c256169..2259159 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -110,7 +110,8 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
/* size check */
if (im->xsize > INT_MAX / im->bands ||
im->ysize > INT_MAX / im->bands) {
- return IMAGING_CODEC_MEMORY;
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
}
/* Get all data from File descriptor */
@@ -125,12 +126,14 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
Check here before we allocate any memory
*/
if (c->bufsize < 8*c->tablen) {
- return IMAGING_CODEC_MEMORY;
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
}
ptr = malloc(sizeof(UINT8) * c->bufsize);
if (!ptr) {
- return IMAGING_CODEC_MEMORY;
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
}
_imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);
_imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize);
@@ -178,7 +181,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
if (c->rleoffset + c->rlelength > c->bufsize) {
state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
+ goto sgi_finish_decode;
}
/* row decompression */
@@ -190,7 +193,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
}
if (status == -1) {
state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
+ goto sgi_finish_decode;
} else if (status == 1) {
goto sgi_finish_decode;
}
@@ -211,7 +214,8 @@ sgi_finish_decode: ;
free(c->lengthtab);
free(ptr);
if (err != 0){
- return err;
+ state->errcode=err;
+ return -1;
}
return state->count - c->bufsize;
}
--
2.29.2

@ -1,83 +0,0 @@
From 1dd0fb64bd3cc221b5877ece4ce2f300245b638f Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 17 Feb 2020 14:19:32 +0100
Subject: [PATCH] CVE-2020-5311
---
src/libImaging/SgiRleDecode.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index 39e7b3a..6367ae7 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -25,7 +25,7 @@ static void read4B(UINT32* dest, UINT8* buf)
*dest = (UINT32)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
}
-static int expandrow(UINT8* dest, UINT8* src, int n, int z)
+static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
{
UINT8 pixel, count;
@@ -37,6 +37,9 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z)
count = pixel & RLE_MAX_RUN;
if (!count)
return count;
+ if (count > xsize) {
+ return -1;
+ }
if (pixel & RLE_COPY_FLAG) {
while(count--) {
*dest = *src++;
@@ -56,7 +59,7 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z)
return 0;
}
-static int expandrow2(UINT16* dest, UINT16* src, int n, int z)
+static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize)
{
UINT8 pixel, count;
@@ -70,6 +73,9 @@ static int expandrow2(UINT16* dest, UINT16* src, int n, int z)
count = pixel & RLE_MAX_RUN;
if (!count)
return count;
+ if (count > xsize) {
+ return -1;
+ }
if (pixel & RLE_COPY_FLAG) {
while(count--) {
*dest = *src++;
@@ -95,6 +101,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
UINT8 *ptr;
SGISTATE *c;
int err = 0;
+ int status;
/* Get all data from File descriptor */
c = (SGISTATE*)state->context;
@@ -163,12 +170,16 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
/* row decompression */
if (c->bpc ==1) {
- if(expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands))
- goto sgi_finish_decode;
+ status = expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize);
}
else {
- if(expandrow2((UINT16*)&state->buffer[c->channo * 2], (UINT16*)&ptr[c->rleoffset], c->rlelength, im->bands))
- goto sgi_finish_decode;
+ status = expandrow2(&state->buffer[c->channo * 2], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize);
+ }
+ if (status == -1) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ } else if (status == 1) {
+ goto sgi_finish_decode;
}
state->count += c->rlelength;
--
2.24.1

@ -1,183 +0,0 @@
From cc9658731ba1ea291f83ea959acc27ac28384a2c Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Fri, 14 Feb 2020 11:14:53 +0100
Subject: [PATCH] Combined fix for CVE-2020-5312 and CVE-2019-16865
---
src/PIL/GifImagePlugin.py | 1 +
src/PIL/IcoImagePlugin.py | 1 +
src/PIL/PsdImagePlugin.py | 6 ++++--
src/PIL/TiffImagePlugin.py | 4 ++--
src/libImaging/FliDecode.c | 14 +++++++++++---
src/libImaging/PcxDecode.c | 8 ++++++++
src/libImaging/RawDecode.c | 11 +++++++++--
src/libImaging/SgiRleDecode.c | 5 +++++
8 files changed, 41 insertions(+), 9 deletions(-)
diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py
index c01adff..99af4a5 100644
--- a/src/PIL/GifImagePlugin.py
+++ b/src/PIL/GifImagePlugin.py
@@ -251,6 +251,7 @@ class GifImageFile(ImageFile.ImageFile):
self.dispose = None
elif self.disposal_method == 2:
# replace with background colour
+ Image._decompression_bomb_check(self.size)
self.dispose = Image.core.fill("P", self.size,
self.info["background"])
else:
diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py
index 428fdd4..2b6d1e0 100644
--- a/src/PIL/IcoImagePlugin.py
+++ b/src/PIL/IcoImagePlugin.py
@@ -167,6 +167,7 @@ class IcoFile(object):
else:
# XOR + AND mask bmp frame
im = BmpImagePlugin.DibImageFile(self.buf)
+ Image._decompression_bomb_check(im.size)
# change tile dimension to only encompass XOR image
im.size = (im.size[0], int(im.size[1] / 2))
diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py
index f6e04f7..fe2a2ff 100644
--- a/src/PIL/PsdImagePlugin.py
+++ b/src/PIL/PsdImagePlugin.py
@@ -209,9 +209,11 @@ def _layerinfo(file):
# skip over blend flags and extra information
filler = read(12)
name = ""
- size = i32(read(4))
+ size = i32(read(4)) # length of the extra data field
combined = 0
if size:
+ data_end = file.tell() + size
+
length = i32(read(4))
if length:
mask_y = i32(read(4))
@@ -233,7 +235,7 @@ def _layerinfo(file):
name = read(length).decode('latin-1', 'replace')
combined += length + 1
- file.seek(size - combined, 1)
+ file.seek(data_end)
layers.append((name, mode, (x0, y0, x1, y1)))
# get tiles
diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py
index f903918..b9a1ef7 100644
--- a/src/PIL/TiffImagePlugin.py
+++ b/src/PIL/TiffImagePlugin.py
@@ -1170,8 +1170,8 @@ class TiffImageFile(ImageFile.ImageFile):
print("- fill_order:", fillorder)
# size
- xsize = self.tag_v2.get(IMAGEWIDTH)
- ysize = self.tag_v2.get(IMAGELENGTH)
+ xsize = int(self.tag_v2.get(IMAGEWIDTH))
+ ysize = int(self.tag_v2.get(IMAGELENGTH))
self.size = xsize, ysize
if DEBUG:
diff --git a/src/libImaging/FliDecode.c b/src/libImaging/FliDecode.c
index 6d22c6c..a99aca8 100644
--- a/src/libImaging/FliDecode.c
+++ b/src/libImaging/FliDecode.c
@@ -30,7 +30,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
UINT8* ptr;
int framesize;
- int c, chunks;
+ int c, chunks, advance;
int l, lines;
int i, j, x = 0, y, ymax;
@@ -59,10 +59,16 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
chunks = I16(ptr+6);
ptr += 16;
+ bytes -= 16;
/* Process subchunks */
for (c = 0; c < chunks; c++) {
- UINT8 *data = ptr + 6;
+ UINT8* data;
+ if (bytes < 10) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ data = ptr + 6;
switch (I16(ptr+4)) {
case 4: case 11:
/* FLI COLOR chunk */
@@ -198,7 +204,9 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
state->errcode = IMAGING_CODEC_UNKNOWN;
return -1;
}
- ptr += I32(ptr);
+ advance = I32(ptr);
+ ptr += advance;
+ bytes -= advance;
}
return -1; /* end of frame */
diff --git a/src/libImaging/PcxDecode.c b/src/libImaging/PcxDecode.c
index e5417f1..aaf5867 100644
--- a/src/libImaging/PcxDecode.c
+++ b/src/libImaging/PcxDecode.c
@@ -22,6 +22,14 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
UINT8 n;
UINT8* ptr;
+ if (strcmp(im->mode, "1") == 0 && state->xsize > state->bytes * 8) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ } else if (strcmp(im->mode, "P") == 0 && state->xsize > state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
ptr = buf;
for (;;) {
diff --git a/src/libImaging/RawDecode.c b/src/libImaging/RawDecode.c
index 40c0cb7..d4b7994 100644
--- a/src/libImaging/RawDecode.c
+++ b/src/libImaging/RawDecode.c
@@ -33,8 +33,15 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* get size of image data and padding */
state->bytes = (state->xsize * state->bits + 7) / 8;
- rawstate->skip = (rawstate->stride) ?
- rawstate->stride - state->bytes : 0;
+ if (rawstate->stride) {
+ rawstate->skip = rawstate->stride - state->bytes;
+ if (rawstate->skip < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ } else {
+ rawstate->skip = 0;
+ }
/* check image orientation */
if (state->ystep < 0) {
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index 9d8e563..39e7b3a 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -156,6 +156,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize];
c->rleoffset -= SGI_HEADER_SIZE;
+ if (c->rleoffset + c->rlelength > c->bufsize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
/* row decompression */
if (c->bpc ==1) {
if(expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands))
--
2.24.1

@ -1,38 +0,0 @@
From 697957b79a9473f0f643051265885fb048395127 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Wed, 4 Mar 2020 10:54:54 +0100
Subject: [PATCH] CVE-2020-5313
---
src/libImaging/FliDecode.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/libImaging/FliDecode.c b/src/libImaging/FliDecode.c
index a99aca8..72ba138 100644
--- a/src/libImaging/FliDecode.c
+++ b/src/libImaging/FliDecode.c
@@ -40,8 +40,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
return 0;
/* We don't decode anything unless we have a full chunk in the
- input buffer (on the other hand, the Python part of the driver
- makes sure this is always the case) */
+ input buffer */
ptr = buf;
@@ -52,6 +51,11 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* Make sure this is a frame chunk. The Python driver takes
case of other chunk types. */
+ if (bytes < 8) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
if (I16(ptr+4) != 0xF1FA) {
state->errcode = IMAGING_CODEC_UNKNOWN;
return -1;
--
2.24.1

@ -1,130 +0,0 @@
From 9c781aa2020eef838284dcb348f4528f3c3cc1ab Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 14 Jun 2021 09:06:07 +0200
Subject: [PATCH 1/5] CVE-2021-25287_25288
---
src/libImaging/Jpeg2KDecode.c | 78 +++++++++++++++++++++++++++--------
1 file changed, 61 insertions(+), 17 deletions(-)
diff --git a/src/libImaging/Jpeg2KDecode.c b/src/libImaging/Jpeg2KDecode.c
index 9140e00..fdbd0c0 100644
--- a/src/libImaging/Jpeg2KDecode.c
+++ b/src/libImaging/Jpeg2KDecode.c
@@ -110,6 +110,7 @@ j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
if (shift < 0)
offset += 1 << (-shift - 1);
+ /* csiz*h*w + offset = tileinfo.datasize */
switch (csiz) {
case 1:
for (y = 0; y < h; ++y) {
@@ -557,8 +558,10 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
opj_dparameters_t params;
OPJ_COLOR_SPACE color_space;
j2k_unpacker_t unpack = NULL;
- size_t buffer_size = 0;
- unsigned n;
+ size_t buffer_size = 0, tile_bytes = 0;
+ unsigned n, tile_height, tile_width;
+ int total_component_width = 0;
+
stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
@@ -703,8 +706,62 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
tile_info.x1 = (tile_info.x1 + correction) >> context->reduce;
tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
+ /* Check the tile bounds; if the tile is outside the image area,
+ or if it has a negative width or height (i.e. the coordinates are
+ swapped), bail. */
+ if (tile_info.x0 >= tile_info.x1
+ || tile_info.y0 >= tile_info.y1
+ || tile_info.x0 < image->x0
+ || tile_info.y0 < image->y0
+ || tile_info.x1 - image->x0 > im->xsize
+ || tile_info.y1 - image->y0 > im->ysize) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ if (tile_info.nb_comps != image->numcomps) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Sometimes the tile_info.datasize we get back from openjpeg
+ is less than sum(comp_bytes)*w*h, and we overflow in the
+ shuffle stage */
+
+ tile_width = tile_info.x1 - tile_info.x0;
+ tile_height = tile_info.y1 - tile_info.y0;
+
+ /* Total component width = sum (component_width) e.g, it's
+ legal for an la file to have a 1 byte width for l, and 4 for
+ a. and then a malicious file could have a smaller tile_bytes
+ */
+
+ for (n=0; n < tile_info.nb_comps; n++) {
+ // see csize /acsize calcs
+ int csize = (image->comps[n].prec + 7) >> 3;
+ csize = (csize == 3) ? 4 : csize;
+ total_component_width += csize;
+ }
+ if ((tile_width > UINT_MAX / total_component_width) ||
+ (tile_height > UINT_MAX / total_component_width) ||
+ (tile_width > UINT_MAX / (tile_height * total_component_width)) ||
+ (tile_height > UINT_MAX / (tile_width * total_component_width))) {
+
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ tile_bytes = tile_width * tile_height * total_component_width;
+
+ if (tile_bytes > tile_info.data_size) {
+ tile_info.data_size = tile_bytes;
+ }
+
if (buffer_size < tile_info.data_size) {
- /* malloc check ok, tile_info.data_size from openjpeg */
+ /* malloc check ok, overflow and tile size sanity check above */
UINT8 *new = realloc (state->buffer, tile_info.data_size);
if (!new) {
state->errcode = IMAGING_CODEC_MEMORY;
@@ -715,6 +772,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
buffer_size = tile_info.data_size;
}
+
if (!opj_decode_tile_data(codec,
tile_info.tile_index,
(OPJ_BYTE *)state->buffer,
@@ -725,20 +783,6 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
goto quick_exit;
}
- /* Check the tile bounds; if the tile is outside the image area,
- or if it has a negative width or height (i.e. the coordinates are
- swapped), bail. */
- if (tile_info.x0 >= tile_info.x1
- || tile_info.y0 >= tile_info.y1
- || tile_info.x0 < image->x0
- || tile_info.y0 < image->y0
- || tile_info.x1 - image->x0 > im->xsize
- || tile_info.y1 - image->y0 > im->ysize) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
-
unpack(image, &tile_info, state->buffer, im);
}
--
2.31.1

@ -1,28 +0,0 @@
From c558baf01a97aed376a67ff4641f1c3c864ae3f0 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Thu, 8 Apr 2021 17:55:26 +0200
Subject: [PATCH 1/4] CVE-2021-25290
---
src/libImaging/TiffDecode.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c
index f292da3..d17b557 100644
--- a/src/libImaging/TiffDecode.c
+++ b/src/libImaging/TiffDecode.c
@@ -36,6 +36,11 @@ tsize_t _tiffReadProc(thandle_t hdata, tdata_t buf, tsize_t size) {
TRACE(("_tiffReadProc: %d \n", (int)size));
dump_state(state);
+ if (state->loc > state->eof) {
+ TIFFError("_tiffReadProc", "Invalid Read at loc %d, eof: %d", state->loc, state->eof);
+ return 0;
+ }
+
to_read = min(size, min(state->size, (tsize_t)state->eof) - (tsize_t)state->loc);
TRACE(("to_read: %d\n", (int)to_read));
--
2.30.2

@ -1,27 +0,0 @@
From f60b6ae79d3c2e759f54bb4acb62b4c49f89fef2 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Thu, 8 Apr 2021 17:59:21 +0200
Subject: [PATCH 2/4] CVE-2021-25292
---
src/PIL/PdfParser.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py
index b6938fd..189aed8 100644
--- a/src/PIL/PdfParser.py
+++ b/src/PIL/PdfParser.py
@@ -562,8 +562,9 @@ class PdfParser:
whitespace_or_hex = br"[\000\011\012\014\015\0400-9a-fA-F]"
whitespace_optional = whitespace + b"*"
whitespace_mandatory = whitespace + b"+"
+ whitespace_optional_no_nl = br"[\000\011\014\015\040]*" # no "\012" aka "\n"
newline_only = br"[\r\n]+"
- newline = whitespace_optional + newline_only + whitespace_optional
+ newline = whitespace_optional_no_nl + newline_only + whitespace_optional_no_nl
re_trailer_end = re.compile(whitespace_mandatory + br"trailer" + whitespace_optional + br"\<\<(.*\>\>)" + newline
+ br"startxref" + newline + br"([0-9]+)" + newline + br"%%EOF" + whitespace_optional + br"$", re.DOTALL)
re_trailer_prev = re.compile(whitespace_optional + br"trailer" + whitespace_optional + br"\<\<(.*?\>\>)" + newline
--
2.30.2

@ -1,207 +0,0 @@
From 1312c5426e7dd84e396ef2ff35aa09b64d92d382 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Fri, 9 Apr 2021 19:33:55 +0200
Subject: [PATCH 3/4] CVE-2021-25293
---
src/libImaging/SgiRleDecode.c | 88 +++++++++++++++++++++++++++++------
1 file changed, 75 insertions(+), 13 deletions(-)
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index 2259159..85af456 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -25,13 +25,60 @@ static void read4B(UINT32* dest, UINT8* buf)
*dest = (UINT32)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
}
-static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
+/*
+ SgiRleDecoding is done in a single channel row oriented set of RLE chunks.
+
+ * The file is arranged as
+ - SGI Header
+ - Rle Offset Table
+ - Rle Length Table
+ - Scanline Data
+
+ * Each RLE atom is c->bpc bytes wide (1 or 2)
+
+ * Each RLE Chunk is [specifier atom] [ 1 or n data atoms ]
+
+ * Copy Atoms are a byte with the high bit set, and the low 7 are
+ the number of bytes to copy from the source to the
+ destination. e.g.
+
+ CBBBBBBBB or 0CHLHLHLHLHLHL (B=byte, H/L = Hi low bytes)
+
+ * Run atoms do not have the high bit set, and the low 7 bits are
+ the number of copies of the next atom to copy to the
+ destination. e.g.:
+
+ RB -> BBBBB or RHL -> HLHLHLHLHL
+
+ The upshot of this is, there is no way to determine the required
+ length of the input buffer from reloffset and rlelength without
+ going through the data at that scan line.
+
+ Furthermore, there's no requirement that individual scan lines
+ pointed to from the rleoffset table are in any sort of order or
+ used only once, or even disjoint. There's also no requirement that
+ all of the data in the scan line area of the image file be used
+
+ */
+
+static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize, UINT8 *end_of_buffer)
{
+ /*
+ * n here is the number of rlechunks
+ * z is the number of channels, for calculating the interleave
+ * offset to go to RGBA style pixels
+ * xsize is the row width
+ * end_of_buffer is the address of the end of the input buffer
+ */
+
UINT8 pixel, count;
int x = 0;
for (;n > 0; n--)
{
+ if (src > end_of_buffer) {
+ return -1;
+ }
pixel = *src++;
if (n == 1 && pixel != 0)
return n;
@@ -43,6 +90,9 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
}
x += count;
if (pixel & RLE_COPY_FLAG) {
+ if (src + count > end_of_buffer) {
+ return -1;
+ }
while(count--) {
*dest = *src++;
dest += z;
@@ -50,6 +100,9 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
}
else {
+ if (src > end_of_buffer) {
+ return -1;
+ }
pixel = *src++;
while (count--) {
*dest = pixel;
@@ -61,7 +114,7 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
return 0;
}
-static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize)
+static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize, UINT8 *end_of_buffer)
{
UINT8 pixel, count;
@@ -69,6 +122,9 @@ static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize)
for (;n > 0; n--)
{
+ if (src + 1 > end_of_buffer) {
+ return -1;
+ }
pixel = ((UINT8*)src)[1];
++src;
if (n == 1 && pixel != 0)
@@ -81,12 +137,18 @@ static int expandrow2(UINT16* dest, UINT16* src, int n, int z, int xsize)
}
x += count;
if (pixel & RLE_COPY_FLAG) {
+ if (src + 2 * count > end_of_buffer) {
+ return -1;
+ }
while(count--) {
*dest = *src++;
dest += z;
}
}
else {
+ if (src + 2 > end_of_buffer) {
+ return -1;
+ }
while (count--) {
*dest = *src;
dest += z;
@@ -136,8 +198,10 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
return -1;
}
_imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);
- _imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize);
-
+ if (_imaging_read_pyFd(state->fd, (char *)ptr, c->bufsize) != c->bufsize) {
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ return -1;
+ }
/* decoder initialization */
state->count = 0;
@@ -168,8 +232,6 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
for (c->tabindex = 0, c->bufindex = c->tablen * sizeof(UINT32); c->tabindex < c->tablen; c->tabindex++, c->bufindex+=4)
read4B(&c->lengthtab[c->tabindex], &ptr[c->bufindex]);
- state->count += c->tablen * sizeof(UINT32) * 2;
-
/* read compressed rows */
for (c->rowno = 0; c->rowno < im->ysize; c->rowno++, state->y += state->ystep)
{
@@ -177,19 +239,21 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
{
c->rleoffset = c->starttab[c->rowno + c->channo * im->ysize];
c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize];
- c->rleoffset -= SGI_HEADER_SIZE;
- if (c->rleoffset + c->rlelength > c->bufsize) {
+ // Check for underflow of rleoffset-SGI_HEADER_SIZE
+ if (c->rleoffset < SGI_HEADER_SIZE) {
state->errcode = IMAGING_CODEC_OVERRUN;
goto sgi_finish_decode;
}
+ c->rleoffset -= SGI_HEADER_SIZE;
+
/* row decompression */
if (c->bpc ==1) {
- status = expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize);
+ status = expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize, &ptr[c->bufsize-1]);
}
else {
- status = expandrow2(&state->buffer[c->channo * 2], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize);
+ status = expandrow2(&state->buffer[c->channo * 2], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize, &ptr[c->bufsize-1]);
}
if (status == -1) {
state->errcode = IMAGING_CODEC_OVERRUN;
@@ -198,7 +262,6 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
goto sgi_finish_decode;
}
- state->count += c->rlelength;
}
/* store decompressed data in image */
@@ -206,7 +269,6 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
}
- c->bufsize++;
sgi_finish_decode: ;
@@ -217,5 +279,5 @@ sgi_finish_decode: ;
state->errcode=err;
return -1;
}
- return state->count - c->bufsize;
+ return 0;
}
--
2.30.2

@ -1,58 +0,0 @@
From 357fef8b4bd076e3a15e7ffc58a475626794c7e3 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Fri, 9 Apr 2021 19:41:58 +0200
Subject: [PATCH 4/4] CVE-2021-27921_27922_27923
---
src/PIL/BlpImagePlugin.py | 1 +
src/PIL/IcnsImagePlugin.py | 2 ++
src/PIL/IcoImagePlugin.py | 1 +
3 files changed, 4 insertions(+)
diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py
index ec358db..d56d46c 100644
--- a/src/PIL/BlpImagePlugin.py
+++ b/src/PIL/BlpImagePlugin.py
@@ -362,6 +362,7 @@ class BLP1Decoder(_BLPBaseDecoder):
data = jpeg_header + data
data = BytesIO(data)
image = JpegImageFile(data)
+ Image._decompression_bomb_check(image.size)
self.tile = image.tile # :/
self.fd = image.fp
self.mode = image.mode
diff --git a/src/PIL/IcnsImagePlugin.py b/src/PIL/IcnsImagePlugin.py
index b382a73..2292584 100644
--- a/src/PIL/IcnsImagePlugin.py
+++ b/src/PIL/IcnsImagePlugin.py
@@ -110,6 +110,7 @@ def read_png_or_jpeg2000(fobj, start_length, size):
if sig[:8] == b'\x89PNG\x0d\x0a\x1a\x0a':
fobj.seek(start)
im = PngImagePlugin.PngImageFile(fobj)
+ Image._decompression_bomb_check(im.size)
return {"RGBA": im}
elif sig[:4] == b'\xff\x4f\xff\x51' \
or sig[:4] == b'\x0d\x0a\x87\x0a' \
@@ -122,6 +123,7 @@ def read_png_or_jpeg2000(fobj, start_length, size):
jp2kstream = fobj.read(length)
f = io.BytesIO(jp2kstream)
im = Jpeg2KImagePlugin.Jpeg2KImageFile(f)
+ Image._decompression_bomb_check(im.size)
if im.mode != 'RGBA':
im = im.convert('RGBA')
return {"RGBA": im}
diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py
index 2b6d1e0..30412ad 100644
--- a/src/PIL/IcoImagePlugin.py
+++ b/src/PIL/IcoImagePlugin.py
@@ -164,6 +164,7 @@ class IcoFile(object):
if data[:8] == PngImagePlugin._MAGIC:
# png frame
im = PngImagePlugin.PngImageFile(self.buf)
+ Image._decompression_bomb_check(im.size)
else:
# XOR + AND mask bmp frame
im = BmpImagePlugin.DibImageFile(self.buf)
--
2.30.2

@ -1,146 +0,0 @@
From 7fe3dff241c11206616bf6229be898854ce0d066 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 14 Jun 2021 11:33:36 +0200
Subject: [PATCH] CVE-2021-28675
---
src/PIL/ImageFile.py | 12 ++++++++++--
src/PIL/PsdImagePlugin.py | 33 +++++++++++++++++++++++----------
2 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py
index 1a3c4aa..2cef9ee 100644
--- a/src/PIL/ImageFile.py
+++ b/src/PIL/ImageFile.py
@@ -522,12 +522,18 @@ def _safe_read(fp, size):
:param fp: File handle. Must implement a <b>read</b> method.
:param size: Number of bytes to read.
- :returns: A string containing up to <i>size</i> bytes of data.
+ :returns: A string containing <i>size</i> bytes of data.
+
+ Raises an OSError if the file is truncated and the read can not be completed
+
"""
if size <= 0:
return b""
if size <= SAFEBLOCK:
- return fp.read(size)
+ data = fp.read(size)
+ if len(data) < size:
+ raise OSError("Truncated File Read")
+ return data
data = []
while size > 0:
block = fp.read(min(size, SAFEBLOCK))
@@ -535,6 +541,8 @@ def _safe_read(fp, size):
break
data.append(block)
size -= len(block)
+ if sum(len(d) for d in data) < size:
+ raise OSError("Truncated File Read")
return b"".join(data)
diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py
index fe2a2ff..add9996 100644
--- a/src/PIL/PsdImagePlugin.py
+++ b/src/PIL/PsdImagePlugin.py
@@ -18,6 +18,8 @@
__version__ = "0.4"
+import io
+
from . import Image, ImageFile, ImagePalette
from ._binary import i8, i16be as i16, i32be as i32
@@ -114,7 +116,8 @@ class PsdImageFile(ImageFile.ImageFile):
end = self.fp.tell() + size
size = i32(read(4))
if size:
- self.layers = _layerinfo(self.fp)
+ _layer_data = io.BytesIO(ImageFile._safe_read(self.fp, size))
+ self.layers = _layerinfo(_layer_data, size)
self.fp.seek(end)
#
@@ -164,11 +167,20 @@ class PsdImageFile(ImageFile.ImageFile):
Image.Image.load(self)
-def _layerinfo(file):
+def _layerinfo(fp, ct_bytes):
# read layerinfo block
layers = []
- read = file.read
- for i in range(abs(i16(read(2)))):
+
+ def read(size):
+ return ImageFile._safe_read(fp, size)
+
+ ct = i16(read(2))
+
+ # sanity check
+ if ct_bytes < (abs(ct) * 20):
+ raise SyntaxError("Layer block too short for number of layers requested")
+
+ for i in range(abs(ct)):
# bounding box
y0 = i32(read(4))
@@ -179,7 +191,8 @@ def _layerinfo(file):
# image info
info = []
mode = []
- types = list(range(i16(read(2))))
+ ct_types = i16(read(2))
+ types = list(range(ct_types))
if len(types) > 4:
continue
@@ -212,7 +225,7 @@ def _layerinfo(file):
size = i32(read(4)) # length of the extra data field
combined = 0
if size:
- data_end = file.tell() + size
+ data_end = fp.tell() + size
length = i32(read(4))
if length:
@@ -220,12 +233,12 @@ def _layerinfo(file):
mask_x = i32(read(4))
mask_h = i32(read(4)) - mask_y
mask_w = i32(read(4)) - mask_x
- file.seek(length - 16, 1)
+ fp.seek(length - 16, 1)
combined += length + 4
length = i32(read(4))
if length:
- file.seek(length, 1)
+ fp.seek(length, 1)
combined += length + 4
length = i8(read(1))
@@ -235,7 +248,7 @@ def _layerinfo(file):
name = read(length).decode('latin-1', 'replace')
combined += length + 1
- file.seek(data_end)
+ fp.seek(data_end)
layers.append((name, mode, (x0, y0, x1, y1)))
# get tiles
@@ -243,7 +256,7 @@ def _layerinfo(file):
for name, mode, bbox in layers:
tile = []
for m in mode:
- t = _maketile(file, m, bbox, 1)
+ t = _maketile(fp, m, bbox, 1)
if t:
tile.extend(t)
layers[i] = name, mode, bbox, tile
--
2.31.1

@ -1,28 +0,0 @@
From cedb7ba568161021bc2f2f48af95fcf33e262f77 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 14 Jun 2021 09:30:01 +0200
Subject: [PATCH 4/5] CVE-2021-28676
---
src/libImaging/FliDecode.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/libImaging/FliDecode.c b/src/libImaging/FliDecode.c
index 72ba138..9181b8b 100644
--- a/src/libImaging/FliDecode.c
+++ b/src/libImaging/FliDecode.c
@@ -209,6 +209,11 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
return -1;
}
advance = I32(ptr);
+ if (advance == 0 ) {
+ // If there's no advance, we're in in infinite loop
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
ptr += advance;
bytes -= advance;
}
--
2.31.1

@ -1,41 +0,0 @@
From 8ad7b436649c424e22689a8a874c1b0cd7c1c0fc Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 14 Jun 2021 09:22:45 +0200
Subject: [PATCH 3/5] CVE-2021-28677
---
src/PIL/EpsImagePlugin.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py
index b503487..5f5af15 100644
--- a/src/PIL/EpsImagePlugin.py
+++ b/src/PIL/EpsImagePlugin.py
@@ -167,12 +167,12 @@ class PSFile(object):
self.fp.seek(offset, whence)
def readline(self):
- s = self.char or b""
+ s = [self.char or b""]
self.char = None
c = self.fp.read(1)
- while c not in b"\r\n":
- s = s + c
+ while (c not in b"\r\n") and len(c):
+ s.append(c)
c = self.fp.read(1)
self.char = self.fp.read(1)
@@ -180,7 +180,7 @@ class PSFile(object):
if self.char in b"\r\n":
self.char = None
- return s.decode('latin-1')
+ return b"".join(s).decode("latin-1")
def _accept(prefix):
--
2.31.1

@ -1,122 +0,0 @@
From eaef29c3696cd021147e692360997f4c12377c60 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Mon, 14 Jun 2021 09:19:50 +0200
Subject: [PATCH 2/5] CVE-2021-28678
---
src/PIL/BlpImagePlugin.py | 43 +++++++++++++++++++++------------------
1 file changed, 23 insertions(+), 20 deletions(-)
diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py
index d56d46c..846c83d 100644
--- a/src/PIL/BlpImagePlugin.py
+++ b/src/PIL/BlpImagePlugin.py
@@ -294,33 +294,36 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
raise IOError("Truncated Blp file")
return 0, 0
+ def _safe_read(self, length):
+ return ImageFile._safe_read(self.fd, length)
+
def _read_palette(self):
ret = []
for i in range(256):
try:
- b, g, r, a = struct.unpack("<4B", self.fd.read(4))
+ b, g, r, a = struct.unpack("<4B", self._safe_read(4))
except struct.error:
break
ret.append((b, g, r, a))
return ret
def _read_blp_header(self):
- self._blp_compression, = struct.unpack("<i", self.fd.read(4))
+ self._blp_compression, = struct.unpack("<i", self._safe_read(4))
- self._blp_encoding, = struct.unpack("<b", self.fd.read(1))
- self._blp_alpha_depth, = struct.unpack("<b", self.fd.read(1))
- self._blp_alpha_encoding, = struct.unpack("<b", self.fd.read(1))
- self._blp_mips, = struct.unpack("<b", self.fd.read(1))
+ self._blp_encoding, = struct.unpack("<b", self._safe_read(1))
+ self._blp_alpha_depth, = struct.unpack("<b", self._safe_read(1))
+ self._blp_alpha_encoding, = struct.unpack("<b", self._safe_read(1))
+ self._blp_mips, = struct.unpack("<b", self._safe_read(1))
- self.size = struct.unpack("<II", self.fd.read(8))
+ self.size = struct.unpack("<II", self._safe_read(8))
if self.magic == b"BLP1":
# Only present for BLP1
- self._blp_encoding, = struct.unpack("<i", self.fd.read(4))
- self._blp_subtype, = struct.unpack("<i", self.fd.read(4))
+ self._blp_encoding, = struct.unpack("<i", self._safe_read(4))
+ self._blp_subtype, = struct.unpack("<i", self._safe_read(4))
- self._blp_offsets = struct.unpack("<16I", self.fd.read(16 * 4))
- self._blp_lengths = struct.unpack("<16I", self.fd.read(16 * 4))
+ self._blp_offsets = struct.unpack("<16I", self._safe_read(16 * 4))
+ self._blp_lengths = struct.unpack("<16I", self._safe_read(16 * 4))
class BLP1Decoder(_BLPBaseDecoder):
@@ -333,7 +336,7 @@ class BLP1Decoder(_BLPBaseDecoder):
if self._blp_encoding in (4, 5):
data = bytearray()
palette = self._read_palette()
- _data = BytesIO(self.fd.read(self._blp_lengths[0]))
+ _data = BytesIO(self._safe_read(self._blp_lengths[0]))
while True:
try:
offset, = struct.unpack("<B", _data.read(1))
@@ -355,10 +358,10 @@ class BLP1Decoder(_BLPBaseDecoder):
def _decode_jpeg_stream(self):
from PIL.JpegImagePlugin import JpegImageFile
- jpeg_header_size, = struct.unpack("<I", self.fd.read(4))
- jpeg_header = self.fd.read(jpeg_header_size)
- self.fd.read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
- data = self.fd.read(self._blp_lengths[0])
+ jpeg_header_size, = struct.unpack("<I", self._safe_read(4))
+ jpeg_header = self._safe_read(jpeg_header_size)
+ self._safe_read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
+ data = self._safe_read(self._blp_lengths[0])
data = jpeg_header + data
data = BytesIO(data)
image = JpegImageFile(data)
@@ -380,7 +383,7 @@ class BLP2Decoder(_BLPBaseDecoder):
# Uncompressed or DirectX compression
if self._blp_encoding == BLP_ENCODING_UNCOMPRESSED:
- _data = BytesIO(self.fd.read(self._blp_lengths[0]))
+ _data = BytesIO(self._safe_read(self._blp_lengths[0]))
while True:
try:
offset, = struct.unpack("<B", _data.read(1))
@@ -394,7 +397,7 @@ class BLP2Decoder(_BLPBaseDecoder):
linesize = (self.size[0] + 3) // 4 * 8
for yb in range((self.size[1] + 3) // 4):
for d in decode_dxt1(
- self.fd.read(linesize),
+ self._safe_read(linesize),
alpha=bool(self._blp_alpha_depth)
):
data += d
@@ -402,13 +405,13 @@ class BLP2Decoder(_BLPBaseDecoder):
elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT3:
linesize = (self.size[0] + 3) // 4 * 16
for yb in range((self.size[1] + 3) // 4):
- for d in decode_dxt3(self.fd.read(linesize)):
+ for d in decode_dxt3(self._safe_read(linesize)):
data += d
elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT5:
linesize = (self.size[0] + 3) // 4 * 16
for yb in range((self.size[1] + 3) // 4):
- for d in decode_dxt5(self.fd.read(linesize)):
+ for d in decode_dxt5(self._safe_read(linesize)):
data += d
else:
raise BLPFormatError("Unsupported alpha encoding %r" % (
--
2.31.1

@ -1,33 +0,0 @@
diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c
index b3e48e5..cfed8ad 100644
--- a/src/libImaging/Convert.c
+++ b/src/libImaging/Convert.c
@@ -1338,9 +1338,8 @@ convert(Imaging imOut, Imaging imIn, const char *mode,
return (Imaging) ImagingError_ValueError("conversion not supported");
#else
{
- static char buf[256];
- /* FIXME: may overflow if mode is too large */
- sprintf(buf, "conversion from %s to %s not supported", imIn->mode, mode);
+ static char buf[100];
+ snprintf(buf, 100, "conversion from %.10s to %.10s not supported", imIn->mode, mode);
return (Imaging) ImagingError_ValueError(buf);
}
#endif
@@ -1394,9 +1393,13 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
}
#else
{
- static char buf[256];
- /* FIXME: may overflow if mode is too large */
- sprintf(buf, "conversion from %s to %s not supported in convert_transparent", imIn->mode, mode);
+ static char buf[100];
+ snprintf(
+ buf,
+ 100,
+ "conversion from %.10s to %.10s not supported in convert_transparent",
+ imIn->mode,
+ mode);
return (Imaging) ImagingError_ValueError(buf);
}
#endif

@ -1,69 +0,0 @@
diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py
index 98a6d34..733fd29 100644
--- a/Tests/test_imagepath.py
+++ b/Tests/test_imagepath.py
@@ -67,6 +67,11 @@ class TestImagePath(PillowTestCase):
p = ImagePath.Path(arr.tostring())
self.assertEqual(list(p), [(0.0, 1.0)])
+ def test_getbbox(self):
+ for coords in (0,1):
+ p = ImagePath.Path(coords)
+ self.assertEqual(p.getbbox(), (0.0, 0.0, 0.0, 0.0))
+
def test_overflow_segfault(self):
# Some Pythons fail getting the argument as an integer, and it falls
# through to the sequence. Seeing this on 32-bit Windows.
diff --git a/src/path.c b/src/path.c
index eb1e065..5215f87 100644
--- a/src/path.c
+++ b/src/path.c
@@ -62,7 +62,7 @@ alloc_array(Py_ssize_t count)
PyErr_NoMemory();
return NULL;
}
- xy = malloc(2 * count * sizeof(double) + 1);
+ xy = calloc(2 * count + 1, sizeof(double));
if (!xy)
PyErr_NoMemory();
return xy;
@@ -330,18 +330,27 @@ path_getbbox(PyPathObject* self, PyObject* args)
xy = self->xy;
- x0 = x1 = xy[0];
- y0 = y1 = xy[1];
-
- for (i = 1; i < self->count; i++) {
- if (xy[i+i] < x0)
- x0 = xy[i+i];
- if (xy[i+i] > x1)
- x1 = xy[i+i];
- if (xy[i+i+1] < y0)
- y0 = xy[i+i+1];
- if (xy[i+i+1] > y1)
- y1 = xy[i+i+1];
+ if (self->count == 0) {
+ x0 = x1 = 0;
+ y0 = y1 = 0;
+ } else {
+ x0 = x1 = xy[0];
+ y0 = y1 = xy[1];
+
+ for (i = 1; i < self->count; i++) {
+ if (xy[i + i] < x0) {
+ x0 = xy[i + i];
+ }
+ if (xy[i + i] > x1) {
+ x1 = xy[i + i];
+ }
+ if (xy[i + i + 1] < y0) {
+ y0 = xy[i + i + 1];
+ }
+ if (xy[i + i + 1] > y1) {
+ y1 = xy[i + i + 1];
+ }
+ }
}
return Py_BuildValue("dddd", x0, y0, x1, y1);

@ -1,41 +0,0 @@
diff --git a/Tests/test_imagemath.py b/Tests/test_imagemath.py
index 2329b74..d3b7ba3 100644
--- a/Tests/test_imagemath.py
+++ b/Tests/test_imagemath.py
@@ -58,6 +58,12 @@ class TestImageMath(PillowTestCase):
self.assertEqual(pixel(
ImageMath.eval("float(B)**33", images)), "F 8589934592.0")
+ def test_prevent_exec(self):
+ self.assertRaises(ValueError, ImageMath.eval("exec('pass')"))
+ self.assertRaises(ValueError, ImageMath.eval("(lambda: exec('pass'))()"))
+ self.assertRaises(ValueError, ImageMath.eval("(lambda: (lambda: exec('pass'))())()"))
+
+
def test_logical(self):
self.assertEqual(pixel(ImageMath.eval("not A", images)), 0)
self.assertEqual(pixel(ImageMath.eval("A and B", images)), "L 2")
diff --git a/src/PIL/ImageMath.py b/src/PIL/ImageMath.py
index c5bea70..13839e4 100644
--- a/src/PIL/ImageMath.py
+++ b/src/PIL/ImageMath.py
@@ -263,7 +263,18 @@ def eval(expression, _dict={}, **kw):
if hasattr(v, "im"):
args[k] = _Operand(v)
- out = builtins.eval(expression, args)
+ compiled_code = compile(expression, "<string>", "eval")
+ def scan(code):
+ for const in code.co_consts:
+ if type(const) == type(compiled_code):
+ scan(const)
+
+ for name in code.co_names:
+ if name not in args and name != "abs":
+ raise ValueError(f"'{name}' not allowed")
+
+ scan(compiled_code)
+ out = builtins.eval(expression, {"__builtins": {"abs": abs}}, args)
try:
return out.im
except AttributeError:

@ -1,16 +1,16 @@
diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
--- Pillow-9.5.0/setup.py 2023-04-01 09:49:41.000000000 +0200
+++ Pillow-9.5.0-new/setup.py 2023-04-03 09:25:21.948393861 +0200
@@ -135,7 +135,7 @@ class RequiredDependencyException(Except
diff -rupN --no-dereference Pillow-10.0.1/setup.py Pillow-10.0.1-new/setup.py
--- Pillow-10.0.1/setup.py 2023-09-15 13:55:25.000000000 +0200
+++ Pillow-10.0.1-new/setup.py 2023-09-18 09:36:57.608297698 +0200
@@ -136,7 +136,7 @@ class RequiredDependencyException(Except
pass
-PLATFORM_MINGW = os.name == "nt" and "GCC" in sys.version
+PLATFORM_MINGW = "mingw32" in os.getenv("CC", "")
PLATFORM_PYPY = hasattr(sys, "pypy_version_info")
@@ -504,7 +504,7 @@ class pil_build_ext(build_ext):
def _dbg(s, tp=None):
@@ -509,7 +509,7 @@ class pil_build_ext(build_ext):
#
# add platform directories
@ -19,7 +19,7 @@ diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
pass
elif sys.platform == "cygwin":
@@ -594,7 +594,7 @@ class pil_build_ext(build_ext):
@@ -600,7 +600,7 @@ class pil_build_ext(build_ext):
# FIXME: check /opt/stuff directories here?
# standard locations
@ -28,7 +28,7 @@ diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
_add_directory(library_dirs, "/usr/local/lib")
_add_directory(include_dirs, "/usr/local/include")
@@ -840,7 +840,7 @@ class pil_build_ext(build_ext):
@@ -842,7 +842,7 @@ class pil_build_ext(build_ext):
if feature.xcb:
libs.append(feature.xcb)
defs.append(("HAVE_XCB", None))
@ -37,7 +37,7 @@ diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
libs.extend(["kernel32", "user32", "gdi32"])
if struct.unpack("h", b"\0\1")[0] == 1:
defs.append(("WORDS_BIGENDIAN", None))
@@ -862,6 +862,8 @@ class pil_build_ext(build_ext):
@@ -857,6 +857,8 @@ class pil_build_ext(build_ext):
if feature.freetype:
srcs = []
libs = ["freetype"]
@ -46,7 +46,7 @@ diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
defs = []
if feature.raqm:
if not feature.want_vendor("raqm"): # using system Raqm
@@ -884,7 +886,7 @@ class pil_build_ext(build_ext):
@@ -879,7 +881,7 @@ class pil_build_ext(build_ext):
if feature.lcms:
extra = []
@ -55,7 +55,7 @@ diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
extra.extend(["user32", "gdi32"])
self._update_extension("PIL._imagingcms", [feature.lcms] + extra)
else:
@@ -903,7 +905,7 @@ class pil_build_ext(build_ext):
@@ -898,7 +900,7 @@ class pil_build_ext(build_ext):
else:
self._remove_extension("PIL._webp")
@ -64,11 +64,11 @@ diff -rupN --no-dereference Pillow-9.5.0/setup.py Pillow-9.5.0-new/setup.py
self._update_extension("PIL._imagingtk", tk_libs)
build_ext.build_extensions(self)
diff -rupN --no-dereference Pillow-9.5.0/src/libImaging/ImPlatform.h Pillow-9.5.0-new/src/libImaging/ImPlatform.h
--- Pillow-9.5.0/src/libImaging/ImPlatform.h 2023-04-01 09:49:41.000000000 +0200
+++ Pillow-9.5.0-new/src/libImaging/ImPlatform.h 2023-04-03 09:25:21.949393602 +0200
diff -rupN --no-dereference Pillow-10.0.1/src/libImaging/ImPlatform.h Pillow-10.0.1-new/src/libImaging/ImPlatform.h
--- Pillow-10.0.1/src/libImaging/ImPlatform.h 2023-09-15 13:55:25.000000000 +0200
+++ Pillow-10.0.1-new/src/libImaging/ImPlatform.h 2023-09-18 09:36:57.608297698 +0200
@@ -28,7 +28,7 @@
#if defined(_WIN32) || defined(__CYGWIN__)
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>

@ -5,15 +5,15 @@
# Dependencies are missing to build the documentation
%bcond_with doc
%if 0%{?rhel}
%if 0%{?rhel} || 0%{?flatpak}
%bcond_with mingw
%else
%bcond_without mingw
%endif
Name: python-%{srcname}
Version: 9.5.0
Release: 2%{?dist}
Version: 10.0.1
Release: 1%{?dist}
Summary: Python image processing library
# License: see http://www.pythonware.com/products/pil/license.htm
@ -295,8 +295,14 @@ popd
%changelog
* Wed Sep 20 2023 Arkady L. Shane <tigro@msvsphere-os.ru> - 9.5.0-2
- Rebuilt for MSVSphere 9.2
* Mon Sep 18 2023 Sandro Mani <manisandro@gmail.com> - 10.0.1-1
- Update to 10.0.1
* Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 10.0.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Wed Jul 05 2023 Sandro Mani <manisandro@gmail.com> - 10.0.0-1
- Update to 10.0.0
* Fri Jun 16 2023 Python Maint <python-maint@redhat.com> - 9.5.0-2
- Rebuilt for Python 3.12

@ -0,0 +1 @@
SHA512 (Pillow-10.0.1.tar.gz) = 27e2f0d86563c3b7f5a2e0ba2bbe98fc2cb2fa5871d0b6cbb5a0014e9d9eb03dde9969301419d806d1a22cd4881e624465a355ba9bc42b95746226e1f95712a9
Loading…
Cancel
Save