已开启
fix(cve): 修复 CVE-2026-114605 在 python-dns 中的漏洞 #72
infra_team创建于 12 天前
fix(cve): 修复 CVE-2026-114605 在 python-dns 中的漏洞 #72
已开启
共 2 个文件变更+108-1
| @@ -0,0 +1,102 @@ | |||
| 1 | +From 2398b7043edd894cd22bd5870c72121e245464a8 Mon Sep 17 00:00:00 2001 | ||
E | |||
| 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() | ||
| 7 | +to use excessive CPU for DNS name decompression. Applications which | ||
| 8 | +process untrusted DNS wire form messages with dnspython may be degraded | ||
| 9 | +or DoS'd by the extra CPU use required. | ||
| 10 | + | ||
| 11 | +Credit: | ||
| 12 | + | ||
| 13 | +Evgenios Gkritsis, Department of Informatics, University of Piraeus & Athena Research Center, Greece | ||
| 14 | +Constantinos Patsakis, Department of Informatics, University of Piraeus & Athena Research Center, Greece | ||
| 15 | +George Stergiopoulos, Department of Informatics, Athens University of Economics and Business, Greece | ||
| 16 | + | ||
| 17 | +Upstream-commit: https://github.com/rthalley/dnspython/commit/b485e460c266540a1a09ca6d8d1d7b685b1d3023 | ||
| 18 | +Signed-off-by: infra_team <zhaiwenjie1@huawei.com> | ||
| 19 | +--- | ||
| 20 | + dns/name.py | 11 +++++++++++ | ||
| 21 | + tests/test_name.py | 22 ++++++++++++++++++++++ | ||
| 22 | + 2 files changed, 33 insertions(+) | ||
| 23 | + | ||
| 24 | +diff --git a/dns/name.py b/dns/name.py | ||
| 25 | +index 8905d70..1ff195d 100644 | ||
| 26 | +--- a/dns/name.py | ||
| 27 | ++++ b/dns/name.py | ||
| 28 | +@@ -58,6 +58,10 @@ class BadPointer(dns.exception.FormError): | ||
| 29 | + """A DNS compression pointer points forward instead of backward.""" | ||
| 30 | + | ||
| 31 | + | ||
| 32 | ++class PointerChainTooLong(dns.exception.FormError): | ||
| 33 | ++ """A DNS compression pointer chain was too long.""" | ||
| 34 | ++ | ||
| 35 | ++ | ||
| 36 | + class BadLabelType(dns.exception.FormError): | ||
| 37 | + """The label type in DNS name wire format is unknown.""" | ||
| 38 | + | ||
| 39 | +@@ -959,6 +963,9 @@ def from_text(text, origin=root, idna_codec=None): | ||
| 40 | + return Name(labels) | ||
| 41 | + | ||
| 42 | + | ||
| 43 | ++MAX_COMPRESSION_POINTER_CHAIN = 16 | ||
| 44 | ++ | ||
| 45 | ++ | ||
| 46 | + def from_wire_parser(parser): | ||
| 47 | + """Convert possibly compressed wire format into a Name. | ||
| 48 | + | ||
| 49 | +@@ -974,6 +981,7 @@ def from_wire_parser(parser): | ||
| 50 | + | ||
| 51 | + labels = [] | ||
| 52 | + biggest_pointer = parser.current | ||
| 53 | ++ hops = 0 | ||
| 54 | + with parser.restore_furthest(): | ||
| 55 | + count = parser.get_uint8() | ||
| 56 | + while count != 0: | ||
| 57 | +@@ -984,6 +992,9 @@ def from_wire_parser(parser): | ||
| 58 | + if current >= biggest_pointer: | ||
| 59 | + raise BadPointer | ||
| 60 | + biggest_pointer = current | ||
| 61 | ++ hops += 1 | ||
| 62 | ++ if hops > MAX_COMPRESSION_POINTER_CHAIN: | ||
| 63 | ++ raise PointerChainTooLong | ||
| 64 | + parser.seek(current) | ||
| 65 | + else: | ||
| 66 | + raise BadLabelType | ||
| 67 | +diff --git a/tests/test_name.py b/tests/test_name.py | ||
| 68 | +index f91d7e6..0fde0dd 100644 | ||
| 69 | +--- a/tests/test_name.py | ||
| 70 | ++++ b/tests/test_name.py | ||
| 71 | +@@ -676,6 +676,28 @@ class NameTestCase(unittest.TestCase): | ||
| 72 | + dns.name.from_wire(w, 0) | ||
| 73 | + self.assertRaises(dns.name.BadLabelType, bad) | ||
| 74 | + | ||
| 75 | ++ def testCompressionChainLength(self): | ||
| 76 | ++ # We're going to decode some wire starting two bytes from the end. At this | ||
| 77 | ++ # position is a pointer which points to four bytes from the end, and it points | ||
| 78 | ++ # to one 6 bytes from the end, etc., until finally the 16th pointer points at | ||
| 79 | ++ # offset zero, which is the root label followed by a byte of padding. After | ||
| 80 | ++ # all of this useless pointer hopping, we should get the root name. | ||
| 81 | ++ 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" | ||
| 82 | ++ self.assertEqual(len(w), 34) | ||
| 83 | ++ starts = [c for c in w if c == 0xC0] | ||
| 84 | ++ self.assertEqual(len(starts), dns.name.MAX_COMPRESSION_POINTER_CHAIN) | ||
| 85 | ++ | ||
| 86 | ++ def bad(): | ||
| 87 | ++ # Now we make the wire one pointer longer, which is too long! | ||
| 88 | ++ w1 = w + b"\xc0\x20" | ||
| 89 | ++ self.assertEqual(len(w1), 36) | ||
| 90 | ++ starts = [c for c in w1 if c == 0xC0] | ||
| 91 | ++ self.assertEqual(len(starts), dns.name.MAX_COMPRESSION_POINTER_CHAIN + 1) | ||
| 92 | ++ dns.name.from_wire(w1, 34) | ||
| 93 | ++ | ||
| 94 | ++ self.assertEqual(dns.name.from_wire(w, 32)[0], dns.name.from_text(".")) | ||
| 95 | ++ self.assertRaises(dns.name.PointerChainTooLong, bad) | ||
| 96 | ++ | ||
| 97 | + def testParent1(self): | ||
| 98 | + n = dns.name.from_text('foo.bar.') | ||
| 99 | + self.assertEqual(n.parent(), dns.name.from_text('bar.')) | ||
| 100 | +-- | ||
| 101 | +2.39.5 | ||
| 102 | + | ||
| @@ -14,7 +14,7 @@ messages, names, and records. | |||
| 14 | Name: python-dns | 14 | Name: python-dns |
| 15 | Summary: %{sum} | 15 | Summary: %{sum} |
| 16 | Version: 2.2.1 | 16 | Version: 2.2.1 |
| 17 | -Release: 3 | 17 | +Release: 4 |
| 18 | License: ISC and MIT | 18 | License: ISC and MIT |
| 19 | URL: http://www.dnspython.org/ | 19 | URL: http://www.dnspython.org/ |
| 20 | Source0: https://github.com/rthalley/dnspython/archive/v%{version}/dnspython-%{version}.tar.gz | 20 | Source0: https://github.com/rthalley/dnspython/archive/v%{version}/dnspython-%{version}.tar.gz |
| @@ -25,6 +25,7 @@ Patch2: 0001-update-README-w-codecov-and-lgtm.patch | |||
| 25 | Patch3: backport-001-CVE-2023-29483.patch | 25 | Patch3: backport-001-CVE-2023-29483.patch |
| 26 | Patch4: backport-002-CVE-2023-29483.patch | 26 | Patch4: backport-002-CVE-2023-29483.patch |
| 27 | Patch5: backport-003-CVE-2023-29483.patch | 27 | Patch5: backport-003-CVE-2023-29483.patch |
| 28 | +Patch6: backport-CVE-2026-114605-limit-pointer-chain.patch | ||
| 28 | 29 | ||
| 29 | BuildArch: noarch | 30 | BuildArch: noarch |
| 30 | 31 | ||
| @@ -67,6 +68,10 @@ pytest | |||
| 67 | %doc examples | 68 | %doc examples |
| 68 | 69 | ||
| 69 | %changelog | 70 | %changelog |
| 71 | +* Sat Oct 24 2026 infra_team <zhaiwenjie1@huawei.com> - 2.2.1-4 | ||
| 72 | +- fix CVE-2026-114605 | ||
| 73 | +- limit DNS name decompression to a chain length of at most 16 pointers | ||
| 74 | + | ||
| 70 | * Wed Jul 24 2024 gaihuiying <eaglegai@163.com> - 2.2.1-3 | 75 | * Wed Jul 24 2024 gaihuiying <eaglegai@163.com> - 2.2.1-3 |
| 71 | - fix CVE-2023-29483 | 76 | - fix CVE-2023-29483 |
| 72 | 77 | ||
@infra_team commit id建议跟社区保持一致