]> granicus.if.org Git - libevent/commitdiff
Try /proc on Linux as entropy fallback; use sysctl as last resort
authorNick Mathewson <nickm@torproject.org>
Mon, 3 May 2010 17:00:00 +0000 (13:00 -0400)
committerNick Mathewson <nickm@torproject.org>
Mon, 3 May 2010 17:00:00 +0000 (13:00 -0400)
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.

arc4random.c
evutil.c
util-internal.h

index 5e04464308aed80becf5c02526baccf111346910..c75b5d796f4ef1a6f6b5b8162a7be9914340341a 100644 (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;
 }
index a9d4ab5ce99c5c776725aff280e82f9942253103..af5b069aa1626905e5239f6301909055760f0587 100644 (file)
--- a/evutil.c
+++ b/evutil.c
@@ -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;
+}
index 60d4dfeeaeadffa83eaf23e5a6f1467370626a5a..32cd88cbb7b50c1d9e372274466594b0a3417d2a 100644 (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