changeset 7436:cdb007c1923d HEAD

random_fill(): If read(/dev/urandom) returned EINTR, it could have written random data before the given buffer (buffer underflow). Pointed out by Sami Farin. This function is used only by auth and pop3-login (with APOP enabled) processes, so normal users shouldn't be able to send signals to any of them to exploit this. Even then the data would be random, making it quite unlikely to cause anything else than a crash.
author Timo Sirainen <tss@iki.fi>
date Sun, 23 Mar 2008 17:55:51 +0200
parents 6983dfc231d7
children 498975950370
files src/lib/randgen.c
diffstat 1 files changed, 14 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/randgen.c	Fri Mar 21 08:27:36 2008 +0200
+++ b/src/lib/randgen.c	Sun Mar 23 17:55:51 2008 +0200
@@ -7,6 +7,8 @@
 
 #ifdef HAVE_DEV_URANDOM
 
+#define URANDOM_PATH "/dev/urandom"
+
 #include "fd-close-on-exec.h"
 #include <unistd.h>
 #include <fcntl.h>
@@ -22,10 +24,16 @@
 	i_assert(init_refcount > 0);
 	i_assert(size < SSIZE_T_MAX);
 
-	for (pos = 0; pos < size; pos += ret) {
+	for (pos = 0; pos < size; ) {
 		ret = read(urandom_fd, (char *) buf + pos, size - pos);
-		if (unlikely(ret < 0 && errno != EINTR))
-			i_fatal("Error reading from /dev/urandom: %m");
+		if (unlikely(ret <= 0)) {
+			if (ret == 0)
+				i_fatal("EOF when reading from "URANDOM_PATH);
+			else if (errno != EINTR)
+				i_fatal("read("URANDOM_PATH") failed: %m");
+		} else {
+			pos += ret;
+		}
 	}
 }
 
@@ -36,13 +44,13 @@
 	if (init_refcount++ > 0)
 		return;
 
-	urandom_fd = open("/dev/urandom", O_RDONLY);
+	urandom_fd = open(URANDOM_PATH, O_RDONLY);
 	if (urandom_fd == -1) {
 		if (errno == ENOENT) {
-			i_fatal("/dev/urandom doesn't exist, "
+			i_fatal(URANDOM_PATH" doesn't exist, "
 				"currently we require it");
 		} else {
-			i_fatal("Can't open /dev/urandom: %m");
+			i_fatal("Can't open "URANDOM_PATH": %m");
 		}
 	}