From: Jeremy Harris Date: Tue, 13 Aug 2019 11:50:38 +0000 (+0100) Subject: DNS: use tainted memory for all lookups X-Git-Tag: exim-4.93-RC0~103 X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/8743d3acaaa2262007aa2862ffecd6b19125e38d DNS: use tainted memory for all lookups --- diff --git a/src/src/acl.c b/src/src/acl.c index c8ad795fe..5f0a7864b 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1310,7 +1310,7 @@ acl_verify_csa(const uschar *domain) tree_node *t; const uschar *found; int priority, weight, port; -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; dns_record *rr; int rc, type; @@ -1364,7 +1364,7 @@ Ustrcpy(t->name, domain); /* Now we are ready to do the actual DNS lookup(s). */ found = domain; -switch (dns_special_lookup(&dnsa, domain, T_CSA, &found)) +switch (dns_special_lookup(dnsa, domain, T_CSA, &found)) { /* If something bad happened (most commonly DNS_AGAIN), defer. */ @@ -1385,9 +1385,9 @@ switch (dns_special_lookup(&dnsa, domain, T_CSA, &found)) /* Scan the reply for well-formed CSA SRV records. */ -for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); +for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_SRV) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_SRV) { const uschar * p = rr->data; @@ -1427,7 +1427,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); client's IP address is listed as one of the SRV target addresses. Save the target hostname then break to scan the additional data for its addresses. */ - (void)dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, + (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)target, sizeof(target)); DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target); @@ -1452,7 +1452,7 @@ to the target. If the name server didn't return any additional data (e.g. because it does not fully support SRV records), we need to do another lookup to obtain the target addresses; otherwise we have a definitive result. */ -rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ADDITIONAL, target); +rc = acl_verify_csa_address(dnsa, &dnss, RESET_ADDITIONAL, target); if (rc != CSA_FAIL_NOADDR) return t->data.val = rc; /* The DNS lookup type corresponds to the IP version used by the client. */ @@ -1466,7 +1466,7 @@ else lookup_dnssec_authenticated = NULL; -switch (dns_lookup(&dnsa, target, type, NULL)) +switch (dns_lookup(dnsa, target, type, NULL)) { /* If something bad happened (most commonly DNS_AGAIN), defer. */ @@ -1476,7 +1476,7 @@ switch (dns_lookup(&dnsa, target, type, NULL)) /* If the query succeeded, scan the addresses and return the result. */ case DNS_SUCCEED: - rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ANSWERS, target); + rc = acl_verify_csa_address(dnsa, &dnss, RESET_ANSWERS, target); if (rc != CSA_FAIL_NOADDR) return t->data.val = rc; /* else fall through */ diff --git a/src/src/dkim.c b/src/src/dkim.c index 5883596a7..065170444 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -45,7 +45,7 @@ The return string is tainted, having come from off-site. uschar * dkim_exim_query_dns_txt(const uschar * name) { -dns_answer * dnsa = store_get(sizeof(dns_answer), TRUE); /* use tainted mem */ +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; rmark reset_point = store_mark(); gstring * g = NULL; diff --git a/src/src/functions.h b/src/src/functions.h index de03bb8d0..9f813d5ed 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -850,6 +850,15 @@ return g; } /******************************************************************************/ + +#define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__) + +static inline dns_answer * +store_get_dns_answer_trc(const uschar * func, unsigned line) +{ +return store_get_3(sizeof(dns_answer), TRUE, CCS func, line); /* use tainted mem */ +} + #endif /* !MACRO_PREDEF */ #endif /* _FUNCTIONS_H_ */ diff --git a/src/src/host.c b/src/src/host.c index 30d54b481..d84347cb1 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -177,7 +177,7 @@ const uschar *lname = name; uschar *adds; uschar **alist; struct hostent *yield; -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; DEBUG(D_host_lookup) @@ -231,7 +231,7 @@ if ((ipa = string_is_ip_address(lname, NULL)) != 0) else { int type = (af == AF_INET)? T_A:T_AAAA; - int rc = dns_lookup_timerwrap(&dnsa, lname, type, NULL); + int rc = dns_lookup_timerwrap(dnsa, lname, type, NULL); int count = 0; lookup_dnssec_authenticated = NULL; @@ -246,9 +246,9 @@ else case DNS_FAIL: *error_num = NO_RECOVERY; return NULL; } - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type) count++; yield = store_get(sizeof(struct hostent), FALSE); @@ -261,13 +261,13 @@ else yield->h_length = alen; yield->h_addr_list = CSS alist; - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type) { int x[4]; dns_address *da; - if (!(da = dns_address_from_rr(&dnsa, rr))) break; + if (!(da = dns_address_from_rr(dnsa, rr))) break; *alist++ = adds; for (int n = host_aton(da->address, x), i = 0; i < n; i++) { @@ -1651,7 +1651,7 @@ uschar **aliases; uschar buffer[256]; uschar *ordername; const uschar *list = host_lookup_order; -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE; @@ -1680,7 +1680,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) { dns_init(FALSE, FALSE, FALSE); /* dnssec ctrl by dns_dnssec_ok glbl */ dns_build_reverse(sender_host_address, buffer); - rc = dns_lookup_timerwrap(&dnsa, buffer, T_PTR, NULL); + rc = dns_lookup_timerwrap(dnsa, buffer, T_PTR, NULL); /* The first record we come across is used for the name; others are considered to be aliases. We have to scan twice, in order to find out the @@ -1695,16 +1695,16 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) int count = 0; int old_pool = store_pool; - sender_host_dnssec = dns_is_secure(&dnsa); + sender_host_dnssec = dns_is_secure(dnsa); DEBUG(D_dns) debug_printf("Reverse DNS security status: %s\n", sender_host_dnssec ? "DNSSEC verified (AD)" : "unverified"); store_pool = POOL_PERM; /* Save names in permanent storage */ - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR) count++; /* Get store for the list of aliases. For compatibility with @@ -1714,16 +1714,16 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) /* Re-scan and extract the names */ - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR) { uschar * s = store_get(ssize, TRUE); /* names are tainted */ /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ - if (dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, + if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, US (rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) { log_write(0, LOG_MAIN, "host name alias list truncated for %s", @@ -2309,17 +2309,17 @@ for (; i >= 0; i--) int type = types[i]; int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0) ? 500 : 0; /* Ensures v6/4 sort order */ - dns_answer dnsa; + dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; - int rc = dns_lookup_timerwrap(&dnsa, host->name, type, fully_qualified_name); + int rc = dns_lookup_timerwrap(dnsa, host->name, type, fully_qualified_name); lookup_dnssec_authenticated = !dnssec_request ? NULL - : dns_is_secure(&dnsa) ? US"yes" : US"no"; + : dns_is_secure(dnsa) ? US"yes" : US"no"; DEBUG(D_dns) if ( (dnssec_request || dnssec_require) - && !dns_is_secure(&dnsa) - && dns_is_aa(&dnsa) + && !dns_is_secure(dnsa) + && dns_is_aa(dnsa) ) debug_printf("DNS lookup of %.256s (A/AAAA) requested AD, but got AA\n", host->name); @@ -2347,7 +2347,7 @@ for (; i >= 0; i--) if (dnssec_request) { - if (dns_is_secure(&dnsa)) + if (dns_is_secure(dnsa)) { DEBUG(D_host_lookup) debug_printf("%s A DNSSEC\n", host->name); if (host->dnssec == DS_UNK) /* set in host_find_bydns() */ @@ -2378,11 +2378,11 @@ for (; i >= 0; i--) fully_qualified_name = NULL; - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type) { - dns_address * da = dns_address_from_rr(&dnsa, rr); + dns_address * da = dns_address_from_rr(dnsa, rr); DEBUG(D_host_lookup) if (!da) debug_printf("no addresses extracted from A6 RR for %s\n", @@ -2544,7 +2544,7 @@ host_item *h, *last; int rc = DNS_FAIL; int ind_type = 0; int yield; -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; BOOL dnssec_require = dnssec_d && match_isinlist(host->name, CUSS &dnssec_d->require, @@ -2586,18 +2586,18 @@ if (whichrrs & HOST_FIND_BY_SRV) dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; - rc = dns_lookup_timerwrap(&dnsa, temp_fully_qualified_name, ind_type, + rc = dns_lookup_timerwrap(dnsa, temp_fully_qualified_name, ind_type, CUSS &temp_fully_qualified_name); DEBUG(D_dns) if ((dnssec_request || dnssec_require) - && !dns_is_secure(&dnsa) - && dns_is_aa(&dnsa)) + && !dns_is_secure(dnsa) + && dns_is_aa(dnsa)) debug_printf("DNS lookup of %.256s (SRV) requested AD, but got AA\n", host->name); if (dnssec_request) { - if (dns_is_secure(&dnsa)) + if (dns_is_secure(dnsa)) { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } else { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } @@ -2609,7 +2609,7 @@ if (whichrrs & HOST_FIND_BY_SRV) /* On DNS failures, we give the "try again" error unless the domain is listed as one for which we continue. */ - if (rc == DNS_SUCCEED && dnssec_require && !dns_is_secure(&dnsa)) + if (rc == DNS_SUCCEED && dnssec_require && !dns_is_secure(dnsa)) { log_write(L_host_lookup_failed, LOG_MAIN, "dnssec fail on SRV for %.256s", host->name); @@ -2639,16 +2639,16 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) ind_type = T_MX; dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; - rc = dns_lookup_timerwrap(&dnsa, host->name, ind_type, fully_qualified_name); + rc = dns_lookup_timerwrap(dnsa, host->name, ind_type, fully_qualified_name); DEBUG(D_dns) if ( (dnssec_request || dnssec_require) - && !dns_is_secure(&dnsa) - && dns_is_aa(&dnsa)) + && !dns_is_secure(dnsa) + && dns_is_aa(dnsa)) debug_printf("DNS lookup of %.256s (MX) requested AD, but got AA\n", host->name); if (dnssec_request) - if (dns_is_secure(&dnsa)) + if (dns_is_secure(dnsa)) { DEBUG(D_host_lookup) debug_printf("%s MX DNSSEC\n", host->name); dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; @@ -2664,7 +2664,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) yield = HOST_FIND_FAILED; goto out; case DNS_SUCCEED: - if (!dnssec_require || dns_is_secure(&dnsa)) + if (!dnssec_require || dns_is_secure(dnsa)) break; DEBUG(D_host_lookup) debug_printf("dnssec fail on MX for %.256s", host->name); @@ -2758,9 +2758,9 @@ host which is not the primary hostname. */ last = NULL; /* Indicates that not even the first item is filled yet */ -for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); +for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type) { int precedence, weight; int port = PORT_NONE; @@ -2785,7 +2785,7 @@ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); /* Get the name of the host pointed to. */ - (void)dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, s, + (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, (DN_EXPAND_ARG4_TYPE)data, sizeof(data)); /* Check that we haven't already got this host on the chain; if we have, diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 5654b5615..64d0a5334 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -145,14 +145,14 @@ const uschar *outsep = CUS"\n"; const uschar *outsep2 = NULL; uschar *equals, *domain, *found; +dns_answer * dnsa = store_get_dns_answer(); +dns_scan dnss; + /* Because we're working in the search pool, we try to reclaim as much store as possible later, so we preallocate the result here */ gstring * yield = string_get(256); -dns_answer dnsa; -dns_scan dnss; - handle = handle; /* Keep picky compilers happy */ filename = filename; length = length; @@ -349,18 +349,18 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) { if (searchtype == T_ADDRESSES) searchtype = T_AAAA; else if (searchtype == T_AAAA) searchtype = T_A; - rc = dns_special_lookup(&dnsa, domain, searchtype, CUSS &found); + rc = dns_special_lookup(dnsa, domain, searchtype, CUSS &found); } else #endif - rc = dns_special_lookup(&dnsa, domain, type, CUSS &found); + rc = dns_special_lookup(dnsa, domain, type, CUSS &found); lookup_dnssec_authenticated = dnssec_mode==OK ? NULL - : dns_is_secure(&dnsa) ? US"yes" : US"no"; + : dns_is_secure(dnsa) ? US"yes" : US"no"; if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue; if ( rc != DNS_SUCCEED - || (dnssec_mode == DEFER && !dns_is_secure(&dnsa)) + || (dnssec_mode == DEFER && !dns_is_secure(dnsa)) ) { if (defer_mode == DEFER) @@ -377,15 +377,15 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* Search the returned records */ - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == searchtype) + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == searchtype) { if (*do_cache > rr->ttl) *do_cache = rr->ttl; if (type == T_A || type == T_AAAA || type == T_ADDRESSES) { - for (dns_address * da = dns_address_from_rr(&dnsa, rr); da; da = da->next) + for (dns_address * da = dns_address_from_rr(dnsa, rr); da; da = da->next) { if (yield->ptr) yield = string_catn(yield, outsep, 1); yield = string_cat(yield, da->address); @@ -500,7 +500,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* GETSHORT() has advanced the pointer to the target domain. */ - rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, + rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); /* If an overlong response was received, the data will have been @@ -521,7 +521,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) p += rc; yield = string_catn(yield, outsep2, 1); - rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, + rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); if (rc < 0) { diff --git a/src/src/spf.c b/src/src/spf.c index cf8176e8e..8b7bf4bc9 100644 --- a/src/src/spf.c +++ b/src/src/spf.c @@ -39,15 +39,15 @@ static SPF_dns_rr_t * SPF_dns_exim_lookup(SPF_dns_server_t *spf_dns_server, const char *domain, ns_type rr_type, int should_cache) { -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; SPF_dns_rr_t * spfrr; DEBUG(D_receive) debug_printf("SPF_dns_exim_lookup\n"); -if (dns_lookup(&dnsa, US domain, rr_type, NULL) == DNS_SUCCEED) - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) +if (dns_lookup(dnsa, US domain, rr_type, NULL) == DNS_SUCCEED) + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if ( rr->type == rr_type && Ustrncmp(rr->data+1, "v=spf1", 6) == 0) { diff --git a/src/src/structs.h b/src/src/structs.h index c40750045..bc6edc586 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -809,7 +809,7 @@ typedef struct { #ifdef SUPPORT_DANE BOOL dane:1; /* connection must do dane */ - dns_answer tlsa_dnsa; + dns_answer tlsa_dnsa; /* strictly, this should use tainted mem */ #endif } smtp_connect_args; diff --git a/src/src/verify.c b/src/src/verify.c index 60579668b..84c582cfa 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -3371,7 +3371,7 @@ one_check_dnsbl(uschar *domain, uschar *domain_txt, uschar *keydomain, uschar *prepend, uschar *iplist, BOOL bitmask, int match_type, int defer_return) { -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; tree_node *t; dnsbl_cache_block *cb; @@ -3424,7 +3424,7 @@ else /* Do the DNS lookup . */ HDEBUG(D_dnsbl) debug_printf("new DNS lookup for %s\n", query); - cb->rc = dns_basic_lookup(&dnsa, query, T_A); + cb->rc = dns_basic_lookup(dnsa, query, T_A); cb->text_set = FALSE; cb->text = NULL; cb->rhs = NULL; @@ -3444,11 +3444,11 @@ else if (cb->rc == DNS_SUCCEED) { dns_address ** addrp = &(cb->rhs); - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_A) { - dns_address *da = dns_address_from_rr(&dnsa, rr); + dns_address *da = dns_address_from_rr(dnsa, rr); if (da) { *addrp = da; @@ -3596,9 +3596,9 @@ if (cb->rc == DNS_SUCCEED) if (!cb->text_set) { cb->text_set = TRUE; - if (dns_basic_lookup(&dnsa, query, T_TXT) == DNS_SUCCEED) - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + if (dns_basic_lookup(dnsa, query, T_TXT) == DNS_SUCCEED) + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_TXT) { int len = (rr->data)[0];