aboutsummaryrefslogtreecommitdiff
path: root/mail/exim
diff options
context:
space:
mode:
authorDima Panov <fluffy@FreeBSD.org>2020-02-26 13:46:15 +0000
committerDima Panov <fluffy@FreeBSD.org>2020-02-26 13:46:15 +0000
commit48f01160022949207e9b594fa82966f0e4f17930 (patch)
treeab4eebe3106a3ea484c9862266d7c30b346ee342 /mail/exim
parent3fdf2a763eb36f889191e428e28fa788da562dea (diff)
downloadports-48f01160022949207e9b594fa82966f0e4f17930.tar.gz
ports-48f01160022949207e9b594fa82966f0e4f17930.zip
mail/exim: attempt to fix *taint* and auth issues
Bump PORTREVISION for master port to force all slaves rebuild Drop PORTREVISION for exim-postgresql slave in favor of master settings Adopt recent commits from Exim repo as numerated extra-patches till new maintenance release will be published: 19. SPF: fix result for case of only non-spf TXT RRs 20. Fix error logging for dynamically-loaded modules 21. heimdal auth: fix the increase of big_buffer size 22. Taint: hybrid checking mode 23. Fix taint hybrid-checking on BSD 24. TFO: even in binary built for modern Linux, handle error returned by old Linux kernel 25. Taint: slow-mode checking only 26. Auths: fix cyrus-sasl driver for gssapi use 27. GnuTLS: fix hanging callout connections
Notes
Notes: svn path=/head/; revision=527168
Diffstat (limited to 'mail/exim')
-rw-r--r--mail/exim/Makefile2
-rw-r--r--mail/exim/files/74_19-SPF-fix-result-for-case-of-only-non-spf-TXT-RRs.patch34
-rw-r--r--mail/exim/files/74_20-Fix-error-logging-for-dynamically-loaded-modules.patch70
-rw-r--r--mail/exim/files/74_21-heimdal-auth-fix-the-increase-of-big_buffer-size.patch116
-rw-r--r--mail/exim/files/74_22-Taint-hybrid-checking-mode.patch330
-rw-r--r--mail/exim/files/74_23-Fix-taint-hybrid-checking-on-BSD.patch83
-rw-r--r--mail/exim/files/74_24-TFO-even-in-binary-built-for-modern-Linux-handle-err.patch70
-rw-r--r--mail/exim/files/74_25-Taint-slow-mode-checking-only.patch127
-rw-r--r--mail/exim/files/74_26-Auths-fix-cyrus-sasl-driver-for-gssapi-use.patch50
-rw-r--r--mail/exim/files/74_27-GnuTLS-fix-hanging-callout-connections.patch70
10 files changed, 952 insertions, 0 deletions
diff --git a/mail/exim/Makefile b/mail/exim/Makefile
index 1935c29d3eca..bcd4d6300d53 100644
--- a/mail/exim/Makefile
+++ b/mail/exim/Makefile
@@ -3,6 +3,7 @@
PORTNAME= exim
PORTVERSION?= ${EXIM_VERSION}
+PORTREVISION?= 3
CATEGORIES= mail
MASTER_SITES= EXIM:exim
MASTER_SITE_SUBDIR= /exim4/:exim \
@@ -105,6 +106,7 @@ EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.conf
EXIM_VERSION= 4.93.0.4
SA_EXIM_VERSION=4.2.1
EXIM_INSTALL_ARG+= "-no_chown" "-no_symlink"
+EXTRA_PATCHES+= `${FIND} ${PATCHDIR} -name '74_*.patch'`
.if !defined(EXIMON_ONLY)
PLIST_SUB+= EXIM=""
diff --git a/mail/exim/files/74_19-SPF-fix-result-for-case-of-only-non-spf-TXT-RRs.patch b/mail/exim/files/74_19-SPF-fix-result-for-case-of-only-non-spf-TXT-RRs.patch
new file mode 100644
index 000000000000..71406b254ed2
--- /dev/null
+++ b/mail/exim/files/74_19-SPF-fix-result-for-case-of-only-non-spf-TXT-RRs.patch
@@ -0,0 +1,34 @@
+From dfb8f72b2237627b26767d1e803e8ed95ad659d2 Mon Sep 17 00:00:00 2001
+From: Wolfgang Breyha <wbreyha@gmx.net>
+Date: Tue, 7 Jan 2020 13:03:18 +0000
+Subject: [PATCH 19/21] SPF: fix result for case of only non-spf TXT RRs. Bug
+ 2499
+
+(cherry picked from commit 67794d2b830fc580f87b0635718d95e32b467be1)
+---
+ src/spf.c | 7 ++++++-
+ test/scripts/4600-SPF/4601 | 17 ++++++++---------
+ test/stdout/4601 | 11 ++++++-----
+ 3 files changed, 20 insertions(+), 15 deletions(-)
+
+diff --git src/spf.c src/spf.c
+index 8ead817b9..12b756b46 100644
+--- src/spf.c
++++ src/spf.c
+@@ -139,7 +139,12 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
+ srr.rr[found++] = (void *) s;
+ }
+
+-srr.num_rr = found;
++/* Did we filter out all TXT RRs? Return NO_DATA instead of SUCCESS with
++empty ANSWER section. */
++
++if (!(srr.num_rr = found))
++ srr.herrno = NO_DATA;
++
+ /* spfrr->rr must have been malloc()d for this */
+ SPF_dns_rr_dup(&spfrr, &srr);
+ return spfrr;
+--
+2.24.1
+
diff --git a/mail/exim/files/74_20-Fix-error-logging-for-dynamically-loaded-modules.patch b/mail/exim/files/74_20-Fix-error-logging-for-dynamically-loaded-modules.patch
new file mode 100644
index 000000000000..9dbabeed91ad
--- /dev/null
+++ b/mail/exim/files/74_20-Fix-error-logging-for-dynamically-loaded-modules.patch
@@ -0,0 +1,70 @@
+From 338f36842f10ef84e684dddf59819837fd7792a3 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Wed, 15 Jan 2020 10:40:20 +0000
+Subject: [PATCH 20/21] Fix error logging for dynamically-loaded modules. Bug
+ 2507
+
+(cherry picked from commits b1c673ddfa, 3fc07bd570)
+---
+ doc/ChangeLog | 5 +++++
+ src/drtables.c | 13 +++++++------
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git doc/ChangeLog doc/ChangeLog
+index 32febe1f3..6e26e2f11 100644
+--- doc/ChangeLog
++++ doc/ChangeLog
+@@ -49,6 +49,11 @@ JH/16 Fix the variables set by the gsasl authenticator. Previously a pointer to
+ library live data was being used, so the results became garbage. Make
+ copies while it is still usable.
+
++JH/19 Bug 2507: Modules: on handling a dynamic-module (lookups) open failure,
++ only retrieve the errormessage once. Previously two calls to dlerror()
++ were used, and the second one (for mainlog/paniclog) retrieved null
++ information.
++
+
+ Exim version 4.93
+ -----------------
+diff --git src/drtables.c src/drtables.c
+index 059756284..ca051bd20 100644
+--- src/drtables.c
++++ src/drtables.c
+@@ -740,10 +740,11 @@ init_lookup_list(void)
+
+ dl = dlopen(CS big_buffer, RTLD_NOW);// TJ was LAZY
+ if (dl == NULL) {
+- fprintf(stderr, "Error loading %s: %s\n", name, dlerror());
+- moduleerrors++;
+- log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, dlerror());
+- continue;
++ errormessage = dlerror();
++ fprintf(stderr, "Error loading %s: %s\n", name, errormessage);
++ log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormessage);
++ moduleerrors++;
++ continue;
+ }
+
+ /* FreeBSD nsdispatch() can trigger dlerror() errors about
+@@ -756,16 +757,16 @@ init_lookup_list(void)
+ info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
+ if ((errormsg = dlerror()) != NULL) {
+ fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
++ log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
+ dlclose(dl);
+ moduleerrors++;
+- log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
+ continue;
+ }
+ if (info->magic != LOOKUP_MODULE_INFO_MAGIC) {
+ fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
++ log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
+ dlclose(dl);
+ moduleerrors++;
+- log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
+ continue;
+ }
+
+--
+2.24.1
+
diff --git a/mail/exim/files/74_21-heimdal-auth-fix-the-increase-of-big_buffer-size.patch b/mail/exim/files/74_21-heimdal-auth-fix-the-increase-of-big_buffer-size.patch
new file mode 100644
index 000000000000..19723dd24099
--- /dev/null
+++ b/mail/exim/files/74_21-heimdal-auth-fix-the-increase-of-big_buffer-size.patch
@@ -0,0 +1,116 @@
+From bbeab68df3b3c2d5507b1fdca07509fdbb3ec5a1 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Tue, 14 Jan 2020 17:48:57 +0000
+Subject: [PATCH 21/21] heimdal auth: fix the increase of big_buffer size. Bug
+ 2501
+
+(cherry picked from commit 7a66b3afa11a70021297c176acf56831692be89a)
+---
+ doc/ChangeLog | 7 ++++++-
+ src/auths/README | 2 +-
+ src/auths/heimdal_gssapi.c | 10 ----------
+ src/macros.h | 13 ++++++++++---
+ src/readconf.c | 1 +
+ 5 files changed, 18 insertions(+), 15 deletions(-)
+
+diff --git doc/ChangeLog doc/ChangeLog
+index 6e26e2f11..f112fc9bf 100644
+--- doc/ChangeLog
++++ doc/ChangeLog
+@@ -9,7 +9,7 @@ This is not an official release. It is just a branch, collecting
+ proposed bugfixes. Depending on your environment the fixes may be
+ necessary to build and/or run Exim successfully.
+
+-JH/05 Regard command-line receipients as tainted.
++JH/05 Regard command-line recipients as tainted.
+
+ JH/07 Bug 2489: Fix crash in the "pam" expansion condition. It seems that the
+ PAM library frees one of the arguments given to it, despite the
+@@ -54,6 +54,11 @@ JH/19 Bug 2507: Modules: on handling a dynamic-module (lookups) open failure,
+ were used, and the second one (for mainlog/paniclog) retrieved null
+ information.
+
++JH/21 Bug 2501: Fix init call in the heimdal authenticator. Previously it
++ adjusted the size of a major service buffer; this failed because the
++ buffer was in use at the time. Change to a compile-time increase in the
++ buffer size, when this authenticator is compiled into exim.
++
+
+ Exim version 4.93
+ -----------------
+diff --git src/auths/README src/auths/README
+index d4f125c30..66bdcdcf8 100644
+--- src/auths/README
++++ src/auths/README
+@@ -34,7 +34,7 @@ instance block for this configured mechanism. It must set the flags called
+ the server and/or client functions are available for this authenticator.
+ Typically this depends on whether server or client configuration options have
+ been set, but it is also possible to have an authenticator that has only one of
+-the server or client functions.
++the server or client functions. The function may not touch big_buffer.
+
+ SERVER AUTHENTICATION
+
+diff --git src/auths/heimdal_gssapi.c src/auths/heimdal_gssapi.c
+index 3dfcb8c6a..523f7c69a 100644
+--- src/auths/heimdal_gssapi.c
++++ src/auths/heimdal_gssapi.c
+@@ -200,16 +200,6 @@ if (krc)
+
+ krb5_free_context(context);
+
+-/* RFC 4121 section 5.2, SHOULD support 64K input buffers */
+-if (big_buffer_size < (64 * 1024))
+- {
+- uschar *newbuf;
+- big_buffer_size = 64 * 1024;
+- newbuf = store_malloc(big_buffer_size);
+- store_free(big_buffer);
+- big_buffer = newbuf;
+- }
+-
+ ablock->server = TRUE;
+ }
+
+diff --git src/macros.h src/macros.h
+index 76913d64e..4e6b1b8a9 100644
+--- src/macros.h
++++ src/macros.h
+@@ -152,12 +152,19 @@ enough to hold all the headers from a normal kind of message. */
+ into big_buffer_size and in some circumstances increased. It should be at least
+ as long as the maximum path length. */
+
+-#if defined PATH_MAX && PATH_MAX > 16384
++#ifdef AUTH_HEIMDAL_GSSAPI
++ /* RFC 4121 section 5.2, SHOULD support 64K input buffers */
++# define __BIG_BUFFER_SIZE 65536
++#else
++# define __BIG_BUFFER_SIZE 16384
++#endif
++
++#if defined PATH_MAX && PATH_MAX > __BIG_BUFFER_SIZE
+ # define BIG_BUFFER_SIZE PATH_MAX
+-#elif defined MAXPATHLEN && MAXPATHLEN > 16384
++#elif defined MAXPATHLEN && MAXPATHLEN > __BIG_BUFFER_SIZE
+ # define BIG_BUFFER_SIZE MAXPATHLEN
+ #else
+-# define BIG_BUFFER_SIZE 16384
++# define BIG_BUFFER_SIZE __BIG_BUFFER_SIZE
+ #endif
+
+ /* header size of pipe content
+diff --git src/readconf.c src/readconf.c
+index 0233019cf..62cfcfbf9 100644
+--- src/readconf.c
++++ src/readconf.c
+@@ -3788,6 +3788,7 @@ while ((buffer = get_config_line()) != NULL)
+ if (!d->driver_name)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "no driver defined for %s \"%s\"", class, d->name);
++ /* s is using big_buffer, so this call had better not */
+ (d->info->init)(d);
+ d = NULL;
+ }
+--
+2.24.1
+
diff --git a/mail/exim/files/74_22-Taint-hybrid-checking-mode.patch b/mail/exim/files/74_22-Taint-hybrid-checking-mode.patch
new file mode 100644
index 000000000000..dc63289e1052
--- /dev/null
+++ b/mail/exim/files/74_22-Taint-hybrid-checking-mode.patch
@@ -0,0 +1,330 @@
+From 1ccd26e24267ffa0c40b70c2c3282481fe4977c7 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 16 Jan 2020 14:12:56 +0000
+Subject: [PATCH 22/22] Taint: hybrid checking mode
+
+(cherry picked from commit 36eb5d3d77426d8cbf4243ea752f8d8cd1d5c682)
+---
+ doc/ChangeLog | 8 +++++
+ exim_monitor/em_version.c | 2 ++
+ src/functions.h | 58 +++++++++++++++++++++++++++++++-
+ src/globals.c | 1 +
+ src/globals.h | 1 +
+ src/mytypes.h | 62 +++++------------------------------
+ src/store.c | 40 +++++++++++++++-------
+ 7 files changed, 107 insertions(+), 65 deletions(-)
+
+diff --git doc/ChangeLog doc/ChangeLog
+index f112fc9bf..508b8fa49 100644
+--- doc/ChangeLog
++++ doc/ChangeLog
+@@ -59,6 +59,14 @@ JH/21 Bug 2501: Fix init call in the heimdal authenticator. Previously it
+ buffer was in use at the time. Change to a compile-time increase in the
+ buffer size, when this authenticator is compiled into exim.
+
++JH/22 Taint checking: move to a hybrid approach for checking. Previously, one
++ of two ways was used, depending on a build-time flag. The fast method
++ relied on assumptions about the OS and libc malloc, which were known to
++ not hold for the BSD-derived platforms, and discovered to not hold for
++ 32-bit Linux either. In fact the glibc documentation describes cases
++ where these assumptions do not hold. The new implementation tests for
++ the situation arising and actively switches over from fast to safe mode.
++
+
+ Exim version 4.93
+ -----------------
+diff --git exim_monitor/em_version.c exim_monitor/em_version.c
+index 52c55a4a3..9b9c7d417 100644
+--- exim_monitor/em_version.c
++++ exim_monitor/em_version.c
+@@ -5,6 +5,8 @@
+ /* Copyright (c) University of Cambridge 1995 - 2018 */
+ /* See the file NOTICE for conditions of use and distribution. */
+
++#define EM_VERSION_C
++
+ #include "mytypes.h"
+ #include "store.h"
+ #include "macros.h"
+diff --git src/functions.h src/functions.h
+index 87d1a04d8..0b5905562 100644
+--- src/functions.h
++++ src/functions.h
+@@ -187,6 +187,7 @@ extern void deliver_succeeded(address_item *);
+ extern uschar *deliver_get_sender_address (uschar *id);
+ extern void delivery_re_exec(int);
+
++extern void die_tainted(const uschar *, const uschar *, int);
+ extern BOOL directory_make(const uschar *, const uschar *, int, BOOL);
+ #ifndef DISABLE_DKIM
+ extern uschar *dkim_exim_query_dns_txt(const uschar *);
+@@ -602,6 +603,61 @@ extern BOOL write_chunk(transport_ctx *, uschar *, int);
+ extern ssize_t write_to_fd_buf(int, const uschar *, size_t);
+
+
++/******************************************************************************/
++/* Predicate: if an address is in a tainted pool.
++By extension, a variable pointing to this address is tainted.
++*/
++
++static inline BOOL
++is_tainted(const void * p)
++{
++#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) || defined(EM_VERSION_C)
++return FALSE;
++
++#else
++extern BOOL is_tainted_fn(const void *);
++extern void * tainted_base, * tainted_top;
++
++return f.taint_check_slow
++ ? is_tainted_fn(p) : p >= tainted_base && p < tainted_top;
++#endif
++}
++
++/******************************************************************************/
++/* String functions */
++static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line)
++{
++#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
++if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcat", CUS func, line);
++#endif
++return US strcat(CS dst, CCS src);
++}
++static inline uschar * __Ustrcpy(uschar * dst, const uschar * src, const char * func, int line)
++{
++#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
++if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcpy", CUS func, line);
++#endif
++return US strcpy(CS dst, CCS src);
++}
++static inline uschar * __Ustrncat(uschar * dst, const uschar * src, size_t n, const char * func, int line)
++{
++#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
++if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncat", CUS func, line);
++#endif
++return US strncat(CS dst, CCS src, n);
++}
++static inline uschar * __Ustrncpy(uschar * dst, const uschar * src, size_t n, const char * func, int line)
++{
++#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
++if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncpy", CUS func, line);
++#endif
++return US strncpy(CS dst, CCS src, n);
++}
++/*XXX will likely need unchecked copy also */
++
++
++/******************************************************************************/
++
+ #if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
+ /* exim_chown - in some NFSv4 setups *seemes* to be an issue with
+ chown(<exim-uid>, <exim-gid>).
+@@ -634,8 +690,8 @@ exim_chown(const uschar *name, uid_t owner, gid_t group)
+ return chown(CCS name, owner, group)
+ ? exim_chown_failure(-1, name, owner, group) : 0;
+ }
+-
+ #endif /* !MACRO_PREDEF && !COMPILE_UTILITY */
++
+ /******************************************************************************/
+ /* String functions */
+
+diff --git src/globals.c src/globals.c
+index 85a25a7f2..72449229e 100644
+--- src/globals.c
++++ src/globals.c
+@@ -311,6 +311,7 @@ struct global_flags f =
+ .synchronous_delivery = FALSE,
+ .system_filtering = FALSE,
+
++ .taint_check_slow = FALSE,
+ .tcp_fastopen_ok = FALSE,
+ .tcp_in_fastopen = FALSE,
+ .tcp_in_fastopen_data = FALSE,
+diff --git src/globals.h src/globals.h
+index ca342acc2..ac7bb8ef3 100644
+--- src/globals.h
++++ src/globals.h
+@@ -272,6 +272,7 @@ extern struct global_flags {
+ BOOL synchronous_delivery :1; /* TRUE if -odi is set */
+ BOOL system_filtering :1; /* TRUE when running system filter */
+
++ BOOL taint_check_slow :1; /* malloc/mmap are not returning distinct ranges */
+ BOOL tcp_fastopen_ok :1; /* appears to be supported by kernel */
+ BOOL tcp_in_fastopen :1; /* conn usefully used fastopen */
+ BOOL tcp_in_fastopen_data :1; /* fastopen carried data */
+diff --git src/mytypes.h src/mytypes.h
+index ceb9f1b55..e31ee8c1a 100644
+--- src/mytypes.h
++++ src/mytypes.h
+@@ -100,19 +100,15 @@ functions that are called quite often; for other calls to external libraries
+ #define Uread(f,b,l) read(f,CS(b),l)
+ #define Urename(s,t) rename(CCS(s),CCS(t))
+ #define Ustat(s,t) stat(CCS(s),t)
+-#define Ustrcat(s,t) __Ustrcat(s, CUS(t), __FUNCTION__, __LINE__)
+ #define Ustrchr(s,n) US strchr(CCS(s),n)
+ #define CUstrchr(s,n) CUS strchr(CCS(s),n)
+ #define CUstrerror(n) CUS strerror(n)
+ #define Ustrcmp(s,t) strcmp(CCS(s),CCS(t))
+-#define Ustrcpy(s,t) __Ustrcpy(s, CUS(t), __FUNCTION__, __LINE__)
+ #define Ustrcpy_nt(s,t) strcpy(CS s, CCS t) /* no taint check */
+ #define Ustrcspn(s,t) strcspn(CCS(s),CCS(t))
+ #define Ustrftime(s,m,f,t) strftime(CS(s),m,f,t)
+ #define Ustrlen(s) (int)strlen(CCS(s))
+-#define Ustrncat(s,t,n) __Ustrncat(s, CUS(t),n, __FUNCTION__, __LINE__)
+ #define Ustrncmp(s,t,n) strncmp(CCS(s),CCS(t),n)
+-#define Ustrncpy(s,t,n) __Ustrncpy(s, CUS(t),n, __FUNCTION__, __LINE__)
+ #define Ustrncpy_nt(s,t,n) strncpy(CS s, CCS t, n) /* no taint check */
+ #define Ustrpbrk(s,t) strpbrk(CCS(s),CCS(t))
+ #define Ustrrchr(s,n) US strrchr(CCS(s),n)
+@@ -125,57 +121,17 @@ functions that are called quite often; for other calls to external libraries
+ #define Ustrtoul(s,t,b) strtoul(CCS(s),CSS(t),b)
+ #define Uunlink(s) unlink(CCS(s))
+
+-extern void die_tainted(const uschar *, const uschar *, int);
+-
+-/* Predicate: if an address is in a tainted pool.
+-By extension, a variable pointing to this address is tainted.
+-*/
+-
+-static inline BOOL
+-is_tainted(const void * p)
+-{
+-#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
+-return FALSE;
+-
+-#elif defined(TAINT_CHECK_SLOW)
+-extern BOOL is_tainted_fn(const void *);
+-return is_tainted_fn(p);
+-
++#ifdef EM_VERSION_C
++# define Ustrcat(s,t) strcat(CS(s), CCS(t))
++# define Ustrcpy(s,t) strcpy(CS(s), CCS(t))
++# define Ustrncat(s,t,n) strncat(CS(s), CCS(t), n)
++# define Ustrncpy(s,t,n) strncpy(CS(s), CCS(t), n)
+ #else
+-extern void * tainted_base, * tainted_top;
+-return p >= tainted_base && p < tainted_top;
+-#endif
+-}
+-
+-static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line)
+-{
+-#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
+-if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcat", CUS func, line);
+-#endif
+-return US strcat(CS dst, CCS src);
+-}
+-static inline uschar * __Ustrcpy(uschar * dst, const uschar * src, const char * func, int line)
+-{
+-#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
+-if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcpy", CUS func, line);
+-#endif
+-return US strcpy(CS dst, CCS src);
+-}
+-static inline uschar * __Ustrncat(uschar * dst, const uschar * src, size_t n, const char * func, int line)
+-{
+-#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
+-if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncat", CUS func, line);
+-#endif
+-return US strncat(CS dst, CCS src, n);
+-}
+-static inline uschar * __Ustrncpy(uschar * dst, const uschar * src, size_t n, const char * func, int line)
+-{
+-#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF)
+-if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncpy", CUS func, line);
++# define Ustrcat(s,t) __Ustrcat(s, CUS(t), __FUNCTION__, __LINE__)
++# define Ustrcpy(s,t) __Ustrcpy(s, CUS(t), __FUNCTION__, __LINE__)
++# define Ustrncat(s,t,n) __Ustrncat(s, CUS(t), n, __FUNCTION__, __LINE__)
++# define Ustrncpy(s,t,n) __Ustrncpy(s, CUS(t), n, __FUNCTION__, __LINE__)
+ #endif
+-return US strncpy(CS dst, CCS src, n);
+-}
+-/*XXX will likely need unchecked copy also */
+
+ #endif
+ /* End of mytypes.h */
+diff --git src/store.c src/store.c
+index a06e1c19a..692a993e9 100644
+--- src/store.c
++++ src/store.c
+@@ -162,8 +162,14 @@ static void internal_tainted_free(storeblock *, const char *, int linenumber);
+
+ /******************************************************************************/
+
+-/* Slower version check, for use when platform intermixes malloc and mmap area
+-addresses. */
++/* Test if a pointer refers to tainted memory.
++
++Slower version check, for use when platform intermixes malloc and mmap area
++addresses. Test against the current-block of all tainted pools first, then all
++blocks of all tainted pools.
++
++Return: TRUE iff tainted
++*/
+
+ BOOL
+ is_tainted_fn(const void * p)
+@@ -171,23 +177,20 @@ is_tainted_fn(const void * p)
+ storeblock * b;
+ int pool;
+
+-for (pool = 0; pool < nelem(chainbase); pool++)
++for (pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
+ if ((b = current_block[pool]))
+ {
+- char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
+- if (CS p >= bc && CS p <= bc + b->length) goto hit;
++ uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
++ if (US p >= bc && US p <= bc + b->length) return TRUE;
+ }
+
+-for (pool = 0; pool < nelem(chainbase); pool++)
++for (pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
+ for (b = chainbase[pool]; b; b = b->next)
+ {
+- char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
+- if (CS p >= bc && CS p <= bc + b->length) goto hit;
++ uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
++ if (US p >= bc && US p <= bc + b->length) return TRUE;
+ }
+ return FALSE;
+-
+-hit:
+-return pool >= POOL_TAINT_BASE;
+ }
+
+
+@@ -198,6 +201,13 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n",
+ msg, func, line);
+ }
+
++static void
++use_slow_taint_check(void)
++{
++DEBUG(D_any) debug_printf("switching to slow-mode taint checking\n");
++f.taint_check_slow = TRUE;
++}
++
+
+ /*************************************************
+ * Get a block from the current pool *
+@@ -820,6 +830,14 @@ if (!(yield = malloc((size_t)size)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: "
+ "called from line %d in %s", size, linenumber, func);
+
++/* If malloc ever returns apparently tainted memory, which glibc
++malloc will as it uses mmap for larger requests, we must switch to
++the slower checking for tainting (checking an address against all
++the tainted pool block spans, rather than just the mmap span) */
++
++if (!f.taint_check_slow && is_tainted(yield))
++ use_slow_taint_check();
++
+ return store_alloc_tail(yield, size, func, linenumber, US"Malloc");
+ }
+
+--
+2.24.1
+
diff --git a/mail/exim/files/74_23-Fix-taint-hybrid-checking-on-BSD.patch b/mail/exim/files/74_23-Fix-taint-hybrid-checking-on-BSD.patch
new file mode 100644
index 000000000000..792bf757e144
--- /dev/null
+++ b/mail/exim/files/74_23-Fix-taint-hybrid-checking-on-BSD.patch
@@ -0,0 +1,83 @@
+From ccf4e2396b27b519174aa79552e61d11aafbdc36 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Fri, 17 Jan 2020 21:55:11 +0000
+Subject: [PATCH 23/23] Fix taint hybrid-checking on BSD
+
+(cherry-picked from commit 677481d4fc)
+Broken-by: 1ccd26e242
+---
+ src/store.c | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+diff --git src/store.c src/store.c
+index 692a993e9..6118ef28d 100644
+--- src/store.c
++++ src/store.c
+@@ -175,16 +175,15 @@ BOOL
+ is_tainted_fn(const void * p)
+ {
+ storeblock * b;
+-int pool;
+
+-for (pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
++for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
+ if ((b = current_block[pool]))
+ {
+ uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
+ if (US p >= bc && US p <= bc + b->length) return TRUE;
+ }
+
+-for (pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
++for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
+ for (b = chainbase[pool]; b; b = b->next)
+ {
+ uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
+@@ -204,10 +203,28 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n",
+ static void
+ use_slow_taint_check(void)
+ {
++#ifndef COMPILE_UTILITY
+ DEBUG(D_any) debug_printf("switching to slow-mode taint checking\n");
++#endif
+ f.taint_check_slow = TRUE;
+ }
+
++static void
++verify_all_untainted(void)
++{
++for (int pool = 0; pool < POOL_TAINT_BASE; pool++)
++ for (storeblock * b = chainbase[pool]; b; b = b->next)
++ {
++ uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
++ if (is_tainted(bc))
++ {
++ use_slow_taint_check();
++ return;
++ }
++ }
++}
++
++
+
+ /*************************************************
+ * Get a block from the current pool *
+@@ -740,7 +757,7 @@ int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
+ BOOL release_ok = !tainted && store_last_get[pool] == block;
+ uschar * newtext;
+
+-#ifndef MACRO_PREDEF
++#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
+ if (is_tainted(block) != tainted)
+ die_tainted(US"store_newblock", CUS func, linenumber);
+ #endif
+@@ -799,6 +816,7 @@ if (!(yield = mmap(NULL, (size_t)size,
+
+ if (yield < tainted_base) tainted_base = yield;
+ if ((top = US yield + size) > tainted_top) tainted_top = top;
++if (!f.taint_check_slow) use_slow_taint_check();
+
+ return store_alloc_tail(yield, size, func, line, US"Mmap");
+ }
+--
+2.24.1
+
diff --git a/mail/exim/files/74_24-TFO-even-in-binary-built-for-modern-Linux-handle-err.patch b/mail/exim/files/74_24-TFO-even-in-binary-built-for-modern-Linux-handle-err.patch
new file mode 100644
index 000000000000..2a0f74fe0fe6
--- /dev/null
+++ b/mail/exim/files/74_24-TFO-even-in-binary-built-for-modern-Linux-handle-err.patch
@@ -0,0 +1,70 @@
+From 4ce411ffa737df738e18e1e7b008ad3d3ac5c398 Mon Sep 17 00:00:00 2001
+From: Brian Foley <bpfoley@google.com>
+Date: Sat, 25 Jan 2020 15:27:49 +0000
+Subject: [PATCH 24/25] TFO: even in binary built for modern Linux, handle
+ error returned by old Linux kernel. Bug 2518
+
+(cherry picked from commit c3da38a12a2372a7f6a48be97ebfd80aeceda828)
+---
+ src/ip.c | 40 +++++++++++++++++++++++-----------------
+ 1 file changed, 23 insertions(+), 17 deletions(-)
+
+diff --git src/ip.c src/ip.c
+index 70e3e2064..43ca6a1c9 100644
+--- src/ip.c
++++ src/ip.c
+@@ -269,28 +269,34 @@ if (fastopen_blob && f.tcp_fastopen_ok)
+ /*XXX also seen on successful TFO, sigh */
+ tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA;
+ }
+- else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */
++ else switch (errno)
++ {
++ case EINPROGRESS: /* expected if we had no cookie for peer */
+ /* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */
+ /* apparently no visibility of the diffference at this point */
+ /* seen for with-data, proper TFO opt, cookie-req */
+ /* with netwk delay, post-conn tcp_info sees unacked 1 for R, 2 for C; code in smtp_out.c */
+ /* ? older Experimental TFO option behaviour ? */
+- { /* queue unsent data */
+- DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n",
+- fastopen_blob->len > 0 ? "with" : "no");
+- if (!fastopen_blob->data)
+- {
+- tcp_out_fastopen = TFO_ATTEMPTED_NODATA; /* we tried; unknown if useful yet */
+- rc = 0;
+- }
+- else
+- rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
+- }
+- else if(errno == EOPNOTSUPP)
+- {
+- DEBUG(D_transport)
+- debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
+- goto legacy_connect;
++ DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n",
++ fastopen_blob->len > 0 ? "with" : "no");
++ if (!fastopen_blob->data)
++ {
++ tcp_out_fastopen = TFO_ATTEMPTED_NODATA; /* we tried; unknown if useful yet */
++ rc = 0;
++ }
++ else /* queue unsent data */
++ rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
++ break;
++
++ case EOPNOTSUPP:
++ DEBUG(D_transport)
++ debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
++ goto legacy_connect;
++
++ case EPIPE:
++ DEBUG(D_transport)
++ debug_printf("Tried TCP Fast Open but kernel too old to support it\n");
++ goto legacy_connect;
+ }
+ # endif
+ # ifdef EXIM_TFO_CONNECTX
+--
+2.24.1
+
diff --git a/mail/exim/files/74_25-Taint-slow-mode-checking-only.patch b/mail/exim/files/74_25-Taint-slow-mode-checking-only.patch
new file mode 100644
index 000000000000..a2ea80741eba
--- /dev/null
+++ b/mail/exim/files/74_25-Taint-slow-mode-checking-only.patch
@@ -0,0 +1,127 @@
+From 69b2f92c0b5da548eaafe4813319f4647fa9c19a Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 30 Jan 2020 11:38:30 +0000
+Subject: [PATCH 25/25] Taint: slow-mode checking only
+
+(cherry-picked from 4381d60bc9)
+---
+ doc/ChangeLog | 10 +++-------
+ src/functions.h | 5 +----
+ src/store.c | 43 -------------------------------------------
+ 3 files changed, 4 insertions(+), 54 deletions(-)
+
+diff --git doc/ChangeLog doc/ChangeLog
+index 508b8fa49..be7ec2a8e 100644
+--- doc/ChangeLog
++++ doc/ChangeLog
+@@ -59,13 +59,9 @@ JH/21 Bug 2501: Fix init call in the heimdal authenticator. Previously it
+ buffer was in use at the time. Change to a compile-time increase in the
+ buffer size, when this authenticator is compiled into exim.
+
+-JH/22 Taint checking: move to a hybrid approach for checking. Previously, one
+- of two ways was used, depending on a build-time flag. The fast method
+- relied on assumptions about the OS and libc malloc, which were known to
+- not hold for the BSD-derived platforms, and discovered to not hold for
+- 32-bit Linux either. In fact the glibc documentation describes cases
+- where these assumptions do not hold. The new implementation tests for
+- the situation arising and actively switches over from fast to safe mode.
++JH/22 Taint-checking: move to safe-mode taint checking on all platforms. The
++ previous fast-mode was untenable in the face of glibs using mmap to
++ support larger malloc requests.
+
+
+ Exim version 4.93
+diff --git src/functions.h src/functions.h
+index 0b5905562..af633851b 100644
+--- src/functions.h
++++ src/functions.h
+@@ -616,10 +616,7 @@ return FALSE;
+
+ #else
+ extern BOOL is_tainted_fn(const void *);
+-extern void * tainted_base, * tainted_top;
+-
+-return f.taint_check_slow
+- ? is_tainted_fn(p) : p >= tainted_base && p < tainted_top;
++return is_tainted_fn(p);
+ #endif
+ }
+
+diff --git src/store.c src/store.c
+index 6118ef28d..c81744a7b 100644
+--- src/store.c
++++ src/store.c
+@@ -102,13 +102,6 @@ static storeblock *current_block[NPOOLS];
+ static void *next_yield[NPOOLS];
+ static int yield_length[NPOOLS] = { -1, -1, -1, -1, -1, -1 };
+
+-/* The limits of the tainted pools. Tracking these on new allocations enables
+-a fast is_tainted implementation. We assume the kernel only allocates mmaps using
+-one side or the other of data+heap, not both. */
+-
+-void * tainted_base = (void *)-1;
+-void * tainted_top = (void *)0;
+-
+ /* pool_malloc holds the amount of memory used by the store pools; this goes up
+ and down as store is reset or released. nonpool_malloc is the total got by
+ malloc from other calls; this doesn't go down because it is just freed by
+@@ -200,30 +193,6 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n",
+ msg, func, line);
+ }
+
+-static void
+-use_slow_taint_check(void)
+-{
+-#ifndef COMPILE_UTILITY
+-DEBUG(D_any) debug_printf("switching to slow-mode taint checking\n");
+-#endif
+-f.taint_check_slow = TRUE;
+-}
+-
+-static void
+-verify_all_untainted(void)
+-{
+-for (int pool = 0; pool < POOL_TAINT_BASE; pool++)
+- for (storeblock * b = chainbase[pool]; b; b = b->next)
+- {
+- uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
+- if (is_tainted(bc))
+- {
+- use_slow_taint_check();
+- return;
+- }
+- }
+-}
+-
+
+
+ /*************************************************
+@@ -814,10 +783,6 @@ if (!(yield = mmap(NULL, (size_t)size,
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to mmap %d bytes of memory: "
+ "called from line %d of %s", size, line, func);
+
+-if (yield < tainted_base) tainted_base = yield;
+-if ((top = US yield + size) > tainted_top) tainted_top = top;
+-if (!f.taint_check_slow) use_slow_taint_check();
+-
+ return store_alloc_tail(yield, size, func, line, US"Mmap");
+ }
+
+@@ -848,14 +813,6 @@ if (!(yield = malloc((size_t)size)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: "
+ "called from line %d in %s", size, linenumber, func);
+
+-/* If malloc ever returns apparently tainted memory, which glibc
+-malloc will as it uses mmap for larger requests, we must switch to
+-the slower checking for tainting (checking an address against all
+-the tainted pool block spans, rather than just the mmap span) */
+-
+-if (!f.taint_check_slow && is_tainted(yield))
+- use_slow_taint_check();
+-
+ return store_alloc_tail(yield, size, func, linenumber, US"Malloc");
+ }
+
+--
+2.24.1
+
diff --git a/mail/exim/files/74_26-Auths-fix-cyrus-sasl-driver-for-gssapi-use.patch b/mail/exim/files/74_26-Auths-fix-cyrus-sasl-driver-for-gssapi-use.patch
new file mode 100644
index 000000000000..0a21347a8b3f
--- /dev/null
+++ b/mail/exim/files/74_26-Auths-fix-cyrus-sasl-driver-for-gssapi-use.patch
@@ -0,0 +1,50 @@
+From 59bcc75f56ffeb9fa220f1eb53d45bf254258ac7 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 13 Feb 2020 14:08:31 +0000
+Subject: [PATCH 26/27] Auths: fix cyrus-sasl driver for gssapi use. Bug 2524
+
+Broken-by: c0fb53b74e
+Cherry-picked from: 5c329a4388
+---
+ doc/ChangeLog | 6 ++++++
+ src/auths/cyrus_sasl.c | 6 +++---
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git doc/ChangeLog doc/ChangeLog
+index be7ec2a8e..97fe878dc 100644
+--- doc/ChangeLog
++++ doc/ChangeLog
+@@ -63,6 +63,12 @@ JH/22 Taint-checking: move to safe-mode taint checking on all platforms. The
+ previous fast-mode was untenable in the face of glibs using mmap to
+ support larger malloc requests.
+
++JH/24 Bug 2524: fix the cyrus_sasl auth driver gssapi usage. A previous fix
++ had introduced a string-copy (for ensuring NUL-termination) which was not
++ appropriate for that case, which can include embedded NUL bytes in the
++ block of data. Investigation showed the copy to actually be needless, the
++ data being length-specified.
++
+
+ Exim version 4.93
+ -----------------
+diff --git src/auths/cyrus_sasl.c src/auths/cyrus_sasl.c
+index 480010bab..19416a1bb 100644
+--- src/auths/cyrus_sasl.c
++++ src/auths/cyrus_sasl.c
+@@ -347,10 +347,10 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; )
+ }
+ else
+ {
+- /* make sure that we have a null-terminated string */
+- out2 = string_copyn(output, outlen);
++ /* auth_get_data() takes a length-specfied block of binary
++ which can include zeroes; no terminating NUL is needed */
+
+- if ((rc = auth_get_data(&input, out2, outlen)) != OK)
++ if ((rc = auth_get_data(&input, output, outlen)) != OK)
+ {
+ /* we couldn't get the data, so free up the library before
+ * returning whatever error we get */
+--
+2.24.1
+
diff --git a/mail/exim/files/74_27-GnuTLS-fix-hanging-callout-connections.patch b/mail/exim/files/74_27-GnuTLS-fix-hanging-callout-connections.patch
new file mode 100644
index 000000000000..82f3d749c795
--- /dev/null
+++ b/mail/exim/files/74_27-GnuTLS-fix-hanging-callout-connections.patch
@@ -0,0 +1,70 @@
+From 26b045604bd574a6d93868ed437c08503c67d289 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 13 Feb 2020 16:52:52 +0000
+Subject: [PATCH 27/27] GnuTLS: fix hanging callout connections
+
+Broken-by: 925ac8e4f1
+Cherry-picked from: bd95ffc2ba
+---
+ doc/ChangeLog | 5 +++++
+ src/tls-gnu.c | 11 +++++++----
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git doc/ChangeLog doc/ChangeLog
+index 97fe878dc..d9833c8e1 100644
+--- doc/ChangeLog
++++ doc/ChangeLog
+@@ -69,6 +69,11 @@ JH/24 Bug 2524: fix the cyrus_sasl auth driver gssapi usage. A previous fix
+ block of data. Investigation showed the copy to actually be needless, the
+ data being length-specified.
+
++JH/25 Fix use of concurrent TLS connections under GnuTLS. When a callout was
++ done during a receiving connection, and both used TLS, global info was
++ used rather than per-connection info for tracking the state of data
++ queued for transmission. This could result in a connection hang.
++
+
+ Exim version 4.93
+ -----------------
+diff --git src/tls-gnu.c src/tls-gnu.c
+index fc426a251..574dcafd9 100644
+--- src/tls-gnu.c
++++ src/tls-gnu.c
+@@ -181,6 +181,10 @@ typedef struct exim_gnutls_state {
+ BOOL peer_dane_verified;
+ BOOL trigger_sni_changes;
+ BOOL have_set_peerdn;
++#ifdef SUPPORT_CORK
++ BOOL corked:1;
++#endif
++
+ const struct host_item *host; /* NULL if server */
+ gnutls_x509_crt_t peercert;
+ uschar *peerdn;
+@@ -3309,9 +3313,8 @@ ssize_t outbytes;
+ size_t left = len;
+ exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server;
+ #ifdef SUPPORT_CORK
+-static BOOL corked = FALSE;
+
+-if (more && !corked) gnutls_record_cork(state->session);
++if (more && !state->corked) gnutls_record_cork(state->session);
+ #endif
+
+ DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__,
+@@ -3352,10 +3355,10 @@ if (len > INT_MAX)
+ }
+
+ #ifdef SUPPORT_CORK
+-if (more != corked)
++if (more != state->corked)
+ {
+ if (!more) (void) gnutls_record_uncork(state->session, 0);
+- corked = more;
++ state->corked = more;
+ }
+ #endif
+
+--
+2.24.1
+