components/python/imaging/patches/06-CVE-2016-9189.patch
changeset 7369 a206d468357a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/imaging/patches/06-CVE-2016-9189.patch	Mon Nov 21 13:24:12 2016 -0800
@@ -0,0 +1,317 @@
+For CVE-2016-9189
+https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-9189
+
+Python Imaging allows context-dependent attackers to obtain sensitive
+information by using the "crafted image file" approach, related to an
+"Integer Overflow" issue affecting the Image.core.map_buffer in map.c
+component.
+
+Code changes based on those found upstream for Pillow at:
+
+https://github.com/python-pillow/Pillow/pull/2146/commits/c50ebe6459a131a1ea8ca531f10da616d3ceaa0f
+for:
+  map.c
+
+https://github.com/python-pillow/Pillow/pull/2146/commits/445451c0b9347b50e0f603db33f196e207de470d
+for:
+  PIL/Image.py
+
+https://github.com/python-pillow/Pillow/pull/2146/commits/1a43da7a8bda884a597f3a1623364f4719d21c14
+for:
+  PIL/EpsImagePlugin.py
+  PIL/IptcImagePlugin.py
+  PIL/JPegImagePlugin.py
+  PIL/PpmImagePlugin.py
+  _imaging.c
+  libImaging/File.c
+
+--- Imaging-1.1.7/map.c.orig	2016-11-21 07:50:42.925380355 +0000
++++ Imaging-1.1.7/map.c	2016-11-21 07:53:34.182039527 +0000
+@@ -339,8 +339,18 @@
+             stride = xsize * 4;
+     }
+ 
++    if (ysize > INT_MAX / stride) {
++        PyErr_SetString(PyExc_MemoryError, "Integer overflow in ysize");
++        return NULL;
++    }
++
+     size = ysize * stride;
+ 
++    if (offset > SIZE_MAX - size) {
++        PyErr_SetString(PyExc_MemoryError, "Integer overflow in offset");
++        return NULL;
++    }
++
+     /* check buffer size */
+     bytes = PyImaging_ReadBuffer(target, (const void**) &ptr);
+     if (bytes < 0) {
+--- Imaging-1.1.7/PIL/Image.py.orig	2016-11-21 07:58:09.978008218 +0000
++++ Imaging-1.1.7/PIL/Image.py	2016-11-21 08:02:12.063288055 +0000
+@@ -1740,6 +1740,25 @@
+ 
+     return Image()._new(core.wedge("L"))
+ 
++
++def _check_size(size):
++    """
++    Common check to enforce type and sanity check on size tuples
++
++    :param size: Should be a 2 tuple of (width, height)
++    :returns: True, or raises a ValueError
++    """
++
++    if not isinstance(size, tuple):
++        raise ValueError("Size must be a tuple")
++    if len(size) != 2:
++        raise ValueError("Size must be a tuple of length 2")
++    if size[0] <= 0 or size[1] <= 0:
++        raise ValueError("Width and Height must be > 0")
++
++    return True
++
++
+ ##
+ # Creates a new image with the given mode and size.
+ #
+@@ -1756,6 +1775,8 @@
+ def new(mode, size, color=0):
+     "Create a new image"
+ 
++    _check_size(size)
++
+     if color is None:
+         # don't initialize
+         return Image()._new(core.new(mode, size))
+@@ -1792,6 +1813,8 @@
+ def fromstring(mode, size, data, decoder_name="raw", *args):
+     "Load image from string"
+ 
++    _check_size(size)
++
+     # may pass tuple instead of argument list
+     if len(args) == 1 and isTupleType(args[0]):
+         args = args[0]
+@@ -1839,6 +1862,8 @@
+ def frombuffer(mode, size, data, decoder_name="raw", *args):
+     "Load image from string or buffer"
+ 
++    _check_size(size)
++
+     # may pass tuple instead of argument list
+     if len(args) == 1 and isTupleType(args[0]):
+         args = args[0]
+--- Imaging-1.1.7/PIL/EpsImagePlugin.py.orig	2016-11-21 08:07:25.697709727 +0000
++++ Imaging-1.1.7/PIL/EpsImagePlugin.py	2016-11-21 08:12:17.177879463 +0000
+@@ -74,12 +74,13 @@
+         status = gs.close()
+         if status:
+             raise IOError("gs failed (status %d)" % status)
+-        im = Image.core.open_ppm(file)
++        im = Image.open(outfile)
++        im.load()
+     finally:
+         try: os.unlink(file)
+         except: pass
+ 
+-    return im
++    return im.im.copy()
+ 
+ 
+ class PSFile:
+--- Imaging-1.1.7/PIL/IptcImagePlugin.py.orig	2016-11-21 08:07:25.704128117 +0000
++++ Imaging-1.1.7/PIL/IptcImagePlugin.py	2016-11-21 08:14:00.062399442 +0000
+@@ -192,14 +192,9 @@
+         o.close()
+ 
+         try:
+-            try:
+-                # fast
+-                self.im = Image.core.open_ppm(outfile)
+-            except:
+-                # slightly slower
+-                im = Image.open(outfile)
+-                im.load()
+-                self.im = im.im
++            _im = Image.open(outfile)
++            _im.load()
++            self.im = _im.im
+         finally:
+             try: os.unlink(outfile)
+             except: pass
+--- Imaging-1.1.7/PIL/JpegImagePlugin.py.orig	2016-11-21 08:16:20.362838015 +0000
++++ Imaging-1.1.7/PIL/JpegImagePlugin.py	2016-11-21 08:19:06.852441772 +0000
+@@ -352,7 +352,9 @@
+             raise ValueError("Invalid Filename")
+ 
+         try:
+-            self.im = Image.core.open_ppm(path)
++            _im = Image.open(path)
++            _im.load()
++            self.im = _im.im
+         finally:
+             try: os.unlink(path)
+             except: pass
+--- Imaging-1.1.7/PIL/PpmImagePlugin.py.orig	2016-11-21 08:07:25.708512595 +0000
++++ Imaging-1.1.7/PIL/PpmImagePlugin.py	2016-11-21 08:19:55.525463844 +0000
+@@ -93,11 +93,6 @@
+                      self.fp.tell(),
+                      (rawmode, 0, 1))]
+ 
+-        # ALTERNATIVE: load via builtin debug function
+-        # self.im = Image.core.open_ppm(self.filename)
+-        # self.mode = self.im.mode
+-        # self.size = self.im.size
+-
+ #
+ # --------------------------------------------------------------------
+ 
+--- Imaging-1.1.7/_imaging.c.orig	2016-11-21 08:07:25.710428542 +0000
++++ Imaging-1.1.7/_imaging.c	2016-11-21 08:21:03.690730505 +0000
+@@ -684,17 +684,6 @@
+ }
+ 
+ static PyObject* 
+-_open_ppm(PyObject* self, PyObject* args)
+-{
+-    char* filename;
+-
+-    if (!PyArg_ParseTuple(args, "s", &filename))
+-	return NULL;
+-
+-    return PyImagingNew(ImagingOpenPPM(filename));
+-}
+-
+-static PyObject* 
+ _blend(ImagingObject* self, PyObject* args)
+ {
+     ImagingObject* imagep1;
+@@ -3215,9 +3204,6 @@
+     {"crc32", (PyCFunction)_crc32, 1},
+     {"getcodecstatus", (PyCFunction)_getcodecstatus, 1},
+ 
+-    /* Debugging stuff */
+-    {"open_ppm", (PyCFunction)_open_ppm, 1},
+-
+     /* Special effects (experimental) */
+ #ifdef WITH_EFFECTS
+     {"effect_mandelbrot", (PyCFunction)_effect_mandelbrot, 1},
+--- Imaging-1.1.7/libImaging/File.c.orig	2016-11-21 08:07:25.712276651 +0000
++++ Imaging-1.1.7/libImaging/File.c	2016-11-21 08:22:37.837774950 +0000
+@@ -20,116 +20,6 @@
+ 
+ #include <ctype.h>
+ 
+-Imaging
+-ImagingOpenPPM(const char* infile)
+-{
+-    FILE* fp;
+-    int i, c, v;
+-    char* mode;
+-    int x, y, max;
+-    Imaging im;
+-
+-    if (!infile)
+-	return ImagingError_ValueError(NULL);
+-
+-    fp = fopen(infile, "rb");
+-    if (!fp)
+-	return ImagingError_IOError();
+-
+-    /* PPM magic */
+-    if (fgetc(fp) != 'P')
+-	goto error;
+-    switch (fgetc(fp)) {
+-    case '4': /* FIXME: 1-bit images are not yet supported */
+-	goto error;
+-    case '5':
+-	mode = "L";
+-	break;
+-    case '6':
+-	mode = "RGB";
+-	break;
+-    default:
+-	goto error;
+-    }
+-
+-    i = 0;
+-    c = fgetc(fp);
+-
+-    x = y = max = 0;
+-
+-    while (i < 3) {	
+-
+-	/* Ignore optional comment fields */
+-	while (c == '\n') {
+-	    c = fgetc(fp);
+-	    if (c == '#') {
+-		do {
+-		    c = fgetc(fp);
+-		    if (c == EOF)
+-			goto error;
+-		} while (c != '\n');
+-		c = fgetc(fp);
+-	    }
+-	}
+-
+-	/* Skip forward to next value */
+-	while (isspace(c))
+-	    c = fgetc(fp);
+-
+-	/* And parse it */
+-	v = 0;
+-	while (isdigit(c)) {
+-	    v = v * 10 + (c - '0');
+-	    c = fgetc(fp);
+-	}
+-
+-	if (c == EOF)
+-	    goto error;
+-
+-	switch (i++) {
+-	case 0:
+-	    x = v;
+-	    break;
+-	case 1:
+-	    y = v;
+-	    break;
+-	case 2:
+-	    max = v;
+-	    break;
+-	}
+-    }
+-
+-    im = ImagingNew(mode, x, y);
+-    if (!im)
+-	return NULL;
+-
+-    /* if (max != 255) ... FIXME: does anyone ever use this feature? */
+-
+-    if (strcmp(im->mode, "L") == 0) {
+-
+-	/* PPM "L" */
+-	for (y = 0; y < im->ysize; y++)
+-	    if (fread(im->image[y], im->xsize, 1, fp) != 1)
+-		goto error;
+-
+-    } else {
+-
+-	/* PPM "RGB" or PyPPM mode */
+-	for (y = 0; y < im->ysize; y++)
+-	    for (x = i = 0; x < im->xsize; x++, i += im->pixelsize)
+-		if (fread(im->image[y]+i, im->bands, 1, fp) != 1)
+-		    goto error;
+-    }
+-
+-    fclose(fp);
+-
+-    return im;
+-
+-error:
+-    fclose(fp);
+-    return ImagingError_IOError();
+-}
+-
+ 
+ int
+ ImagingSaveRaw(Imaging im, FILE* fp)