From 2c20c73044b5881f91e3207172ebca945db1dd86 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 2 May 2021 06:49:03 -0700 Subject: [PATCH] bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated (GH-25099) (GH-25815) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reverts commit e653d4d8e820a7a004ad399530af0135b45db27a and makes parsing even more strict. Like socket.inet_pton() any leading zero is now treated as invalid input. Signed-off-by: Christian Heimes Co-authored-by: Łukasz Langa (cherry picked from commit 60ce8f0be6354ad565393ab449d8de5d713f35bc) Gbp-Pq: Name 0009-bpo-36384-Leading-zeros-in-IPv4-addresses-are-no-lon.patch --- Doc/library/ipaddress.rst | 19 +++++++++++++++++-- Doc/tools/susp-ignored.csv | 4 ++-- Lib/ipaddress.py | 5 +++++ Lib/test/test_ipaddress.py | 21 +++++++++++++++++---- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index d6d1f1e..1c2263b 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -104,8 +104,7 @@ write code that handles both IP versions correctly. Address objects are 1. A string in decimal-dot notation, consisting of four decimal integers in the inclusive range 0--255, separated by dots (e.g. ``192.168.0.1``). Each integer represents an octet (byte) in the address. Leading zeroes are - tolerated only for values less than 8 (as there is no ambiguity - between the decimal and octal interpretations of such strings). + not tolerated to prevent confusion with octal notation. 2. An integer that fits into 32 bits. 3. An integer packed into a :class:`bytes` object of length 4 (most significant octet first). @@ -117,6 +116,22 @@ write code that handles both IP versions correctly. Address objects are >>> ipaddress.IPv4Address(b'\xC0\xA8\x00\x01') IPv4Address('192.168.0.1') + .. versionchanged:: 3.8 + + Leading zeros are tolerated, even in ambiguous cases that look like + octal notation. + + .. versionchanged:: 3.10 + + Leading zeros are no longer tolerated and are treated as an error. + IPv4 address strings are now parsed as strict as glibc + :func:`~socket.inet_pton`. + + .. versionchanged:: 3.9.5 + + The above change was also included in Python 3.9 starting with + version 3.9.5. + .. attribute:: version The appropriate version number: ``4`` for IPv4, ``6`` for IPv6. diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index 9f0c42a..7d20bea 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -151,8 +151,8 @@ library/ipaddress,,:db8,>>> ipaddress.IPv6Address('2001:db8::1000') library/ipaddress,,::,>>> ipaddress.IPv6Address('2001:db8::1000') library/ipaddress,,:db8,'2001:db8::1000' library/ipaddress,,::,'2001:db8::1000' -library/ipaddress,231,:db8,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" -library/ipaddress,231,::,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" +library/ipaddress,,:db8,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" +library/ipaddress,,::,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" library/ipaddress,,::,IPv6Address('ff02::5678%1') library/ipaddress,,::,fe80::1234 library/ipaddress,,:db8,">>> ipaddress.ip_address(""2001:db8::1"").reverse_pointer" diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index bc662c4..6cb92ed 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1223,6 +1223,11 @@ class _BaseV4: if len(octet_str) > 3: msg = "At most 3 characters permitted in %r" raise ValueError(msg % octet_str) + # Handle leading zeros as strict as glibc's inet_pton() + # See security bug bpo-36384 + if octet_str != '0' and octet_str[0] == '0': + msg = "Leading zeros are not permitted in %r" + raise ValueError(msg % octet_str) # Convert to integer (we know digits are legal) octet_int = int(octet_str, 10) if octet_int > 255: diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 3c07008..cdd9880 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -96,10 +96,23 @@ class CommonTestMixin: class CommonTestMixin_v4(CommonTestMixin): def test_leading_zeros(self): - self.assertInstancesEqual("000.000.000.000", "0.0.0.0") - self.assertInstancesEqual("192.168.000.001", "192.168.0.1") - self.assertInstancesEqual("016.016.016.016", "16.16.16.16") - self.assertInstancesEqual("001.000.008.016", "1.0.8.16") + # bpo-36384: no leading zeros to avoid ambiguity with octal notation + msg = "Leading zeros are not permitted in '\d+'" + addresses = [ + "000.000.000.000", + "192.168.000.001", + "016.016.016.016", + "192.168.000.001", + "001.000.008.016", + "01.2.3.40", + "1.02.3.40", + "1.2.03.40", + "1.2.3.040", + ] + for address in addresses: + with self.subTest(address=address): + with self.assertAddressError(msg): + self.factory(address) def test_int(self): self.assertInstancesEqual(0, "0.0.0.0") -- 2.30.2