debdiff for my NMU.
diff -Nru pillow-8.1.2+dfsg/debian/changelog pillow-8.1.2+dfsg/debian/changelog --- pillow-8.1.2+dfsg/debian/changelog 2021-04-24 15:51:24.000000000 +0200 +++ pillow-8.1.2+dfsg/debian/changelog 2021-06-13 18:11:04.000000000 +0200 @@ -1,3 +1,12 @@ +pillow (8.1.2+dfsg-0.2) unstable; urgency=medium + + * Non-maintainer upload. + * Cherrypick security fixes from 8.2: + - CVE-2021-25287 / CVE-2021-25288 / CVE-2021-28675 / CVE-2021-28676 + CVE-2021-28677 / CVE-2021-28678 (Closes: #989062) + + -- Moritz Muehlenhoff <j...@debian.org> Sun, 13 Jun 2021 18:11:04 +0200 + pillow (8.1.2+dfsg-0.1) unstable; urgency=medium * Non-maintainer upload. diff -Nru pillow-8.1.2+dfsg/debian/patches/CVE-2021-25287_CVE-2021-25288.patch pillow-8.1.2+dfsg/debian/patches/CVE-2021-25287_CVE-2021-25288.patch --- pillow-8.1.2+dfsg/debian/patches/CVE-2021-25287_CVE-2021-25288.patch 1970-01-01 01:00:00.000000000 +0100 +++ pillow-8.1.2+dfsg/debian/patches/CVE-2021-25287_CVE-2021-25288.patch 2021-06-13 18:08:32.000000000 +0200 @@ -0,0 +1,69 @@ +From 3bf5eddb89afdf690eceaa52bc4d3546ba9a5f87 Mon Sep 17 00:00:00 2001 +From: Eric Soroos <eric-git...@soroos.net> +Date: Sun, 7 Mar 2021 12:32:12 +0100 +Subject: [PATCH] Fix OOB Read in Jpeg2KDecode CVE-2021-25287,CVE-2021-25288 + +* For J2k images with multiple bands, it's legal in to have different + widths for each band, e.g. 1 byte for L, 4 bytes for A +* This dates to Pillow 2.4.0 + +--- pillow-8.1.2+dfsg.orig/src/libImaging/Jpeg2KDecode.c ++++ pillow-8.1.2+dfsg/src/libImaging/Jpeg2KDecode.c +@@ -589,7 +589,7 @@ j2k_decode_entry(Imaging im, ImagingCode + j2k_unpacker_t unpack = NULL; + size_t buffer_size = 0, tile_bytes = 0; + unsigned n, tile_height, tile_width; +- int components; ++ int total_component_width = 0; + + + stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE); +@@ -753,23 +753,40 @@ j2k_decode_entry(Imaging im, ImagingCode + 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 numcomps*w*h, and we overflow in the ++ 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; +- components = tile_info.nb_comps == 3 ? 4 : tile_info.nb_comps; +- if (( tile_width > UINT_MAX / components ) || +- ( tile_height > UINT_MAX / components ) || +- ( tile_width > UINT_MAX / (tile_height * components )) || +- ( tile_height > UINT_MAX / (tile_width * components ))) { ++ ++ /* 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 * components; ++ ++ tile_bytes = tile_width * tile_height * total_component_width; + + if (tile_bytes > tile_info.data_size) { + tile_info.data_size = tile_bytes; diff -Nru pillow-8.1.2+dfsg/debian/patches/CVE-2021-28675.patch pillow-8.1.2+dfsg/debian/patches/CVE-2021-28675.patch --- pillow-8.1.2+dfsg/debian/patches/CVE-2021-28675.patch 1970-01-01 01:00:00.000000000 +0100 +++ pillow-8.1.2+dfsg/debian/patches/CVE-2021-28675.patch 2021-06-13 18:09:24.000000000 +0200 @@ -0,0 +1,132 @@ +From 22e9bee4ef225c0edbb9323f94c26cee0c623497 Mon Sep 17 00:00:00 2001 +From: Eric Soroos <eric-git...@soroos.net> +Date: Sun, 7 Mar 2021 19:04:25 +0100 +Subject: [PATCH] Fix DOS in PSDImagePlugin -- CVE-2021-28675 + +* PSDImagePlugin did not sanity check the number of input layers and + vs the size of the data block, this could lead to a DOS on + Image.open prior to Image.load. +* This issue dates to the PIL fork + +--- pillow-8.1.2+dfsg.orig/src/PIL/ImageFile.py ++++ pillow-8.1.2+dfsg/src/PIL/ImageFile.py +@@ -555,12 +555,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)) +@@ -568,9 +574,13 @@ 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) + + ++ ++ + class PyCodecState: + def __init__(self): + self.xsize = 0 +--- pillow-8.1.2+dfsg.orig/src/PIL/PsdImagePlugin.py ++++ pillow-8.1.2+dfsg/src/PIL/PsdImagePlugin.py +@@ -119,7 +119,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) + self.n_frames = len(self.layers) + self.is_animated = self.n_frames > 1 +@@ -170,12 +171,20 @@ class PsdImageFile(ImageFile.ImageFile): + finally: + self.__fp = None + +- +-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)) +@@ -186,7 +195,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 + +@@ -219,16 +229,16 @@ 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: +- file.seek(length - 16, io.SEEK_CUR) ++ fp.seek(length - 16, io.SEEK_CUR) + combined += length + 4 + + length = i32(read(4)) + if length: +- file.seek(length, io.SEEK_CUR) ++ fp.seek(length, io.SEEK_CUR) + combined += length + 4 + + length = i8(read(1)) +@@ -238,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 +@@ -246,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 diff -Nru pillow-8.1.2+dfsg/debian/patches/CVE-2021-28676.patch pillow-8.1.2+dfsg/debian/patches/CVE-2021-28676.patch --- pillow-8.1.2+dfsg/debian/patches/CVE-2021-28676.patch 1970-01-01 01:00:00.000000000 +0100 +++ pillow-8.1.2+dfsg/debian/patches/CVE-2021-28676.patch 2021-06-13 18:10:02.000000000 +0200 @@ -0,0 +1,24 @@ +From bb6c11fb889e6c11b0ee122b828132ee763b5856 Mon Sep 17 00:00:00 2001 +From: Eric Soroos <eric-git...@soroos.net> +Date: Thu, 11 Mar 2021 22:12:35 +0100 +Subject: [PATCH] Fix FLI DOS -- CVE-2021-28676 + +* FliDecode did not properly check that the block advance was + non-zero, potentally leading to an infinite loop on load. +* This dates to the PIL Fork +* Found with oss-fuzz + +--- pillow-8.1.2+dfsg.orig/src/libImaging/FliDecode.c ++++ pillow-8.1.2+dfsg/src/libImaging/FliDecode.c +@@ -242,6 +242,11 @@ ImagingFliDecode(Imaging im, ImagingCode + 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; ++ } + if (advance < 0 || advance > bytes) { + state->errcode = IMAGING_CODEC_OVERRUN; + return -1; diff -Nru pillow-8.1.2+dfsg/debian/patches/CVE-2021-28677.patch pillow-8.1.2+dfsg/debian/patches/CVE-2021-28677.patch --- pillow-8.1.2+dfsg/debian/patches/CVE-2021-28677.patch 1970-01-01 01:00:00.000000000 +0100 +++ pillow-8.1.2+dfsg/debian/patches/CVE-2021-28677.patch 2021-06-13 17:54:06.000000000 +0200 @@ -0,0 +1,41 @@ +From 5a5e6db0abf4e7a638fb1b3408c4e495a096cb92 Mon Sep 17 00:00:00 2001 +From: Eric Soroos <eric-git...@soroos.net> +Date: Mon, 8 Mar 2021 20:31:41 +0100 +Subject: [PATCH] Fix EPS DOS on _open -- CVE-2021-28677 + +* The readline used in EPS has to deal with any combination of \r and + \n as line endings. It used an accidentally quadratic method of + accumulating lines while looking for a line ending. +* A malicious EPS file could use this to perform a DOS of Pillow in + the open phase, before an image was accepted for opening. +* This dates to the PIL Fork + +diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py +index dc61f48edc9..3bf8ee0ab35 100644 +--- a/src/PIL/EpsImagePlugin.py ++++ b/src/PIL/EpsImagePlugin.py +@@ -170,12 +170,12 @@ def seek(self, offset, whence=io.SEEK_SET): + 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) +@@ -183,7 +183,7 @@ def readline(self): + 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): diff -Nru pillow-8.1.2+dfsg/debian/patches/CVE-2021-28678.patch pillow-8.1.2+dfsg/debian/patches/CVE-2021-28678.patch --- pillow-8.1.2+dfsg/debian/patches/CVE-2021-28678.patch 1970-01-01 01:00:00.000000000 +0100 +++ pillow-8.1.2+dfsg/debian/patches/CVE-2021-28678.patch 2021-06-13 17:54:06.000000000 +0200 @@ -0,0 +1,119 @@ +From 496245aa4365d0827390bd0b6fbd11287453b3a1 Mon Sep 17 00:00:00 2001 +From: Eric Soroos <eric-git...@soroos.net> +Date: Sun, 7 Mar 2021 19:00:17 +0100 +Subject: [PATCH] Fix BLP DOS -- CVE-2021-28678 + +* BlpImagePlugin did not properly check that reads after jumping to + file offsets returned data. This could lead to a DOS where the + decoder could be run a large number of times on empty data +* This dates to Pillow 5.1.0 + +diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py +index 88aae80eb96..e07474621d9 100644 +--- a/src/PIL/BlpImagePlugin.py ++++ b/src/PIL/BlpImagePlugin.py +@@ -286,33 +286,36 @@ def decode(self, buffer): + raise OSError("Truncated Blp file") from e + 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): +@@ -324,7 +327,7 @@ def _load(self): + 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)) +@@ -346,10 +349,10 @@ def _load(self): + 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) +@@ -370,7 +373,7 @@ def _load(self): + # 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)) +@@ -384,20 +387,20 @@ def _load(self): + 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), alpha=bool(self._blp_alpha_depth) ++ self._safe_read(linesize), alpha=bool(self._blp_alpha_depth) + ): + data += d + + 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( diff -Nru pillow-8.1.2+dfsg/debian/patches/series pillow-8.1.2+dfsg/debian/patches/series --- pillow-8.1.2+dfsg/debian/patches/series 2020-10-19 19:55:33.000000000 +0200 +++ pillow-8.1.2+dfsg/debian/patches/series 2021-06-13 18:10:51.000000000 +0200 @@ -2,3 +2,8 @@ generate-webp-file js-script-file.diff no-sphinx-removed-in.diff +CVE-2021-25287_CVE-2021-25288.patch +CVE-2021-28675.patch +CVE-2021-28676.patch +CVE-2021-28677.patch +CVE-2021-28678.patch