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
|
From 1d38781da934809e6ce0b8c3718c4b3bccdfe1d2 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Wed, 28 Dec 2022 19:39:06 +0000
Subject: [PATCH] Fix recursion on dns_again_means_nonexist. Bug 2911
---
doc/ChangeLog | 8 +++++
src/dns.c | 12 ++++++++
test/confs/2202 | 18 +++++++++--
test/scripts/2200-dnsdb/2202 | 8 +++++
test/stderr/2202 | 58 +++++++++++++++++++++++++++++++++++-
test/stdout/2202 | 8 +++++
6 files changed, 108 insertions(+), 4 deletions(-)
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -33,10 +33,18 @@ JH/14 Bug 2933: Fix regex substring matc
JH/18 Fix a fencepost error in logging. Previously (since 4.92) when a log line
was exactly sized compared to the log buffer, a crash occurred with the
misleading message "bad memory reference; pool not found".
Found and traced by Jasen Betts.
+JH/19 Bug 2911: Fix a recursion in DNS lookups. Previously, if the main option
+ dns_again_means_nonexist included an element causing a DNS lookup which
+ iteslf returned DNS_AGAIN, unbounded recursion occurred. Possible results
+ included (though probably not limited to) a process crash from stack
+ memory limit, or from excessive open files. Replace this with a paniclog
+ whine (as this is likely a configuration error), and returning
+ DNS_NOMATCH.
+
Exim version 4.96
-----------------
--- a/src/dns.c
+++ b/src/dns.c
@@ -799,10 +799,11 @@ int
dns_basic_lookup(dns_answer * dnsa, const uschar * name, int type)
{
int rc;
#ifndef STAND_ALONE
const uschar * save_domain;
+static BOOL try_again_recursion = FALSE;
#endif
/* DNS lookup failures of any kind are cached in a tree. This is mainly so that
a timeout on one domain doesn't happen time and time again for messages that
have many addresses in the same domain. We rely on the resolver and name server
@@ -903,15 +904,26 @@ if (dnsa->answerlen < 0) switch (h_errno
DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n",
name, dns_text_type(type));
/* Cut this out for various test programs */
#ifndef STAND_ALONE
+ if (try_again_recursion)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "dns_again_means_nonexist recursion seen for %s (assuming nonexist)",
+ name);
+ return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH);
+ }
+
+ try_again_recursion = TRUE;
save_domain = deliver_domain;
deliver_domain = string_copy(name); /* set $domain */
rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
&domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
deliver_domain = save_domain;
+ try_again_recursion = FALSE;
+
if (rc != OK)
{
DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n");
return dns_fail_return(name, type, 0, DNS_AGAIN);
}
|