From f9a3fcddba223133019368e7cd6d51449fc54e7b Mon Sep 17 00:00:00 2001 From: "Heiko Schlittermann (HS12-RIPE)" Date: Thu, 1 Apr 2021 22:44:31 +0200 Subject: [PATCH] Introduce main config option allow_insecure_tainted_data This option is deprecated already now. (cherry picked from commit ec06d64532e4952fc36429f73e0222d26997ef7c) --- src/src/EDITME | 7 +++++ src/src/config.h.defaults | 2 ++ src/src/functions.h | 54 ++++++++++++++++++++++++++++++--------- src/src/globals.c | 10 ++++++++ src/src/globals.h | 4 +++ src/src/macros.h | 3 +++ src/src/readconf.c | 3 +++ 7 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/src/EDITME b/src/src/EDITME index 8cd34e8be..f4329fabf 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -748,6 +748,13 @@ FIXED_NEVER_USERS=root # WHITELIST_D_MACROS=TLS:SPOOL +# The next setting enables a main config option +# "allow_insecure_tainted_data" to turn taint failures into warnings. +# Though this option is new, it is deprecated already now, and will be +# ignored in future releases of Exim. It is meant as mitigation for +# upgrading old (possibly insecure) configurations to more secure ones. +ALLOW_INSECURE_TAINTED_DATA=yes + #------------------------------------------------------------------------------ # Exim has support for the AUTH (authentication) extension of the SMTP # protocol, as defined by RFC 2554. If you don't know what SMTP authentication diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index e233fb3e5..877cc7bc4 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -17,6 +17,8 @@ Do not put spaces between # and the 'define'. #define ALT_CONFIG_PREFIX #define TRUSTED_CONFIG_LIST +#define ALLOW_INSECURE_TAINTED_DATA + #define APPENDFILE_MODE 0600 #define APPENDFILE_DIRECTORY_MODE 0700 #define APPENDFILE_LOCKFILE_MODE 0600 diff --git a/src/src/functions.h b/src/src/functions.h index 4212c3328..27c298cfa 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1125,20 +1125,50 @@ if (f.running_in_test_harness && f.testsuite_delays) millisleep(millisec); /******************************************************************************/ /* Taint-checked file opens */ +static inline uschar * +is_tainted2(const void *p, int lflags, const uschar* fmt, ...) +{ +va_list ap; +uschar *msg; +rmark mark; + +if (!is_tainted(p)) + return NULL; + +mark = store_mark(); +va_start(ap, fmt); +msg = string_from_gstring(string_vformat(NULL, SVFMT_TAINT_NOCHK|SVFMT_EXTEND, fmt, ap)); +va_end(ap); + +#ifdef ALLOW_INSECURE_TAINTED_DATA +if (allow_insecure_tainted_data) + { + if LOGGING(tainted) log_write(0, LOG_MAIN, "Warning: %s", msg); + store_reset(mark); + return NULL; + } +#endif + +if (lflags) log_write(0, lflags, "%s", msg); +return msg; /* no store_reset(), as the message might be used afterwards and Exim + is expected to exit anyway, so we do not care about the leaked + storage */ +} static inline int exim_open2(const char *pathname, int flags) { -if (!is_tainted(pathname)) return open(pathname, flags); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname)) + return open(pathname, flags); errno = EACCES; return -1; } + static inline int exim_open(const char *pathname, int flags, mode_t mode) { -if (!is_tainted(pathname)) return open(pathname, flags, mode); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname)) + return open(pathname, flags, mode); errno = EACCES; return -1; } @@ -1146,16 +1176,16 @@ return -1; static inline int exim_openat(int dirfd, const char *pathname, int flags) { -if (!is_tainted(pathname)) return openat(dirfd, pathname, flags); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname)) + return openat(dirfd, pathname, flags); errno = EACCES; return -1; } static inline int exim_openat4(int dirfd, const char *pathname, int flags, mode_t mode) { -if (!is_tainted(pathname)) return openat(dirfd, pathname, flags, mode); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname)) + return openat(dirfd, pathname, flags, mode); errno = EACCES; return -1; } @@ -1164,8 +1194,8 @@ return -1; static inline FILE * exim_fopen(const char *pathname, const char *mode) { -if (!is_tainted(pathname)) return fopen(pathname, mode); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname)) + return fopen(pathname, mode); errno = EACCES; return NULL; } @@ -1173,8 +1203,8 @@ return NULL; static inline DIR * exim_opendir(const uschar * name) { -if (!is_tainted(name)) return opendir(CCS name); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name); +if (!is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name)) + return opendir(CCS name); errno = EACCES; return NULL; } diff --git a/src/src/globals.c b/src/src/globals.c index e96586048..9e68aaca8 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -98,6 +98,10 @@ int sqlite_lock_timeout = 5; BOOL move_frozen_messages = FALSE; #endif +#ifdef ALLOW_INSECURE_TAINTED_DATA +BOOL allow_insecure_tainted_data = FALSE; +#endif + /* These variables are outside the #ifdef because it keeps the code less cluttered in several places (e.g. during logging) if we can always refer to them. Also, the tls_ variables are now always visible. Note that these are @@ -1055,6 +1059,9 @@ int log_default[] = { /* for initializing log_selector */ Li_size_reject, Li_skip_delivery, Li_smtp_confirmation, +#ifdef ALLOW_INSECURE_TAINTED_DATA + Li_tainted, +#endif Li_tls_certificate_verified, Li_tls_cipher, -1 @@ -1124,6 +1131,9 @@ bit_table log_options[] = { /* must be in alphabetical order, BIT_TABLE(L, smtp_protocol_error), BIT_TABLE(L, smtp_syntax_error), BIT_TABLE(L, subject), +#ifdef ALLOW_INSECURE_TAINTED_DATA + BIT_TABLE(L, tainted), +#endif BIT_TABLE(L, tls_certificate_verified), BIT_TABLE(L, tls_cipher), BIT_TABLE(L, tls_peerdn), diff --git a/src/src/globals.h b/src/src/globals.h index 937cce776..657e6c706 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -77,6 +77,10 @@ extern int sqlite_lock_timeout; /* Internal lock waiting timeout */ extern BOOL move_frozen_messages; /* Get them out of the normal directory */ #endif +#ifdef ALLOW_INSECURE_TAINTED_DATA +extern BOOL allow_insecure_tainted_data; +#endif + /* These variables are outside the #ifdef because it keeps the code less cluttered in several places (e.g. during logging) if we can always refer to them. Also, the tls_ variables are now always visible. */ diff --git a/src/src/macros.h b/src/src/macros.h index f8987d604..ccdcc451f 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -491,6 +491,9 @@ enum logbit { Li_smtp_mailauth, Li_smtp_no_mail, Li_subject, +#ifdef ALLOW_INSECURE_TAINTED_DATA + Li_tainted, +#endif Li_tls_certificate_verified, Li_tls_cipher, Li_tls_peerdn, diff --git a/src/src/readconf.c b/src/src/readconf.c index ae36fa0c5..34ebf8769 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -68,6 +68,9 @@ static optionlist optionlist_config[] = { { "add_environment", opt_stringptr, {&add_environment} }, { "admin_groups", opt_gidlist, {&admin_groups} }, { "allow_domain_literals", opt_bool, {&allow_domain_literals} }, +#ifdef ALLOW_INSECURE_TAINTED_DATA + { "allow_insecure_tainted_data", opt_bool, {&allow_insecure_tainted_data} }, +#endif { "allow_mx_to_ip", opt_bool, {&allow_mx_to_ip} }, { "allow_utf8_domains", opt_bool, {&allow_utf8_domains} }, { "auth_advertise_hosts", opt_stringptr, {&auth_advertise_hosts} }, -- 2.30.2