]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.8-20220129
authorWietse Venema <wietse@porcupine.org>
Sat, 29 Jan 2022 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sun, 30 Jan 2022 16:40:56 +0000 (11:40 -0500)
postfix/HISTORY
postfix/proto/stop.double-cc
postfix/proto/stop.spell-cc
postfix/src/global/mail_version.h
postfix/src/util/Makefile.in
postfix/src/util/hash_fnv.c
postfix/src/util/hash_fnv.h
postfix/src/util/htable.c
postfix/src/util/ldseed.c [new file with mode: 0644]
postfix/src/util/ldseed.h [new file with mode: 0644]

index f7e4c0ecd82696890d87a27f88f647c1603ad481..55d4d410904a0e5492c318422ced0fdd978cd12b 100644 (file)
@@ -26258,6 +26258,12 @@ Apologies for any names omitted.
 
 20220128
 
-       Clenaup: standardize on FNV hash, having verified that
-       collisions will depend on the hash seed value, and that the
-       collision rate is low. Files: util/htable.c, util/fnv_hash.[hc].
+       Clenaup: standardize on FNV hash, after having verified
+       that collisions will change with the hash seed value, and
+       that the collision rate is low. Files: util/htable.c,
+       util/hash_fnv.[hc].
+
+20220129
+
+       Cleanup: factored out the non-cryptographic seeder. Files:
+       ldseed.[hc].
index 3671205f52caf4d73339240eb09a4c9af5c16eb1..9a4cc5aec51a0d79281371e90ba8db138869aacc 100644 (file)
@@ -327,3 +327,4 @@ more  more useful and more consistent
  Fatal error error opening existing file 
 XXX  XXX 
  int compar DNS_RR DNS_RR 
+NO_64_BITS  NO_64_BITS 
index 31863165d9f720ac3ed3f9205a8c0251698e6d6a..3f49e14217fc51be871e730a984985d73fd6c901 100644 (file)
@@ -1770,3 +1770,14 @@ vars
 verboten
 versioning
 wiki
+DSTRICT
+FNV
+NONBLOCK
+Vo
+chongo
+fnv
+isthe
+ldseed
+softwareengineering
+stackexchange
+stdint
index 010dd06cd0c56ca3e19d9b0be138f638b267a7df..282be696dbba7aa1bda573e7c895452788acf9d8 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20220128"
+#define MAIL_RELEASE_DATE      "20220129"
 #define MAIL_VERSION_NUMBER    "3.8"
 
 #ifdef SNAPSHOT
index 538623f83984ea51723c5cdc3b75b9ea8721f807..b0bfc2fa015ae643de601ebcc56a791bf1d4d642 100644 (file)
@@ -43,7 +43,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        split_qnameval.c argv_attr_print.c argv_attr_scan.c dict_file.c \
        msg_logger.c logwriter.c unix_dgram_connect.c unix_dgram_listen.c \
        byte_mask.c known_tcp_ports.c argv_split_at.c dict_stream.c \
-       sane_strtol.c hash_fnv.c
+       sane_strtol.c hash_fnv.c ldseed.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -88,7 +88,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        split_qnameval.o argv_attr_print.o argv_attr_scan.o dict_file.o \
        msg_logger.o logwriter.o unix_dgram_connect.o unix_dgram_listen.o \
        byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
-       sane_strtol.o hash_fnv.o
+       sane_strtol.o hash_fnv.o ldseed.o
 # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
 # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
 # otherwise it sets the PLUGIN_* macros.
@@ -119,7 +119,7 @@ HDRS        = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \
        valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \
        check_arg.h argv_attr.h msg_logger.h logwriter.h byte_mask.h \
-       known_tcp_ports.h sane_strtol.h hash_fnv.h
+       known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h
 TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
        stream_test.c dup2_pass_on_exec.c
 DEFS   = -I. -D$(SYSTYPE)
@@ -1909,6 +1909,7 @@ get_hostname.o: sys_defs.h
 get_hostname.o: valid_hostname.h
 hash_fnv.o: hash_fnv.c
 hash_fnv.o: hash_fnv.h
+hash_fnv.o: ldseed.h
 hash_fnv.o: msg.h
 hash_fnv.o: sys_defs.h
 hex_code.o: check_arg.h
@@ -2038,6 +2039,10 @@ known_tcp_ports.o: stringops.h
 known_tcp_ports.o: sys_defs.h
 known_tcp_ports.o: vbuf.h
 known_tcp_ports.o: vstring.h
+ldseed.o: iostuff.h
+ldseed.o: ldseed.c
+ldseed.o: msg.h
+ldseed.o: sys_defs.h
 line_number.o: check_arg.h
 line_number.o: line_number.c
 line_number.o: line_number.h
@@ -2541,6 +2546,7 @@ stream_trigger.o: mymalloc.h
 stream_trigger.o: stream_trigger.c
 stream_trigger.o: sys_defs.h
 stream_trigger.o: trigger.h
+sys_compat.o: iostuff.h
 sys_compat.o: sys_compat.c
 sys_compat.o: sys_defs.h
 timecmp.o: timecmp.c
index 095083783b78ecc555ba8f004a7ba59257ceda8c..d8baac549195621b198bd54e37651f2e46335f44 100644 (file)
 /*     const void *src,
 /*     size_t  len)
 /* DESCRIPTION
-/*     hash_fnv() implements the FNV type 1a hash function.
+/*     hash_fnv() implements a modified FNV type 1a hash function.
 /*
 /*     To thwart collision attacks, the hash function is seeded
 /*     once from /dev/urandom, and if that is unavailable, from
 /*     wallclock time, monotonic system clocks, and the process
-/*     ID. To disable seeding in tests, specify the NORANDOMIZE
-/*     environment variable (the value does not matter).
+/*     ID. To disable seeding (typically, for regression tests),
+/*     specify the NORANDOMIZE environment variable; the value
+/*     does not matter.
 /*
-/*     By default, the function is modified to avoid a sticky state
-/*     where a zero hash value remains zero when the next input
-/*     byte value is zero. Compile with -DSTRICT_FNV1A to get the
-/*     standard behavior.
+/*     This function implements a workaround for a "sticky state"
+/*     problem with FNV hash functions: when an input produces a
+/*     zero intermediate hash state, and the next input byte is
+/*     zero, then the operations "hash ^= 0" and "hash *= FNV_prime"
+/*     would not change the hash value. To avoid this, hash_fnv()
+/*     adds 1 to each input byte. Compile with -DSTRICT_FNV1A to
+/*     get the standard behavior.
 /*
 /*     The default HASH_FNV_T result type is uint64_t. When compiled
-/*     with -DNO_64_BITS, the result type is uint32_t.
+/*     with -DNO_64_BITS, the result type is uint32_t. On ancient
+/*     systems without <stdint.h>, define HASH_FNV_T on the compiler
+/*     command line as an unsigned 32-bit or 64-bit integer type.
 /* SEE ALSO
 /*     http://www.isthe.com/chongo/tech/comp/fnv/index.html
 /*     https://softwareengineering.stackexchange.com/questions/49550/
   * System library
   */
 #include <sys_defs.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
 #include <stdlib.h>
-#include <fcntl.h>
 #include <unistd.h>
 
  /*
   * Utility library.
   */
 #include <msg.h>
+#include <ldseed.h>
 #include <hash_fnv.h>
 
  /*
 #define FNV_offset_basis       0xcbf29ce484222325ULL
 #endif
 
- /*
-  * Fall back to a mix of absolute and time-since-boot information in the
-  * rare case that /dev/urandom is unavailable.
-  */
-#ifdef CLOCK_UPTIME
-#define NON_WALLTIME_CLOCK      CLOCK_UPTIME
-#elif defined(CLOCK_BOOTTIME)
-#define NON_WALLTIME_CLOCK      CLOCK_BOOTTIME
-#elif defined(CLOCK_MONOTONIC)
-#define NON_WALLTIME_CLOCK      CLOCK_MONOTONIC
-#elif defined(CLOCK_HIGHRES)
-#define NON_WALLTIME_CLOCK      CLOCK_HIGHRES
-#endif
-
-/* fnv_seed - randomize the hash function */
-
-static HASH_FNV_T fnv_seed(void)
-{
-    HASH_FNV_T result = 0;
-
-    /*
-     * Medium-quality seed, for defenses against local and remote attacks.
-     */
-    int     fd;
-    int     count;
-
-    if ((fd = open("/dev/urandom", O_RDONLY)) > 0) {
-       count = read(fd, &result, sizeof(result));
-       (void) close(fd);
-       if (count == sizeof(result) && result != 0)
-           return (result);
-    }
-
-    /*
-     * Low-quality seed, for defenses against remote attacks. Based on 1) the
-     * time since boot (good when an attacker knows the program start time
-     * but not the system boot time), and 2) absolute time (good when an
-     * attacker does not know the program start time). Assumes a system with
-     * better than microsecond resolution, and a network stack that does not
-     * leak the time since boot, for example, through TCP or ICMP timestamps.
-     * With those caveats, this seed is good for 20-30 bits of randomness.
-     */
-#ifdef NON_WALLTIME_CLOCK
-    {
-       struct timespec ts;
-
-       if (clock_gettime(NON_WALLTIME_CLOCK, &ts) != 0)
-           msg_fatal("clock_gettime() failed: %m");
-       result += (HASH_FNV_T) ts.tv_sec ^ (HASH_FNV_T) ts.tv_nsec;
-    }
-#elif defined(USE_GETHRTIME)
-    result += gethrtime();
-#endif
-
-#ifdef CLOCK_REALTIME
-    {
-       struct timespec ts;
-
-       if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
-           msg_fatal("clock_gettime() failed: %m");
-       result += (HASH_FNV_T) ts.tv_sec ^ (HASH_FNV_T) ts.tv_nsec;
-    }
-#else
-    {
-       struct timeval tv;
-
-       if (GETTIMEOFDAY(&tv) != 0)
-           msg_fatal("gettimeofday() failed: %m");
-       result += (HASH_FNV_T) tv.tv_sec + (HASH_FNV_T) tv.tv_usec;
-    }
-#endif
-    return (result + getpid());
-}
-
 /* hash_fnv - modified FNV 1a hash */
 
 HASH_FNV_T hash_fnv(const void *src, size_t len)
@@ -152,30 +81,25 @@ HASH_FNV_T hash_fnv(const void *src, size_t len)
     /*
      * Initialize.
      */
-    while (randomize) {
-       if (getenv("NORANDOMIZE")) {
-           randomize = 0;
-       } else {
-           basis ^= fnv_seed();
-           if (basis != FNV_offset_basis)
-               randomize = 0;
+    if (randomize) {
+       if (!getenv("NORANDOMIZE")) {
+           HASH_FNV_T seed;
+
+           ldseed(&seed, sizeof(seed));
+           basis ^= seed;
        }
+       randomize = 0;
     }
 
-    /*
-     * Add 1 to each input character, to avoid a sticky state (with hash ==
-     * 0, doing "hash ^= 0" and "hash *= FNV_prime" would not change the hash
-     * value.
-     */
 #ifdef STRICT_FNV1A
-#define FNV_NEXT_CHAR(s) ((HASH_FNV_T) * (const unsigned char *) s++)
+#define FNV_NEXT_BYTE(s) ((HASH_FNV_T) * (const unsigned char *) s++)
 #else
-#define FNV_NEXT_CHAR(s) (1 + (HASH_FNV_T) * (const unsigned char *) s++)
+#define FNV_NEXT_BYTE(s) (1 + (HASH_FNV_T) * (const unsigned char *) s++)
 #endif
 
     hash = basis;
     while (len-- > 0) {
-       hash ^= FNV_NEXT_CHAR(src);
+       hash ^= FNV_NEXT_BYTE(src);
        hash *= FNV_prime;
     }
     return (hash);
index 9409352e80bf32b4b4a9f1b8ad177feb817d1fef..19122aeef2c1df718ad3fc589acc002183f193b3 100644 (file)
 /* DESCRIPTION
 /* .nf
 
- /*
-  * Systemn library.
-  */
-#ifndef NO_STDINT_H
-#include <stdint.h>
-#endif
-
  /*
   * External interface.
   */
+#ifndef HASH_FNV_T
+#include <stdint.h>
 #ifdef NO_64_BITS
 #define HASH_FNV_T     uint32_t
-#else
-#define        HASH_FNV_T      uint64_t
-#endif
+#else                                  /* NO_64_BITS */
+#define HASH_FNV_T     uint64_t
+#endif                                 /* NO_64_BITS */
+#endif                                 /* HASH_FNV_T */
 
 extern HASH_FNV_T hash_fnv(const void *, size_t);
 
index 6117f52508810ac6fb7f81c12c121a9309d9ec88..f2ccf2ec3bc4edd7a34f05d6349543a7ada33f96 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* C library */
 
 #include "mymalloc.h"
 #include "msg.h"
-#ifndef NO_HASH_FNV
-#include "hash_fnv.h"
-#endif
 #include "htable.h"
 
 /* htable_hash - hash a string */
 
 #ifndef NO_HASH_FNV
+#include "hash_fnv.h"
 
 #define htable_hash(s, size) (hash_fnv((s), strlen(s)) % (size))
 
@@ -147,14 +150,15 @@ static size_t htable_hash(const char *s, size_t size)
      */
 
     while (*s) {
-        h = (h << 4U) + *(unsigned const char *) s++;
-        if ((g = (h & 0xf0000000)) != 0) {
-            h ^= (g >> 24U);
-            h ^= g;
-        }
+       h = (h << 4U) + *(unsigned const char *) s++;
+       if ((g = (h & 0xf0000000)) != 0) {
+           h ^= (g >> 24U);
+           h ^= g;
+       }
     }
     return (h % size);
 }
+
 #endif
 
 /* htable_link - insert element into table */
diff --git a/postfix/src/util/ldseed.c b/postfix/src/util/ldseed.c
new file mode 100644 (file)
index 0000000..7bce668
--- /dev/null
@@ -0,0 +1,137 @@
+/*++
+/* NAME
+/*     ldseed 3
+/* SUMMARY
+/*     seed for non-cryptographic applications
+/* SYNOPSIS
+/*     #include <ldseed.h>
+/*
+/*     void    ldseed(
+/*     void    *dst,
+/*     size_t  len)
+/* DESCRIPTION
+/*     ldseed() preferably extracts pseudo-random bits from
+/*     /dev/urandom, a non-blocking device that is available on
+/*     modern systems.
+/*
+/*     On systems where /dev/urandom is unavailable or does not
+/*     immediately return the requested amount of randomness,
+/*     ldseed() falls back to a combination of wallclock time,
+/*     the time since boot, and the process ID.
+/* BUGS
+/*     With Linux "the O_NONBLOCK flag has no effect when opening
+/*     /dev/urandom", but reads "can incur an appreciable delay
+/*     when requesting large amounts of data". Apparently, "large"
+/*     means more than 256 bytes.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+ /*
+  * System library
+  */
+#include <sys_defs.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>                    /* CHAR_BIT */
+
+ /*
+  * Utility library.
+  */
+#include <iostuff.h>
+#include <msg.h>
+
+ /*
+  * Different systems have different names for non-wallclock time.
+  */
+#ifdef CLOCK_UPTIME
+#define NON_WALLTIME_CLOCK      CLOCK_UPTIME
+#elif defined(CLOCK_BOOTTIME)
+#define NON_WALLTIME_CLOCK      CLOCK_BOOTTIME
+#elif defined(CLOCK_MONOTONIC)
+#define NON_WALLTIME_CLOCK      CLOCK_MONOTONIC
+#elif defined(CLOCK_HIGHRES)
+#define NON_WALLTIME_CLOCK      CLOCK_HIGHRES
+#endif
+
+/* ldseed - best-effort, low-dependency seed */
+
+void    ldseed(void *dst, size_t len)
+{
+    int     count;
+    int     fd;
+    int     n;
+    time_t  fallback = 0;
+
+    /*
+     * Medium-quality seed.
+     */
+    if ((fd = open("/dev/urandom", O_RDONLY)) > 0) {
+       non_blocking(fd, NON_BLOCKING);
+       count = read(fd, dst, len);
+       (void) close(fd);
+       if (count == len)
+           return;
+    }
+
+    /*
+     * Low-quality seed. Based on 1) the time since boot (good when an
+     * attacker knows the program start time but not the system boot time),
+     * and 2) absolute time (good when an attacker does not know the program
+     * start time). Assumes a system with better than microsecond resolution,
+     * and a network stack that does not leak the time since boot, for
+     * example, through TCP or ICMP timestamps. With those caveats, this seed
+     * is good for 20-30 bits of randomness.
+     */
+#ifdef NON_WALLTIME_CLOCK
+    {
+       struct timespec ts;
+
+       if (clock_gettime(NON_WALLTIME_CLOCK, &ts) != 0)
+           msg_fatal("clock_gettime() failed: %m");
+       fallback += ts.tv_sec ^ ts.tv_nsec;
+    }
+#elif defined(USE_GETHRTIME)
+    fallback += gethrtime();
+#endif
+
+#ifdef CLOCK_REALTIME
+    {
+       struct timespec ts;
+
+       if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
+           msg_fatal("clock_gettime() failed: %m");
+       fallback += ts.tv_sec ^ ts.tv_nsec;
+    }
+#else
+    {
+       struct timeval tv;
+
+       if (GETTIMEOFDAY(&tv) != 0)
+           msg_fatal("gettimeofday() failed: %m");
+       fallback += tv.tv_sec + tv.tv_usec;
+    }
+#endif
+    fallback += getpid();
+
+    /*
+     * Copy the least significant bytes first, because those are the most
+     * volatile.
+     */
+    for (n = 0; n < sizeof(fallback) && n < len; n++) {
+       *(char *) dst++ ^= (fallback & 0xff);
+       fallback >>= CHAR_BIT;
+    }
+    return;
+}
diff --git a/postfix/src/util/ldseed.h b/postfix/src/util/ldseed.h
new file mode 100644 (file)
index 0000000..891986e
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _LDSEED_H_INCLUDED_
+#define _LDSEED_H_INCLUDED_
+
+/*++
+/* NAME
+/*     ldseed 3h
+/* SUMMARY
+/*     seed for non-cryptographic applications
+/* SYNOPSIS
+/*     #include <ldseed.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * External interface.
+  */
+extern void ldseed(void *, size_t);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*--*/
+
+#endif