diff --git a/Tests/test_font_bdf.py b/Tests/test_font_bdf.py index b4155c8793b..033b5f8fbd5 100644 --- a/Tests/test_font_bdf.py +++ b/Tests/test_font_bdf.py @@ -4,7 +4,7 @@ import pytest -from PIL import BdfFontFile, FontFile +from PIL import BdfFontFile, FontFile, Image filename = "Tests/images/courB08.bdf" @@ -24,6 +24,14 @@ def test_zero_width_chars() -> None: BdfFontFile.BdfFontFile(io.BytesIO(data)) +def test_decompression_bomb() -> None: + with open(filename, "rb") as fp: + data = fp.read() + b = io.BytesIO(data.replace(b"BBX 1 1", b"BBX 13378 13378")) + with pytest.raises(Image.DecompressionBombError): + BdfFontFile.BdfFontFile(b) + + def test_invalid_file() -> None: with open("Tests/images/flower.jpg", "rb") as fp: with pytest.raises(SyntaxError): diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py index 321dd85603a..d5b080add96 100644 --- a/Tests/test_font_pcf.py +++ b/Tests/test_font_pcf.py @@ -1,12 +1,13 @@ from __future__ import annotations import os +from io import BytesIO from pathlib import Path from typing import AnyStr import pytest -from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile +from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile, _binary from .helper import ( assert_image_equal_tofile, @@ -117,3 +118,21 @@ def test_high_characters(request: pytest.FixtureRequest, tmp_path: Path) -> None _test_high_characters(request, tmp_path, message) # accept bytes instances. _test_high_characters(request, tmp_path, message.encode("latin1")) + + +def test_decompression_bomb() -> None: + with open(fontname, "rb") as fp: + data = fp.read() + b = BytesIO( + data[:900] + + _binary.o32le(0) # jumbo format + + _binary.o32le(1) # number of metrics + + _binary.o16le(0) # left + + _binary.o16le(65535) # right + + _binary.o16le(0) # width + + _binary.o16le(0) # ascent + + _binary.o16le(65535) # descent + + _binary.o16le(0) # attributes + ) + with pytest.raises(Image.DecompressionBombError): + PcfFontFile.PcfFontFile(b) diff --git a/Tests/test_fontfile.py b/Tests/test_fontfile.py index 1a9069fd892..bf857e230b8 100644 --- a/Tests/test_fontfile.py +++ b/Tests/test_fontfile.py @@ -30,6 +30,13 @@ def test_compile() -> None: assert font.ysize == 2 +def test_decompression_bomb() -> None: + font = FontFile.FontFile() + font.glyph[0] = ((0, 0), (0, 0, 0, 0), (0, 0, 10000, 10000), Image.new("L", (0, 0))) + with pytest.raises(Image.DecompressionBombError): + font.compile() + + def test_save(tmp_path: Path) -> None: tempname = str(tmp_path / "temp.pil") diff --git a/src/PIL/BdfFontFile.py b/src/PIL/BdfFontFile.py index 1c8c28ff038..098779bfd6e 100644 --- a/src/PIL/BdfFontFile.py +++ b/src/PIL/BdfFontFile.py @@ -70,6 +70,7 @@ def bdf_char( # and x and y displacement (BBxoff0, BByoff0) # of the lower left corner from the origin of the character. width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split()) + Image._decompression_bomb_check((width, height)) # The word DWIDTH # followed by the width in x and y of the character in device pixels. diff --git a/src/PIL/FontFile.py b/src/PIL/FontFile.py index 341431d3f45..c3be4ae3ddd 100644 --- a/src/PIL/FontFile.py +++ b/src/PIL/FontFile.py @@ -74,7 +74,7 @@ def compile(self) -> None: if glyph: d, dst, src, im = glyph h = max(h, src[3] - src[1]) - w = w + (src[2] - src[0]) + w += src[2] - src[0] if w > WIDTH: lines += 1 w = src[2] - src[0] @@ -89,6 +89,7 @@ def compile(self) -> None: self.ysize = h # paste glyphs into bitmap + Image._decompression_bomb_check((xsize, ysize)) self.bitmap = Image.new("1", (xsize, ysize)) self.metrics: list[ tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]] diff --git a/src/PIL/PcfFontFile.py b/src/PIL/PcfFontFile.py index c69f3bef9c7..985444106a1 100644 --- a/src/PIL/PcfFontFile.py +++ b/src/PIL/PcfFontFile.py @@ -168,6 +168,7 @@ def append( ) -> None: xsize = right - left ysize = ascent + descent + Image._decompression_bomb_check((xsize, ysize)) metrics.append( (xsize, ysize, left, right, width, ascent, descent, attributes) )