Use pool storage for regex operations
authorJeremy Harris <jgh146exb@wizmail.org>
Fri, 10 Jun 2022 10:54:17 +0000 (11:54 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Fri, 10 Jun 2022 10:57:59 +0000 (11:57 +0100)
src/src/exim.c
src/src/expand.c
src/src/filter.c
src/src/globals.c
src/src/globals.h
src/src/malware.c
src/src/regex.c
src/src/transports/appendfile.c
src/src/transports/smtp.c
src/src/transports/tf_maildir.c

index eac0cb2b986fcfd9fed22ed8925689330f489b02..052c6bf5c54cc547dcf8738e9d95c9883a19464f 100644 (file)
@@ -59,6 +59,18 @@ if (block) store_free(block);
 }
 
 
+static void *
+function_store_get(PCRE2_SIZE size, void * tag)
+{
+return store_get((int)size, GET_UNTAINTED);    /* loses track of taint */
+}
+
+static void
+function_store_nullfree(void * block, void * tag)
+{
+}
+
+
 
 
 /*************************************************
@@ -96,19 +108,9 @@ size_t offset;
 int options = caseless ? PCRE_COPT|PCRE2_CASELESS : PCRE_COPT;
 const pcre2_code * yield;
 int err;
-pcre2_general_context * gctx;
-pcre2_compile_context * cctx;
-
-if (use_malloc)
-  {
-  gctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
-  cctx = pcre2_compile_context_create(gctx);
-  }
-else
-  cctx = pcre_cmp_ctx;
 
 if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options,
-  &err, &offset, cctx)))
+  &err, &offset, use_malloc ? pcre_mlc_cmp_ctx : pcre_gen_cmp_ctx)))
   {
   uschar errbuf[128];
   pcre2_get_error_message(err, errbuf, sizeof(errbuf));
@@ -116,11 +118,6 @@ if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options,
     "%s at offset %ld while compiling %s", errbuf, (long)offset, pattern);
   }
 
-if (use_malloc)
-  {
-  pcre2_compile_context_free(cctx);
-  pcre2_general_context_free(gctx);
-  }
 return yield;
 }
 
@@ -128,9 +125,13 @@ return yield;
 static void
 pcre_init(void)
 {
-pcre_gen_ctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
-pcre_cmp_ctx = pcre2_compile_context_create(pcre_gen_ctx);
-pcre_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx);
+pcre_mlc_ctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
+pcre_gen_ctx = pcre2_general_context_create(function_store_get, function_store_nullfree, NULL);
+
+pcre_mlc_cmp_ctx = pcre2_compile_context_create(pcre_mlc_ctx);
+pcre_gen_cmp_ctx = pcre2_compile_context_create(pcre_gen_ctx);
+
+pcre_gen_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx);
 }
 
 
@@ -160,7 +161,7 @@ regex_match_and_setup(const pcre2_code * re, const uschar * subject, int options
 {
 pcre2_match_data * md = pcre2_match_data_create_from_pattern(re, pcre_gen_ctx);
 int res = pcre2_match(re, (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0,
-                       PCRE_EOPT | options, md, pcre_mtc_ctx);
+                       PCRE_EOPT | options, md, pcre_gen_mtc_ctx);
 BOOL yield;
 
 if ((yield = (res >= 0)))
@@ -182,7 +183,7 @@ else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any)
   pcre2_get_error_message(res, errbuf, sizeof(errbuf));
   debug_printf_indent("pcre2: %s\n", errbuf);
   }
-pcre2_match_data_free(md);
+/* pcre2_match_data_free(md);  gen ctx needs no free */
 return yield;
 }
 
@@ -204,13 +205,18 @@ regex_match(const pcre2_code * re, const uschar * subject, int slen, uschar ** r
 pcre2_match_data * md = pcre2_match_data_create(1, pcre_gen_ctx);
 int rc = pcre2_match(re, (PCRE2_SPTR)subject,
                      slen >= 0 ? slen : PCRE2_ZERO_TERMINATED,
-                     0, PCRE_EOPT, md, pcre_mtc_ctx);
+                     0, PCRE_EOPT, md, pcre_gen_mtc_ctx);
 PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
-if (rc < 0)
-  return FALSE;
-if (rptr)
-  *rptr = string_copyn(subject + ovec[0], ovec[1] - ovec[0]);
-return TRUE;
+BOOL ret = FALSE;
+
+if (rc >= 0)
+  {
+  if (rptr)
+    *rptr = string_copyn(subject + ovec[0], ovec[1] - ovec[0]);
+  ret = TRUE;
+  }
+/* pcre2_match_data_free(md);  gen ctx needs no free */
+return ret;
 }
 
 
index 744ab4d0b934ca4baa4f18a7e1725992a9168148..03ae3206e6550e74fca03e1f790763d5ba020a2d 100644 (file)
@@ -2949,7 +2949,7 @@ switch(cond_type = identify_operator(&s, &opname))
       int err;
 
       if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
-                               PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
+                               PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
        {
        uschar errbuf[128];
        pcre2_get_error_message(err, errbuf, sizeof(errbuf));
@@ -3444,7 +3444,7 @@ switch(cond_type = identify_operator(&s, &opname))
                            TRUE, FALSE);
     md = pcre2_match_data_create(4+1, pcre_gen_ctx);
     if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT,
-                   md, pcre_mtc_ctx) < 0)
+                   md, pcre_gen_mtc_ctx) < 0)
       {
       DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n");
       goto srs_result;
@@ -3521,6 +3521,7 @@ switch(cond_type = identify_operator(&s, &opname))
     boolvalue = TRUE;
 
 srs_result:
+    /* pcre2_match_data_free(md);      gen ctx needs no free */
     if (yield) *yield = (boolvalue == testfor);
     return s;
     }
@@ -5899,7 +5900,7 @@ while (*s)
       /* Compile the regular expression */
 
       if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
-                 PCRE_COPT, &err, &roffset, pcre_cmp_ctx)))
+                 PCRE_COPT, &err, &roffset, pcre_gen_cmp_ctx)))
         {
         uschar errbuf[128];
        pcre2_get_error_message(err, errbuf, sizeof(errbuf));
@@ -5922,7 +5923,7 @@ while (*s)
         {
        PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
        int n = pcre2_match(re, (PCRE2_SPTR)subject, slen, moffset + moffsetextra,
-         PCRE_EOPT | emptyopt, md, pcre_mtc_ctx);
+         PCRE_EOPT | emptyopt, md, pcre_gen_mtc_ctx);
         uschar * insert;
 
         /* No match - if we previously set PCRE_NOTEMPTY after a null match, this
@@ -5984,6 +5985,7 @@ while (*s)
 
       /* All done - restore numerical variables. */
 
+      /* pcre2_match_data_free(md);    gen ctx needs no free */
       restore_expand_strings(save_expand_nmax, save_expand_nstring,
         save_expand_nlength);
       break;
index ad017e5673383b7bd68ef066cccf1267280664e2..a3e31a3b52cd8a9de2721789fd46bd90c7df518d 100644 (file)
@@ -1599,7 +1599,7 @@ switch (c->type)
 
       if (!(re = pcre2_compile((PCRE2_SPTR)exp[1], PCRE2_ZERO_TERMINATED,
                  PCRE_COPT | (c->type == cond_matches ? PCRE2_CASELESS : 0),
-                 &err, &offset, pcre_cmp_ctx)))
+                 &err, &offset, pcre_gen_cmp_ctx)))
        {
        uschar errbuf[128];
        pcre2_get_error_message(err, errbuf, sizeof(errbuf));
index 18988e9da2c5afa5a6b1d738b2f53f2922e4ee44..62c9b265989908d1cd5bfe9f262f4aea6bf6a40d 100644 (file)
@@ -1209,8 +1209,10 @@ uschar *override_pid_file_path = NULL;
 
 BOOL    panic_coredump        = FALSE;
 pcre2_general_context * pcre_gen_ctx = NULL;
-pcre2_compile_context * pcre_cmp_ctx = NULL;
-pcre2_match_context * pcre_mtc_ctx = NULL;
+pcre2_compile_context * pcre_gen_cmp_ctx = NULL;
+pcre2_match_context * pcre_gen_mtc_ctx = NULL;
+pcre2_general_context * pcre_mlc_ctx = NULL;
+pcre2_compile_context * pcre_mlc_cmp_ctx = NULL;
 
 uschar *percent_hack_domains   = NULL;
 uschar *pid_file_path          = US PID_FILE_PATH
index ca5b0ccc9c2595275cfb6735b291798826432fab..0f047110109f61968ad3c579d760079f48bea428 100644 (file)
@@ -794,8 +794,10 @@ extern uschar *override_pid_file_path; /* Value of -oP argument */
 
 extern BOOL    panic_coredump;        /* SEGV rather than exit, on LOG_PANIC_DIE */
 extern pcre2_general_context * pcre_gen_ctx;   /* pcre memory management */
-extern pcre2_compile_context * pcre_cmp_ctx;
-extern pcre2_match_context *   pcre_mtc_ctx;
+extern pcre2_compile_context * pcre_gen_cmp_ctx;
+extern pcre2_match_context *   pcre_gen_mtc_ctx;
+extern pcre2_general_context * pcre_mlc_ctx;
+extern pcre2_compile_context * pcre_mlc_cmp_ctx;
 
 extern uschar *percent_hack_domains;   /* Local domains for which '% operates */
 extern uschar *pid_file_path;          /* For writing daemon pids */
index 4719a5d616c3018cb502f6d9526549784a4d839e..97643851154096ad164281043572cf40a62c6534 100644 (file)
@@ -306,7 +306,7 @@ PCRE2_SIZE roffset;
 const pcre2_code * cre;
 
 if (!(cre = pcre2_compile((PCRE2_SPTR)re, PCRE2_ZERO_TERMINATED,
-             PCRE_COPT, &err, &roffset, pcre_cmp_ctx)))
+             PCRE_COPT, &err, &roffset, pcre_gen_cmp_ctx)))
   {
   uschar errbuf[128];
   pcre2_get_error_message(err, errbuf, sizeof(errbuf));
@@ -320,12 +320,13 @@ uschar *
 m_pcre_exec(const pcre2_code * cre, uschar * text)
 {
 pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
-int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_mtc_ctx);
+int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_gen_mtc_ctx);
 PCRE2_UCHAR * substr = NULL;
 PCRE2_SIZE slen;
 
 if (i >= 2)                            /* Got it */
-  pcre2_substring_get_bynumber(md, 1, &substr, &slen);
+  pcre2_substring_get_bynumber(md, 1, &substr, &slen); /* uses same ctx as md */
+/* pcre2_match_data_free(md);  gen ctx needs no free */
 return US substr;
 }
 
@@ -945,7 +946,7 @@ badseek:  err = errno;
 
          /* try matcher on the line, grab substring */
          result = pcre2_match(drweb_re, (PCRE2_SPTR)tmpbuf, PCRE2_ZERO_TERMINATED,
-                               0, 0, md, pcre_mtc_ctx);
+                               0, 0, md, pcre_gen_mtc_ctx);
          if (result >= 2)
            {
            PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
@@ -959,6 +960,7 @@ badseek:  err = errno;
              g = string_catn(g, US ovec[2], ovec[3] - ovec[2]);
              }
            }
+         /* pcre2_match_data_free(md); gen ctx needs no free */
          }
          malware_name = string_from_gstring(g);
        }
index 5c0f7c4e097dec55878208612703de54f8fe93b2..9b7b07405a78c1b3ac7f1436906026884f0b44ac 100644 (file)
@@ -46,7 +46,7 @@ while ((regex_string = string_nextinlist(&list, &sep, NULL, 0)))
 
     /* compile our regular expression */
     if (!(re = pcre2_compile( (PCRE2_SPTR) regex_string, PCRE2_ZERO_TERMINATED,
-                 0, &err, &pcre_erroffset, pcre_cmp_ctx)))
+                 0, &err, &pcre_erroffset, pcre_gen_cmp_ctx)))
       {
       uschar errbuf[128];
       pcre2_get_error_message(err, errbuf, sizeof(errbuf));
@@ -75,7 +75,7 @@ for (pcre_list * ri = re_list_head; ri; ri = ri->next)
   int n;
 
   /* try matcher on the line */
-  if ((n = pcre2_match(ri->re, (PCRE2_SPTR)linebuffer, len, 0, 0, md, pcre_mtc_ctx)) > 0)
+  if ((n = pcre2_match(ri->re, (PCRE2_SPTR)linebuffer, len, 0, 0, md, pcre_gen_mtc_ctx)) > 0)
     {
     Ustrncpy(regex_match_string_buffer, ri->pcre_text,
              sizeof(regex_match_string_buffer)-1);
@@ -85,14 +85,14 @@ for (pcre_list * ri = re_list_head; ri; ri = ri->next)
       {
       PCRE2_UCHAR * cstr;
       PCRE2_SIZE cslen;
-      pcre2_substring_get_bynumber(md, nn, &cstr, &cslen);
+      pcre2_substring_get_bynumber(md, nn, &cstr, &cslen);     /* uses same ctx as md */
       regex_vars[nn-1] = CUS cstr;
       }
 
     return OK;
     }
   }
-pcre2_match_data_free(md);
+/* pcre2_match_data_free(md);  gen ctx needs no free */
 return FAIL;
 }
 
index 93281efdab245b5f65d39919785a201fff356bc6..600fb6125e4b458c46c7df060fdfe00f11135948 100644 (file)
@@ -681,7 +681,7 @@ for (struct dirent *ent; ent = readdir(dir); )
     {
     pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
     int rc = pcre2_match(re, (PCRE2_SPTR)name, PCRE2_ZERO_TERMINATED,
-                         0, 0, md, pcre_mtc_ctx);
+                         0, 0, md, pcre_gen_mtc_ctx);
     PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
     if (  rc >= 0
        && (rc = pcre2_get_ovector_count(md)) >= 2)
@@ -694,9 +694,11 @@ for (struct dirent *ent; ent = readdir(dir); )
         DEBUG(D_transport)
           debug_printf("check_dir_size: size from %s is " OFF_T_FMT "\n", name,
             size);
+       /* pcre2_match_data_free(md);   gen ctx needs no free */
         continue;
         }
       }
+    /* pcre2_match_data_free(md);      gen ctx needs no free */
     DEBUG(D_transport)
       debug_printf("check_dir_size: regex did not match %s\n", name);
     }
@@ -2219,7 +2221,7 @@ else
     if (ob->quota_size_regex)
       {
       if (!(re = pcre2_compile((PCRE2_SPTR)ob->quota_size_regex,
-                 PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
+                 PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
         {
        uschar errbuf[128];
        pcre2_get_error_message(err, errbuf, sizeof(errbuf));
@@ -2308,7 +2310,7 @@ else
       int check_path_len = Ustrlen(check_path);
 
       if (!(dir_regex = pcre2_compile((PCRE2_SPTR)ob->maildir_dir_regex,
-           PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
+           PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
         {
        uschar errbuf[128];
        pcre2_get_error_message(err, errbuf, sizeof(errbuf));
index 7f529b7cac7987464252c4dd0e800ce4db25d33c..4450d948d39c2da3f1e7ea2954138f13a7ade135 100644 (file)
@@ -1849,57 +1849,57 @@ pcre2_match_data * md = pcre2_match_data_create(1, pcre_gen_ctx);
 #ifndef DISABLE_TLS
 if (  checks & OPTION_TLS
    && pcre2_match(regex_STARTTLS,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
 #endif
   checks &= ~OPTION_TLS;
 
 if (  checks & OPTION_IGNQ
    && pcre2_match(regex_IGNOREQUOTA,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
   checks &= ~OPTION_IGNQ;
 
 if (  checks & OPTION_CHUNKING
    && pcre2_match(regex_CHUNKING,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
   checks &= ~OPTION_CHUNKING;
 
 #ifndef DISABLE_PRDR
 if (  checks & OPTION_PRDR
    && pcre2_match(regex_PRDR,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
 #endif
   checks &= ~OPTION_PRDR;
 
 #ifdef SUPPORT_I18N
 if (  checks & OPTION_UTF8
    && pcre2_match(regex_UTF8,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
 #endif
   checks &= ~OPTION_UTF8;
 
 if (  checks & OPTION_DSN
    && pcre2_match(regex_DSN,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
   checks &= ~OPTION_DSN;
 
 if (  checks & OPTION_PIPE
    && pcre2_match(regex_PIPELINING,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
   checks &= ~OPTION_PIPE;
 
 if (  checks & OPTION_SIZE
    && pcre2_match(regex_SIZE,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
   checks &= ~OPTION_SIZE;
 
 #ifndef DISABLE_PIPE_CONNECT
 if (  checks & OPTION_EARLY_PIPE
    && pcre2_match(regex_EARLY_PIPE,
-                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
+                 (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0)
 #endif
   checks &= ~OPTION_EARLY_PIPE;
 
-pcre2_match_data_free(md);
+/* pcre2_match_data_free(md);  gen ctx needs no free */
 /* debug_printf("%s: found     0x%04x\n", __FUNCTION__, checks); */
 return checks;
 }
index a83fc6f09c221b67df8a5eba66ff7af93d17c308..6bff1eb69769197f152d1e1a65c49174e1f6668a 100644 (file)
@@ -149,7 +149,7 @@ if (maildirfolder_create_regex)
   DEBUG(D_transport) debug_printf("checking for maildirfolder requirement\n");
 
   if (!(re = pcre2_compile((PCRE2_SPTR)maildirfolder_create_regex,
-             PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
+             PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
     {
     uschar errbuf[128];
     pcre2_get_error_message(err, errbuf, sizeof(errbuf));