From a4f6bf00297f9ca3af4dbc7b831d7bbdb3a578a7 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 30 Mar 2021 16:45:55 +0200 Subject: [PATCH 01/10] bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated 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 --- Doc/library/ipaddress.rst | 14 +++++++++++-- Lib/ipaddress.py | 5 +++++ Lib/test/test_ipaddress.py | 21 +++++++++++++++---- .../2021-03-30-16-29-51.bpo-36384.sCAmLs.rst | 6 ++++++ 4 files changed, 40 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 d6d1f1e362137b..af13f5cb3f85de 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,17 @@ 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`. + .. attribute:: version The appropriate version number: ``4`` for IPv4, ``6`` for IPv6. diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 160b16dbc162fc..af7aedfa6e51a1 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1223,6 +1223,11 @@ def _parse_octet(cls, octet_str): 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 3c070080a6aaeb..cdd9880c3c17fa 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -96,10 +96,23 @@ def pickle_test(self, addr): 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 00000000000000..f956cde948ec57 --- /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. From 634b10011ba5780296efe75a6e40a86dbbd83e66 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 31 Mar 2021 13:28:20 +0200 Subject: [PATCH 02/10] bpo-36384: whatsnew --- Doc/library/ipaddress.rst | 2 +- Doc/whatsnew/3.8.rst | 15 +++++++++++++++ Doc/whatsnew/3.9.rst | 11 +++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index af13f5cb3f85de..b1a06812c6451d 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -121,7 +121,7 @@ write code that handles both IP versions correctly. Address objects are Leading zeros are tolerated, even in ambiguous cases that look like octal notation. - .. versionchanged:: 3.10 + .. versionchanged:: 3.8.9/3.9.3 Leading zeros are no longer tolerated and are treated as an error. IPv4 address strings are now parsed as strict as glibc diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 91afffb58a7e6e..068f4ee2180659 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -910,6 +910,14 @@ fails. The exception is ignored silently by default in release build. (Contributed by Victor Stinner in :issue:`18748`.) +ipaddress +--------- + +Starting with Python 3.8.9 and 3.9.2 the :mod:`ipaddress` module no longer +accepts any leading zeros in IPv4 address strings. +(Contributed by Christian Heimes in :issue:`36384`). + + itertools --------- @@ -1847,6 +1855,13 @@ Changes in Python behavior or :c:func:`sys.is_finalizing`. (Contributed by Joannah Nanjekye in :issue:`36475`.) +* Starting with Python 3.8.9 and 3.9.2 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. + (Contributed by Christian Heimes in :issue:`36384`). Changes in the Python API ------------------------- diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 3086930569dc98..7bd24b4ffedd17 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -533,6 +533,10 @@ Scoped IPv6 addresses can be parsed using :class:`ipaddress.IPv6Address`. If present, scope zone ID is available through the :attr:`~ipaddress.IPv6Address.scope_id` attribute. (Contributed by Oleksandr Pavliuk in :issue:`34788`.) +Starting with Python 3.8.9 and 3.9.2 the :mod:`ipaddress` module no longer +accepts any leading zeros in IPv4 address strings. +(Contributed by Christian Heimes in :issue:`36384`). + math ---- @@ -1110,6 +1114,13 @@ Changes in the Python API compatible classes that don't inherit from those mentioned types. (Contributed by Roger Aiudi in :issue:`34775`). +* Starting with Python 3.8.9 and 3.9.2 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. + (Contributed by Christian Heimes in :issue:`36384`). Changes in the C API -------------------- From a91c18a1961e7f59d12f59677c35880ae7e8993c Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 31 Mar 2021 22:11:47 +0200 Subject: [PATCH 03/10] Set versionchanged to current version --- Doc/library/ipaddress.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index b1a06812c6451d..af13f5cb3f85de 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -121,7 +121,7 @@ write code that handles both IP versions correctly. Address objects are Leading zeros are tolerated, even in ambiguous cases that look like octal notation. - .. versionchanged:: 3.8.9/3.9.3 + .. 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 From 0319e436737c90cc6ec7ff5e166ec7b5fcc405a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 11:38:03 +0200 Subject: [PATCH 04/10] Remove mention of change in 3.8.x --- Doc/whatsnew/3.8.rst | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 068f4ee2180659..249b1e4c6280ff 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -910,14 +910,6 @@ fails. The exception is ignored silently by default in release build. (Contributed by Victor Stinner in :issue:`18748`.) -ipaddress ---------- - -Starting with Python 3.8.9 and 3.9.2 the :mod:`ipaddress` module no longer -accepts any leading zeros in IPv4 address strings. -(Contributed by Christian Heimes in :issue:`36384`). - - itertools --------- @@ -2261,4 +2253,4 @@ separator key, with ``&`` as the default. This change also affects :func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected functions internally. For more details, please see their respective documentation. -(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) \ No newline at end of file +(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) From 66b36fe1b3c58b7a165a3d419d25dd8e8b11f2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 11:41:23 +0200 Subject: [PATCH 05/10] Update 3.9 version to 3.9.5, remove mention of 3.8 --- Doc/whatsnew/3.9.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 7bd24b4ffedd17..8be1d9871bb7a9 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -533,7 +533,7 @@ Scoped IPv6 addresses can be parsed using :class:`ipaddress.IPv6Address`. If present, scope zone ID is available through the :attr:`~ipaddress.IPv6Address.scope_id` attribute. (Contributed by Oleksandr Pavliuk in :issue:`34788`.) -Starting with Python 3.8.9 and 3.9.2 the :mod:`ipaddress` module no longer +Starting with Python 3.9.5 the :mod:`ipaddress` module no longer accepts any leading zeros in IPv4 address strings. (Contributed by Christian Heimes in :issue:`36384`). @@ -1114,7 +1114,7 @@ Changes in the Python API compatible classes that don't inherit from those mentioned types. (Contributed by Roger Aiudi in :issue:`34775`). -* Starting with Python 3.8.9 and 3.9.2 the :mod:`ipaddress` module no longer +* Starting with Python 3.9.5 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 From ad918f6f7907b81a778c1afa1605d0428f237147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 11:42:11 +0200 Subject: [PATCH 06/10] Remove mention of change in 3.8 --- Doc/whatsnew/3.8.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 249b1e4c6280ff..d6644a12e18b14 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1847,14 +1847,6 @@ Changes in Python behavior or :c:func:`sys.is_finalizing`. (Contributed by Joannah Nanjekye in :issue:`36475`.) -* Starting with Python 3.8.9 and 3.9.2 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. - (Contributed by Christian Heimes in :issue:`36384`). - Changes in the Python API ------------------------- From 46ca00eb79091f1faf7725e28936e190bfbc9531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 12:09:11 +0200 Subject: [PATCH 07/10] Create 3.8.rst --- Doc/whatsnew/3.8.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index d6644a12e18b14..dbc3875aae61b3 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1847,6 +1847,7 @@ Changes in Python behavior or :c:func:`sys.is_finalizing`. (Contributed by Joannah Nanjekye in :issue:`36475`.) + Changes in the Python API ------------------------- From 06724d64d3a69dabc75b6ab28b17efe8dba32b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 12:11:01 +0200 Subject: [PATCH 08/10] Mention 3.9.5 in versionchanged --- Doc/library/ipaddress.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index af13f5cb3f85de..2bfeda100a4fc5 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -127,6 +127,11 @@ write code that handles both IP versions correctly. Address objects are 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. From 84d5b537ab184f7b69909db62318e1beb9c5ef26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 12:24:42 +0200 Subject: [PATCH 09/10] Remove trailing whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🙄 --- Doc/library/ipaddress.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 2bfeda100a4fc5..1c2263b128a8fe 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -128,7 +128,7 @@ write code that handles both IP versions correctly. Address objects are :func:`~socket.inet_pton`. .. versionchanged:: 3.9.5 - + The above change was also included in Python 3.9 starting with version 3.9.5. From bd8ba89ada5e168d48ab6863eb48eee981efc0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sun, 2 May 2021 13:08:41 +0200 Subject: [PATCH 10/10] Fix suspicious ignores to not include hard-coded line numbers --- Doc/tools/susp-ignored.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index 5a2d85d262b2e7..d56a2b9fd0bfb9 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -149,8 +149,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"