aboutsummaryrefslogtreecommitdiffstats
path: root/main/samba/0001-CVE-2018-14629-dns-CNAME-loop-prevention-using-count.patch
blob: 0e6eaa9763a8ff5841616f8fa38c7f7904631528 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
From f7a8294d65e5a7424da93499074a30cb65418ce7 Mon Sep 17 00:00:00 2001
From: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Date: Tue, 23 Oct 2018 17:25:51 +1300
Subject: [PATCH] CVE-2018-14629 dns: CNAME loop prevention using counter

Count number of answers generated by internal DNS query routine and stop at
20 to match Microsoft's loop prevention mechanism.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13600

Signed-off-by: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
---
 python/samba/tests/dns.py      | 24 ++++++++++++++++++++++++
 selftest/knownfail.d/dns       |  6 ++++++
 source4/dns_server/dns_query.c |  6 ++++++
 3 files changed, 36 insertions(+)

diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py
index 1b5b64da3a4..3390a3990c9 100644
--- a/python/samba/tests/dns.py
+++ b/python/samba/tests/dns.py
@@ -798,6 +798,30 @@ class TestComplexQueries(DNSTest):
         self.assertEquals(response.answers[1].name, name2)
         self.assertEquals(response.answers[1].rdata, name0)
 
+    def test_cname_loop(self):
+        cname1 = "cnamelooptestrec." + self.get_dns_domain()
+        cname2 = "cnamelooptestrec2." + self.get_dns_domain()
+        cname3 = "cnamelooptestrec3." + self.get_dns_domain()
+        self.make_dns_update(cname1, cname2, dnsp.DNS_TYPE_CNAME)
+        self.make_dns_update(cname2, cname3, dnsp.DNS_TYPE_CNAME)
+        self.make_dns_update(cname3, cname1, dnsp.DNS_TYPE_CNAME)
+
+        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
+        questions = []
+
+        q = self.make_name_question(cname1,
+                                    dns.DNS_QTYPE_A,
+                                    dns.DNS_QCLASS_IN)
+        questions.append(q)
+        self.finish_name_packet(p, questions)
+
+        (response, response_packet) =\
+            self.dns_transaction_udp(p, host=self.server_ip)
+
+        max_recursion_depth = 20
+        self.assertEquals(len(response.answers), max_recursion_depth)
+
+
 class TestInvalidQueries(DNSTest):
     def setUp(self):
         super(TestInvalidQueries, self).setUp()
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index e8de304c8bb..fafadb6ac6f 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -40,6 +40,7 @@
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_DNS
+#define MAX_Q_RECURSION_DEPTH 20
 
 struct forwarder_string {
 	const char *forwarder;
@@ -470,6 +471,11 @@ static struct tevent_req *handle_dnsrpcrec_send(
 	state->answers = answers;
 	state->nsrecs = nsrecs;
 
+	if (talloc_array_length(*answers) >= MAX_Q_RECURSION_DEPTH) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
 	resolve_cname = ((rec->wType == DNS_TYPE_CNAME) &&
 			 ((question->question_type == DNS_QTYPE_A) ||
 			  (question->question_type == DNS_QTYPE_AAAA)));
-- 
2.18.1