[Pkg-openssl-devel] OpenSSL bug in libcrypto.so:RAND_poll() crashes apache2 @ startup

vito at hostway.com vito at hostway.com
Thu Mar 23 07:01:14 UTC 2006


Hello Christoph,

Included below is an email I've already submitted to openssl-bugs at openssl.org,
you may want to get the debian package updated to fix this bug for debian users.

Cheers,
Vito Caputo
Hostway Linux Systems Developer


-------------------------------------------------------------------------

Hello,

I have found a bug in libcrypto.so which causes Apache2 to crash or
deadlock when a few hundred virtual hosts are configured in a
SSL-enabled Apache2 instance.

The problem is Apache2 opens a number of files per virtual host before
initializing libcrypto.so's random seed, given enough virtual hosts the
file descriptor the RAND_poll() open() gets when it opens its entropy
source will exceed FD_SETSIZE.  This is a serious problem because RAND_poll()
internally uses select() to watch for data ready to be read from the
entropy source.  When the fd exceeds FD_SETSIZE (1024 on modern linux
systems) this will cause deadlocks / segfaults.

I have created a patch to convert this to use poll() which does not have
this limitation and is much better suited for watching a single file
descriptor.  The patch is included below.  I'm not sure if you guys need
to make this check if poll() is available in the system to keep things
portable, but if the select() call needs to be kept when poll() is
unavailable, it has to deal with fd >= FD_SETSIZE and not give it to
select().

This was using 0.9.7e-3sarge1 from debian stable as the original source tree, I
checked the 0.9.7i source on openssl.org and the related code is the same.

It's a relatively high priority because it makes apache2 flip out when it gets
hit, might wanna get a fixed version out soon.

Thanks for the OpenSSL project,
Vito Caputo
Hostway Linux Systems Developer





--- rand_unix.c.orig	2006-03-21 17:01:24.000000000 -0600
+++ rand_unix.c	2006-03-21 21:58:12.000000000 -0600
@@ -114,6 +114,7 @@
 #include "cryptlib.h"
 #include <openssl/rand.h>
 #include "rand_lcl.h"
+#include <sys/poll.h>
 
 #if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS))
 
@@ -124,6 +125,7 @@
 #include <unistd.h>
 #include <time.h>
 
+
 #ifdef __OpenBSD__
 int RAND_poll(void)
 {
@@ -165,53 +167,37 @@ int RAND_poll(void)
 	 * have this. Use /dev/urandom if you can as /dev/random may block
 	 * if it runs out of random entries.  */
 
-	for (randomfile = randomfiles; *randomfile && n < ENTROPY_NEEDED; randomfile++)
-		{
+	for (randomfile = randomfiles; *randomfile && n < ENTROPY_NEEDED; randomfile++) {
 		if ((fd = open(*randomfile, O_RDONLY|O_NONBLOCK
 #ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do not make it
 		   our controlling tty */
-			|O_NOCTTY
+		|O_NOCTTY
 #endif
 #ifdef O_NOFOLLOW /* Fail if the file is a symbolic link */
-			|O_NOFOLLOW
+		|O_NOFOLLOW
 #endif
-			)) >= 0)
-			{
-			struct timeval t = { 0, 10*1000 }; /* Spend 10ms on
-							      each file. */
+		)) >= 0) {
 			int r;
-			fd_set fset;
+			struct pollfd rfd = {fd, POLLIN, 0};
+			int t = 10; /* Spend 10ms on each file. */
+
+			/* Patched to use poll() instead of select(), sometimes this gets called
+			 * with >= FD_SETSIZE files opened already (apache2).
+			 * When fd is >= FD_SETSIZE the behavior is undefined (likely a buffer
+			 * overflow...), I observed segfaults & deadlocks.
+			 * 3/21/2006 - Vito Caputo - <vito at hostway.com> */
 
-			do
-				{
-				FD_ZERO(&fset);
-				FD_SET(fd, &fset);
+			do {
 				r = -1;
 
-				if (select(fd+1,&fset,NULL,NULL,&t) < 0)
-					t.tv_usec=0;
-				else if (FD_ISSET(fd, &fset))
-					{
-					r=read(fd,(unsigned char *)tmpbuf+n,
-					       ENTROPY_NEEDED-n);
-					if (r > 0)
-						n += r;
-					}
-
-				/* Some Unixen will update t, some
-				   won't.  For those who won't, give
-				   up here, otherwise, we will do
-				   this once again for the remaining
-				   time. */
-				if (t.tv_usec == 10*1000)
-					t.tv_usec=0;
+				if((poll(&rfd, 1, t) > 0) && (rfd.revents & POLLIN)) {
+					r = read(fd, (unsigned char *)tmpbuf + n, ENTROPY_NEEDED - n);
+					if(r > 0) n += r;
 				}
-			while ((r > 0 || (errno == EINTR || errno == EAGAIN))
-				&& t.tv_usec != 0 && n < ENTROPY_NEEDED);
-
+			} while((r > 0 || (errno == EINTR || errno == EAGAIN)) && n < ENTROPY_NEEDED);
 			close(fd);
-			}
 		}
+	}
 #endif
 
 #ifdef DEVRANDOM_EGD




More information about the Pkg-openssl-devel mailing list