components/python/imaging/patches/06-CVE-2016-9189.patch
changeset 7369 a206d468357a
equal deleted inserted replaced
7368:13871af9f746 7369:a206d468357a
       
     1 For CVE-2016-9189
       
     2 https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-9189
       
     3 
       
     4 Python Imaging allows context-dependent attackers to obtain sensitive
       
     5 information by using the "crafted image file" approach, related to an
       
     6 "Integer Overflow" issue affecting the Image.core.map_buffer in map.c
       
     7 component.
       
     8 
       
     9 Code changes based on those found upstream for Pillow at:
       
    10 
       
    11 https://github.com/python-pillow/Pillow/pull/2146/commits/c50ebe6459a131a1ea8ca531f10da616d3ceaa0f
       
    12 for:
       
    13   map.c
       
    14 
       
    15 https://github.com/python-pillow/Pillow/pull/2146/commits/445451c0b9347b50e0f603db33f196e207de470d
       
    16 for:
       
    17   PIL/Image.py
       
    18 
       
    19 https://github.com/python-pillow/Pillow/pull/2146/commits/1a43da7a8bda884a597f3a1623364f4719d21c14
       
    20 for:
       
    21   PIL/EpsImagePlugin.py
       
    22   PIL/IptcImagePlugin.py
       
    23   PIL/JPegImagePlugin.py
       
    24   PIL/PpmImagePlugin.py
       
    25   _imaging.c
       
    26   libImaging/File.c
       
    27 
       
    28 --- Imaging-1.1.7/map.c.orig	2016-11-21 07:50:42.925380355 +0000
       
    29 +++ Imaging-1.1.7/map.c	2016-11-21 07:53:34.182039527 +0000
       
    30 @@ -339,8 +339,18 @@
       
    31              stride = xsize * 4;
       
    32      }
       
    33  
       
    34 +    if (ysize > INT_MAX / stride) {
       
    35 +        PyErr_SetString(PyExc_MemoryError, "Integer overflow in ysize");
       
    36 +        return NULL;
       
    37 +    }
       
    38 +
       
    39      size = ysize * stride;
       
    40  
       
    41 +    if (offset > SIZE_MAX - size) {
       
    42 +        PyErr_SetString(PyExc_MemoryError, "Integer overflow in offset");
       
    43 +        return NULL;
       
    44 +    }
       
    45 +
       
    46      /* check buffer size */
       
    47      bytes = PyImaging_ReadBuffer(target, (const void**) &ptr);
       
    48      if (bytes < 0) {
       
    49 --- Imaging-1.1.7/PIL/Image.py.orig	2016-11-21 07:58:09.978008218 +0000
       
    50 +++ Imaging-1.1.7/PIL/Image.py	2016-11-21 08:02:12.063288055 +0000
       
    51 @@ -1740,6 +1740,25 @@
       
    52  
       
    53      return Image()._new(core.wedge("L"))
       
    54  
       
    55 +
       
    56 +def _check_size(size):
       
    57 +    """
       
    58 +    Common check to enforce type and sanity check on size tuples
       
    59 +
       
    60 +    :param size: Should be a 2 tuple of (width, height)
       
    61 +    :returns: True, or raises a ValueError
       
    62 +    """
       
    63 +
       
    64 +    if not isinstance(size, tuple):
       
    65 +        raise ValueError("Size must be a tuple")
       
    66 +    if len(size) != 2:
       
    67 +        raise ValueError("Size must be a tuple of length 2")
       
    68 +    if size[0] <= 0 or size[1] <= 0:
       
    69 +        raise ValueError("Width and Height must be > 0")
       
    70 +
       
    71 +    return True
       
    72 +
       
    73 +
       
    74  ##
       
    75  # Creates a new image with the given mode and size.
       
    76  #
       
    77 @@ -1756,6 +1775,8 @@
       
    78  def new(mode, size, color=0):
       
    79      "Create a new image"
       
    80  
       
    81 +    _check_size(size)
       
    82 +
       
    83      if color is None:
       
    84          # don't initialize
       
    85          return Image()._new(core.new(mode, size))
       
    86 @@ -1792,6 +1813,8 @@
       
    87  def fromstring(mode, size, data, decoder_name="raw", *args):
       
    88      "Load image from string"
       
    89  
       
    90 +    _check_size(size)
       
    91 +
       
    92      # may pass tuple instead of argument list
       
    93      if len(args) == 1 and isTupleType(args[0]):
       
    94          args = args[0]
       
    95 @@ -1839,6 +1862,8 @@
       
    96  def frombuffer(mode, size, data, decoder_name="raw", *args):
       
    97      "Load image from string or buffer"
       
    98  
       
    99 +    _check_size(size)
       
   100 +
       
   101      # may pass tuple instead of argument list
       
   102      if len(args) == 1 and isTupleType(args[0]):
       
   103          args = args[0]
       
   104 --- Imaging-1.1.7/PIL/EpsImagePlugin.py.orig	2016-11-21 08:07:25.697709727 +0000
       
   105 +++ Imaging-1.1.7/PIL/EpsImagePlugin.py	2016-11-21 08:12:17.177879463 +0000
       
   106 @@ -74,12 +74,13 @@
       
   107          status = gs.close()
       
   108          if status:
       
   109              raise IOError("gs failed (status %d)" % status)
       
   110 -        im = Image.core.open_ppm(file)
       
   111 +        im = Image.open(outfile)
       
   112 +        im.load()
       
   113      finally:
       
   114          try: os.unlink(file)
       
   115          except: pass
       
   116  
       
   117 -    return im
       
   118 +    return im.im.copy()
       
   119  
       
   120  
       
   121  class PSFile:
       
   122 --- Imaging-1.1.7/PIL/IptcImagePlugin.py.orig	2016-11-21 08:07:25.704128117 +0000
       
   123 +++ Imaging-1.1.7/PIL/IptcImagePlugin.py	2016-11-21 08:14:00.062399442 +0000
       
   124 @@ -192,14 +192,9 @@
       
   125          o.close()
       
   126  
       
   127          try:
       
   128 -            try:
       
   129 -                # fast
       
   130 -                self.im = Image.core.open_ppm(outfile)
       
   131 -            except:
       
   132 -                # slightly slower
       
   133 -                im = Image.open(outfile)
       
   134 -                im.load()
       
   135 -                self.im = im.im
       
   136 +            _im = Image.open(outfile)
       
   137 +            _im.load()
       
   138 +            self.im = _im.im
       
   139          finally:
       
   140              try: os.unlink(outfile)
       
   141              except: pass
       
   142 --- Imaging-1.1.7/PIL/JpegImagePlugin.py.orig	2016-11-21 08:16:20.362838015 +0000
       
   143 +++ Imaging-1.1.7/PIL/JpegImagePlugin.py	2016-11-21 08:19:06.852441772 +0000
       
   144 @@ -352,7 +352,9 @@
       
   145              raise ValueError("Invalid Filename")
       
   146  
       
   147          try:
       
   148 -            self.im = Image.core.open_ppm(path)
       
   149 +            _im = Image.open(path)
       
   150 +            _im.load()
       
   151 +            self.im = _im.im
       
   152          finally:
       
   153              try: os.unlink(path)
       
   154              except: pass
       
   155 --- Imaging-1.1.7/PIL/PpmImagePlugin.py.orig	2016-11-21 08:07:25.708512595 +0000
       
   156 +++ Imaging-1.1.7/PIL/PpmImagePlugin.py	2016-11-21 08:19:55.525463844 +0000
       
   157 @@ -93,11 +93,6 @@
       
   158                       self.fp.tell(),
       
   159                       (rawmode, 0, 1))]
       
   160  
       
   161 -        # ALTERNATIVE: load via builtin debug function
       
   162 -        # self.im = Image.core.open_ppm(self.filename)
       
   163 -        # self.mode = self.im.mode
       
   164 -        # self.size = self.im.size
       
   165 -
       
   166  #
       
   167  # --------------------------------------------------------------------
       
   168  
       
   169 --- Imaging-1.1.7/_imaging.c.orig	2016-11-21 08:07:25.710428542 +0000
       
   170 +++ Imaging-1.1.7/_imaging.c	2016-11-21 08:21:03.690730505 +0000
       
   171 @@ -684,17 +684,6 @@
       
   172  }
       
   173  
       
   174  static PyObject* 
       
   175 -_open_ppm(PyObject* self, PyObject* args)
       
   176 -{
       
   177 -    char* filename;
       
   178 -
       
   179 -    if (!PyArg_ParseTuple(args, "s", &filename))
       
   180 -	return NULL;
       
   181 -
       
   182 -    return PyImagingNew(ImagingOpenPPM(filename));
       
   183 -}
       
   184 -
       
   185 -static PyObject* 
       
   186  _blend(ImagingObject* self, PyObject* args)
       
   187  {
       
   188      ImagingObject* imagep1;
       
   189 @@ -3215,9 +3204,6 @@
       
   190      {"crc32", (PyCFunction)_crc32, 1},
       
   191      {"getcodecstatus", (PyCFunction)_getcodecstatus, 1},
       
   192  
       
   193 -    /* Debugging stuff */
       
   194 -    {"open_ppm", (PyCFunction)_open_ppm, 1},
       
   195 -
       
   196      /* Special effects (experimental) */
       
   197  #ifdef WITH_EFFECTS
       
   198      {"effect_mandelbrot", (PyCFunction)_effect_mandelbrot, 1},
       
   199 --- Imaging-1.1.7/libImaging/File.c.orig	2016-11-21 08:07:25.712276651 +0000
       
   200 +++ Imaging-1.1.7/libImaging/File.c	2016-11-21 08:22:37.837774950 +0000
       
   201 @@ -20,116 +20,6 @@
       
   202  
       
   203  #include <ctype.h>
       
   204  
       
   205 -Imaging
       
   206 -ImagingOpenPPM(const char* infile)
       
   207 -{
       
   208 -    FILE* fp;
       
   209 -    int i, c, v;
       
   210 -    char* mode;
       
   211 -    int x, y, max;
       
   212 -    Imaging im;
       
   213 -
       
   214 -    if (!infile)
       
   215 -	return ImagingError_ValueError(NULL);
       
   216 -
       
   217 -    fp = fopen(infile, "rb");
       
   218 -    if (!fp)
       
   219 -	return ImagingError_IOError();
       
   220 -
       
   221 -    /* PPM magic */
       
   222 -    if (fgetc(fp) != 'P')
       
   223 -	goto error;
       
   224 -    switch (fgetc(fp)) {
       
   225 -    case '4': /* FIXME: 1-bit images are not yet supported */
       
   226 -	goto error;
       
   227 -    case '5':
       
   228 -	mode = "L";
       
   229 -	break;
       
   230 -    case '6':
       
   231 -	mode = "RGB";
       
   232 -	break;
       
   233 -    default:
       
   234 -	goto error;
       
   235 -    }
       
   236 -
       
   237 -    i = 0;
       
   238 -    c = fgetc(fp);
       
   239 -
       
   240 -    x = y = max = 0;
       
   241 -
       
   242 -    while (i < 3) {	
       
   243 -
       
   244 -	/* Ignore optional comment fields */
       
   245 -	while (c == '\n') {
       
   246 -	    c = fgetc(fp);
       
   247 -	    if (c == '#') {
       
   248 -		do {
       
   249 -		    c = fgetc(fp);
       
   250 -		    if (c == EOF)
       
   251 -			goto error;
       
   252 -		} while (c != '\n');
       
   253 -		c = fgetc(fp);
       
   254 -	    }
       
   255 -	}
       
   256 -
       
   257 -	/* Skip forward to next value */
       
   258 -	while (isspace(c))
       
   259 -	    c = fgetc(fp);
       
   260 -
       
   261 -	/* And parse it */
       
   262 -	v = 0;
       
   263 -	while (isdigit(c)) {
       
   264 -	    v = v * 10 + (c - '0');
       
   265 -	    c = fgetc(fp);
       
   266 -	}
       
   267 -
       
   268 -	if (c == EOF)
       
   269 -	    goto error;
       
   270 -
       
   271 -	switch (i++) {
       
   272 -	case 0:
       
   273 -	    x = v;
       
   274 -	    break;
       
   275 -	case 1:
       
   276 -	    y = v;
       
   277 -	    break;
       
   278 -	case 2:
       
   279 -	    max = v;
       
   280 -	    break;
       
   281 -	}
       
   282 -    }
       
   283 -
       
   284 -    im = ImagingNew(mode, x, y);
       
   285 -    if (!im)
       
   286 -	return NULL;
       
   287 -
       
   288 -    /* if (max != 255) ... FIXME: does anyone ever use this feature? */
       
   289 -
       
   290 -    if (strcmp(im->mode, "L") == 0) {
       
   291 -
       
   292 -	/* PPM "L" */
       
   293 -	for (y = 0; y < im->ysize; y++)
       
   294 -	    if (fread(im->image[y], im->xsize, 1, fp) != 1)
       
   295 -		goto error;
       
   296 -
       
   297 -    } else {
       
   298 -
       
   299 -	/* PPM "RGB" or PyPPM mode */
       
   300 -	for (y = 0; y < im->ysize; y++)
       
   301 -	    for (x = i = 0; x < im->xsize; x++, i += im->pixelsize)
       
   302 -		if (fread(im->image[y]+i, im->bands, 1, fp) != 1)
       
   303 -		    goto error;
       
   304 -    }
       
   305 -
       
   306 -    fclose(fp);
       
   307 -
       
   308 -    return im;
       
   309 -
       
   310 -error:
       
   311 -    fclose(fp);
       
   312 -    return ImagingError_IOError();
       
   313 -}
       
   314 -
       
   315  
       
   316  int
       
   317  ImagingSaveRaw(Imaging im, FILE* fp)