Gitweb:
https://git.exim.org/exim.git/commitdiff/6acb441b40bbcded2e85819c71a068db713e7ca6
Commit: 6acb441b40bbcded2e85819c71a068db713e7ca6
Parent: ca22cc0abe93c28f3d296d99c239413bb0d079c4
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Mon Jan 11 19:48:12 2021 +0000
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Fri Jan 15 00:42:38 2021 +0000
Hints DB: harden against corrupt files by ignoring unexpected size records
---
doc/doc-txt/ChangeLog | 4 ++++
src/src/dbfn.c | 28 ++++++++++++++++++++++++++++
src/src/dbfunctions.h | 3 ++-
src/src/enq.c | 4 ++--
src/src/transports/smtp.c | 2 +-
5 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 87bf0d0..e1381c1 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -177,6 +177,10 @@ JH/36 Bug 2687: Fix interpretation of multiple ^ chars in a plaintext
documentation. There is still no way to get a leading ^ immediately
after a NUL (ie. for the password of a PLAIN method authenticator.
+JH/37 Enforce the expected size, for fixed-size records read from hints-DB
+ files. For bad sizes read, delete the record and whine to paniclog.
+
+
Exim version 4.94
-----------------
diff --git a/src/src/dbfn.c b/src/src/dbfn.c
index a37271f..452e2ad 100644
--- a/src/src/dbfn.c
+++ b/src/src/dbfn.c
@@ -333,6 +333,34 @@ return yield;
}
+/* Read a record. If the length is not as expected then delete it, write
+an error log line and return NULL.
+Use this for fixed-size records (so not retry or wait records).
+
+Arguments:
+ dbblock a pointer to an open database block
+ key the key of the record to be read
+ length the expected record length
+
+Returns: a pointer to the retrieved record, or
+ NULL if the record is not found/bad
+*/
+
+void *
+dbfn_read_enforce_length(open_db * dbblock, const uschar * key, size_t length)
+{
+int rlen;
+void * yield = dbfn_read_with_length(dbblock, key, &rlen);
+
+if (yield)
+ {
+ if (rlen == length) return yield;
+ log_write(0, LOG_MAIN|LOG_PANIC, "Bad db record size for '%s'", key);
+ dbfn_delete(dbblock, key);
+ }
+return NULL;
+}
+
/*************************************************
* Write to database file *
diff --git a/src/src/dbfunctions.h b/src/src/dbfunctions.h
index 2e18e0e..f3b04ad 100644
--- a/src/src/dbfunctions.h
+++ b/src/src/dbfunctions.h
@@ -2,7 +2,7 @@
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
@@ -12,6 +12,7 @@ void dbfn_close(open_db *);
int dbfn_delete(open_db *, const uschar *);
open_db *dbfn_open(uschar *, int, open_db *, BOOL, BOOL);
void *dbfn_read_with_length(open_db *, const uschar *, int *);
+void *dbfn_read_enforce_length(open_db *, const uschar *, size_t);
uschar *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
int dbfn_write(open_db *, const uschar *, void *, int);
diff --git a/src/src/enq.c b/src/src/enq.c
index 7feba55..0dcb9a7 100644
--- a/src/src/enq.c
+++ b/src/src/enq.c
@@ -53,7 +53,7 @@ if (!(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
/* See if there is a record for this host or queue run; if there is, we cannot
proceed with the connection unless the record is very old. */
-serial_record = dbfn_read(dbm_file, key);
+serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize));
if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60)
{
if (serial_record->count >= lim)
@@ -102,7 +102,7 @@ dbdata_serialize *serial_record;
DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
if ( !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))
- || !(serial_record = dbfn_read(dbm_file, key))
+ || !(serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize)))
)
return;
if (--serial_record->count > 0)
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 2a600d4..301d84c 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -805,7 +805,7 @@ else
uschar * ehlo_resp_key = ehlo_cache_key(sx);
dbdata_ehlo_resp * er;
- if (!(er = dbfn_read(dbm_file, ehlo_resp_key)))
+ if (!(er = dbfn_read_enforce_length(dbm_file, ehlo_resp_key, sizeof(dbdata_ehlo_resp))))
{ DEBUG(D_transport) debug_printf("no ehlo-resp record\n"); }
else if (time(NULL) - er->time_stamp > retry_data_expire)
{