Try /proc on Linux as entropy fallback; use sysctl as last resort

It turns out that the happy fun Linux kernel is deprecating sysctl,
and using sysctl to fetch entropy will spew messages in the kernel
logs.  Let's not do that.  Instead, let's call sysctl for our
entropy only when all other means fail.

Additionally, let's add another means, and try
/proc/sys/kernel/random/uuid if /dev/urandom fails.
This commit is contained in:
Nick Mathewson 2010-05-03 13:00:00 -04:00
parent 71afc52580
commit 20fda296c5
3 changed files with 80 additions and 5 deletions

View File

@ -201,6 +201,49 @@ arc4_seed_sysctl_linux(void)
}
#endif
#ifdef __linux__
#define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
static int
arc4_seed_proc_sys_kernel_random_uuid(void)
{
/* Occasionally, somebody will make /proc/sys accessible in a chroot,
* but not /dev/urandom. Let's try /proc/sys/kernel/random/uuid.
* Its format is stupid, so we need to decode it from hex.
*/
int fd;
char buf[128];
unsigned char entropy[64];
int bytes, n, i, nybbles;
for (bytes = 0; bytes<ADD_ENTROPY; ) {
fd = open("/proc/sys/kernel/random/uuid", O_RDONLY, 0);
if (fd < 0)
return -1;
n = read(fd, buf, sizeof(buf));
close(fd);
if (n<=0)
return -1;
memset(entropy, 0, sizeof(entropy));
for (i=nybbles=0; i<n; ++i) {
if (EVUTIL_ISXDIGIT(buf[i])) {
int nyb = evutil_hex_char_to_int(buf[i]);
if (nybbles & 1) {
entropy[nybbles/2] |= nyb;
} else {
entropy[nybbles/2] |= nyb<<4;
}
++nybbles;
}
}
if (nybbles < 2)
return -1;
arc4_addrandom(entropy, nybbles/2);
bytes += nybbles/2;
}
memset(entropy, 0, sizeof(entropy));
memset(buf, 0, sizeof(buf));
return 0;
}
#if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_ARND
#define TRY_SEED_SYSCTL_BSD
static int
@ -284,17 +327,23 @@ arc4_seed(void)
if (0 == arc4_seed_win32())
ok = 1;
#endif
#ifdef TRY_SEED_URANDOM
if (0 == arc4_seed_urandom())
ok = 1;
#endif
#define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
if (0 == arc4_seed_proc_sys_kernel_random_uuid())
ok = 1;
#endif
#ifdef TRY_SEED_SYSCTL_LINUX
if (0 == arc4_seed_sysctl_linux())
/* Apparently Linux is deprecating sysctl, and spewing warning
* messages when you try to use it. */
if (!ok && 0 == arc4_seed_sysctl_linux())
ok = 1;
#endif
#ifdef TRY_SEED_SYSCTL_BSD
if (0 == arc4_seed_sysctl_bsd())
ok = 1;
#endif
#ifdef TRY_SEED_URANDOM
if (0 == arc4_seed_urandom())
ok = 1;
#endif
return ok ? 0 : -1;
}

View File

@ -1946,3 +1946,27 @@ evutil_tv_to_msec(const struct timeval *tv)
return (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
}
int
evutil_hex_char_to_int(char c)
{
switch(c)
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A': case 'a': return 10;
case 'B': case 'b': return 11;
case 'C': case 'c': return 12;
case 'D': case 'd': return 13;
case 'E': case 'e': return 14;
case 'F': case 'f': return 15;
}
return -1;
}

View File

@ -223,6 +223,8 @@ const char *evutil_format_sockaddr_port(const struct sockaddr *sa, char *out, si
long evutil_tv_to_msec(const struct timeval *tv);
int evutil_hex_char_to_int(char c);
#ifdef __cplusplus
}
#endif