Fix message-reception clock usage. Bug 2615
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 30 Jun 2020 20:16:42 +0000 (21:16 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 30 Jun 2020 20:16:42 +0000 (21:16 +0100)
Broken-by: 6906c131d1 (4.94)
doc/doc-txt/ChangeLog
src/src/exim.c
src/src/functions.h
src/src/receive.c

index 41a9629cfe5081225c226eecebdb3dd8de0e77eb..83908a58a8b48de56ead0df8b50d2882294e6ab7 100644 (file)
@@ -73,6 +73,14 @@ JH/15 Fix "spam" ACL condition.  Previously, tainted values for the "name"
       argument resulted in a trap.  There is no reason to disallow such; this
       was a coding error.
 
+JH/16 Bug 2615: Fix pause during message reception, on systems that have been
+      suspended/resumed.  This Linux CLOCK_MONOTONIC does not account for time
+      spent suspended, ignoring the Posix definintion.  Previously we assumed
+      it did and a constant offset from real time could be used as a correction.
+      Change to using the same clock source for the start-of-message and the
+      post-message next-tick-wait.  Also change to using CLOCK_BOOTTIME if it
+      exists, just to get a clock slightly more aligned to reality.
+
 
 Exim version 4.94
 -----------------
index 9d3d456ef3f80c8db619e977efda15e6cfd2b95c..dd3a17f14f5199e3aa964428ff494759cbd9b0c6 100644 (file)
@@ -383,14 +383,20 @@ return 0;
 *************************************************/
 
 #ifdef _POSIX_MONOTONIC_CLOCK
-/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */
+# ifdef CLOCK_BOOTTIME
+#  define EXIM_CLOCKTYPE CLOCK_BOOTTIME
+# else
+#  define EXIM_CLOCKTYPE CLOCK_MONOTONIC
+# endif
+
+/* Amount EXIM_CLOCK is behind realtime, at startup. */
 static struct timespec offset_ts;
 
 static void
 exim_clock_init(void)
 {
 struct timeval tv;
-if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return;
+if (clock_gettime(EXIM_CLOCKTYPE, &offset_ts) != 0) return;
 (void)gettimeofday(&tv, NULL);
 offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec;
 offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec;
@@ -401,6 +407,29 @@ offset_ts.tv_nsec += 1000*1000*1000;
 #endif
 
 
+void
+exim_gettime(struct timeval * tv)
+{
+#ifdef _POSIX_MONOTONIC_CLOCK
+struct timespec now_ts;
+
+if (clock_gettime(EXIM_CLOCKTYPE, &now_ts) == 0)
+  {
+  now_ts.tv_sec += offset_ts.tv_sec;
+  if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
+    {
+    now_ts.tv_sec++;
+    now_ts.tv_nsec -= 1000*1000*1000;
+    }
+  tv->tv_sec = now_ts.tv_sec;
+  tv->tv_usec = now_ts.tv_nsec / 1000;
+  }
+else
+#endif
+  (void)gettimeofday(tv, NULL);
+}
+
+
 /* Exim uses a time + a pid to generate a unique identifier in two places: its
 message IDs, and in file names for maildir deliveries. Because some OS now
 re-use pids within the same second, sub-second times are now being used.
@@ -427,28 +456,9 @@ exim_wait_tick(struct timeval * tgt_tv, int resolution)
 struct timeval now_tv;
 long int now_true_usec;
 
-#ifdef _POSIX_MONOTONIC_CLOCK
-struct timespec now_ts;
-
-if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0)
-  {
-  now_ts.tv_sec += offset_ts.tv_sec;
-  if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
-    {
-    now_ts.tv_sec++;
-    now_ts.tv_nsec -= 1000*1000*1000;
-    }
-  now_tv.tv_sec = now_ts.tv_sec;
-  now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution;
-  now_tv.tv_usec = now_true_usec;
-  }
-else
-#endif
-  {
-  (void)gettimeofday(&now_tv, NULL);
-  now_true_usec = now_tv.tv_usec;
-  now_tv.tv_usec = (now_true_usec/resolution) * resolution;
-  }
+exim_gettime(&now_tv);
+now_true_usec = now_tv.tv_usec;
+now_tv.tv_usec = (now_true_usec/resolution) * resolution;
 
 while (exim_tvcmp(&now_tv, tgt_tv) <= 0)
   {
@@ -1728,7 +1738,7 @@ make quite sure. */
 
 setlocale(LC_ALL, "C");
 
-/* Get the offset between CLOCK_MONOTONIC and wallclock */
+/* Get the offset between CLOCK_MONOTONIC/CLOCK_BOOTTIME and wallclock */
 
 #ifdef _POSIX_MONOTONIC_CLOCK
 exim_clock_init();
index 54de974c6074ff73dd6bdd5040464a4458758b45..623ae6da617d4f48b1f75f031ae778e419558bde 100644 (file)
@@ -235,6 +235,7 @@ extern void    msg_event_raise(const uschar *, const address_item *);
 extern int     exim_chown_failure(int, const uschar*, uid_t, gid_t);
 extern const uschar * exim_errstr(int);
 extern void    exim_exit(int) NORETURN;
+extern void    exim_gettimg(struct timeval *);
 extern void    exim_nullstd(void);
 extern void    exim_setugid(uid_t, gid_t, BOOL, uschar *);
 extern void    exim_underbar_exit(int) NORETURN;
index df8719ec666a6eaeea95ea890405a673911045f8..76b4d378db6de573c9fed674b46684b18c3551c6 100644 (file)
@@ -1784,7 +1784,7 @@ if (sender_host_address) dmarc_init();    /* initialize libopendmarc */
 ids, and fractions of a second are required. See the comments that precede the
 message id creation below. */
 
-(void)gettimeofday(&message_id_tv, NULL);
+exim_gettime(&message_id_tv);
 
 /* For other uses of the received time we can operate with granularity of one
 second, and for that we use the global variable received_time. This is for