WIP: allow_insecure_tainted_data
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Thu, 1 Apr 2021 20:44:31 +0000 (22:44 +0200)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Tue, 6 Apr 2021 16:11:55 +0000 (18:11 +0200)
src/src/EDITME
src/src/config.h.defaults
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/macros.h
src/src/readconf.c

index b583a993c4f70c977474cf37160d49137da333c8..694a0f16b3ff99dff537836b9474cb83413758da 100644 (file)
@@ -746,6 +746,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
index 02031b7df5ef4966cb648d1c4be940fd8b097ad4..f5659e6c9c6164d27ff37ea9b10ec37f1564f43a 100644 (file)
@@ -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
index f1e5b466e0f8dcae5a7db7d72f8d0da217fd171a..64fbfcbfc31b06085b88c6a4d003e95707ef6068 100644 (file)
@@ -1114,20 +1114,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;
 }
@@ -1135,16 +1165,17 @@ 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);
+uschar *msg;
+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;
 }
@@ -1153,8 +1184,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;
 }
@@ -1162,8 +1193,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;
 }
index 04e47050ec190b556490fb287cd1c335f9b94af7..2e5a873e99e5f415e5958b412dc8489c21efc319 100644 (file)
@@ -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
@@ -1040,6 +1044,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
@@ -1108,6 +1115,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),
index 652518ade62252292298d808fbcf4eb4eaddcb1e..7924c12825358fbff2365a9df29d808086808511 100644 (file)
@@ -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. */
index 0b647569b1148a3d7470e82790c8974fe804fe0a..dfb198fdc3d31a94c696556cf554b9ce94ae3886 100644 (file)
@@ -492,6 +492,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,
index 0ae3166c330b91baffc4007d4082fbd4cca168bc..b64af33f9f2dc1534bbcc6c90aeaf8288ad04594 100644 (file)
@@ -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} },