Compare commits

...

16 Commits
main ... 3.1.x

Author SHA1 Message Date
wiredfool
acf1c8559b 3.1.2 Release Versioning 2016-04-01 05:27:31 -07:00
wiredfool
c62b544084 Release Notes 2016-04-01 05:24:51 -07:00
wiredfool
d00d8571c2 Fixed j2k integer overflow error on encode - CVE-2016-3076 2016-04-01 05:24:37 -07:00
wiredfool
bebc58974b Updated CVE id 2016-02-22 13:34:54 +00:00
wiredfool
7df66aa5f7 Updated Changes.rst [ci skip]
Added final CVE ID
2016-02-22 13:34:02 +00:00
wiredfool
eb72bf86fb Add .pcd to MANIFEST.in 2016-02-04 08:17:58 -08:00
wiredfool
ef68acb403 3.1.1 versioning 2016-02-04 07:46:21 -08:00
wiredfool
777ef4f523 Changes & release notes 2016-02-04 07:46:21 -08:00
wiredfool
28fd74742b input parameter filtering 2016-02-04 07:39:43 -08:00
wiredfool
c8f70e19e1 test for #1711 2016-02-04 07:39:43 -08:00
Ned Williamson
41fae6d9e2 fix integer overflow in Resample.c 2016-02-04 07:39:43 -08:00
Eric Soroos
5fdf23ab1c change ifd entry to use uint following libtiff interface 2016-02-04 04:21:55 -08:00
Eric Soroos
6dcbf5bd96 Fix for buffer overflow in TiffDecode.c CVE-2016-0740 2016-02-04 04:21:51 -08:00
wiredfool
5bdf54b5a7 PCD decoder overruns the shuffle buffer, Fixes #568 2016-02-04 04:21:43 -08:00
wiredfool
bcaaf97f4f FLI overflow error fix and testcase CVE-2016-0775 2016-02-02 22:01:43 +00:00
wiredfool
a4065997df Updated Changes.rst (release date!) [ci skip] 2016-01-04 13:52:04 +00:00
23 changed files with 320 additions and 14 deletions

View File

@ -1,7 +1,30 @@
Changelog (Pillow) Changelog (Pillow)
================== ==================
3.1.0 (unreleased) 3.1.2 (2016-04-01)
------------------
- Fixed an integer overflow in Jpeg2KEncode.c causing a buffer overflow. CVE-2016-3076
[wiredfool]
3.1.1 (2016-02-04)
------------------
- Fixed an integer overflow in Resample.c causing writes in the Python heap.
[nedwill]
- Fixed a buffer overflow in PcdDecode.c causing a segfault when opening PhotoCD files. CVE-2016-2533
[wiredfool]
- Fixed a buffer overflow in FliDecode.c causing a segfault when opening FLI files. CVE-2016-0775
[wiredfool]
- Fixed a buffer overflow in TiffDecode.c causing an arbitrary amount of memory to be overwritten when opening a specially crafted invalid TIFF file. CVE-2016-0740
[wiredfool]
3.1.0 (2016-01-04)
------------------ ------------------
- Fixing test failures on Python 2.6/Windows #1633 - Fixing test failures on Python 2.6/Windows #1633

View File

@ -45,6 +45,7 @@ recursive-include Tests *.msp
recursive-include Tests *.pbm recursive-include Tests *.pbm
recursive-include Tests *.pcf recursive-include Tests *.pcf
recursive-include Tests *.pcx recursive-include Tests *.pcx
recursive-include Tests *.pcd
recursive-include Tests *.pgm recursive-include Tests *.pgm
recursive-include Tests *.pil recursive-include Tests *.pil
recursive-include Tests *.png recursive-include Tests *.png

View File

@ -12,7 +12,7 @@
# ;-) # ;-)
VERSION = '1.1.7' # PIL version VERSION = '1.1.7' # PIL version
PILLOW_VERSION = '3.1.0' # Pillow PILLOW_VERSION = '3.1.2' # Pillow
_plugins = ['BmpImagePlugin', _plugins = ['BmpImagePlugin',
'BufrStubImagePlugin', 'BufrStubImagePlugin',

View File

@ -0,0 +1,16 @@
from helper import unittest, PillowTestCase
from PIL import Image
TEST_FILE = "Tests/images/fli_overflow.fli"
class TestFliOverflow(PillowTestCase):
def test_fli_overflow(self):
# this should not crash with a malloc error or access violation
im = Image.open(TEST_FILE)
im.load()
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,23 @@
from helper import unittest, PillowTestCase
from PIL import Image
TEST_FILE = "Tests/images/libtiff_segfault.tif"
class TestLibtiffSegfault(PillowTestCase):
def test_segfault(self):
""" This test should not segfault. It will on Pillow <= 3.1.0 and
libtiff >= 4.0.0
"""
try:
im = Image.open(TEST_FILE)
im.load()
except IOError:
self.assertTrue(True, "Got expected IOError")
except Exception:
self.fail("Should have returned IOError")
if __name__ == '__main__':
unittest.main()

Binary file not shown.

BIN
Tests/images/hopper.pcd Normal file

Binary file not shown.

Binary file not shown.

21
Tests/test_file_pcd.py Normal file
View File

@ -0,0 +1,21 @@
from helper import unittest, PillowTestCase, hopper
from PIL import Image
class TestFilePcd(PillowTestCase):
def test_load_raw(self):
im = Image.open('Tests/images/hopper.pcd')
im.load() # should not segfault.
# Note that this image was created with a resized hopper
# image, which was then converted to pcd with imagemagick
# and the colors are wonky in Pillow. It's unclear if this
# is a pillow or a convert issue, as other images not generated
# from convert look find on pillow and not imagemagick.
#target = hopper().resize((768,512))
#self.assert_image_similar(im, target, 10)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,36 @@
from helper import unittest, PillowTestCase, hopper
from PIL import Image
class TestImagingCoreResize(PillowTestCase):
#see https://github.com/python-pillow/Pillow/issues/1710
def test_overflow(self):
im = hopper('L')
xsize = 0x100000008 // 4
ysize = 1000 # unimportant
try:
# any resampling filter will do here
im.im.resize((xsize, ysize), Image.LINEAR)
self.fail("Resize should raise MemoryError on invalid xsize")
except MemoryError:
self.assertTrue(True, "Should raise MemoryError")
def test_invalid_size(self):
im = hopper()
im.resize((100,100))
self.assertTrue(True, "Should not Crash")
try:
im.resize((-100,100))
self.fail("Resize should raise a value error on x negative size")
except ValueError:
self.assertTrue(True, "Should raise ValueError")
try:
im.resize((100,-100))
self.fail("Resize should raise a value error on y negative size")
except ValueError:
self.assertTrue(True, "Should raise ValueError")
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,18 @@
from PIL import Image
from helper import unittest, PillowTestCase
class TestJ2kEncodeOverflow(PillowTestCase):
def test_j2k_overflow(self):
im = Image.new('RGBA', (1024, 131584))
target = self.tempfile('temp.jpc')
try:
im.save(target)
self.assertTrue(False, "Expected IOError, save succeeded?")
except IOError as err:
self.assertTrue(True, "IOError is expected")
except Exception as err:
self.assertTrue(False, "Expected IOError, got %s" %type(err))
if __name__ == '__main__':
unittest.main()

View File

@ -71,7 +71,7 @@
* See the README file for information on usage and redistribution. * See the README file for information on usage and redistribution.
*/ */
#define PILLOW_VERSION "3.1.0" #define PILLOW_VERSION "3.1.2"
#include "Python.h" #include "Python.h"
@ -1532,6 +1532,10 @@ _resize(ImagingObject* self, PyObject* args)
imIn = self->image; imIn = self->image;
if (xsize < 1 || ysize < 1) {
return ImagingError_ValueError("height and width must be > 0");
}
if (imIn->xsize == xsize && imIn->ysize == ysize) { if (imIn->xsize == xsize && imIn->ysize == ysize) {
imOut = ImagingCopy(imIn); imOut = ImagingCopy(imIn);
} }

View File

@ -1,4 +1,4 @@
version: 3.1.0.{build} version: 3.1.2.{build}
clone_folder: c:\pillow clone_folder: c:\pillow
init: init:
- ECHO %PYTHON% - ECHO %PYTHON%

View File

@ -0,0 +1,78 @@
3.1.1
=====
CVE-2016-0740 -- Buffer overflow in TiffDecode.c
------------------------------------------------
Pillow 3.1.0 and earlier when linked against libtiff >= 4.0.0 on x64
may overflow a buffer when reading a specially crafted tiff file.
Specifically, libtiff >= 4.0.0 changed the return type of
``TIFFScanlineSize`` from ``int32`` to machine dependent
``int32|64``. If the scanline is sized so that it overflows an
``int32``, it may be interpreted as a negative number, which will then
pass the size check in ``TiffDecode.c`` line 236. To do this, the
logical scanline size has to be > 2gb, and for the test file, the
allocated buffer size is 64k against a roughly 4gb scan line size. Any
image data over 64k is written over the heap, causing a segfault.
This issue was found by security researcher FourOne.
CVE-2016-0775 -- Buffer overflow in FliDecode.c
-----------------------------------------------
In all versions of Pillow, dating back at least to the last PIL 1.1.7
release, FliDecode.c has a buffer overflow error.
Around line 192::
case 16:
/* COPY chunk */
for (y = 0; y < state->ysize; y++) {
UINT8* buf = (UINT8*) im->image[y];
memcpy(buf+x, data, state->xsize);
data += state->xsize;
}
break;
The memcpy has error where ``x`` is added to the target buffer
address. ``X`` is used in several internal temporary variable roles,
but can take a value up to the width of the image. ``Im->image[y]``
is a set of row pointers to segments of memory that are the size of
the row. At the max ``y``, this will write the contents of the line
off the end of the memory buffer, causing a segfault.
This issue was found by Alyssa Besseling at Atlassian
CVE-2016-2533 -- Buffer overflow in PcdDecode.c
----------------------------------------------
In all versions of Pillow, dating back at least to the last PIL 1.1.7
release, ``PcdDecode.c`` has a buffer overflow error.
The ``state.buffer`` for ``PcdDecode.c`` is allocated based on a 3
bytes per pixel sizing, where ``PcdDecode.c`` wrote into the buffer
assuming 4 bytes per pixel. This writes 768 bytes beyond the end of
the buffer into other Python object storage. In some cases, this
causes a segfault, in others an internal Python malloc error.
Integer overflow in Resample.c
------------------------------
If a large value was passed into the new size for an image, it is
possible to overflow an int32 value passed into malloc.
kk = malloc(xsize * kmax * sizeof(float));
...
xbounds = malloc(xsize * 2 * sizeof(int));
``xsize`` is trusted user input. These multiplications can overflow,
leading the malloc'd buffer to be undersized. These allocations are
followed by a loop that writes out of bounds. This can lead to
corruption on the heap of the Python process with attacker controlled
float data.
This issue was found by Ned Williamson.

View File

@ -0,0 +1,43 @@
3.1.2
=====
CVE-2016-3076 -- Buffer overflow in Jpeg2KEncode.c
--------------------------------------------------
Pillow between 2.5.0 and 3.1.1 may overflow a buffer when writing
large Jpeg2000 files, allowing for code execution or other memory
corruption.
This occurs specifically in the function ``j2k_encode_entry``, at the line::
state->buffer = malloc (tile_width * tile_height * components * prec / 8);
This vulnerability requires a particular value for ``height * width``
such that ``height * width * components * precision`` overflows, at
which point the malloc will be for a smaller value than expected. The
buffer that is allocated will be ``((height * width * components *
precision) mod (2^31) / 8)``, where components is 1-4 and precision is
either 8 or
16. Common values would be 4 components at precision 8 for a standard
``RGBA`` image.
The unpackers then split an image that is laid out::
RGBARGBARGBA....
into::
RRR.
GGG.
BBB.
AAA.
If this buffer is smaller than expected, the jpeg2k unpacker functions
will write outside the allocation and onto the heap, corrupting
memory.
This issue was found by Alyssa Besseling at Atlassian.

View File

@ -6,6 +6,8 @@ Release Notes
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
3.1.2
3.1.1
3.1.0 3.1.0
3.0.0 3.0.0
2.8.0 2.8.0

View File

@ -185,7 +185,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* COPY chunk */ /* COPY chunk */
for (y = 0; y < state->ysize; y++) { for (y = 0; y < state->ysize; y++) {
UINT8* buf = (UINT8*) im->image[y]; UINT8* buf = (UINT8*) im->image[y];
memcpy(buf+x, data, state->xsize); memcpy(buf, data, state->xsize);
data += state->xsize; data += state->xsize;
} }
break; break;

View File

@ -265,6 +265,10 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
unsigned prec = 8; unsigned prec = 8;
unsigned bpp = 8; unsigned bpp = 8;
unsigned _overflow_scale_factor;
/* SIZE_MAX is not working in the conditionals unless it's a typed
variable */
unsigned _SIZE__MAX = SIZE_MAX;
stream = opj_stream_default_create(OPJ_FALSE); stream = opj_stream_default_create(OPJ_FALSE);
@ -335,6 +339,11 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
} }
image = opj_image_create(components, image_params, color_space); image = opj_image_create(components, image_params, color_space);
if (!image) {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
goto quick_exit;
}
/* Setup compression context */ /* Setup compression context */
context->error_msg = NULL; context->error_msg = NULL;
@ -471,7 +480,24 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0) tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0)
+ tile_height - 1) / tile_height; + tile_height - 1) / tile_height;
/* check for integer overflow for the malloc line, checking any expression
that may multiply either tile_width or tile_height */
_overflow_scale_factor = components * prec;
if (( tile_width > _SIZE__MAX / _overflow_scale_factor ) ||
( tile_height > _SIZE__MAX / _overflow_scale_factor ) ||
( tile_width > _SIZE__MAX / (tile_height * _overflow_scale_factor )) ||
( tile_height > _SIZE__MAX / (tile_width * _overflow_scale_factor ))) {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
goto quick_exit;
}
/* malloc check ok, checked for overflow above */
state->buffer = malloc (tile_width * tile_height * components * prec / 8); state->buffer = malloc (tile_width * tile_height * components * prec / 8);
if (!state->buffer) {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
goto quick_exit;
}
tile_ndx = 0; tile_ndx = 0;
for (y = 0; y < tiles_y; ++y) { for (y = 0; y < tiles_y; ++y) {

View File

@ -47,7 +47,7 @@ ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
out[0] = ptr[x]; out[0] = ptr[x];
out[1] = ptr[(x+4*state->xsize)/2]; out[1] = ptr[(x+4*state->xsize)/2];
out[2] = ptr[(x+5*state->xsize)/2]; out[2] = ptr[(x+5*state->xsize)/2];
out += 4; out += 3;
} }
state->shuffle((UINT8*) im->image[state->y], state->shuffle((UINT8*) im->image[state->y],
@ -62,7 +62,7 @@ ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
out[0] = ptr[x+state->xsize]; out[0] = ptr[x+state->xsize];
out[1] = ptr[(x+4*state->xsize)/2]; out[1] = ptr[(x+4*state->xsize)/2];
out[2] = ptr[(x+5*state->xsize)/2]; out[2] = ptr[(x+5*state->xsize)/2];
out += 4; out += 3;
} }
state->shuffle((UINT8*) im->image[state->y], state->shuffle((UINT8*) im->image[state->y],

View File

@ -138,11 +138,23 @@ ImagingResampleHorizontal(Imaging imIn, int xsize, int filter)
/* maximum number of coofs */ /* maximum number of coofs */
kmax = (int) ceil(support) * 2 + 1; kmax = (int) ceil(support) * 2 + 1;
// check for overflow
if (kmax > 0 && xsize > SIZE_MAX / kmax)
return (Imaging) ImagingError_MemoryError();
// sizeof(float) should be greater than 0
if (xsize * kmax > SIZE_MAX / sizeof(float))
return (Imaging) ImagingError_MemoryError();
/* coefficient buffer */ /* coefficient buffer */
kk = malloc(xsize * kmax * sizeof(float)); kk = malloc(xsize * kmax * sizeof(float));
if ( ! kk) if ( ! kk)
return (Imaging) ImagingError_MemoryError(); return (Imaging) ImagingError_MemoryError();
// sizeof(int) should be greater than 0 as well
if (xsize > SIZE_MAX / (2 * sizeof(int)))
return (Imaging) ImagingError_MemoryError();
xbounds = malloc(xsize * 2 * sizeof(int)); xbounds = malloc(xsize * 2 * sizeof(int));
if ( ! xbounds) { if ( ! xbounds) {
free(kk); free(kk);

View File

@ -169,7 +169,7 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
char *filename = "tempfile.tif"; char *filename = "tempfile.tif";
char *mode = "r"; char *mode = "r";
TIFF *tiff; TIFF *tiff;
int size; tsize_t size;
/* buffer is the encoded file, bytes is the length of the encoded file */ /* buffer is the encoded file, bytes is the length of the encoded file */
@ -222,8 +222,8 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
if (clientstate->ifd){ if (clientstate->ifd){
int rv; int rv;
unsigned int ifdoffset = clientstate->ifd; uint32 ifdoffset = clientstate->ifd;
TRACE(("reading tiff ifd %d\n", ifdoffset)); TRACE(("reading tiff ifd %u\n", ifdoffset));
rv = TIFFSetSubDirectory(tiff, ifdoffset); rv = TIFFSetSubDirectory(tiff, ifdoffset);
if (!rv){ if (!rv){
TRACE(("error in TIFFSetSubDirectory")); TRACE(("error in TIFFSetSubDirectory"));

View File

@ -32,10 +32,13 @@ typedef struct {
toff_t loc; /* toff_t == uint32 */ toff_t loc; /* toff_t == uint32 */
tsize_t size; /* tsize_t == int32 */ tsize_t size; /* tsize_t == int32 */
int fp; int fp;
int ifd; /* offset of the ifd, used for multipage */ uint32 ifd; /* offset of the ifd, used for multipage
TIFF *tiff; /* Used in write */ * Should be uint32 for libtiff 3.9.x
* uint64 for libtiff 4.0.x
*/
TIFF *tiff; /* Used in write */
toff_t eof; toff_t eof;
int flrealloc; /* may we realloc */ int flrealloc;/* may we realloc */
} TIFFSTATE; } TIFFSTATE;

View File

@ -90,7 +90,7 @@ except (ImportError, OSError):
NAME = 'Pillow' NAME = 'Pillow'
PILLOW_VERSION = '3.1.0' PILLOW_VERSION = '3.1.2'
TCL_ROOT = None TCL_ROOT = None
JPEG_ROOT = None JPEG_ROOT = None
JPEG2K_ROOT = None JPEG2K_ROOT = None