[exim-cvs] Utilities: harden exim_tidydb against corrupt wa…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] Utilities: harden exim_tidydb against corrupt wait-records. Bug 2343
Gitweb: https://git.exim.org/exim.git/commitdiff/fc96555ab63243de9d468325aeaaa14cd77b9943
Commit:     fc96555ab63243de9d468325aeaaa14cd77b9943
Parent:     80acfd092b5f785bd971dcf911b4fe7aec9faaa2
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sat Jan 9 13:08:35 2021 +0000
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sat Jan 9 13:08:35 2021 +0000


    Utilities: harden exim_tidydb against corrupt wait-records.  Bug 2343
---
 src/src/exim_dbutil.c | 30 ++++++++++++++++++++++++++----
 src/src/macros.h      |  3 ++-
 2 files changed, 28 insertions(+), 5 deletions(-)


diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c
index 7429527..7ca7a30 100644
--- a/src/src/exim_dbutil.c
+++ b/src/src/exim_dbutil.c
@@ -388,7 +388,7 @@ pick out the timestamps, etc., do the copying centrally here.
 Arguments:
   dbblock   a pointer to an open database block
   key       the key of the record to be read
-  length    where to put the length (or NULL if length not wanted)
+  length    where to put the length (or NULL if length not wanted). Includes overhead.


 Returns: a pointer to the retrieved record, or
          NULL if the record is not found
@@ -416,7 +416,7 @@ we should store the taint status along with the data. */


yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
-if (length != NULL) *length = EXIM_DATUM_SIZE(result_datum);
+if (length) *length = EXIM_DATUM_SIZE(result_datum);

 EXIM_DATUM_FREE(result_datum);    /* Some DBM libs require freeing */
 return yield;
@@ -616,6 +616,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor);
     t = wait->text;
     name[MESSAGE_ID_LENGTH] = 0;


+    /* Leave corrupt records alone */
     if (wait->count > WAIT_NAME_MAX)
       {
       fprintf(stderr,
@@ -1218,7 +1219,7 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point))
   /* A continuation record may have been deleted or renamed already, so
   non-existence is not serious. */


- if (value == NULL) continue;
+ if (!value) continue;

/* Delete if too old */

@@ -1239,12 +1240,33 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point))

     /* Leave corrupt records alone */


+    if (wait->time_stamp > time(NULL))
+      {
+      printf("**** Data for '%s' corrupted\n  time in future: %s\n",
+        key, print_time(((dbdata_generic *)value)->time_stamp));
+      continue;
+      }
     if (wait->count > WAIT_NAME_MAX)
       {
-      printf("**** Data for %s corrupted\n  count=%d=0x%x max=%d\n",
+      printf("**** Data for '%s' corrupted\n  count=%d=0x%x max=%d\n",
         key, wait->count, wait->count, WAIT_NAME_MAX);
       continue;
       }
+    if (wait->sequence > WAIT_CONT_MAX)
+      {
+      printf("**** Data for '%s' corrupted\n  sequence=%d=0x%x max=%d\n",
+        key, wait->sequence, wait->sequence, WAIT_CONT_MAX);
+      continue;
+      }
+
+    /* Record over 1 year old; just remove it */
+
+    if (wait->time_stamp < time(NULL) - 365*24*60*60)
+      {
+      dbfn_delete(dbm, key);
+      printf("deleted %s (too old)\n", key);
+      continue;
+      }


     /* Loop for renamed continuation records. For each message id,
     check to see if the message exists, and if not, remove its entry
diff --git a/src/src/macros.h b/src/src/macros.h
index a584551..68470a9 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -192,9 +192,10 @@ message id with a trailing "-H" or "-D" added. */
 #define SPOOL_NAME_LENGTH (MESSAGE_ID_LENGTH+2)


/* The maximum number of message ids to store in a waiting database
-record. */
+record, and the max number of continuation records allowed. */

#define WAIT_NAME_MAX 50
+#define WAIT_CONT_MAX 1000

/* Fixed option values for all PCRE functions */