From 48f01160022949207e9b594fa82966f0e4f17930 Mon Sep 17 00:00:00 2001 From: Dima Panov Date: Wed, 26 Feb 2020 13:46:15 +0000 Subject: [PATCH] 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 --- mail/exim-postgresql/Makefile | 1 - mail/exim/Makefile | 2 + ...ult-for-case-of-only-non-spf-TXT-RRs.patch | 34 ++ ...gging-for-dynamically-loaded-modules.patch | 70 ++++ ...-fix-the-increase-of-big_buffer-size.patch | 116 ++++++ .../74_22-Taint-hybrid-checking-mode.patch | 330 ++++++++++++++++++ ..._23-Fix-taint-hybrid-checking-on-BSD.patch | 83 +++++ ...ry-built-for-modern-Linux-handle-err.patch | 70 ++++ .../74_25-Taint-slow-mode-checking-only.patch | 127 +++++++ ...fix-cyrus-sasl-driver-for-gssapi-use.patch | 50 +++ ...uTLS-fix-hanging-callout-connections.patch | 70 ++++ 11 files changed, 952 insertions(+), 1 deletion(-) create mode 100644 mail/exim/files/74_19-SPF-fix-result-for-case-of-only-non-spf-TXT-RRs.patch create mode 100644 mail/exim/files/74_20-Fix-error-logging-for-dynamically-loaded-modules.patch create mode 100644 mail/exim/files/74_21-heimdal-auth-fix-the-increase-of-big_buffer-size.patch create mode 100644 mail/exim/files/74_22-Taint-hybrid-checking-mode.patch create mode 100644 mail/exim/files/74_23-Fix-taint-hybrid-checking-on-BSD.patch create mode 100644 mail/exim/files/74_24-TFO-even-in-binary-built-for-modern-Linux-handle-err.patch create mode 100644 mail/exim/files/74_25-Taint-slow-mode-checking-only.patch create mode 100644 mail/exim/files/74_26-Auths-fix-cyrus-sasl-driver-for-gssapi-use.patch create mode 100644 mail/exim/files/74_27-GnuTLS-fix-hanging-callout-connections.patch diff --git a/mail/exim-postgresql/Makefile b/mail/exim-postgresql/Makefile index 486f18ef8f24..2dafd81b5cb8 100644 --- a/mail/exim-postgresql/Makefile +++ b/mail/exim-postgresql/Makefile @@ -1,7 +1,6 @@ # Created by: Sheldon Hearn # $FreeBSD$ -PORTREVISION= 2 PKGNAMESUFFIX= -postgresql MASTERDIR= ${.CURDIR}/../exim 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 +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 +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 +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 +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(, ). +@@ -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 +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 +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 +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 +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 +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 +