Merge pull request #7244 from radarhere/imagefont_max_string_length

Added ImageFont.MAX_STRING_LENGTH
This commit is contained in:
Andrew Murray 2023-07-01 09:41:01 +10:00 committed by GitHub
commit e37b25087d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 0 deletions

View File

@ -1038,6 +1038,25 @@ def test_render_mono_size():
assert_image_equal_tofile(im, "Tests/images/text_mono.gif") assert_image_equal_tofile(im, "Tests/images/text_mono.gif")
def test_too_many_characters(font):
with pytest.raises(ValueError):
font.getlength("A" * 1_000_001)
with pytest.raises(ValueError):
font.getbbox("A" * 1_000_001)
with pytest.raises(ValueError):
font.getmask2("A" * 1_000_001)
transposed_font = ImageFont.TransposedFont(font)
with pytest.raises(ValueError):
transposed_font.getlength("A" * 1_000_001)
default_font = ImageFont.load_default()
with pytest.raises(ValueError):
default_font.getlength("A" * 1_000_001)
with pytest.raises(ValueError):
default_font.getbbox("A" * 1_000_001)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_file", "test_file",
[ [

View File

@ -18,6 +18,15 @@ OpenType fonts (as well as other font formats supported by the FreeType
library). For earlier versions, TrueType support is only available as part of library). For earlier versions, TrueType support is only available as part of
the imToolkit package. the imToolkit package.
.. warning::
To protect against potential DOS attacks when using arbitrary strings as
text input, Pillow will raise a ``ValueError`` if the number of characters
is over a certain limit, :py:data:`MAX_STRING_LENGTH`.
This threshold can be changed by setting
:py:data:`MAX_STRING_LENGTH`. It can be disabled by setting
``ImageFont.MAX_STRING_LENGTH = None``.
Example Example
------- -------
@ -73,3 +82,12 @@ Constants
Requires Raqm, you can check support using Requires Raqm, you can check support using
:py:func:`PIL.features.check_feature` with ``feature="raqm"``. :py:func:`PIL.features.check_feature` with ``feature="raqm"``.
Constants
---------
.. data:: MAX_STRING_LENGTH
Set to 1,000,000, to protect against potential DOS attacks. Pillow will
raise a ``ValueError`` if the number of characters is over this limit. The
check can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.

View File

@ -170,6 +170,18 @@ now been fixed.
This effectively dates to the PIL fork, since problem images would still have This effectively dates to the PIL fork, since problem images would still have
been processed before Pillow started checking for decompression bombs. been processed before Pillow started checking for decompression bombs.
Added ImageFont.MAX_STRING_LENGTH
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To protect against potential DOS attacks when using arbitrary strings as text
input, Pillow will now raise a ``ValueError`` if the number of characters
passed into ImageFont methods is over a certain limit,
:py:data:`PIL.ImageFont.MAX_STRING_LENGTH`.
This threshold can be changed by setting
:py:data:`PIL.ImageFont.MAX_STRING_LENGTH`. It can be disabled by setting
``ImageFont.MAX_STRING_LENGTH = None``.
Other Changes Other Changes
============= =============

View File

@ -41,6 +41,9 @@ class Layout(IntEnum):
RAQM = 1 RAQM = 1
MAX_STRING_LENGTH = 1_000_000
try: try:
from . import _imagingft as core from . import _imagingft as core
except ImportError as ex: except ImportError as ex:
@ -49,6 +52,12 @@ except ImportError as ex:
core = DeferredError(ex) core = DeferredError(ex)
def _string_length_check(text):
if MAX_STRING_LENGTH is not None and len(text) > MAX_STRING_LENGTH:
msg = "too many characters in string"
raise ValueError(msg)
# FIXME: add support for pilfont2 format (see FontFile.py) # FIXME: add support for pilfont2 format (see FontFile.py)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -152,6 +161,7 @@ class ImageFont:
:return: ``(left, top, right, bottom)`` bounding box :return: ``(left, top, right, bottom)`` bounding box
""" """
_string_length_check(text)
width, height = self.font.getsize(text) width, height = self.font.getsize(text)
return 0, 0, width, height return 0, 0, width, height
@ -162,6 +172,7 @@ class ImageFont:
.. versionadded:: 9.2.0 .. versionadded:: 9.2.0
""" """
_string_length_check(text)
width, height = self.font.getsize(text) width, height = self.font.getsize(text)
return width return width
@ -309,6 +320,7 @@ class FreeTypeFont:
:return: Width for horizontal, height for vertical text. :return: Width for horizontal, height for vertical text.
""" """
_string_length_check(text)
return self.font.getlength(text, mode, direction, features, language) / 64 return self.font.getlength(text, mode, direction, features, language) / 64
def getbbox( def getbbox(
@ -368,6 +380,7 @@ class FreeTypeFont:
:return: ``(left, top, right, bottom)`` bounding box :return: ``(left, top, right, bottom)`` bounding box
""" """
_string_length_check(text)
size, offset = self.font.getsize( size, offset = self.font.getsize(
text, mode, direction, features, language, anchor text, mode, direction, features, language, anchor
) )
@ -546,6 +559,7 @@ class FreeTypeFont:
:py:mod:`PIL.Image.core` interface module, and the text offset, the :py:mod:`PIL.Image.core` interface module, and the text offset, the
gap between the starting coordinate and the first marking gap between the starting coordinate and the first marking
""" """
_string_length_check(text)
if start is None: if start is None:
start = (0, 0) start = (0, 0)
im, size, offset = self.font.render( im, size, offset = self.font.render(
@ -684,6 +698,7 @@ class TransposedFont:
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270):
msg = "text length is undefined for text rotated by 90 or 270 degrees" msg = "text length is undefined for text rotated by 90 or 270 degrees"
raise ValueError(msg) raise ValueError(msg)
_string_length_check(text)
return self.font.getlength(text, *args, **kwargs) return self.font.getlength(text, *args, **kwargs)