From 7c055c161d4d6f9bea3362463d413f8c6eef67ae Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jun 25 2021 04:19:48 +0000 Subject: import python-pillow-5.1.1-15.el8 --- diff --git a/SOURCES/CVE-2021-25287_25288.patch b/SOURCES/CVE-2021-25287_25288.patch new file mode 100644 index 0000000..acb42a8 --- /dev/null +++ b/SOURCES/CVE-2021-25287_25288.patch @@ -0,0 +1,130 @@ +From 9c781aa2020eef838284dcb348f4528f3c3cc1ab Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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 + diff --git a/SOURCES/CVE-2021-28675.patch b/SOURCES/CVE-2021-28675.patch new file mode 100644 index 0000000..db8d38a --- /dev/null +++ b/SOURCES/CVE-2021-28675.patch @@ -0,0 +1,146 @@ +From 7fe3dff241c11206616bf6229be898854ce0d066 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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 read method. + :param size: Number of bytes to read. +- :returns: A string containing up to size bytes of data. ++ :returns: A string containing size 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 + diff --git a/SOURCES/CVE-2021-28676.patch b/SOURCES/CVE-2021-28676.patch new file mode 100644 index 0000000..4a222ea --- /dev/null +++ b/SOURCES/CVE-2021-28676.patch @@ -0,0 +1,28 @@ +From cedb7ba568161021bc2f2f48af95fcf33e262f77 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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 + diff --git a/SOURCES/CVE-2021-28677.patch b/SOURCES/CVE-2021-28677.patch new file mode 100644 index 0000000..64d0f68 --- /dev/null +++ b/SOURCES/CVE-2021-28677.patch @@ -0,0 +1,41 @@ +From 8ad7b436649c424e22689a8a874c1b0cd7c1c0fc Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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 + diff --git a/SOURCES/CVE-2021-28678.patch b/SOURCES/CVE-2021-28678.patch new file mode 100644 index 0000000..5bab189 --- /dev/null +++ b/SOURCES/CVE-2021-28678.patch @@ -0,0 +1,122 @@ +From eaef29c3696cd021147e692360997f4c12377c60 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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(" - 5.1.1-15 +- Fixes for CVE-2021-25288, CVE-2021-25287, CVE-2021-28675, CVE-2021-28676, +CVE-2021-28677 and CVE-2021-28678 +Resolves: rhbz#1958231, rhbz#1958226, rhbz#1958240, rhbz#1958252, rhbz#1958257, rhbz#1958263 + * Fri Apr 09 2021 Lumír Balhar - 5.1.1-14 - Fixes for CVE-2021-25290, CVE-2021-25292, CVE-2021-25293, CVE-2021-27921 CVE-2021-27922, and CVE-2021-27923