From d06072ff467abac16973ddab4189587aad770ca4 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 5 Jul 2014 14:30:34 -0700 Subject: [PATCH 01/12] Multiplication needs to be 64bit, to handle overflow regardless of the bittedness of the machine, fixes #771# --- libImaging/Storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libImaging/Storage.c b/libImaging/Storage.c index d31db5cb2..c6d2e5c5e 100644 --- a/libImaging/Storage.c +++ b/libImaging/Storage.c @@ -379,7 +379,7 @@ ImagingNew(const char* mode, int xsize, int ysize) } else bytes = strlen(mode); /* close enough */ - if ((Py_ssize_t) xsize * ysize * bytes <= THRESHOLD) { + if ((int64_t) xsize * (int64_t) ysize * bytes <= THRESHOLD) { im = ImagingNewBlock(mode, xsize, ysize); if (im) return im; From 07c68e2d6879544f4356887e8222dc3bc96fae15 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 5 Jul 2014 15:06:17 -0700 Subject: [PATCH 02/12] Windows compatibility --- libImaging/ImPlatform.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libImaging/ImPlatform.h b/libImaging/ImPlatform.h index be1f20f3f..70ee63119 100644 --- a/libImaging/ImPlatform.h +++ b/libImaging/ImPlatform.h @@ -69,4 +69,6 @@ #define FLOAT32 float #define FLOAT64 double - +#ifdef _MSC_VER +typedef signed __int64 int64_t; +#endif From fb51604296c83b26bd2cfca632a1a017d1ed06a2 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Wed, 9 Jul 2014 10:12:43 -0700 Subject: [PATCH 03/12] Don't install mp_compile if multiprocessing.Pool() fails, or if 1 process is going to be used --- mp_compile.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/mp_compile.py b/mp_compile.py index 71b4089e1..b7c3e7ce4 100644 --- a/mp_compile.py +++ b/mp_compile.py @@ -5,6 +5,11 @@ from multiprocessing import Pool, cpu_count from distutils.ccompiler import CCompiler import os +try: + MAX_PROCS = int(os.environ.get('MAX_CONCURRENCY', cpu_count())) +except: + MAX_PROCS = None + # hideous monkeypatching. but. but. but. def _mp_compile_one(tp): @@ -31,22 +36,27 @@ def _mp_compile(self, sources, output_dir=None, macros=None, output_dir, macros, include_dirs, sources, depends, extra_postargs) cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) - try: - max_procs = int(os.environ.get('MAX_CONCURRENCY', cpu_count())) - except: - max_procs = None - pool = Pool(max_procs) + pool = Pool(MAX_PROCS) try: print ("Building using %d processes" % pool._processes) except: pass - arr = [ - (self, obj, build, cc_args, extra_postargs, pp_opts) for obj in objects - ] + arr = [(self, obj, build, cc_args, extra_postargs, pp_opts) + for obj in objects] pool.map_async(_mp_compile_one, arr) pool.close() pool.join() # Return *all* object filenames, not just the ones we just built. return objects -CCompiler.compile = _mp_compile +# explicitly don't enable if environment says 1 processor +if MAX_PROCS != 1: + try: + # bug, only enable if we can make a Pool. see issue #790 and + # http://stackoverflow.com/questions/6033599/oserror-38-errno-38-with-multiprocessing + pool = Pool(2) + CCompiler.compile = _mp_compile + except Exception as msg: + print("Exception installing mp_compile, proceeding without: %s" %msg) +else: + print("Single threaded build, not installing mp_compile: %s processes" %MAX_PROCS) From cacc11eaedbb4a3008ef43384db41327135c5e6c Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 8 Jul 2014 12:24:06 -0700 Subject: [PATCH 04/12] Updated CHANGES.rst --- CHANGES.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index b80639db7..4bd8381d0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,15 @@ Changelog (Pillow) ================== +2.5.1 (2014-07-09) +------------------ + +- Fixed install issue if Multiprocessing.Pool is not available + [wiredfool] + +- 32bit mult overflow fix #782 + [wiredfool] + 2.5.0 (2014-07-01) ------------------ From ef041675a26ba3f99485083074de2b4bf43ca1b6 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 8 Jul 2014 12:44:51 -0700 Subject: [PATCH 05/12] Bump the versions --- PIL/__init__.py | 2 +- _imaging.c | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PIL/__init__.py b/PIL/__init__.py index d446aa19b..50b13b158 100644 --- a/PIL/__init__.py +++ b/PIL/__init__.py @@ -12,7 +12,7 @@ # ;-) VERSION = '1.1.7' # PIL version -PILLOW_VERSION = '2.5.0' # Pillow +PILLOW_VERSION = '2.5.1' # Pillow _plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', diff --git a/_imaging.c b/_imaging.c index 92258032f..7ac283e8a 100644 --- a/_imaging.c +++ b/_imaging.c @@ -71,7 +71,7 @@ * See the README file for information on usage and redistribution. */ -#define PILLOW_VERSION "2.5.0" +#define PILLOW_VERSION "2.5.1" #include "Python.h" diff --git a/setup.py b/setup.py index e94e34d28..40d50577f 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ except (ImportError, OSError): NAME = 'Pillow' -PILLOW_VERSION = '2.5.0' +PILLOW_VERSION = '2.5.1' TCL_ROOT = None JPEG_ROOT = None JPEG2K_ROOT = None From 1ab78b8fb7e1f7078dd110bc8d9fba3cc0006e51 Mon Sep 17 00:00:00 2001 From: Alex Clark Date: Thu, 10 Jul 2014 17:54:59 -0400 Subject: [PATCH 06/12] Bump [ci skip] --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 4bd8381d0..c40866e41 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,7 @@ Changelog (Pillow) ================== -2.5.1 (2014-07-09) +2.5.1 (2014-07-10) ------------------ - Fixed install issue if Multiprocessing.Pool is not available From a029e5da9342caba6c0652d8b8fce84c04480a84 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 5 Jul 2014 10:56:40 -0700 Subject: [PATCH 07/12] Skip Known Bad Tests --- Tests/helper.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Tests/helper.py b/Tests/helper.py index 1c9851e25..6dc117ebb 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -123,6 +123,21 @@ class PillowTestCase(unittest.TestCase): self.assertTrue(found) return result + def skipKnownBadTest(self, msg=None, platform=None, travis=None): + # Skip if platform/travis matches, and + # PILLOW_RUN_KNOWN_BAD is not true in the environment. + if bool(os.environ.get('PILLOW_RUN_KNOWN_BAD', False)): + print (os.environ.get('PILLOW_RUN_KNOWN_BAD', False)) + return + + skip = True + if platform is not None: + skip = sys.platform.startswith(platform) + if travis is not None: + skip = skip and (travis == bool(os.environ.get('TRAVIS',False))) + if skip: + self.skipTest(msg or "Known Bad Test") + def tempfile(self, template): assert template[:5] in ("temp.", "temp_") (fd, path) = tempfile.mkstemp(template[4:], template[:4]) From fa7817a4d3673874af7d4b3d528c567718208aa1 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 5 Jul 2014 13:14:42 -0700 Subject: [PATCH 08/12] Known Bad tests -- skipping jpeg2k tests on travis on OSX --- Tests/test_file_icns.py | 4 ++++ Tests/test_file_jpeg2k.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index f19eb16b7..f604b8739 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -57,6 +57,10 @@ class TestFileIcns(PillowTestCase): if not enable_jpeg2k: return + self.skipKnownBadTest("Jpeg2000 hangs on Travis on OSX", + platform='darwin', + travis=True) + im = Image.open('Tests/images/pillow3.icns') for w, h, r in im.info['sizes']: wr = w * r diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index 23564c434..e306d4535 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -18,6 +18,9 @@ class TestFileJpeg2k(PillowTestCase): def setUp(self): if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs: self.skipTest('JPEG 2000 support not available') + self.skipKnownBadTest("Jpeg2000 hangs on Travis on OSX", + platform='darwin', + travis=True) def roundtrip(self, im, **options): out = BytesIO() From d47611e6fbb808ea109366781dd76559ffb80bcd Mon Sep 17 00:00:00 2001 From: wiredfool Date: Wed, 6 Aug 2014 16:42:43 -0700 Subject: [PATCH 09/12] Icns DOS fix -- CVE-2014-3589 Found and reported by Andrew Drake of dropbox.com --- PIL/IcnsImagePlugin.py | 2 ++ Tests/check_icns_dos.py | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 Tests/check_icns_dos.py diff --git a/PIL/IcnsImagePlugin.py b/PIL/IcnsImagePlugin.py index 6951c9325..ca7a14931 100644 --- a/PIL/IcnsImagePlugin.py +++ b/PIL/IcnsImagePlugin.py @@ -179,6 +179,8 @@ class IcnsFile: i = HEADERSIZE while i < filesize: sig, blocksize = nextheader(fobj) + if blocksize <= 0: + raise SyntaxError('invalid block header') i += HEADERSIZE blocksize -= HEADERSIZE dct[sig] = (i, blocksize) diff --git a/Tests/check_icns_dos.py b/Tests/check_icns_dos.py new file mode 100644 index 000000000..ce6338a71 --- /dev/null +++ b/Tests/check_icns_dos.py @@ -0,0 +1,10 @@ +# Tests potential DOS of IcnsImagePlugin with 0 length block. +# Run from anywhere that PIL is importable. + +from PIL import Image +from io import BytesIO + +if bytes is str: + Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00'))) +else: + Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00', 'latin-1'))) From 4081f9f6a504c9d3b83237fafdecf2be042976a8 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 12 Aug 2014 11:44:56 -0700 Subject: [PATCH 10/12] Bump Versions/Changelog --- CHANGES.rst | 6 ++++++ PIL/__init__.py | 2 +- _imaging.c | 2 +- setup.py | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index c40866e41..524f4100d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,12 @@ Changelog (Pillow) ================== +2.5.2 (2014-08-13) +------------------ + +- Fixed CVE-2014-3589, a DOS in the IcnsImagePlugin + [Andrew Drake] + 2.5.1 (2014-07-10) ------------------ diff --git a/PIL/__init__.py b/PIL/__init__.py index 50b13b158..ea785d373 100644 --- a/PIL/__init__.py +++ b/PIL/__init__.py @@ -12,7 +12,7 @@ # ;-) VERSION = '1.1.7' # PIL version -PILLOW_VERSION = '2.5.1' # Pillow +PILLOW_VERSION = '2.5.2' # Pillow _plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', diff --git a/_imaging.c b/_imaging.c index 7ac283e8a..eff632082 100644 --- a/_imaging.c +++ b/_imaging.c @@ -71,7 +71,7 @@ * See the README file for information on usage and redistribution. */ -#define PILLOW_VERSION "2.5.1" +#define PILLOW_VERSION "2.5.2" #include "Python.h" diff --git a/setup.py b/setup.py index 40d50577f..f01ac1d9b 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ except (ImportError, OSError): NAME = 'Pillow' -PILLOW_VERSION = '2.5.1' +PILLOW_VERSION = '2.5.2' TCL_ROOT = None JPEG_ROOT = None JPEG2K_ROOT = None From 05a169d65c19940495c26769ae66c5d1a001cb9f Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 12 Aug 2014 12:31:37 -0700 Subject: [PATCH 11/12] J2k DOS fix -- CVE-2014-3598 Found and reported by Andrew Drake of dropbox.com --- PIL/Jpeg2KImagePlugin.py | 3 +++ Tests/check_j2k_dos.py | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 Tests/check_j2k_dos.py diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index 0a7a6e297..53b10ca1a 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -70,6 +70,9 @@ def _parse_jp2_header(fp): else: hlen = 8 + if lbox < hlen: + raise SyntaxError('Invalid JP2 header length') + if tbox == b'jp2h': header = fp.read(lbox - hlen) break diff --git a/Tests/check_j2k_dos.py b/Tests/check_j2k_dos.py new file mode 100644 index 000000000..68f065bbc --- /dev/null +++ b/Tests/check_j2k_dos.py @@ -0,0 +1,11 @@ +# Tests potential DOS of Jpeg2kImagePlugin with 0 length block. +# Run from anywhere that PIL is importable. + +from PIL import Image +from io import BytesIO + +if bytes is str: + Image.open(BytesIO(bytes('\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang'))) +else: + Image.open(BytesIO(bytes('\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang', 'latin-1'))) + From 68c6904c280ad872620cc8d904e6d4e6ecc5b6f9 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 12 Aug 2014 12:40:15 -0700 Subject: [PATCH 12/12] Bump Version/Changelog --- CHANGES.rst | 7 +++++++ PIL/__init__.py | 2 +- _imaging.c | 2 +- setup.py | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 524f4100d..b038633d1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,13 @@ Changelog (Pillow) ================== +2.5.3 (2014-08-18) +------------------ + +- Fixed CVE-2014-3598, a DOS in the Jpeg2KImagePlugin + [Andrew Drake] + + 2.5.2 (2014-08-13) ------------------ diff --git a/PIL/__init__.py b/PIL/__init__.py index ea785d373..d5894c447 100644 --- a/PIL/__init__.py +++ b/PIL/__init__.py @@ -12,7 +12,7 @@ # ;-) VERSION = '1.1.7' # PIL version -PILLOW_VERSION = '2.5.2' # Pillow +PILLOW_VERSION = '2.5.3' # Pillow _plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', diff --git a/_imaging.c b/_imaging.c index eff632082..0fc7f3d21 100644 --- a/_imaging.c +++ b/_imaging.c @@ -71,7 +71,7 @@ * See the README file for information on usage and redistribution. */ -#define PILLOW_VERSION "2.5.2" +#define PILLOW_VERSION "2.5.3" #include "Python.h" diff --git a/setup.py b/setup.py index f01ac1d9b..7d00d25a8 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ except (ImportError, OSError): NAME = 'Pillow' -PILLOW_VERSION = '2.5.2' +PILLOW_VERSION = '2.5.3' TCL_ROOT = None JPEG_ROOT = None JPEG2K_ROOT = None