components/python/imaging/patches/06-CVE-2016-9189.patch
author Rich Burridge <rich.burridge@oracle.com>
Mon, 21 Nov 2016 13:24:12 -0800
changeset 7369 a206d468357a
permissions -rw-r--r--
25052020 problem in PYTHON-MOD/PIL 25052021 problem in PYTHON-MOD/PIL

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)