commit 632a65a0a3976570ced1e88f71d5d774e882b2a2 Author: Jacob Welsh AuthorDate: Sat Nov 19 05:26:01 2022 +0000 Commit: Jacob Welsh CommitDate: Sat Nov 19 05:40:32 2022 +0000 Type: cleanup lib: untangle the getrandom vs. urandom code paths and add required config.h settings Separate the two methods and their error handling, straightening out the error cases, whether in normal or fallback use. Remove unnecessary extra macros and second definition of getrandom_present. Use consistent return type on random_read, removing a spurious integer truncation. diff --git a/config.h b/config.h index 4a21d7f865..635c243b8b 100644 --- a/config.h +++ b/config.h @@ -1,5 +1,17 @@ /* Adapted from output of configure on Gales Linux, x86_64 */ +/* Define if libbsd headers must be included (currently for arc4random_buf) */ +/* #undef HAVE_LIBBSD */ + +/* Define if you have arc4random_buf() */ +/* #undef HAVE_ARC4RANDOM */ + +/* Define if you have getrandom() */ +#define HAVE_GETRANDOM 1 + +/* Define to the desired RNG device path as fallback if neither getrandom nor arc4random_buf are available */ +#define DEV_URANDOM_PATH "/dev/urandom" + /* Define if you have buggy CMSG macros */ /* #undef BUGGY_CMSG_MACROS */ diff --git a/src/lib/randgen.c b/src/lib/randgen.c index f6b2da9c99..6b1a5eb492 100644 --- a/src/lib/randgen.c +++ b/src/lib/randgen.c @@ -43,24 +43,17 @@ int rand_get_last_seed(unsigned int *seed_r) /* get randomness from either getrandom, arc4random or /dev/urandom */ -#if defined(HAVE_GETRANDOM) && HAVE_DECL_GETRANDOM != 0 +#if defined(HAVE_GETRANDOM) # include -# define USE_GETRANDOM static bool getrandom_present = TRUE; -#elif defined(HAVE_ARC4RANDOM) -# if defined(HAVE_LIBBSD) -# include -# endif -# define USE_ARC4RANDOM -#else -static bool getrandom_present = FALSE; -# define USE_RANDOM_DEV +#elif defined(HAVE_ARC4RANDOM) && defined(HAVE_LIBBSD) +# include #endif static int init_refcount = 0; static int urandom_fd = -1; -#if defined(USE_GETRANDOM) || defined(USE_RANDOM_DEV) +#ifndef HAVE_ARC4RANDOM /* Use a small buffer when reading randomness. This is mainly to make small random reads more efficient, such as i_rand*(). When reading larger amount of randomness this buffer is bypassed. @@ -87,42 +80,44 @@ static void random_open_urandom(void) fd_close_on_exec(urandom_fd, TRUE); } -static inline int random_read(unsigned char *buf, size_t size) +static ssize_t random_read(unsigned char *buf, size_t size) { ssize_t ret = 0; -# if defined(USE_GETRANDOM) +# ifdef HAVE_GETRANDOM if (getrandom_present) { ret = getrandom(buf, size, 0); - if (ret < 0 && errno == ENOSYS) { - getrandom_present = FALSE; - /* It gets complicated here... While the libc (and its - headers) indicated that getrandom() was available when - we were compiled, the kernel disagreed just now at - runtime. Fall back to reading /dev/urandom. */ - random_open_urandom(); + if (unlikely(ret <= 0)) { + if (ret == 0) { + i_fatal("getrandom() failed: EOF"); /* inconceivable! */ + } else if (errno == EINTR) { + return ret; + } else if (errno == ENOSYS) { + /* getrandom() is present in libc but the underlying syscall is not available in the running kernel. Fall back to reading /dev/urandom. */ + getrandom_present = FALSE; + random_open_urandom(); + return random_read(buf, size); + } else { + i_fatal("getrandom() failed: %m"); + } } + i_assert(ret > 0); + return ret; } - /* this is here to avoid clang complain, - because getrandom_present will be always FALSE - if USE_GETRANDOM is not defined */ - if (!getrandom_present) # endif - ret = read(urandom_fd, buf, size); + ret = read(urandom_fd, buf, size); if (unlikely(ret <= 0)) { if (ret == 0) { i_fatal("read("DEV_URANDOM_PATH") failed: EOF"); - } else if (errno != EINTR) { - if (getrandom_present) { - i_fatal("getrandom() failed: %m"); - } else { - i_fatal("read("DEV_URANDOM_PATH") failed: %m"); - } + } else if (errno == EINTR) { + return ret; + } else { + i_fatal("read("DEV_URANDOM_PATH") failed: %m"); } } - i_assert(ret > 0 || errno == EINTR); + i_assert(ret > 0); return ret; } -#endif +#endif /* not HAVE_ARC4RANDOM */ void random_fill(void *buf, size_t size) { @@ -137,7 +132,7 @@ void random_fill(void *buf, size_t size) } #endif -#if defined(USE_ARC4RANDOM) +#ifdef HAVE_ARC4RANDOM arc4random_buf(buf, size); #else size_t pos; @@ -170,7 +165,7 @@ void random_fill(void *buf, size_t size) } } } -#endif /* defined(USE_ARC4RANDOM) */ +#endif } void random_init(void) @@ -194,7 +189,7 @@ void random_init(void) i_warning("DOVECOT_SRAND is not available in non-debug builds"); #endif /* DEBUG */ -#if defined(USE_RANDOM_DEV) +#if !defined(HAVE_GETRANDOM) && !defined(HAVE_ARC4RANDOM) random_open_urandom(); #endif /* DO NOT REMOVE THIS - It is also