Skip to content

Commit 2e30341

Browse files
miss-islingtonsethmlarsonhugovkserhiy-storchakagpshead
authored
[3.13] gh-128840: Limit the number of parts in IPv6 address parsing (GH-128841) (#134611)
gh-128840: Limit the number of parts in IPv6 address parsing (GH-128841) GH-128840: Limit the number of parts in IPv6 address parsing Limit length of IP address string to 39 --------- (cherry picked from commit 47f1161) Co-authored-by: Seth Michael Larson <seth@python.org> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parent e4c4ecc commit 2e30341

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

Lib/ipaddress.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,8 +1674,16 @@ def _ip_int_from_string(cls, ip_str):
16741674
"""
16751675
if not ip_str:
16761676
raise AddressValueError('Address cannot be empty')
1677+
if len(ip_str) > 39:
1678+
msg = ("At most 39 characters expected in "
1679+
f"{ip_str[:14]!r}({len(ip_str)-28} chars elided){ip_str[-14:]!r}")
1680+
raise AddressValueError(msg)
16771681

1678-
parts = ip_str.split(':')
1682+
# We want to allow more parts than the max to be 'split'
1683+
# to preserve the correct error message when there are
1684+
# too many parts combined with '::'
1685+
_max_parts = cls._HEXTET_COUNT + 1
1686+
parts = ip_str.split(':', maxsplit=_max_parts)
16791687

16801688
# An IPv6 address needs at least 2 colons (3 parts).
16811689
_min_parts = 3
@@ -1695,7 +1703,6 @@ def _ip_int_from_string(cls, ip_str):
16951703
# An IPv6 address can't have more than 8 colons (9 parts).
16961704
# The extra colon comes from using the "::" notation for a single
16971705
# leading or trailing zero part.
1698-
_max_parts = cls._HEXTET_COUNT + 1
16991706
if len(parts) > _max_parts:
17001707
msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str)
17011708
raise AddressValueError(msg)

Lib/test/test_ipaddress.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,17 @@ def assertBadSplit(addr):
397397
# A trailing IPv4 address is two parts
398398
assertBadSplit("10:9:8:7:6:5:4:3:42.42.42.42%scope")
399399

400+
def test_bad_address_split_v6_too_long(self):
401+
def assertBadSplit(addr):
402+
msg = r"At most 39 characters expected in %s"
403+
with self.assertAddressError(msg, repr(re.escape(addr[:14]))):
404+
ipaddress.IPv6Address(addr)
405+
406+
# Long IPv6 address
407+
long_addr = ("0:" * 10000) + "0"
408+
assertBadSplit(long_addr)
409+
assertBadSplit(long_addr + "%zoneid")
410+
400411
def test_bad_address_split_v6_too_many_parts(self):
401412
def assertBadSplit(addr):
402413
msg = "Exactly 8 parts expected without '::' in %r"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Short-circuit the processing of long IPv6 addresses early in :mod:`ipaddress` to prevent excessive
2+
memory consumption and a minor denial-of-service.

0 commit comments

Comments
 (0)