From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:55:27 +0000 (+0200) Subject: [3.10] gh-128840: Limit the number of parts in IPv6 address parsing (GH-128841) ... X-Git-Tag: v3.10.18~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c0e26585254cde2b25385c19c3b63550de4d6351;p=thirdparty%2FPython%2Fcpython.git [3.10] gh-128840: Limit the number of parts in IPv6 address parsing (GH-128841) (GH-134614) Limit length of IP address string to 39 (cherry picked from commit 47f1161d3a2bec52b5b5e952150141709c247da2) Co-authored-by: Seth Michael Larson Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Serhiy Storchaka Co-authored-by: Gregory P. Smith --- diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 68e34a49fccc..28ff61ec0285 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1649,8 +1649,16 @@ class _BaseV6: """ if not ip_str: raise AddressValueError('Address cannot be empty') + if len(ip_str) > 39: + msg = ("At most 39 characters expected in " + f"{ip_str[:14]!r}({len(ip_str)-28} chars elided){ip_str[-14:]!r}") + raise AddressValueError(msg) - parts = ip_str.split(':') + # We want to allow more parts than the max to be 'split' + # to preserve the correct error message when there are + # too many parts combined with '::' + _max_parts = cls._HEXTET_COUNT + 1 + parts = ip_str.split(':', maxsplit=_max_parts) # An IPv6 address needs at least 2 colons (3 parts). _min_parts = 3 @@ -1670,7 +1678,6 @@ class _BaseV6: # An IPv6 address can't have more than 8 colons (9 parts). # The extra colon comes from using the "::" notation for a single # leading or trailing zero part. - _max_parts = cls._HEXTET_COUNT + 1 if len(parts) > _max_parts: msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str) raise AddressValueError(msg) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index a40da7e85930..b8b2e76a4a02 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -389,6 +389,17 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): # A trailing IPv4 address is two parts assertBadSplit("10:9:8:7:6:5:4:3:42.42.42.42%scope") + def test_bad_address_split_v6_too_long(self): + def assertBadSplit(addr): + msg = r"At most 39 characters expected in %s" + with self.assertAddressError(msg, repr(re.escape(addr[:14]))): + ipaddress.IPv6Address(addr) + + # Long IPv6 address + long_addr = ("0:" * 10000) + "0" + assertBadSplit(long_addr) + assertBadSplit(long_addr + "%zoneid") + def test_bad_address_split_v6_too_many_parts(self): def assertBadSplit(addr): msg = "Exactly 8 parts expected without '::' in %r" diff --git a/Misc/NEWS.d/next/Security/2025-01-14-11-19-07.gh-issue-128840.M1doZW.rst b/Misc/NEWS.d/next/Security/2025-01-14-11-19-07.gh-issue-128840.M1doZW.rst new file mode 100644 index 000000000000..b57ec3e70dcc --- /dev/null +++ b/Misc/NEWS.d/next/Security/2025-01-14-11-19-07.gh-issue-128840.M1doZW.rst @@ -0,0 +1,2 @@ +Short-circuit the processing of long IPv6 addresses early in :mod:`ipaddress` to prevent excessive +memory consumption and a minor denial-of-service.