The Samba-Bugzilla – Attachment 14670 Details for
Bug 13600
[SECURITY] CVE-2018-14629 CNAME loops in Samba AD DC DNS server
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
possible patch for 4.5
v-early-cname-loop.patch (text/plain), 13.84 KB, created by
Andrew Bartlett
on 2018-11-21 04:57:13 UTC
(
hide
)
Description:
possible patch for 4.5
Filename:
MIME Type:
Creator:
Andrew Bartlett
Created:
2018-11-21 04:57:13 UTC
Size:
13.84 KB
patch
obsolete
>From 92c84d9594b4306a5808c1df4166cef8bd5ae7a9 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Fri, 12 Aug 2016 16:40:05 +0200 >Subject: [PATCH 1/4] libreplace: Ask for eventfd(2) > >This will be used in tevent soon > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit 4771d0792e4343cc8631a36247a2f3c7c31d58b3) >--- > lib/replace/wscript | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/lib/replace/wscript b/lib/replace/wscript >index 145300d235c..1dfd90293ea 100644 >--- a/lib/replace/wscript >+++ b/lib/replace/wscript >@@ -483,6 +483,9 @@ removeea setea > if conf.CONFIG_SET('HAVE_PORT_CREATE') and conf.CONFIG_SET('HAVE_PORT_H'): > conf.DEFINE('HAVE_SOLARIS_PORTS', 1) > >+ if conf.CHECK_FUNCS('eventfd', headers='sys/eventfd.h'): >+ conf.DEFINE('HAVE_EVENTFD', 1) >+ > conf.CHECK_HEADERS('poll.h') > conf.CHECK_FUNCS('poll') > >-- >2.11.0 > > >From 288fdc54121988105e28adeb35ef2bb6daa509f6 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 15 Aug 2016 10:33:09 +0200 >Subject: [PATCH 2/4] tevent: Fix a typo > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit c4ef0c8f3ecc4266fed3af8537ba2998730b3750) >--- > lib/tevent/tevent_threads.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c >index 15882e4f40b..22b854c410f 100644 >--- a/lib/tevent/tevent_threads.c >+++ b/lib/tevent/tevent_threads.c >@@ -108,7 +108,7 @@ static void schedule_immediate_functions(struct tevent_thread_proxy *tp) > if (tp->tofree_im_list != NULL) { > /* > * Once the current immediate events >- * are processed, we need to reshedule >+ * are processed, we need to reschedule > * ourselves to free them. This works > * as tevent_schedule_immediate() > * always adds events to the *END* of >-- >2.11.0 > > >From 2988c42c7fb06dea5d952ec50be5e767b0e9efc0 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Fri, 29 Jul 2016 08:53:59 +0200 >Subject: [PATCH 3/4] tevent: Move the async wakeup pipe to common > >Signalling the main event loop will also happen from threads soon, and >that will use the same mechanism. This also keeps the pipe open after the last >signal handler is removed. Threaded jobs will come and go very frequently, and >always setting up and tearing down the pipe for each job will be expensive. >Also, this is "just" two file descriptors, and with eventfd just one. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit 8a9b8ac72461657a3a5de2fd5232eaa9861bf696) >--- > lib/tevent/ABI/tevent-0.9.29.sigs | 3 ++ > lib/tevent/tevent.c | 87 +++++++++++++++++++++++++++++++++++++-- > lib/tevent/tevent_internal.h | 4 ++ > lib/tevent/tevent_poll.c | 5 +-- > lib/tevent/tevent_signal.c | 60 ++++----------------------- > 5 files changed, 99 insertions(+), 60 deletions(-) > >diff --git a/lib/tevent/ABI/tevent-0.9.29.sigs b/lib/tevent/ABI/tevent-0.9.29.sigs >index 135775171ea..4b647419d08 100644 >--- a/lib/tevent/ABI/tevent-0.9.29.sigs >+++ b/lib/tevent/ABI/tevent-0.9.29.sigs >@@ -28,10 +28,13 @@ tevent_common_fd_destructor: int (struct tevent_fd *) > tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) > tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) > tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_common_have_events: bool (struct tevent_context *) > tevent_common_loop_immediate: bool (struct tevent_context *) > tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) > tevent_common_loop_wait: int (struct tevent_context *, const char *) > tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_common_wakeup: int (struct tevent_context *) >+tevent_common_wakeup_init: int (struct tevent_context *) > tevent_context_init: struct tevent_context *(TALLOC_CTX *) > tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) > tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) >diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c >index 843cf0560f3..34cd402d5e4 100644 >--- a/lib/tevent/tevent.c >+++ b/lib/tevent/tevent.c >@@ -620,6 +620,28 @@ done: > return ret; > } > >+bool tevent_common_have_events(struct tevent_context *ev) >+{ >+ if (ev->fd_events != NULL) { >+ if (ev->fd_events != ev->pipe_fde) { >+ return true; >+ } >+ if (ev->fd_events->next != NULL) { >+ return true; >+ } >+ >+ /* >+ * At this point we just have the wakeup pipe event as >+ * the only fd_event. That one does not count as a >+ * regular event, so look at the other event types. >+ */ >+ } >+ >+ return ((ev->timer_events != NULL) || >+ (ev->immediate_events != NULL) || >+ (ev->signal_events != NULL)); >+} >+ > /* > return on failure or (with 0) if all fd events are removed > */ >@@ -629,10 +651,7 @@ int tevent_common_loop_wait(struct tevent_context *ev, > /* > * loop as long as we have events pending > */ >- while (ev->fd_events || >- ev->timer_events || >- ev->immediate_events || >- ev->signal_events) { >+ while (tevent_common_have_events(ev)) { > int ret; > ret = _tevent_loop_once(ev, location); > if (ret != 0) { >@@ -670,3 +689,63 @@ int tevent_re_initialise(struct tevent_context *ev) > > return ev->ops->context_init(ev); > } >+ >+static void wakeup_pipe_handler(struct tevent_context *ev, >+ struct tevent_fd *fde, >+ uint16_t flags, void *_private) >+{ >+ ssize_t ret; >+ >+ char c[16]; >+ /* its non-blocking, doesn't matter if we read too much */ >+ do { >+ ret = read(fde->fd, c, sizeof(c)); >+ } while (ret == -1 && errno == EINTR); >+} >+ >+/* >+ * Initialize the wakeup pipe and pipe fde >+ */ >+ >+int tevent_common_wakeup_init(struct tevent_context *ev) >+{ >+ int ret; >+ >+ if (ev->pipe_fde != NULL) { >+ return 0; >+ } >+ >+ ret = pipe(ev->pipe_fds); >+ if (ret == -1) { >+ return errno; >+ } >+ ev_set_blocking(ev->pipe_fds[0], false); >+ ev_set_blocking(ev->pipe_fds[1], false); >+ >+ ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0], >+ TEVENT_FD_READ, >+ wakeup_pipe_handler, NULL); >+ if (ev->pipe_fde == NULL) { >+ close(ev->pipe_fds[0]); >+ close(ev->pipe_fds[1]); >+ return ENOMEM; >+ } >+ >+ return 0; >+} >+ >+int tevent_common_wakeup(struct tevent_context *ev) >+{ >+ ssize_t ret; >+ >+ if (ev->pipe_fds[1] == -1) { >+ return ENOTCONN; >+ } >+ >+ do { >+ char c = '\0'; >+ ret = write(ev->pipe_fds[1], &c, 1); >+ } while ((ret == -1) && (errno == EINTR)); >+ >+ return 0; >+} >diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h >index 10cc4a47f83..83627705095 100644 >--- a/lib/tevent/tevent_internal.h >+++ b/lib/tevent/tevent_internal.h >@@ -328,6 +328,10 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im, > const char *location); > bool tevent_common_loop_immediate(struct tevent_context *ev); > >+bool tevent_common_have_events(struct tevent_context *ev); >+int tevent_common_wakeup_init(struct tevent_context *ev); >+int tevent_common_wakeup(struct tevent_context *ev); >+ > struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, > TALLOC_CTX *mem_ctx, > int signum, >diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c >index e1c305d20ea..3547e912b2c 100644 >--- a/lib/tevent/tevent_poll.c >+++ b/lib/tevent/tevent_poll.c >@@ -667,10 +667,7 @@ static int poll_event_loop_wait(struct tevent_context *ev, > /* > * loop as long as we have events pending > */ >- while (ev->fd_events || >- ev->timer_events || >- ev->immediate_events || >- ev->signal_events || >+ while (tevent_common_have_events(ev) || > poll_ev->fresh || > poll_ev->disabled) { > int ret; >diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c >index 635a7a177aa..c85e1c528c4 100644 >--- a/lib/tevent/tevent_signal.c >+++ b/lib/tevent/tevent_signal.c >@@ -95,7 +95,6 @@ static uint32_t tevent_sig_count(struct tevent_sigcounter s) > */ > static void tevent_common_signal_handler(int signum) > { >- char c = 0; > struct tevent_common_signal_list *sl; > struct tevent_context *ev = NULL; > int saved_errno = errno; >@@ -106,13 +105,8 @@ static void tevent_common_signal_handler(int signum) > /* Write to each unique event context. */ > for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) { > if (sl->se->event_ctx && sl->se->event_ctx != ev) { >- ssize_t ret; >- > ev = sl->se->event_ctx; >- /* doesn't matter if this pipe overflows */ >- do { >- ret = write(ev->pipe_fds[1], &c, 1); >- } while (ret == -1 && errno == EINTR); >+ tevent_common_wakeup(ev); > } > } > >@@ -198,16 +192,6 @@ static int tevent_signal_destructor(struct tevent_signal *se) > struct tevent_context *ev = se->event_ctx; > > DLIST_REMOVE(ev->signal_events, se); >- >- if (ev->signal_events == NULL && ev->pipe_fde != NULL) { >- /* >- * This was the last signal. Destroy the pipe. >- */ >- TALLOC_FREE(ev->pipe_fde); >- >- close(ev->pipe_fds[0]); >- close(ev->pipe_fds[1]); >- } > } > > talloc_free(sl); >@@ -233,21 +217,6 @@ static int tevent_signal_destructor(struct tevent_signal *se) > } > > /* >- this is part of the pipe hack needed to avoid the signal race condition >-*/ >-static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, >- uint16_t flags, void *_private) >-{ >- ssize_t ret; >- >- char c[16]; >- /* its non-blocking, doesn't matter if we read too much */ >- do { >- ret = read(fde->fd, c, sizeof(c)); >- } while (ret == -1 && errno == EINTR); >-} >- >-/* > add a signal event > return NULL on failure (memory allocation error) > */ >@@ -263,6 +232,13 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, > struct tevent_signal *se; > struct tevent_common_signal_list *sl; > sigset_t set, oldset; >+ int ret; >+ >+ ret = tevent_common_wakeup_init(ev); >+ if (ret != 0) { >+ errno = ret; >+ return NULL; >+ } > > if (signum >= TEVENT_NUM_SIGNALS) { > errno = EINVAL; >@@ -304,26 +280,6 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, > return NULL; > } > >- /* we need to setup the pipe hack handler if not already >- setup */ >- if (ev->pipe_fde == NULL) { >- if (pipe(ev->pipe_fds) == -1) { >- talloc_free(se); >- return NULL; >- } >- ev_set_blocking(ev->pipe_fds[0], false); >- ev_set_blocking(ev->pipe_fds[1], false); >- ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0], >- TEVENT_FD_READ, >- signal_pipe_handler, NULL); >- if (!ev->pipe_fde) { >- close(ev->pipe_fds[0]); >- close(ev->pipe_fds[1]); >- talloc_free(se); >- return NULL; >- } >- } >- > /* only install a signal handler if not already installed */ > if (sig_state->sig_handlers[signum] == NULL) { > struct sigaction act; >-- >2.11.0 > > >diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py >index 43eccddd957..9d040acdea4 100644 >--- a/python/samba/tests/dns.py >+++ b/python/samba/tests/dns.py >@@ -937,6 +937,29 @@ 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 = self.dns_transaction_udp(p) >+ >+ max_recursion_depth = 20 >+ self.assertEquals(len(response.answers), max_recursion_depth) >+ >+ > class TestInvalidQueries(DNSTest): > > def test_one_a_query(self): >diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns >index 6553c1fffe0..a22bcce6bf4 100644 >--- a/selftest/knownfail.d/dns >+++ b/selftest/knownfail.d/dns >@@ -45,6 +45,11 @@ samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\) > samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(vampire_dc:local\) > samba.tests.dns.__main__.TestSimpleQueries.test_one_a_query\(vampire_dc:local\) > samba.tests.dns.__main__.TestSimpleQueries.test_one_a_query_tcp\(vampire_dc: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\) > samba.tests.dns.__main__.TestSimpleQueries.test_one_mx_query\(vampire_dc:local\) > samba.tests.dns.__main__.TestSimpleQueries.test_qtype_all_query\(vampire_dc:local\) > samba.tests.dns.__main__.TestSimpleQueries.test_soa_hostname_query\(vampire_dc:local\) >diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c >index b8ecc2e7ac7..89199e16787 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)));
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 13600
:
14460
|
14537
|
14572
|
14573
|
14574
|
14575
|
14594
|
14631
|
14632
|
14635
|
14636
|
14649
|
14667
|
14668
|
14670
|
14685
|
14691
|
14692
|
14693
|
14694
|
14696
|
14697
|
14704
|
14711
|
14712
|
14717
|
14719
|
14720
|
14724
|
17140