Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corrected negative seeks #4101

Merged
merged 1 commit into from Sep 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file added Tests/images/combined_larger_than_size.psd
Binary file not shown.
Binary file added Tests/images/raw_negative_stride.bin
Binary file not shown.
9 changes: 9 additions & 0 deletions Tests/test_file_psd.py
Expand Up @@ -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")
8 changes: 8 additions & 0 deletions Tests/test_imagefile.py
Expand Up @@ -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")
Expand Down
6 changes: 4 additions & 2 deletions src/PIL/PsdImagePlugin.py
Expand Up @@ -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)
Expand All @@ -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
Expand Down
11 changes: 9 additions & 2 deletions src/libImaging/RawDecode.c
Expand Up @@ -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) {
Expand Down