CVE-2018-14629 dns: fix CNAME loop prevention using counter regression
authorStefan Metzmacher <metze@samba.org>
Wed, 28 Nov 2018 14:21:56 +0000 (15:21 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 4 Dec 2018 07:52:29 +0000 (08:52 +0100)
The loop prevention should only be done for CNAME records!

Otherwise we truncate the answer records for A, AAAA or
SRV queries, which is a bad idea if you have more than 20 DCs.

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

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Tue Dec  4 08:52:29 CET 2018 on sn-devel-144

selftest/knownfail.d/dns
source4/dns_server/dns_query.c

index 4bf01bdd89ea4f9c99feb80cf4ba3b40ba6d9262..ec345372046a31ac833aaf13c41f4443f8f29f3a 100644 (file)
@@ -87,9 +87,3 @@ samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\)
 ^samba.tests.dns.__main__.TestComplexQueries.test_cname_limit\(rodc:local\)
 ^samba.tests.dns.__main__.TestComplexQueries.test_cname_any_query\(vampire_dc:local\)
 ^samba.tests.dns.__main__.TestComplexQueries.test_cname_any_query\(rodc:local\)
-
-# These all fail until the next patch
-^samba.tests.dns.__main__.TestComplexQueries.test_cname_limit
-^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_SRV
-^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_AAAA
-^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_A
index 65faeac3b6a4c89657e33122ebfe493d41b9efb7..b75fabe7e827591ada313365509991db9c773a70 100644 (file)
@@ -388,7 +388,8 @@ static struct tevent_req *handle_authoritative_send(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev,
        struct dns_server *dns, const char *forwarder,
        struct dns_name_question *question,
-       struct dns_res_rec **answers, struct dns_res_rec **nsrecs);
+       struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
+       size_t cname_depth);
 static WERROR handle_authoritative_recv(struct tevent_req *req);
 
 struct handle_dnsrpcrec_state {
@@ -404,7 +405,8 @@ static struct tevent_req *handle_dnsrpcrec_send(
        struct dns_server *dns, const char *forwarder,
        const struct dns_name_question *question,
        struct dnsp_DnssrvRpcRecord *rec,
-       struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
+       struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
+       size_t cname_depth)
 {
        struct tevent_req *req, *subreq;
        struct handle_dnsrpcrec_state *state;
@@ -420,7 +422,7 @@ static struct tevent_req *handle_dnsrpcrec_send(
        state->answers = answers;
        state->nsrecs = nsrecs;
 
-       if (talloc_array_length(*answers) >= MAX_Q_RECURSION_DEPTH) {
+       if (cname_depth >= MAX_Q_RECURSION_DEPTH) {
                tevent_req_done(req);
                return tevent_req_post(req, ev);
        }
@@ -465,7 +467,8 @@ static struct tevent_req *handle_dnsrpcrec_send(
        if (dns_authoritative_for_zone(dns, new_q->name)) {
                subreq = handle_authoritative_send(
                        state, ev, dns, forwarder, new_q,
-                       state->answers, state->nsrecs);
+                       state->answers, state->nsrecs,
+                       cname_depth + 1);
                if (tevent_req_nomem(subreq, req)) {
                        return tevent_req_post(req, ev);
                }
@@ -549,6 +552,8 @@ struct handle_authoritative_state {
 
        struct dns_res_rec **answers;
        struct dns_res_rec **nsrecs;
+
+       size_t cname_depth;
 };
 
 static void handle_authoritative_done(struct tevent_req *subreq);
@@ -557,7 +562,8 @@ static struct tevent_req *handle_authoritative_send(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev,
        struct dns_server *dns, const char *forwarder,
        struct dns_name_question *question,
-       struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
+       struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
+       size_t cname_depth)
 {
        struct tevent_req *req, *subreq;
        struct handle_authoritative_state *state;
@@ -575,6 +581,7 @@ static struct tevent_req *handle_authoritative_send(
        state->forwarder = forwarder;
        state->answers = answers;
        state->nsrecs = nsrecs;
+       state->cname_depth = cname_depth;
 
        werr = dns_name2dn(dns, state, question->name, &dn);
        if (tevent_req_werror(req, werr)) {
@@ -595,7 +602,8 @@ static struct tevent_req *handle_authoritative_send(
        subreq = handle_dnsrpcrec_send(
                state, state->ev, state->dns, state->forwarder,
                state->question, &state->recs[state->recs_done],
-               state->answers, state->nsrecs);
+               state->answers, state->nsrecs,
+               state->cname_depth);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -627,7 +635,8 @@ static void handle_authoritative_done(struct tevent_req *subreq)
        subreq = handle_dnsrpcrec_send(
                state, state->ev, state->dns, state->forwarder,
                state->question, &state->recs[state->recs_done],
-               state->answers, state->nsrecs);
+               state->answers, state->nsrecs,
+               state->cname_depth);
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
@@ -1000,7 +1009,8 @@ struct tevent_req *dns_server_process_query_send(
 
                subreq = handle_authoritative_send(
                        state, ev, dns, (forwarders == NULL ? NULL : forwarders[0]),
-                       &in->questions[0], &state->answers, &state->nsrecs);
+                       &in->questions[0], &state->answers, &state->nsrecs,
+                       0); /* cname_depth */
                if (tevent_req_nomem(subreq, req)) {
                        return tevent_req_post(req, ev);
                }
@@ -1102,7 +1112,8 @@ static void dns_server_process_query_got_auth(struct tevent_req *subreq)
                subreq = handle_authoritative_send(state, state->ev, state->dns,
                                                   state->forwarders->forwarder,
                                                   state->question, &state->answers,
-                                                  &state->nsrecs);
+                                                  &state->nsrecs,
+                                                  0); /* cname_depth */
 
                if (tevent_req_nomem(subreq, req)) {
                        return;