已开启
fix(cve): 修复 CVE-2026-114605 在 python-dns 中的漏洞 #74
fix(cve): 修复 CVE-2026-114605 在 python-dns 中的漏洞 #74
已开启
infra_team创建于 12 天前
共 2 个文件变更+103-2
@@ -0,0 +1,97 @@
1+From b485e460c266540a1a09ca6d8d1d7b685b1d3023 Mon Sep 17 00:00:00 2001
2+From: Bob Halley <halley@dnspython.org>
3+Date: Sat, 26 Sep 2026 13:38:07 -0700
4+Subject: [PATCH] fix: CVE-2026-114605 - limit decompression to a chain length
5+ of at most 16 pointers
6+ 
7+A maliciously crafted DNS message may cause dns.name.from_wire() to use
8+excessive CPU for DNS name decompression. Applications which process
9+untrusted DNS wire form messages with dnspython may be degraded or DoS'd
10+by the extra CPU use required.
11+ 
12+Backport of upstream commit b485e460 to dnspython 1.16.0, adapted to the
13+1.16.0 from_wire(message, current) implementation (the upstream diff
14+targets the 2.x from_wire_parser() refactor and cannot be applied as-is;
15+doc/whatsnew.rst does not exist in 1.16.0 and is dropped). The hops
16+counter already exists in 1.16.0 and is now also used to bound the
17+compression pointer chain at MAX_COMPRESSION_POINTER_CHAIN = 16.
18+ 
19+Credit: Evgenios Gkritsis, Constantinos Patsakis, George Stergiopoulos
20+ 
21+Upstream-commit: https://github.com/rthalley/dnspython/commit/b485e460c266540a1a09ca6d8d1d7b685b1d3023
22+Signed-off-by: infra_team <zhaiwenjie1@huawei.com>
23+---
24+ dns/name.py | 9 +++++++++
25+ tests/test_name.py | 22 ++++++++++++++++++++++
26+ 2 files changed, 31 insertions(+)
27+ 
28+diff --git a/dns/name.py b/dns/name.py
29+index 3bc01ac..70b6749 100644
30+--- a/dns/name.py
31++++ b/dns/name.py
32+@@ -66,6 +66,10 @@ class BadPointer(dns.exception.FormError):
33+ """A DNS compression pointer points forward instead of backward."""
34+
35+
36++class PointerChainTooLong(dns.exception.FormError):
37++ """A DNS compression pointer chain was too long."""
38++
39++
40+ class BadLabelType(dns.exception.FormError):
41+ """The label type in DNS name wire format is unknown."""
42+
43+@@ -957,6 +961,9 @@ def from_text(text, origin=root, idna_codec=None):
44+ return Name(labels)
45+
46+
47++MAX_COMPRESSION_POINTER_CHAIN = 16
48++
49++
50+ def from_wire(message, current):
51+ """Convert possibly compressed wire format into a Name.
52+
53+@@ -999,6 +1006,8 @@ def from_wire(message, current):
54+ raise BadPointer
55+ biggest_pointer = current
56+ hops += 1
57++ if hops > MAX_COMPRESSION_POINTER_CHAIN:
58++ raise PointerChainTooLong
59+ else:
60+ raise BadLabelType
61+ count = message[current]
62+diff --git a/tests/test_name.py b/tests/test_name.py
63+index bea30a2..231e577 100644
64+--- a/tests/test_name.py
65++++ b/tests/test_name.py
66+@@ -627,6 +627,28 @@ class NameTestCase(unittest.TestCase):
67+ dns.name.from_wire(w, 0)
68+ self.failUnlessRaises(dns.name.BadLabelType, bad)
69+
70++ def testCompressionChainLength(self):
71++ # We're going to decode some wire starting two bytes from the end. At this
72++ # position is a pointer which points to four bytes from the end, and it points
73++ # to one 6 bytes from the end, etc., until finally the 16th pointer points at
74++ # offset zero, which is the root label followed by a byte of padding. After
75++ # all of this useless pointer hopping, we should get the root name.
76++ w = b"\x00\x00\xc0\x00\xc0\x02\xc0\x04\xc0\x06\xc0\x08\xc0\x0a\xc0\x0c\xc0\x0e\xc0\x10\xc0\x12\xc0\x14\xc0\x16\xc0\x18\xc0\x1a\xc0\x1c\xc0\x1e"
77++ self.assertEqual(len(w), 34)
78++ starts = [c for c in w if c == 0xC0]
79++ self.assertEqual(len(starts), dns.name.MAX_COMPRESSION_POINTER_CHAIN)
80++
81++ def bad():
82++ # Now we make the wire one pointer longer, which is too long!
83++ w1 = w + b"\xc0\x20"
84++ self.assertEqual(len(w1), 36)
85++ starts = [c for c in w1 if c == 0xC0]
86++ self.assertEqual(len(starts), dns.name.MAX_COMPRESSION_POINTER_CHAIN + 1)
87++ dns.name.from_wire(w1, 34)
88++
89++ self.assertEqual(dns.name.from_wire(w, 32)[0], dns.name.from_text("."))
90++ self.assertRaises(dns.name.PointerChainTooLong, bad)
91++
92+ def testParent1(self):
93+ n = dns.name.from_text('foo.bar.')
94+ self.failUnless(n.parent() == dns.name.from_text('bar.'))
95+--
96+2.39.5
97+ 
@@ -14,7 +14,7 @@ messages, names, and records.
14Name: python-dns14Name: python-dns
15Summary: %{sum}15Summary: %{sum}
16Version: 1.16.016Version: 1.16.0
17-Release: 217+Release: 3
18License: MIT18License: MIT
19URL: http://www.dnspython.org/19URL: http://www.dnspython.org/
20Source0: http://www.dnspython.org/kits/%{version}/dnspython-%{version}.tar.gz20Source0: http://www.dnspython.org/kits/%{version}/dnspython-%{version}.tar.gz
@@ -23,7 +23,8 @@ BuildArch: noarch
23Patch0: unicode_label_escapify.patch23Patch0: unicode_label_escapify.patch
24Patch1: collections_abc.patch24Patch1: collections_abc.patch
25Patch2: base64.patch25Patch2: base64.patch
26-Patch3: fix-failed-tests.patch 26+Patch3: fix-failed-tests.patch
27+Patch4: backport-CVE-2026-114605-limit-pointer-chain.patch
27 28 
28BuildRequires: python2-devel python2-setuptools python2-pycryptodome python2-ecdsa29BuildRequires: python2-devel python2-setuptools python2-pycryptodome python2-ecdsa
29BuildRequires: python3-devel python3-setuptools python3-pycryptodome python3-ecdsa30BuildRequires: python3-devel python3-setuptools python3-pycryptodome python3-ecdsa
@@ -78,6 +79,9 @@ find examples -type f | xargs chmod a-x
78%doc examples79%doc examples
79 80 
80%changelog81%changelog
82+* Sat Oct 24 2026 infra_team <zhaiwenjie1@huawei.com> - 1.16.0-3
83+- fix CVE-2026-114605: limit DNS name decompression to a chain length of at most 16 pointers
84+ 
81* Tue Jun 15 2021 gaihuiying <gaihuiying1@huawei.com> - 1.16.0-285* Tue Jun 15 2021 gaihuiying <gaihuiying1@huawei.com> - 1.16.0-2
82- remove python2 test86- remove python2 test
83 87