1From 69950390b2d8063b6540dc75941a30ea56d11918 Mon Sep 17 00:00:00 2001 2From: Ben Noordhuis <info@bnoordhuis.nl> 3Date: Thu, 25 May 2023 21:31:33 +0200 4Subject: [PATCH] rand: add support for getrandom() (#526) 5 6glibc provides arc4random_buf() but musl does not and /dev/urandom is 7not always available. 8 9Conflict: NA 10Reference: https://github.com/c-ares/c-ares/commit/69950390b2d8063b6540dc75941a30ea56d11918 11--- 12 CMakeLists.txt | 6 +++ 13 configure.ac | 1 + 14 include/ares_build.h.cmake | 5 ++ 15 m4/cares-functions.m4 | 102 ++++++++++++++++++++++++++++++++++++ 16 src/lib/ares_config.h.cmake | 3 ++ 17 src/lib/ares_rand.c | 17 +++++- 18 src/lib/setup_once.h | 4 ++ 19 7 files changed, 137 insertions(+), 1 deletion(-) 20 21diff --git a/CMakeLists.txt b/CMakeLists.txt 22index e2290af10..0a403880a 100644 23--- a/CMakeLists.txt 24+++ b/CMakeLists.txt 25@@ -164,6 +164,7 @@ CARES_FUNCTION_IN_LIBRARY (clock_gettime rt HAVE_LIBRT) 26 27 # Look for necessary includes 28 CHECK_INCLUDE_FILES (sys/types.h HAVE_SYS_TYPES_H) 29+CHECK_INCLUDE_FILES (sys/random.h HAVE_SYS_RANDOM_H) 30 CHECK_INCLUDE_FILES (sys/socket.h HAVE_SYS_SOCKET_H) 31 CHECK_INCLUDE_FILES (sys/sockio.h HAVE_SYS_SOCKIO_H) 32 CHECK_INCLUDE_FILES (arpa/inet.h HAVE_ARPA_INET_H) 33@@ -281,6 +282,7 @@ CARES_EXTRAINCLUDE_IFSET (HAVE_STDLIB_H stdlib.h) 34 CARES_EXTRAINCLUDE_IFSET (HAVE_STRING_H string.h) 35 CARES_EXTRAINCLUDE_IFSET (HAVE_STRINGS_H strings.h) 36 CARES_EXTRAINCLUDE_IFSET (HAVE_SYS_IOCTL_H sys/ioctl.h) 37+CARES_EXTRAINCLUDE_IFSET (HAVE_SYS_RANDOM_H sys/random.h) 38 CARES_EXTRAINCLUDE_IFSET (HAVE_SYS_SELECT_H sys/select.h) 39 CARES_EXTRAINCLUDE_IFSET (HAVE_SYS_SOCKET_H sys/socket.h) 40 CARES_EXTRAINCLUDE_IFSET (HAVE_SYS_SOCKIO_H sys/sockio.h) 41@@ -365,6 +367,7 @@ CHECK_SYMBOL_EXISTS (gethostbyaddr "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETHOST 42 CHECK_SYMBOL_EXISTS (gethostbyname "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETHOSTBYNAME) 43 CHECK_SYMBOL_EXISTS (gethostname "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETHOSTNAME) 44 CHECK_SYMBOL_EXISTS (getnameinfo "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETNAMEINFO) 45+CHECK_SYMBOL_EXISTS (getrandom "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETRANDOM) 46 CHECK_SYMBOL_EXISTS (getservbyport_r "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETSERVBYPORT_R) 47 CHECK_SYMBOL_EXISTS (getservbyname_r "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETSERVBYNAME_R) 48 CHECK_SYMBOL_EXISTS (gettimeofday "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETTIMEOFDAY) 49@@ -562,6 +565,9 @@ ENDIF () 50 IF (HAVE_SYS_TYPES_H) 51 SET (CARES_HAVE_SYS_TYPES_H 1) 52 ENDIF () 53+IF (HAVE_SYS_RANDOM_H) 54+ SET (CARES_HAVE_SYS_RANDOM_H 1) 55+ENDIF() 56 IF (HAVE_SYS_SOCKET_H) 57 SET (CARES_HAVE_SYS_SOCKET_H 1) 58 ENDIF() 59diff --git a/configure.ac b/configure.ac 60index 54e79d6e2..2d65eb73c 100644 61--- a/configure.ac 62+++ b/configure.ac 63@@ -666,6 +666,7 @@ CARES_CHECK_FUNC_GETENV 64 CARES_CHECK_FUNC_GETHOSTBYADDR 65 CARES_CHECK_FUNC_GETHOSTBYNAME 66 CARES_CHECK_FUNC_GETHOSTNAME 67+CARES_CHECK_FUNC_GETRANDOM 68 CARES_CHECK_FUNC_GETSERVBYPORT_R 69 CARES_CHECK_FUNC_INET_NET_PTON 70 CARES_CHECK_FUNC_INET_NTOP 71diff --git a/include/ares_build.h.cmake b/include/ares_build.h.cmake 72index e847f17ea..6bad69a21 100644 73--- a/include/ares_build.h.cmake 74+++ b/include/ares_build.h.cmake 75@@ -8,6 +8,7 @@ 76 * files. We need to include some dependent headers that may be system specific 77 * for C-Ares */ 78 #cmakedefine CARES_HAVE_SYS_TYPES_H 79+#cmakedefine CARES_HAVE_SYS_RANDOM_H 80 #cmakedefine CARES_HAVE_SYS_SOCKET_H 81 #cmakedefine CARES_HAVE_WINDOWS_H 82 #cmakedefine CARES_HAVE_WS2TCPIP_H 83@@ -20,6 +21,10 @@ 84 # include <sys/types.h> 85 #endif 86 87+#ifdef CARES_HAVE_SYS_RANDOM_H 88+# include <sys/random.h> 89+#endif 90+ 91 #ifdef CARES_HAVE_SYS_SOCKET_H 92 # include <sys/socket.h> 93 #endif 94diff --git a/m4/cares-functions.m4 b/m4/cares-functions.m4 95index d4f4f994c..ce8d2f908 100644 96--- a/m4/cares-functions.m4 97+++ b/m4/cares-functions.m4 98@@ -186,6 +186,24 @@ cares_includes_stropts="\ 99 ]) 100 101 102+dnl CARES_INCLUDES_SYS_RANDOM 103+dnl ------------------------------------------------- 104+dnl Set up variable with list of headers that must be 105+dnl included when sys/random.h is to be included. 106+ 107+AC_DEFUN([CARES_INCLUDES_SYS_RANDOM], [ 108+cares_includes_sys_random="\ 109+/* includes start */ 110+#ifdef HAVE_SYS_RANDOM_H 111+# include <sys/random.h> 112+#endif 113+/* includes end */" 114+ AC_CHECK_HEADERS( 115+ sys/random.h, 116+ [], [], [$cares_includes_sys_random]) 117+]) 118+ 119+ 120 dnl CARES_INCLUDES_SYS_SOCKET 121 dnl ------------------------------------------------- 122 dnl Set up variable with list of headers that must be 123@@ -1520,6 +1538,90 @@ AC_DEFUN([CARES_CHECK_FUNC_GETHOSTNAME], [ 124 fi 125 ]) 126 127+dnl CARES_CHECK_FUNC_GETRANDOM 128+dnl ------------------------------------------------- 129+dnl Verify if getrandom is available, prototyped, and 130+dnl can be compiled. If all of these are true, and 131+dnl usage has not been previously disallowed with 132+dnl shell variable cares_disallow_getrandom, then 133+dnl HAVE_GETRANDOM will be defined. 134+ 135+AC_DEFUN([CARES_CHECK_FUNC_GETRANDOM], [ 136+ AC_REQUIRE([CARES_INCLUDES_SYS_RANDOM])dnl 137+ # 138+ tst_links_getrandom="unknown" 139+ tst_proto_getrandom="unknown" 140+ tst_compi_getrandom="unknown" 141+ tst_allow_getrandom="unknown" 142+ # 143+ AC_MSG_CHECKING([if getrandom can be linked]) 144+ AC_LINK_IFELSE([ 145+ AC_LANG_FUNC_LINK_TRY([getrandom]) 146+ ],[ 147+ AC_MSG_RESULT([yes]) 148+ tst_links_getrandom="yes" 149+ ],[ 150+ AC_MSG_RESULT([no]) 151+ tst_links_getrandom="no" 152+ ]) 153+ # 154+ if test "$tst_links_getrandom" = "yes"; then 155+ AC_MSG_CHECKING([if getrandom is prototyped]) 156+ AC_EGREP_CPP([getrandom],[ 157+ $cares_includes_sys_random 158+ ],[ 159+ AC_MSG_RESULT([yes]) 160+ tst_proto_getrandom="yes" 161+ ],[ 162+ AC_MSG_RESULT([no]) 163+ tst_proto_getrandom="no" 164+ ]) 165+ fi 166+ # 167+ if test "$tst_proto_getrandom" = "yes"; then 168+ AC_MSG_CHECKING([if getrandom is compilable]) 169+ AC_COMPILE_IFELSE([ 170+ AC_LANG_PROGRAM([[ 171+ $cares_includes_sys_random 172+ ]],[[ 173+ if(0 != getrandom(0, 0, 0)) 174+ return 1; 175+ ]]) 176+ ],[ 177+ AC_MSG_RESULT([yes]) 178+ tst_compi_getrandom="yes" 179+ ],[ 180+ AC_MSG_RESULT([no]) 181+ tst_compi_getrandom="no" 182+ ]) 183+ fi 184+ # 185+ if test "$tst_compi_getrandom" = "yes"; then 186+ AC_MSG_CHECKING([if getrandom usage allowed]) 187+ if test "x$cares_disallow_getrandom" != "xyes"; then 188+ AC_MSG_RESULT([yes]) 189+ tst_allow_getrandom="yes" 190+ else 191+ AC_MSG_RESULT([no]) 192+ tst_allow_getrandom="no" 193+ fi 194+ fi 195+ # 196+ AC_MSG_CHECKING([if getrandom might be used]) 197+ if test "$tst_links_getrandom" = "yes" && 198+ test "$tst_proto_getrandom" = "yes" && 199+ test "$tst_compi_getrandom" = "yes" && 200+ test "$tst_allow_getrandom" = "yes"; then 201+ AC_MSG_RESULT([yes]) 202+ AC_DEFINE_UNQUOTED(HAVE_GETRANDOM, 1, 203+ [Define to 1 if you have the getrandom function.]) 204+ ac_cv_func_getrandom="yes" 205+ else 206+ AC_MSG_RESULT([no]) 207+ ac_cv_func_getrandom="no" 208+ fi 209+]) 210+ 211 212 dnl CARES_CHECK_FUNC_GETSERVBYPORT_R 213 dnl ------------------------------------------------- 214diff --git a/src/lib/ares_config.h.cmake b/src/lib/ares_config.h.cmake 215index 798820a3a..db0dfe768 100644 216--- a/src/lib/ares_config.h.cmake 217+++ b/src/lib/ares_config.h.cmake 218@@ -123,6 +123,9 @@ 219 /* Define to 1 if you have the getnameinfo function. */ 220 #cmakedefine HAVE_GETNAMEINFO 221 222+/* Define to 1 if you have the getrandom function. */ 223+#cmakedefine HAVE_GETRANDOM 224+ 225 /* Define to 1 if you have the getservbyport_r function. */ 226 #cmakedefine HAVE_GETSERVBYPORT_R 227 228diff --git a/src/lib/ares_rand.c b/src/lib/ares_rand.c 229index 766c1e6ea..f07d419d4 100644 230--- a/src/lib/ares_rand.c 231+++ b/src/lib/ares_rand.c 232@@ -155,7 +155,7 @@ static int ares__init_rand_engine(ares_rand_state *state) 233 { 234 memset(state, 0, sizeof(*state)); 235 236-#if defined(HAVE_ARC4RANDOM_BUF) || defined(_WIN32) 237+#if defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_GETRANDOM) || defined(_WIN32) 238 state->type = ARES_RAND_OS; 239 return 1; 240 #elif defined(CARES_RANDOM_FILE) 241@@ -241,6 +241,21 @@ static void ares__rand_bytes(ares_rand_state *state, unsigned char *buf, size_t 242 #elif defined(HAVE_ARC4RANDOM_BUF) 243 arc4random_buf(buf, len); 244 return; 245+#elif defined(HAVE_GETRANDOM) 246+ while (1) { 247+ size_t n = len - bytes_read; 248+ /* getrandom() on Linux always succeeds and is never 249+ * interrupted by a signal when requesting <= 256 bytes. 250+ */ 251+ ssize_t rv = getrandom(buf + bytes_read, n > 256 ? 256 : n, 0); 252+ if (rv <= 0) 253+ continue; /* Just retry. */ 254+ 255+ bytes_read += rv; 256+ if (bytes_read == len) 257+ return; 258+ } 259+ break; 260 #else 261 /* Shouldn't be possible to be here */ 262 break; 263diff --git a/src/lib/setup_once.h b/src/lib/setup_once.h 264index a8cfe6bec..4b0f9cec2 100644 265--- a/src/lib/setup_once.h 266+++ b/src/lib/setup_once.h 267@@ -91,6 +91,10 @@ 268 # endif 269 #endif 270 271+#ifdef HAVE_SYS_RANDOM_H 272+#include <sys/random.h> 273+#endif 274+ 275 #ifdef HAVE_SYS_SOCKET_H 276 #include <sys/socket.h> 277 #endif 278