From 87c43b66a5ffe0d21e04dce631a5fd4004e6021b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 29 Sep 2019 14:16:30 +1000 Subject: [PATCH] Corrected negative seeks --- Tests/images/combined_larger_than_size.psd | Bin 0 -> 285 bytes Tests/images/raw_negative_stride.bin | Bin 0 -> 2461 bytes Tests/test_file_psd.py | 9 +++++++++ Tests/test_imagefile.py | 8 ++++++++ src/PIL/PsdImagePlugin.py | 6 ++++-- src/libImaging/RawDecode.c | 11 +++++++++-- 6 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 Tests/images/combined_larger_than_size.psd create mode 100644 Tests/images/raw_negative_stride.bin diff --git a/Tests/images/combined_larger_than_size.psd b/Tests/images/combined_larger_than_size.psd new file mode 100644 index 0000000000000000000000000000000000000000..2e6caef39ee445401716c0c156750a10a921d50e GIT binary patch literal 285 zcmcC;3J7LkWPku>Ak_fI91I{f2xwV2dHOOx1+xVh5`Z)#5JG8?91B>AfeAz%umWP! zFK`3FQVsvn0mv4X|Nj{nn83R1K_)WTYk|zLp9(TFFTW@kC=CJ@5Q>4}+unI|rYtDR zFU?bA0IA6-&C3MJNdPeygA+p{Lo!1)LpnndLq0<(Lmo^Q5)E}IPz35BhiVe}#cjndKP+-&F<%twsh04rT@h#tA?SQp5y8|6w48aoNJo06%wL zE-5acB(JB3OAwGY0AWU;Hiq0Y*++mBbAV5X>zSGVH~IA_0J*%LE{-7*my;7DSg)`! zFa|I%E`M}OZ176NQvnPyFONDGC2bD=#A*c0J`Av&`4h|m6Iuu+HkPk{kSju5ynum$ ztq_>QxebMcfWq9yAi%%@G#Hza`UsuKEbL|i4K+d-I>>YUX!1u%{=nEJv&=RI)*rws z<2!?>U^*y`Fb)2kgh-k!YIrLr)_(}4)UVJO9#bg_hEj-AKNyEbATscxG=iWlBVfCT GfdK#}Aa7Fu literal 0 HcmV?d00001 diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index f55ee1dcbb6..8381ceaefcd 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -87,3 +87,12 @@ def test_no_icc_profile(self): im = Image.open("Tests/images/hopper_merged.psd") self.assertNotIn("icc_profile", im.info) + + def test_combined_larger_than_size(self): + # The 'combined' sizes of the individual parts is larger than the + # declared 'size' of the extra data field, resulting in a backwards seek. + + # If we instead take the 'size' of the extra data field as the source of truth, + # then the seek can't be negative + with self.assertRaises(IOError): + Image.open("Tests/images/combined_larger_than_size.psd") diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index ceccd22855f..a367f62dfae 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -103,6 +103,14 @@ def test_raise_typeerror(self): parser = ImageFile.Parser() parser.feed(1) + def test_negative_stride(self): + with open("Tests/images/raw_negative_stride.bin", "rb") as f: + input = f.read() + p = ImageFile.Parser() + p.feed(input) + with self.assertRaises(IOError): + p.close() + def test_truncated_with_errors(self): if "zip_encoder" not in codecs: self.skipTest("PNG (zlib) encoder not available") diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 9eb0c09669f..f72ad5f4433 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -224,9 +224,11 @@ def _layerinfo(file): # skip over blend flags and extra information read(12) # filler name = "" - size = i32(read(4)) + size = i32(read(4)) # length of the extra data field combined = 0 if size: + data_end = file.tell() + size + length = i32(read(4)) if length: file.seek(length - 16, io.SEEK_CUR) @@ -244,7 +246,7 @@ def _layerinfo(file): name = read(length).decode("latin-1", "replace") combined += length + 1 - file.seek(size - combined, io.SEEK_CUR) + file.seek(data_end) layers.append((name, mode, (x0, y0, x1, y1))) # get tiles diff --git a/src/libImaging/RawDecode.c b/src/libImaging/RawDecode.c index 774d4245b85..c069bdb8864 100644 --- a/src/libImaging/RawDecode.c +++ b/src/libImaging/RawDecode.c @@ -33,8 +33,15 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* get size of image data and padding */ state->bytes = (state->xsize * state->bits + 7) / 8; - rawstate->skip = (rawstate->stride) ? - rawstate->stride - state->bytes : 0; + if (rawstate->stride) { + rawstate->skip = rawstate->stride - state->bytes; + if (rawstate->skip < 0) { + state->errcode = IMAGING_CODEC_CONFIG; + return -1; + } + } else { + rawstate->skip = 0; + } /* check image orientation */ if (state->ystep < 0) {