Skip to content

Commit 823df3b

Browse files
authored
Merge pull request from GHSA-8r8p-23f3-64c2
* segment random number generation into own file * abstract random code to make it more modular so we can have multiple backends * rand: add support for arc4random_buf() and also direct CARES_RANDOM_FILE reading * autotools: fix detection of arc4random_buf * rework initial rc4 seed for PRNG as last fallback * rc4: more proper implementation, simplified for clarity * clarifications
1 parent a2b8a4d commit 823df3b

File tree

10 files changed

+387
-126
lines changed

10 files changed

+387
-126
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ CHECK_SYMBOL_EXISTS (strncasecmp "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNCAS
393393
CHECK_SYMBOL_EXISTS (strncmpi "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNCMPI)
394394
CHECK_SYMBOL_EXISTS (strnicmp "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNICMP)
395395
CHECK_SYMBOL_EXISTS (writev "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_WRITEV)
396+
CHECK_SYMBOL_EXISTS (arc4random_buf "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_ARC4RANDOM_BUF)
397+
396398

397399
# On Android, the system headers may define __system_property_get(), but excluded
398400
# from libc. We need to perform a link test instead of a header/symbol test.

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ CARES_CHECK_FUNC_STRNCASECMP
683683
CARES_CHECK_FUNC_STRNCMPI
684684
CARES_CHECK_FUNC_STRNICMP
685685
CARES_CHECK_FUNC_WRITEV
686+
CARES_CHECK_FUNC_ARC4RANDOM_BUF
686687

687688

688689
dnl check for AF_INET6

m4/cares-functions.m4

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3753,3 +3753,88 @@ AC_DEFUN([CARES_CHECK_FUNC_WRITEV], [
37533753
ac_cv_func_writev="no"
37543754
fi
37553755
])
3756+
3757+
dnl CARES_CHECK_FUNC_ARC4RANDOM_BUF
3758+
dnl -------------------------------------------------
3759+
dnl Verify if arc4random_buf is available, prototyped, and
3760+
dnl can be compiled. If all of these are true, and
3761+
dnl usage has not been previously disallowed with
3762+
dnl shell variable cares_disallow_arc4random_buf, then
3763+
dnl HAVE_ARC4RANDOM_BUF will be defined.
3764+
3765+
AC_DEFUN([CARES_CHECK_FUNC_ARC4RANDOM_BUF], [
3766+
AC_REQUIRE([CARES_INCLUDES_STDLIB])dnl
3767+
#
3768+
tst_links_arc4random_buf="unknown"
3769+
tst_proto_arc4random_buf="unknown"
3770+
tst_compi_arc4random_buf="unknown"
3771+
tst_allow_arc4random_buf="unknown"
3772+
#
3773+
AC_MSG_CHECKING([if arc4random_buf can be linked])
3774+
AC_LINK_IFELSE([
3775+
AC_LANG_FUNC_LINK_TRY([arc4random_buf])
3776+
],[
3777+
AC_MSG_RESULT([yes])
3778+
tst_links_arc4random_buf="yes"
3779+
],[
3780+
AC_MSG_RESULT([no])
3781+
tst_links_arc4random_buf="no"
3782+
])
3783+
#
3784+
if test "$tst_links_arc4random_buf" = "yes"; then
3785+
AC_MSG_CHECKING([if arc4random_buf is prototyped])
3786+
AC_EGREP_CPP([arc4random_buf],[
3787+
$cares_includes_stdlib
3788+
],[
3789+
AC_MSG_RESULT([yes])
3790+
tst_proto_arc4random_buf="yes"
3791+
],[
3792+
AC_MSG_RESULT([no])
3793+
tst_proto_arc4random_buf="no"
3794+
])
3795+
fi
3796+
#
3797+
if test "$tst_proto_arc4random_buf" = "yes"; then
3798+
AC_MSG_CHECKING([if arc4random_buf is compilable])
3799+
AC_COMPILE_IFELSE([
3800+
AC_LANG_PROGRAM([[
3801+
$cares_includes_stdlib
3802+
]],[[
3803+
arc4random_buf(NULL, 0);
3804+
return 1;
3805+
]])
3806+
],[
3807+
AC_MSG_RESULT([yes])
3808+
tst_compi_arc4random_buf="yes"
3809+
],[
3810+
AC_MSG_RESULT([no])
3811+
tst_compi_arc4random_buf="no"
3812+
])
3813+
fi
3814+
#
3815+
if test "$tst_compi_arc4random_buf" = "yes"; then
3816+
AC_MSG_CHECKING([if arc4random_buf usage allowed])
3817+
if test "x$cares_disallow_arc4random_buf" != "xyes"; then
3818+
AC_MSG_RESULT([yes])
3819+
tst_allow_arc4random_buf="yes"
3820+
else
3821+
AC_MSG_RESULT([no])
3822+
tst_allow_arc4random_buf="no"
3823+
fi
3824+
fi
3825+
#
3826+
AC_MSG_CHECKING([if arc4random_buf might be used])
3827+
if test "$tst_links_arc4random_buf" = "yes" &&
3828+
test "$tst_proto_arc4random_buf" = "yes" &&
3829+
test "$tst_compi_arc4random_buf" = "yes" &&
3830+
test "$tst_allow_arc4random_buf" = "yes"; then
3831+
AC_MSG_RESULT([yes])
3832+
AC_DEFINE_UNQUOTED(HAVE_ARC4RANDOM_BUF, 1,
3833+
[Define to 1 if you have the arc4random_buf function.])
3834+
ac_cv_func_arc4random_buf="yes"
3835+
else
3836+
AC_MSG_RESULT([no])
3837+
ac_cv_func_arc4random_buf="no"
3838+
fi
3839+
])
3840+

src/lib/Makefile.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ CSOURCES = ares__addrinfo2hostent.c \
4545
ares_platform.c \
4646
ares_process.c \
4747
ares_query.c \
48+
ares_rand.c \
4849
ares_search.c \
4950
ares_send.c \
5051
ares_strcasecmp.c \

src/lib/ares_config.h.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@
346346
/* Define to 1 if you need the memory.h header file even with stdlib.h */
347347
#cmakedefine NEED_MEMORY_H
348348

349+
/* Define if have arc4random_buf() */
350+
#cmakedefine HAVE_ARC4RANDOM_BUF
351+
349352
/* a suitable file/device to read random data from */
350353
#cmakedefine CARES_RANDOM_FILE "@CARES_RANDOM_FILE@"
351354

src/lib/ares_destroy.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ void ares_destroy(ares_channel channel)
9595
if (channel->hosts_path)
9696
ares_free(channel->hosts_path);
9797

98+
if (channel->rand_state)
99+
ares__destroy_rand_state(channel->rand_state);
100+
98101
ares_free(channel);
99102
}
100103

src/lib/ares_init.c

Lines changed: 9 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,6 @@
6161
#undef WIN32 /* Redefined in MingW/MSVC headers */
6262
#endif
6363

64-
/* Define RtlGenRandom = SystemFunction036. This is in advapi32.dll. There is
65-
* no need to dynamically load this, other software used widely does not.
66-
* http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
67-
* https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
68-
*/
69-
#ifdef _WIN32
70-
BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength);
71-
# ifndef RtlGenRandom
72-
# define RtlGenRandom(a,b) SystemFunction036(a,b)
73-
# endif
74-
#endif
7564

7665
static int init_by_options(ares_channel channel,
7766
const struct ares_options *options,
@@ -87,7 +76,6 @@ static int config_nameserver(struct server_state **servers, int *nservers,
8776
static int set_search(ares_channel channel, const char *str);
8877
static int set_options(ares_channel channel, const char *str);
8978
static const char *try_option(const char *p, const char *q, const char *opt);
90-
static int init_id_key(rc4_key* key,int key_data_len);
9179

9280
static int config_sortlist(struct apattern **sortlist, int *nsort,
9381
const char *str);
@@ -165,6 +153,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
165153
channel->sock_func_cb_data = NULL;
166154
channel->resolvconf_path = NULL;
167155
channel->hosts_path = NULL;
156+
channel->rand_state = NULL;
168157

169158
channel->last_server = 0;
170159
channel->last_timeout_processed = (time_t)now.tv_sec;
@@ -218,9 +207,13 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
218207
/* Generate random key */
219208

220209
if (status == ARES_SUCCESS) {
221-
status = init_id_key(&channel->id_key, ARES_ID_KEY_LEN);
210+
channel->rand_state = ares__init_rand_state();
211+
if (channel->rand_state == NULL) {
212+
status = ARES_ENOMEM;
213+
}
214+
222215
if (status == ARES_SUCCESS)
223-
channel->next_id = ares__generate_new_id(&channel->id_key);
216+
channel->next_id = ares__generate_new_id(channel->rand_state);
224217
else
225218
DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
226219
ares_strerror(status)));
@@ -242,6 +235,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
242235
ares_free(channel->resolvconf_path);
243236
if(channel->hosts_path)
244237
ares_free(channel->hosts_path);
238+
if (channel->rand_state)
239+
ares__destroy_rand_state(channel->rand_state);
245240
ares_free(channel);
246241
return status;
247242
}
@@ -2182,72 +2177,6 @@ static int sortlist_alloc(struct apattern **sortlist, int *nsort,
21822177
}
21832178

21842179

2185-
/* initialize an rc4 key. If possible a cryptographically secure random key
2186-
is generated using a suitable function otherwise the code defaults to
2187-
cross-platform albeit less secure mechanism using rand
2188-
*/
2189-
static void randomize_key(unsigned char* key,int key_data_len)
2190-
{
2191-
int randomized = 0;
2192-
int counter=0;
2193-
#ifdef WIN32
2194-
BOOLEAN res;
2195-
2196-
res = RtlGenRandom(key, key_data_len);
2197-
if (res)
2198-
randomized = 1;
2199-
2200-
#else /* !WIN32 */
2201-
# ifdef CARES_RANDOM_FILE
2202-
FILE *f = fopen(CARES_RANDOM_FILE, "rb");
2203-
if(f) {
2204-
setvbuf(f, NULL, _IONBF, 0);
2205-
counter = aresx_uztosi(fread(key, 1, key_data_len, f));
2206-
fclose(f);
2207-
}
2208-
# endif
2209-
#endif /* WIN32 */
2210-
2211-
if (!randomized) {
2212-
for (;counter<key_data_len;counter++)
2213-
key[counter]=(unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */
2214-
}
2215-
}
2216-
2217-
static int init_id_key(rc4_key* key,int key_data_len)
2218-
{
2219-
unsigned char index1;
2220-
unsigned char index2;
2221-
unsigned char* state;
2222-
short counter;
2223-
unsigned char *key_data_ptr = 0;
2224-
2225-
key_data_ptr = ares_malloc(key_data_len);
2226-
if (!key_data_ptr)
2227-
return ARES_ENOMEM;
2228-
memset(key_data_ptr, 0, key_data_len);
2229-
2230-
state = &key->state[0];
2231-
for(counter = 0; counter < 256; counter++)
2232-
/* unnecessary AND but it keeps some compilers happier */
2233-
state[counter] = (unsigned char)(counter & 0xff);
2234-
randomize_key(key->state,key_data_len);
2235-
key->x = 0;
2236-
key->y = 0;
2237-
index1 = 0;
2238-
index2 = 0;
2239-
for(counter = 0; counter < 256; counter++)
2240-
{
2241-
index2 = (unsigned char)((key_data_ptr[index1] + state[counter] +
2242-
index2) % 256);
2243-
ARES_SWAP_BYTE(&state[counter], &state[index2]);
2244-
2245-
index1 = (unsigned char)((index1 + 1) % key_data_len);
2246-
}
2247-
ares_free(key_data_ptr);
2248-
return ARES_SUCCESS;
2249-
}
2250-
22512180
void ares_set_local_ip4(ares_channel channel, unsigned int local_ip)
22522181
{
22532182
channel->local_ip4 = local_ip;

src/lib/ares_private.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ W32_FUNC const char *_w32_GetHostsFile (void);
101101

102102
#endif
103103

104-
#define ARES_ID_KEY_LEN 31
105-
106104
#include "ares_ipv6.h"
107105
#include "ares_llist.h"
108106

@@ -262,12 +260,8 @@ struct apattern {
262260
unsigned short type;
263261
};
264262

265-
typedef struct rc4_key
266-
{
267-
unsigned char state[256];
268-
unsigned char x;
269-
unsigned char y;
270-
} rc4_key;
263+
struct ares_rand_state;
264+
typedef struct ares_rand_state ares_rand_state;
271265

272266
struct ares_channeldata {
273267
/* Configuration data */
@@ -302,8 +296,8 @@ struct ares_channeldata {
302296

303297
/* ID to use for next query */
304298
unsigned short next_id;
305-
/* key to use when generating new ids */
306-
rc4_key id_key;
299+
/* random state to use when generating new ids */
300+
ares_rand_state *rand_state;
307301

308302
/* Generation number to use for the next TCP socket open/close */
309303
int tcp_connection_generation;
@@ -362,7 +356,10 @@ void ares__close_sockets(ares_channel channel, struct server_state *server);
362356
int ares__get_hostent(FILE *fp, int family, struct hostent **host);
363357
int ares__read_line(FILE *fp, char **buf, size_t *bufsize);
364358
void ares__free_query(struct query *query);
365-
unsigned short ares__generate_new_id(rc4_key* key);
359+
360+
ares_rand_state *ares__init_rand_state(void);
361+
void ares__destroy_rand_state(ares_rand_state *state);
362+
unsigned short ares__generate_new_id(ares_rand_state *state);
366363
struct timeval ares__tvnow(void);
367364
int ares__expand_name_validated(const unsigned char *encoded,
368365
const unsigned char *abuf,

src/lib/ares_query.c

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,6 @@ struct qquery {
3333

3434
static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen);
3535

36-
static void rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len)
37-
{
38-
unsigned char x;
39-
unsigned char y;
40-
unsigned char* state;
41-
unsigned char xorIndex;
42-
int counter;
43-
44-
x = key->x;
45-
y = key->y;
46-
47-
state = &key->state[0];
48-
for(counter = 0; counter < buffer_len; counter ++)
49-
{
50-
x = (unsigned char)((x + 1) % 256);
51-
y = (unsigned char)((state[x] + y) % 256);
52-
ARES_SWAP_BYTE(&state[x], &state[y]);
53-
54-
xorIndex = (unsigned char)((state[x] + state[y]) % 256);
55-
56-
buffer_ptr[counter] = (unsigned char)(buffer_ptr[counter]^state[xorIndex]);
57-
}
58-
key->x = x;
59-
key->y = y;
60-
}
61-
6236
static struct query* find_query_by_id(ares_channel channel, unsigned short id)
6337
{
6438
unsigned short qid;
@@ -78,7 +52,6 @@ static struct query* find_query_by_id(ares_channel channel, unsigned short id)
7852
return NULL;
7953
}
8054

81-
8255
/* a unique query id is generated using an rc4 key. Since the id may already
8356
be used by a running query (as infrequent as it may be), a lookup is
8457
performed per id generation. In practice this search should happen only
@@ -89,19 +62,12 @@ static unsigned short generate_unique_id(ares_channel channel)
8962
unsigned short id;
9063

9164
do {
92-
id = ares__generate_new_id(&channel->id_key);
65+
id = ares__generate_new_id(channel->rand_state);
9366
} while (find_query_by_id(channel, id));
9467

9568
return (unsigned short)id;
9669
}
9770

98-
unsigned short ares__generate_new_id(rc4_key* key)
99-
{
100-
unsigned short r=0;
101-
rc4(key, (unsigned char *)&r, sizeof(r));
102-
return r;
103-
}
104-
10571
void ares_query(ares_channel channel, const char *name, int dnsclass,
10672
int type, ares_callback callback, void *arg)
10773
{

0 commit comments

Comments
 (0)