Skip to content

Commit 1fe1bb4

Browse files
committed
Added ImageFont.MAX_STRING_LENGTH
1 parent 7c945f5 commit 1fe1bb4

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

Tests/test_imagefont.py

+19
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,25 @@ def test_render_mono_size():
10381038
assert_image_equal_tofile(im, "Tests/images/text_mono.gif")
10391039

10401040

1041+
def test_too_many_characters(font):
1042+
with pytest.raises(ValueError):
1043+
font.getlength("A" * 1000001)
1044+
with pytest.raises(ValueError):
1045+
font.getbbox("A" * 1000001)
1046+
with pytest.raises(ValueError):
1047+
font.getmask2("A" * 1000001)
1048+
1049+
transposed_font = ImageFont.TransposedFont(font)
1050+
with pytest.raises(ValueError):
1051+
transposed_font.getlength("A" * 1000001)
1052+
1053+
default_font = ImageFont.load_default()
1054+
with pytest.raises(ValueError):
1055+
default_font.getlength("A" * 1000001)
1056+
with pytest.raises(ValueError):
1057+
default_font.getbbox("A" * 1000001)
1058+
1059+
10411060
@pytest.mark.parametrize(
10421061
"test_file",
10431062
[

docs/reference/ImageFont.rst

+18
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ OpenType fonts (as well as other font formats supported by the FreeType
1818
library). For earlier versions, TrueType support is only available as part of
1919
the imToolkit package.
2020

21+
.. warning::
22+
To protect against potential DOS attacks when using arbitrary strings as
23+
text input, Pillow will raise a ``ValueError`` if the number of characters
24+
is over a certain limit, :py:data:`MAX_STRING_LENGTH`.
25+
26+
This threshold can be changed by setting
27+
:py:data:`MAX_STRING_LENGTH`. It can be disabled by setting
28+
``ImageFont.MAX_STRING_LENGTH = None``.
29+
2130
Example
2231
-------
2332

@@ -73,3 +82,12 @@ Constants
7382

7483
Requires Raqm, you can check support using
7584
:py:func:`PIL.features.check_feature` with ``feature="raqm"``.
85+
86+
Constants
87+
---------
88+
89+
.. data:: MAX_STRING_LENGTH
90+
91+
Set to 1,000,000, to protect against potential DOS attacks. Pillow will
92+
raise a ``ValueError`` if the number of characters is over this limit. The
93+
check can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.

docs/releasenotes/10.0.0.rst

+12
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,18 @@ now been fixed.
170170
This effectively dates to the PIL fork, since problem images would still have
171171
been processed before Pillow started checking for decompression bombs.
172172

173+
Added ImageFont.MAX_STRING_LENGTH
174+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
175+
176+
To protect against potential DOS attacks when using arbitrary strings as text
177+
input, Pillow will now raise a ``ValueError`` if the number of characters
178+
passed into ImageFont methods is over a certain limit,
179+
:py:data:`PIL.ImageFont.MAX_STRING_LENGTH`.
180+
181+
This threshold can be changed by setting
182+
:py:data:`PIL.ImageFont.MAX_STRING_LENGTH`. It can be disabled by setting
183+
``ImageFont.MAX_STRING_LENGTH = None``.
184+
173185
Other Changes
174186
=============
175187

src/PIL/ImageFont.py

+15
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class Layout(IntEnum):
4141
RAQM = 1
4242

4343

44+
MAX_STRING_LENGTH = 1000000
45+
46+
4447
try:
4548
from . import _imagingft as core
4649
except ImportError as ex:
@@ -49,6 +52,12 @@ class Layout(IntEnum):
4952
core = DeferredError(ex)
5053

5154

55+
def _string_length_check(text):
56+
if MAX_STRING_LENGTH is not None and len(text) > MAX_STRING_LENGTH:
57+
msg = "too many characters in string"
58+
raise ValueError(msg)
59+
60+
5261
# FIXME: add support for pilfont2 format (see FontFile.py)
5362

5463
# --------------------------------------------------------------------
@@ -152,6 +161,7 @@ def getbbox(self, text, *args, **kwargs):
152161
153162
:return: ``(left, top, right, bottom)`` bounding box
154163
"""
164+
_string_length_check(text)
155165
width, height = self.font.getsize(text)
156166
return 0, 0, width, height
157167

@@ -162,6 +172,7 @@ def getlength(self, text, *args, **kwargs):
162172
163173
.. versionadded:: 9.2.0
164174
"""
175+
_string_length_check(text)
165176
width, height = self.font.getsize(text)
166177
return width
167178

@@ -309,6 +320,7 @@ def getlength(self, text, mode="", direction=None, features=None, language=None)
309320
310321
:return: Width for horizontal, height for vertical text.
311322
"""
323+
_string_length_check(text)
312324
return self.font.getlength(text, mode, direction, features, language) / 64
313325

314326
def getbbox(
@@ -368,6 +380,7 @@ def getbbox(
368380
369381
:return: ``(left, top, right, bottom)`` bounding box
370382
"""
383+
_string_length_check(text)
371384
size, offset = self.font.getsize(
372385
text, mode, direction, features, language, anchor
373386
)
@@ -546,6 +559,7 @@ def getmask2(
546559
:py:mod:`PIL.Image.core` interface module, and the text offset, the
547560
gap between the starting coordinate and the first marking
548561
"""
562+
_string_length_check(text)
549563
if start is None:
550564
start = (0, 0)
551565
im, size, offset = self.font.render(
@@ -684,6 +698,7 @@ def getlength(self, text, *args, **kwargs):
684698
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270):
685699
msg = "text length is undefined for text rotated by 90 or 270 degrees"
686700
raise ValueError(msg)
701+
_string_length_check(text)
687702
return self.font.getlength(text, *args, **kwargs)
688703

689704

0 commit comments

Comments
 (0)