Open
fix(cve): 修复 CVE-2026-114605 在 python-dns 中的漏洞 #73
fix(cve): 修复 CVE-2026-114605 在 python-dns 中的漏洞 #73
Open
infra_teamAdd on 15 days ago
Total: 2 files changed+103-1
@@ -0,0 +1,95 @@
1+From 875bb21c7474898dd5dc2b813ef4670a1cd6b232 Mon Sep 17 00:00:00 2001
E
Eeaglegai13 days ago

@infra_team commit id建议跟社区保持一致

likedislike
2+From: Bob Halley <halley@dnspython.org>
3+Date: Sat, 26 Sep 2026 13:38:07 -0700
4+Subject: [PATCH] Limit decompression to a chain length of at most 16 pointers.
5+ 
6+A maliciously crafted DNS message may cause dns.name.from_wire_parser() to use excessive CPU for DNS name decompression. Applications which process untrusted DNS wire form messages with dnspython may be degraded or DoS'd by the extra CPU use required.
7+ 
8+Backport notes: drop the doc/whatsnew.rst hunk (2.4.2 has no 2.9.0 section) and re-anchor the MAX_COMPRESSION_POINTER_CHAIN insertion above from_wire_parser().
9+ 
10+Upstream-commit: https://github.com/rthalley/dnspython/commit/b485e460c266540a1a09ca6d8d1d7b685b1d3023
11+Signed-off-by: infra_team <zhaiwenjie1@huawei.com>
12+---
13+ dns/name.py | 11 +++++++++++
14+ tests/test_name.py | 22 ++++++++++++++++++++++
15+ 2 files changed, 33 insertions(+)
16+ 
17+diff --git a/dns/name.py b/dns/name.py
18+index f452bfe..8d701ab 100644
19+--- a/dns/name.py
20++++ b/dns/name.py
21+@@ -84,6 +84,10 @@ class BadPointer(dns.exception.FormError):
22+ """A DNS compression pointer points forward instead of backward."""
23+
24+
25++class PointerChainTooLong(dns.exception.FormError):
26++ """A DNS compression pointer chain was too long."""
27++
28++
29+ class BadLabelType(dns.exception.FormError):
30+ """The label type in DNS name wire format is unknown."""
31+
32+@@ -1022,6 +1026,9 @@ def from_text(
33+ return Name(labels)
34+
35+
36++MAX_COMPRESSION_POINTER_CHAIN = 16
37++
38++
39+ # we need 'dns.wire.Parser' quoted as dns.name and dns.wire depend on each other.
40+
41+
42+@@ -1040,6 +1047,7 @@ def from_wire_parser(parser: "dns.wire.Parser") -> Name:
43+
44+ labels = []
45+ biggest_pointer = parser.current
46++ hops = 0
47+ with parser.restore_furthest():
48+ count = parser.get_uint8()
49+ while count != 0:
50+@@ -1050,6 +1058,9 @@ def from_wire_parser(parser: "dns.wire.Parser") -> Name:
51+ if current >= biggest_pointer:
52+ raise BadPointer
53+ biggest_pointer = current
54++ hops += 1
55++ if hops > MAX_COMPRESSION_POINTER_CHAIN:
56++ raise PointerChainTooLong
57+ parser.seek(current)
58+ else:
59+ raise BadLabelType
60+diff --git a/tests/test_name.py b/tests/test_name.py
61+index 1d18ce3..e9303ae 100644
62+--- a/tests/test_name.py
63++++ b/tests/test_name.py
64+@@ -693,6 +693,28 @@ class NameTestCase(unittest.TestCase):
65+
66+ self.assertRaises(dns.name.BadLabelType, bad)
67+
68++ def testCompressionChainLength(self):
69++ # We're going to decode some wire starting two bytes from the end. At this
70++ # position is a pointer which points to four bytes from the end, and it points
71++ # to one 6 bytes from the end, etc., until finally the 16th pointer points at
72++ # offset zero, which is the root label followed by a byte of padding. After
73++ # all of this useless pointer hopping, we should get the root name.
74++ 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"
75++ self.assertEqual(len(w), 34)
76++ starts = [c for c in w if c == 0xC0]
77++ self.assertEqual(len(starts), dns.name.MAX_COMPRESSION_POINTER_CHAIN)
78++
79++ def bad():
80++ # Now we make the wire one pointer longer, which is too long!
81++ w1 = w + b"\xc0\x20"
82++ self.assertEqual(len(w1), 36)
83++ starts = [c for c in w1 if c == 0xC0]
84++ self.assertEqual(len(starts), dns.name.MAX_COMPRESSION_POINTER_CHAIN + 1)
85++ dns.name.from_wire(w1, 34)
86++
87++ self.assertEqual(dns.name.from_wire(w, 32)[0], dns.name.from_text("."))
88++ self.assertRaises(dns.name.PointerChainTooLong, bad)
89++
90+ def testParent1(self):
91+ n = dns.name.from_text("foo.bar.")
92+ self.assertEqual(n.parent(), dns.name.from_text("bar."))
93+--
94+2.39.5
95+ 
@@ -14,7 +14,7 @@ messages, names, and records.
14Name: python-dns14Name: python-dns
15Summary: %{sum}15Summary: %{sum}
16Version: 2.4.216Version: 2.4.2
17-Release: 417+Release: 5
18License: ISC and MIT18License: ISC and MIT
19URL: http://www.dnspython.org/19URL: http://www.dnspython.org/
20Source0: https://github.com/rthalley/dnspython/archive/v%{version}/dnspython-%{version}.tar.gz20Source0: https://github.com/rthalley/dnspython/archive/v%{version}/dnspython-%{version}.tar.gz
@@ -31,6 +31,9 @@ Patch0007: backport-Retry-on-test-timeout.patch
31Patch0008: backport-add-more-wrapping-accidentally-omitted-from-the-PR.patch31Patch0008: backport-add-more-wrapping-accidentally-omitted-from-the-PR.patch
32Patch0009: fix-to-skip-unsupport-testcases.patch32Patch0009: fix-to-skip-unsupport-testcases.patch
33 33 
34+# fix CVE-2026-114605
35+Patch0010: backport-CVE-2026-114605-limit-compression-pointer-chain.patch
36+ 
34BuildArch: noarch37BuildArch: noarch
35 38 
36BuildRequires: python3-devel python3-setuptools python3-cryptography39BuildRequires: python3-devel python3-setuptools python3-cryptography
@@ -83,6 +86,10 @@ fi
83%doc examples86%doc examples
84 87 
85%changelog88%changelog
89+* Sat Oct 24 2026 infra_team <zhaiwenjie1@huawei.com> - 2.4.2-5
90+- fix CVE-2026-114605
91+- Limit DNS name decompression to a chain length of at most 16 pointers
92+ 
86* Wed Oct 29 2025 gaihuiying <eaglegai@163.com> - 2.4.2-493* Wed Oct 29 2025 gaihuiying <eaglegai@163.com> - 2.4.2-4
87- sync to skip testResolveTCP on loongarch6494- sync to skip testResolveTCP on loongarch64
88 95