25052020 problem in PYTHON-MOD/PIL
authorRich Burridge <rich.burridge@oracle.com>
Mon, 21 Nov 2016 13:24:12 -0800
changeset 7369 a206d468357a
parent 7368 13871af9f746
child 7370 6f65cee26eca
25052020 problem in PYTHON-MOD/PIL 25052021 problem in PYTHON-MOD/PIL
components/python/imaging/patches/06-CVE-2016-9189.patch
components/python/imaging/patches/07-CVE-2016-9190.patch
--- /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
[email protected]@ -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
[email protected]@ -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.
+ #
[email protected]@ -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))
[email protected]@ -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]
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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;
[email protected]@ -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
[email protected]@ -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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/imaging/patches/07-CVE-2016-9190.patch	Mon Nov 21 13:24:12 2016 -0800
@@ -0,0 +1,26 @@
+CVE-2016-9190
+https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-9190
+
+Python Imaging allows context-dependent attackers to execute arbitrary code
+by using the "crafted image file" approach, related to an "Insecure Sign
+Extension" issue affecting the ImagingNew in Storage.c component.
+
+Code changes based on those found upstream for Pillow at:
+
+https://github.com/python-pillow/Pillow/pull/2146/commits/5d8a0be45aad78c5a22c8d099118ee26ef8144af
+for:
+  libImaging/Storage.c
+
+--- Imaging-1.1.7/libImaging/Storage.c.orig	2016-11-21 07:38:52.301251099 +0000
++++ Imaging-1.1.7/libImaging/Storage.c	2016-11-21 07:40:39.795030452 +0000
[email protected]@ -369,6 +369,10 @@
+     } else
+         bytes = strlen(mode); /* close enough */
+ 
++    if (xsize < 0 || ysize < 0) {
++        return (Imaging) ImagingError_ValueError("bad image size");
++    }
++
+     if ((long) xsize * ysize * bytes <= THRESHOLD) {
+         im = ImagingNewBlock(mode, xsize, ysize);
+         if (im)