From fc96555ab63243de9d468325aeaaa14cd77b9943 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 9 Jan 2021 13:08:35 +0000 Subject: [PATCH] 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 742952758..7ca7a3073 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 a584551d3..68470a9f1 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 */ -- 2.30.2