diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index be8e21d5a..1801cd8ff 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -3,7 +3,14 @@ import re from io import BytesIO import pytest -from PIL import ExifTags, Image, ImageFile, JpegImagePlugin, features +from PIL import ( + ExifTags, + Image, + ImageFile, + JpegImagePlugin, + UnidentifiedImageError, + features, +) from .helper import ( assert_image, @@ -709,6 +716,24 @@ class TestFileJpeg: with Image.open("Tests/images/icc-after-SOF.jpg") as im: assert im.info["icc_profile"] == b"profile" + def test_jpeg_magic_number(self): + size = 4097 + buffer = BytesIO(b"\xFF" * size) # Many xFF bytes + buffer.max_pos = 0 + orig_read = buffer.read + + def read(n=-1): + res = orig_read(n) + buffer.max_pos = max(buffer.max_pos, buffer.tell()) + return res + + buffer.read = read + with pytest.raises(UnidentifiedImageError): + Image.open(buffer) + + # Assert the entire file has not been read + assert 0 < buffer.max_pos < size + @pytest.mark.skipif(not is_win32(), reason="Windows only") @skip_unless_feature("jpg") diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 89e70f0e9..6edaee795 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -323,7 +323,8 @@ MARKER = { def _accept(prefix): - return prefix[0:1] == b"\377" + # Magic number was taken from https://en.wikipedia.org/wiki/JPEG + return prefix[0:3] == b"\xFF\xD8\xFF" ## @@ -337,10 +338,11 @@ class JpegImageFile(ImageFile.ImageFile): def _open(self): - s = self.fp.read(1) + s = self.fp.read(3) - if i8(s) != 255: + if s != b"\xFF\xD8\xFF": raise SyntaxError("not a JPEG file") + s = b"\xFF" # Create attributes self.bits = self.layers = 0