diff options
author | Christian Heimes <christian@python.org> | 2021-05-02 12:00:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-02 12:00:35 (GMT) |
commit | 60ce8f0be6354ad565393ab449d8de5d713f35bc (patch) | |
tree | 131beaabf8c731503be540fdd09e66f7f2000a41 | |
parent | 73766b0341674f3920f4ea86a6f8288b801960f9 (diff) | |
download | cpython-60ce8f0be6354ad565393ab449d8de5d713f35bc.zip cpython-60ce8f0be6354ad565393ab449d8de5d713f35bc.tar.gz cpython-60ce8f0be6354ad565393ab449d8de5d713f35bc.tar.bz2 |
bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated (GH-25099)
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 <christian@python.org>
Co-authored-by: Ćukasz Langa <lukasz@langa.pl>
-rw-r--r-- | Doc/library/ipaddress.rst | 19 | ||||
-rw-r--r-- | Doc/tools/susp-ignored.csv | 4 | ||||
-rw-r--r-- | Doc/whatsnew/3.9.rst | 12 | ||||
-rw-r--r-- | Lib/ipaddress.py | 5 | ||||
-rw-r--r-- | Lib/test/test_ipaddress.py | 21 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Security/2021-03-30-16-29-51.bpo-36384.sCAmLs.rst | 6 |
6 files changed, 59 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 5a2d85d..d56a2b9 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" diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 9a7f2cd..772fb5a 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -537,6 +537,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.9.5 the :mod:`ipaddress` module no longer +accepts any leading zeros in IPv4 address strings. +(Contributed by Christian Heimes in :issue:`36384`). + math ---- @@ -1114,6 +1118,14 @@ 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.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 + notatation. glibc implementation of modern :func:`~socket.inet_pton` does + not accept any leading zeros. + (Contributed by Christian Heimes in :issue:`36384`). + * :func:`codecs.lookup` now normalizes the encoding name the same way as :func:`encodings.normalize_encoding`, except that :func:`codecs.lookup` also converts the name to lower case. For example, ``"latex+latin1"`` encoding diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 160b16d..af7aedf 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") 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. |