• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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