From 03dd89d62413c4a92831ed1b36e2ae8983bcb2d4 Mon Sep 17 00:00:00 2001 From: achraf-mer <51244975+achraf-mer@users.noreply.github.com> Date: Tue, 17 Aug 2021 19:46:37 -0400 Subject: [3.8] bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated (GH-25099) (GH-27801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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 --- Doc/library/ipaddress.rst | 15 +++++++++++++-- Doc/whatsnew/3.8.rst | 16 ++++++++++++++++ Lib/ipaddress.py | 5 +++++ Lib/test/test_ipaddress.py | 21 +++++++++++++++++---- .../2021-03-30-16-29-51.bpo-36384.sCAmLs.rst | 6 ++++++ 5 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2021-03-30-16-29-51.bpo-36384.sCAmLs.rst diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 2cdfddb..5e21d5d 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,18 @@ 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.8.12 + + 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`. + .. attribute:: version The appropriate version number: ``4`` for IPv4, ``6`` for IPv6. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 109a06e..7a3460a 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2307,3 +2307,19 @@ URL by the parser in :mod:`urllib.parse` preventing such attacks. The removal characters are controlled by a new module level variable ``urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE``. (See :issue:`43882`) + +Notable changes in Python 3.8.12 +================================ + +Changes in the Python API +------------------------- + +Starting with Python 3.8.12 the :mod:`ipaddress` module no longer accepts +any leading zeros in IPv4 address strings. Leading zeros are ambiguous and +interpreted as octal notation by some libraries. For example the legacy +function :func:`socket.inet_aton` treats leading zeros as octal notatation. +glibc implementation of modern :func:`~socket.inet_pton` does not accept +any leading zeros. + +(Originally contributed by Christian Heimes in :issue:`36384`, and backported +to 3.8 by Achraf Merzouki) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 28b7b61..d351f07 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1173,6 +1173,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 2f1c5b6..1297b83 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -97,10 +97,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") diff --git a/Misc/NEWS.d/next/Security/2021-03-30-16-29-51.bpo-36384.sCAmLs.rst b/Misc/NEWS.d/next/Security/2021-03-30-16-29-51.bpo-36384.sCAmLs.rst new file mode 100644 index 0000000..f956cde --- /dev/null +++ b/Misc/NEWS.d/next/Security/2021-03-30-16-29-51.bpo-36384.sCAmLs.rst @@ -0,0 +1,6 @@ +:mod:`ipaddress` module no longer accepts any leading zeros in IPv4 address +strings. Leading zeros are ambiguous and interpreted as octal notation by +some libraries. For example the legacy function :func:`socket.inet_aton` +treats leading zeros as octal notatation. glibc implementation of modern +:func:`~socket.inet_pton` does not accept any leading zeros. For a while +the :mod:`ipaddress` module used to accept ambiguous leading zeros. -- cgit v0.12