summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Apolloner <florian@apolloner.eu>2019-07-19 17:04:53 +0200
committerCarlton Gibson <carlton.gibson@noumenal.es>2019-07-29 11:06:54 +0200
commitcf694e6852b0da7799f8b53f1fb2f7d20cf17534 (patch)
tree54a6364a37c9bd1626cc393592b30b9daaf8350e
parent4f5b58f5cd3c57fee9972ab074f8dc6895d8f387 (diff)
[2.2.x] Fixed CVE-2019-14235 -- Fixed potential memory exhaustion in django.utils.encoding.uri_to_iri().
Thanks to Guido Vranken for initial report.
-rw-r--r--django/utils/encoding.py17
-rw-r--r--docs/releases/1.11.23.txt10
-rw-r--r--docs/releases/2.1.11.txt10
-rw-r--r--docs/releases/2.2.4.txt10
-rw-r--r--tests/utils_tests/test_encoding.py14
5 files changed, 52 insertions, 9 deletions
diff --git a/django/utils/encoding.py b/django/utils/encoding.py
index 1a1a6d06b1..98da64730d 100644
--- a/django/utils/encoding.py
+++ b/django/utils/encoding.py
@@ -225,13 +225,16 @@ def repercent_broken_unicode(path):
repercent-encode any octet produced that is not part of a strictly legal
UTF-8 octet sequence.
"""
- try:
- path.decode()
- except UnicodeDecodeError as e:
- repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~")
- path = repercent_broken_unicode(
- path[:e.start] + force_bytes(repercent) + path[e.end:])
- return path
+ while True:
+ try:
+ path.decode()
+ except UnicodeDecodeError as e:
+ # CVE-2019-14235: A recursion shouldn't be used since the exception
+ # handling uses massive amounts of memory
+ repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~")
+ path = path[:e.start] + force_bytes(repercent) + path[e.end:]
+ else:
+ return path
def filepath_to_uri(path):
diff --git a/docs/releases/1.11.23.txt b/docs/releases/1.11.23.txt
index 03b33ebf63..04acca90f1 100644
--- a/docs/releases/1.11.23.txt
+++ b/docs/releases/1.11.23.txt
@@ -45,3 +45,13 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie
<hstorefield.key>` for :class:`~django.contrib.postgres.fields.HStoreField`
were subject to SQL injection, using a suitably crafted dictionary, with
dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``.
+
+CVE-2019-14235: Potential memory exhaustion in ``django.utils.encoding.uri_to_iri()``
+=====================================================================================
+
+If passed certain inputs, :func:`django.utils.encoding.uri_to_iri` could lead
+to significant memory usage due to excessive recursion when re-percent-encoding
+invalid UTF-8 octet sequences.
+
+``uri_to_iri()`` now avoids recursion when re-percent-encoding invalid UTF-8
+octet sequences.
diff --git a/docs/releases/2.1.11.txt b/docs/releases/2.1.11.txt
index 0de4175b5f..ae344f35b3 100644
--- a/docs/releases/2.1.11.txt
+++ b/docs/releases/2.1.11.txt
@@ -45,3 +45,13 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie
<hstorefield.key>` for :class:`~django.contrib.postgres.fields.HStoreField`
were subject to SQL injection, using a suitably crafted dictionary, with
dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``.
+
+CVE-2019-14235: Potential memory exhaustion in ``django.utils.encoding.uri_to_iri()``
+=====================================================================================
+
+If passed certain inputs, :func:`django.utils.encoding.uri_to_iri` could lead
+to significant memory usage due to excessive recursion when re-percent-encoding
+invalid UTF-8 octet sequences.
+
+``uri_to_iri()`` now avoids recursion when re-percent-encoding invalid UTF-8
+octet sequences.
diff --git a/docs/releases/2.2.4.txt b/docs/releases/2.2.4.txt
index 3aac51869c..8a71fec783 100644
--- a/docs/releases/2.2.4.txt
+++ b/docs/releases/2.2.4.txt
@@ -46,6 +46,16 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie
were subject to SQL injection, using a suitably crafted dictionary, with
dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``.
+CVE-2019-14235: Potential memory exhaustion in ``django.utils.encoding.uri_to_iri()``
+=====================================================================================
+
+If passed certain inputs, :func:`django.utils.encoding.uri_to_iri` could lead
+to significant memory usage due to excessive recursion when re-percent-encoding
+invalid UTF-8 octet sequences.
+
+``uri_to_iri()`` now avoids recursion when re-percent-encoding invalid UTF-8
+octet sequences.
+
Bugfixes
========
diff --git a/tests/utils_tests/test_encoding.py b/tests/utils_tests/test_encoding.py
index c461df71ee..ea7ba5f335 100644
--- a/tests/utils_tests/test_encoding.py
+++ b/tests/utils_tests/test_encoding.py
@@ -1,4 +1,5 @@
import datetime
+import sys
import unittest
from unittest import mock
from urllib.parse import quote_plus
@@ -6,8 +7,8 @@ from urllib.parse import quote_plus
from django.test import SimpleTestCase
from django.utils.encoding import (
DjangoUnicodeDecodeError, escape_uri_path, filepath_to_uri, force_bytes,
- force_text, get_system_encoding, iri_to_uri, smart_bytes, smart_text,
- uri_to_iri,
+ force_text, get_system_encoding, iri_to_uri, repercent_broken_unicode,
+ smart_bytes, smart_text, uri_to_iri,
)
from django.utils.functional import SimpleLazyObject
from django.utils.translation import gettext_lazy
@@ -90,6 +91,15 @@ class TestEncodingUtils(SimpleTestCase):
with mock.patch('locale.getdefaultlocale', side_effect=Exception):
self.assertEqual(get_system_encoding(), 'ascii')
+ def test_repercent_broken_unicode_recursion_error(self):
+ # Prepare a string long enough to force a recursion error if the tested
+ # function uses recursion.
+ data = b'\xfc' * sys.getrecursionlimit()
+ try:
+ self.assertEqual(repercent_broken_unicode(data), b'%FC' * sys.getrecursionlimit())
+ except RecursionError:
+ self.fail('Unexpected RecursionError raised.')
+
class TestRFC3987IEncodingUtils(unittest.TestCase):