Skip to content

Commit 5d50a2e

Browse files
apollo13carltongibson
authored andcommitted
[2.1.x] Fixed CVE-2019-14235 -- Fixed potential memory exhaustion in django.utils.encoding.uri_to_iri().
Thanks to Guido Vranken for initial report.
1 parent f74b3ae commit 5d50a2e

File tree

4 files changed

+42
-9
lines changed

4 files changed

+42
-9
lines changed

django/utils/encoding.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,16 @@ def repercent_broken_unicode(path):
228228
repercent-encode any octet produced that is not part of a strictly legal
229229
UTF-8 octet sequence.
230230
"""
231-
try:
232-
path.decode()
233-
except UnicodeDecodeError as e:
234-
repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~")
235-
path = repercent_broken_unicode(
236-
path[:e.start] + force_bytes(repercent) + path[e.end:])
237-
return path
231+
while True:
232+
try:
233+
path.decode()
234+
except UnicodeDecodeError as e:
235+
# CVE-2019-14235: A recursion shouldn't be used since the exception
236+
# handling uses massive amounts of memory
237+
repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~")
238+
path = path[:e.start] + force_bytes(repercent) + path[e.end:]
239+
else:
240+
return path
238241

239242

240243
def filepath_to_uri(path):

docs/releases/1.11.23.txt

+10
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,13 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie
4545
<hstorefield.key>` for :class:`~django.contrib.postgres.fields.HStoreField`
4646
were subject to SQL injection, using a suitably crafted dictionary, with
4747
dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``.
48+
49+
CVE-2019-14235: Potential memory exhaustion in ``django.utils.encoding.uri_to_iri()``
50+
=====================================================================================
51+
52+
If passed certain inputs, :func:`django.utils.encoding.uri_to_iri` could lead
53+
to significant memory usage due to excessive recursion when re-percent-encoding
54+
invalid UTF-8 octet sequences.
55+
56+
``uri_to_iri()`` now avoids recursion when re-percent-encoding invalid UTF-8
57+
octet sequences.

docs/releases/2.1.11.txt

+10
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,13 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie
4545
<hstorefield.key>` for :class:`~django.contrib.postgres.fields.HStoreField`
4646
were subject to SQL injection, using a suitably crafted dictionary, with
4747
dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``.
48+
49+
CVE-2019-14235: Potential memory exhaustion in ``django.utils.encoding.uri_to_iri()``
50+
=====================================================================================
51+
52+
If passed certain inputs, :func:`django.utils.encoding.uri_to_iri` could lead
53+
to significant memory usage due to excessive recursion when re-percent-encoding
54+
invalid UTF-8 octet sequences.
55+
56+
``uri_to_iri()`` now avoids recursion when re-percent-encoding invalid UTF-8
57+
octet sequences.

tests/utils_tests/test_encoding.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import datetime
2+
import sys
23
import unittest
34
from unittest import mock
45
from urllib.parse import quote_plus
56

67
from django.test import SimpleTestCase
78
from django.utils.encoding import (
89
DjangoUnicodeDecodeError, escape_uri_path, filepath_to_uri, force_bytes,
9-
force_text, get_system_encoding, iri_to_uri, smart_bytes, smart_text,
10-
uri_to_iri,
10+
force_text, get_system_encoding, iri_to_uri, repercent_broken_unicode,
11+
smart_bytes, smart_text, uri_to_iri,
1112
)
1213
from django.utils.functional import SimpleLazyObject
1314
from django.utils.translation import gettext_lazy
@@ -86,6 +87,15 @@ def test_get_default_encoding(self):
8687
with mock.patch('locale.getdefaultlocale', side_effect=Exception):
8788
self.assertEqual(get_system_encoding(), 'ascii')
8889

90+
def test_repercent_broken_unicode_recursion_error(self):
91+
# Prepare a string long enough to force a recursion error if the tested
92+
# function uses recursion.
93+
data = b'\xfc' * sys.getrecursionlimit()
94+
try:
95+
self.assertEqual(repercent_broken_unicode(data), b'%FC' * sys.getrecursionlimit())
96+
except RecursionError:
97+
self.fail('Unexpected RecursionError raised.')
98+
8999

90100
class TestRFC3987IEncodingUtils(unittest.TestCase):
91101

0 commit comments

Comments
 (0)