Fix $regex<n> use-after-free. Bug 2915
authorJeremy Harris <jgh146exb@wizmail.org>
Wed, 31 Aug 2022 14:37:40 +0000 (15:37 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 31 Aug 2022 14:57:29 +0000 (15:57 +0100)
doc/doc-txt/ChangeLog
src/src/exim.c
src/src/expand.c
src/src/functions.h
src/src/globals.c
src/src/regex.c
src/src/smtp_in.c
test/confs/4002
test/mail/4002.userx
test/scripts/4000-scanning/4002

index 6a4e10915cc4f4c6d3dbae363de6e35293b85b14..ba5bd23d9f1a4d5c686f27f40ec615b7d707eb55 100644 (file)
@@ -30,11 +30,17 @@ JH/07 OpenSSL Fix auto-reload of changed server OCSP proof. Previously, if
       the file with the proof had an unchanged name, the new proof(s) were
       loaded on top of the old ones (and nover used; the old ones were stapled).
 
+JH/08 Bug 2915: Fix use-after-free for $regex<n> variables. Previously when
+      more than one message arrived in a single connection a reference from
+      the earlier message could be re-used.  Often a sigsegv resulted.
+      These variables were introduced in Exim 4.87.
+      Debug help from Graeme Fowler.
+
 
 Exim version 4.96
 -----------------
 
-JH/01 Move the wait-for-next-tick (needed for unique messmage IDs) from
+JH/01 Move the wait-for-next-tick (needed for unique message IDs) from
       after reception to before a subsequent reception.  This should
       mean slightly faster delivery, and also confirmation of reception
       to senders.
index ea4286af34c318a767f127d59a2176f34fba782f..b9328f017decb15734c935995cda28a66dfbbe32 100644 (file)
@@ -2000,8 +2000,6 @@ regex_whitelisted_macro =
   regex_must_compile(US"^[A-Za-z0-9_/.-]*$", MCS_NOFLAGS, TRUE);
 #endif
 
-for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
-
 /* If the program is called as "mailq" treat it as equivalent to "exim -bp";
 this seems to be a generally accepted convention, since one finds symbolic
 links called "mailq" in standard OS configurations. */
@@ -6089,7 +6087,7 @@ MORELOOP:
   deliver_localpart_data = deliver_domain_data =
   recipient_data = sender_data = NULL;
   acl_var_m = NULL;
-  for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
+  regex_vars_clear();
 
   store_reset(reset_point);
   }
index ffbdc14e514bba1eba144fbba497b5eddb10e8b4..89de56255c9b694ccac7adb77a4247ff421e81a8 100644 (file)
@@ -1860,7 +1860,7 @@ else if (Ustrncmp(name, "r_", 2) == 0)
   return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
   }
 
-/* Handle $auth<n> variables. */
+/* Handle $auth<n>, $regex<n> variables. */
 
 if (Ustrncmp(name, "auth", 4) == 0)
   {
index 92a4831e381eaad21e43d8e67f08a0a5efca2531..345d7bce6749173f6a0635090bf10beb9ec81f9b 100644 (file)
@@ -447,6 +447,7 @@ extern BOOL    regex_match_and_setup(const pcre2_code *, const uschar *, int, in
 extern const pcre2_code *regex_compile(const uschar *, mcs_flags, uschar **,
                pcre2_compile_context *);
 extern const pcre2_code *regex_must_compile(const uschar *, mcs_flags, BOOL);
+extern void    regex_vars_clear(void);
 extern void    retry_add_item(address_item *, uschar *, int);
 extern BOOL    retry_check_address(const uschar *, host_item *, uschar *, BOOL,
                  uschar **, uschar **);
index 574ee60a4819330614fd15f87ba9035aaa0e2a35..cafb1599229de9eae20615c5ffcb7b4e122d9ec2 100644 (file)
@@ -1324,7 +1324,7 @@ const pcre2_code *regex_EARLY_PIPE   = NULL;
 int    regex_cachesize              = 0;
 const pcre2_code *regex_ismsgid      = NULL;
 const pcre2_code *regex_smtp_code    = NULL;
-const uschar *regex_vars[REGEX_VARS];
+const uschar *regex_vars[REGEX_VARS] = { 0 };;
 #ifdef WHITELIST_D_MACROS
 const pcre2_code *regex_whitelisted_macro = NULL;
 #endif
index 5de1c1704d02bc850d625b1d65b9f3d48209e9dd..25496f950db7d09debf46c15f902dda139965238 100644 (file)
@@ -93,19 +93,27 @@ return FAIL;
 }
 
 
+/* reset expansion variables */
+void
+regex_vars_clear(void)
+{
+regex_match_string = NULL;
+for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
+}
+
+
 
 int
-regex(const uschar **listptr, BOOL cacheable)
+regex(const uschar ** listptr, BOOL cacheable)
 {
 unsigned long mbox_size;
-FILE *mbox_file;
-pcre_list *re_list_head;
-uschar *linebuffer;
+FILE * mbox_file;
+pcre_list * re_list_head;
+uschar * linebuffer;
 long f_pos = 0;
 int ret = FAIL;
 
-/* reset expansion variable */
-regex_match_string = NULL;
+regex_vars_clear();
 
 if (!mime_stream)                              /* We are in the DATA ACL */
   {
@@ -167,14 +175,13 @@ return ret;
 int
 mime_regex(const uschar **listptr, BOOL cacheable)
 {
-pcre_list *re_list_head = NULL;
-FILE *f;
-uschar *mime_subject = NULL;
+pcre_list * re_list_head = NULL;
+FILE * f;
+uschar * mime_subject = NULL;
 int mime_subject_len = 0;
 int ret;
 
-/* reset expansion variable */
-regex_match_string = NULL;
+regex_vars_clear();
 
 /* precompile our regexes */
 if (!(re_list_head = compile(*listptr, cacheable)))
index 11e7436b917986af08d27fd13841d42a1f1886c0..a15280bdcfdea6bbf34e1a5d988733ff2fad2cb6 100644 (file)
@@ -2157,8 +2157,10 @@ prdr_requested = FALSE;
 #ifdef SUPPORT_I18N
 message_smtputf8 = FALSE;
 #endif
+regex_vars_clear();
 body_linecount = body_zerocount = 0;
 
+lookup_value = NULL;                           /* Can be set by ACL */
 sender_rate = sender_rate_limit = sender_rate_period = NULL;
 ratelimiters_mail = NULL;           /* Updated by ratelimit ACL condition */
                    /* Note that ratelimiters_conn persists across resets. */
index d9a12a36826b38fcf6d1dd0e0ddea773d70e1f1a..4578cc01909510b7eb8d000fe1d8660db7c121b9 100644 (file)
@@ -10,6 +10,7 @@ rfc1413_query_timeout = 0s
 
 acl_smtp_rcpt = check_rcpt
 acl_smtp_data = check_data
+acl_smtp_mime = check_mime
 acl_not_smtp  = check_data
 
 
@@ -20,6 +21,15 @@ begin acl
 check_rcpt:
   accept
 
+check_mime:
+    warn condition = ${if match{$mime_content_type}{text}}
+         mime_regex = \N(?s)([\w.+=-]+@\w[\w-]*\.[\w.-]+\w)\
+                        (.+?([\w.+=-]+@\w[\w-]*\.[\w.-]+\w))?\
+                        (.+?([\w.+=-]+@\w[\w-]*\.[\w.-]+\w))?\
+                        (.+?([\w.+=-]+@\w[\w-]*\.[\w.-]+\w))?\
+                        (.+?([\w.+=-]+@\w[\w-]*\.[\w.-]+\w))?\N
+    accept
+
 check_data:
   warn     regex   = \N(THIS\s((\w+)\s)?REGEX)\N
            message = X-Regex: Regex matched <$regex1> <$regex3>
index 6bc565c3f002d4e632abc8bb31eb219b0c8b4b98..8ec49da09ebd7bccf2c97c39d48dd57849a5c4c0 100644 (file)
@@ -27,9 +27,16 @@ Subject: A real test message
 Date: Tue, 2 Mar 1999 09:44:33 +0000
 Message-ID: <41C2F849.3060203@projectile.test.ex>
 FakeReject: test fakereject
+MIME-Version: 1.0
+Content-Type: text/plain
 Sender: CALLER_NAME <CALLER@myhost.test.ex>
 X-Regex: Regex matched <THIS gazornenplaz REGEX> <gazornenplaz>
 
 OK, this should look like a genuine message, but
 it will trip on THIS gazornenplaz REGEX.
 
+This checks proper release of variable used for mime_regex
+firstname@foobar.com
+secondname@blaz.com
+thirdname@blaz.com
+
index a660f680533738d5389167fb623b9af3e2eab6ff..fcfae698b73a1a979e96669b376d486f56a0f864 100644 (file)
@@ -30,9 +30,16 @@ Subject: A real test message
 Date: Fri, 17 Dec 2004 16:13:04 +0100
 Message-ID: <41C2F849.3060203@projectile.test.ex>
 FakeReject: test fakereject
+MIME-Version: 1.0
+Content-Type: text/plain
 
 OK, this should look like a genuine message, but
 it will trip on THIS gazornenplaz REGEX.
+
+This checks proper release of variable used for mime_regex
+firstname@foobar.com
+secondname@blaz.com
+thirdname@blaz.com
 .
 quit
 ****