diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index 5cd4f14c45e..6b58ec9a8a2 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -229,23 +229,14 @@ def test_header_errors() -> None: pass -def test_oversized_box_length() -> None: - # Do not raise an OverflowError() when seeking to the end of a box +@pytest.mark.parametrize("tbox", (b"", b"jp2h")) +def test_oversized_box_length(tbox: bytes) -> None: + # Do not raise an OverflowError() when seeking to the end of a box, + # or when reading the contents of a box data = ( b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" # JP2 signature box - + struct.pack(">I4s", 1, b"") # box with 64-bit length - + struct.pack(">Q", 2**63 - 12) # length beyond the seek range - ) - with pytest.raises(SyntaxError, match="Box length too large"): - Jpeg2KImagePlugin.Jpeg2KImageFile(BytesIO(data)) - - -def test_oversized_box_length_when_reading() -> None: - # Do not raise an OverflowError() when reading the contents of a box - data = ( - b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" # JP2 signature box - + struct.pack(">I4s", 1, b"jp2h") # box read into with a 64-bit length - + struct.pack(">Q", 16 + 2**63) # length whose contents overflow fp.read() + + struct.pack(">I4s", 1, tbox) # box with 64-bit length + + struct.pack(">Q", 2**63 - 12) # oversized length ) with pytest.raises(SyntaxError, match="Box length too large"): Jpeg2KImagePlugin.Jpeg2KImageFile(BytesIO(data)) diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index dbacb72f350..7d27fcc8fff 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -54,6 +54,9 @@ def _read_bytes(self, num_bytes: int) -> bytes: if not self._can_read(num_bytes): msg = "Not enough data in header" raise SyntaxError(msg) + if self.fp.tell() + num_bytes >= 2**63: + msg = "Box length too large" + raise SyntaxError(msg) data = self.fp.read(num_bytes) if len(data) < num_bytes: @@ -83,6 +86,9 @@ def has_next_box(self) -> bool: def next_box_type(self) -> bytes: # Skip the rest of the box if it has not been read if self.remaining_in_box > 0: + if self.fp.tell() + self.remaining_in_box >= 2**63: + msg = "Box length too large" + raise SyntaxError(msg) self.fp.seek(self.remaining_in_box, os.SEEK_CUR) self.remaining_in_box = -1 @@ -98,12 +104,6 @@ def next_box_type(self) -> bytes: msg = "Invalid header length" raise SyntaxError(msg) - # Reject a box whose contents would extend beyond the maximum position - # that can be sought or read, before it is stored and later consumed - if self.fp.tell() + lbox - hlen >= 2**63: - msg = "Box length too large" - raise SyntaxError(msg) - self.remaining_in_box = lbox - hlen return tbox