CVE-2018-14629 dns: CNAME loop prevention using counter
authorAaron Haslett <aaronhaslett@catalyst.net.nz>
Tue, 23 Oct 2018 04:25:51 +0000 (17:25 +1300)
committerKarolin Seeger <kseeger@samba.org>
Mon, 26 Nov 2018 08:38:10 +0000 (09:38 +0100)
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
selftest/knownfail.d/dns
source4/dns_server/dns_query.c

index 1b5b64da3a405a5542c7bf3c9b4dec4924b4a9a4..3390a3990c96407c3f5c632c5ccacd57b03d2b29 100644 (file)
@@ -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()
index cb3003240ea30e3a89c1e8aab7c21e730d4ea13e..8c79b3abe00c858e8b4f341800388d15f551d2d5 100644 (file)
@@ -45,3 +45,9 @@ samba.tests.dns.__main__.TestSimpleQueries.test_qtype_all_query\(rodc:local\)
 
 # The SOA override should not pass against the RODC, it must not overstamp
 samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\)
+
+#
+# rodc and vampire_dc require signed dns updates, so the test setup
+# fails, but the test does run on fl2003dc
+^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(rodc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(vampire_dc:local\)
index e8de304c8bb9de813e8107e175781625f1d9f826..fafadb6ac6f2c1234c766241c7d47727b145f080 100644 (file)
@@ -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)));