[krbdev.mit.edu #6317] select(2) if no fds < FD_SETSIZE are available.
Roland C. Dowdeswell via RT
rt-comment at krbdev.mit.edu
Wed Jan 7 16:05:54 EST 2009
sendto_kdc.c uses select(2) and does not check to see if the fds that
it obtains are less than FD_SETSIZE. This can cause undefined behaviour
as FD_SET() does not do bounds checking.
Although, this limitation should probably be addressed by using Niels
Provos' libevent, I provide a small patch which will:
1. return reasonable errors if the size is returned, and
2. increase the limit to DESIRED_FD_SETSIZE which I define
to be 8192.
I think that (1) or something like it should be applied. (2) on
the other hand is quite inelegant. A better approach should be
used, I just in case it is viewed to be a reasonable short term
fix.
I call the inability to obtain a socket < FD_SETSIZE a permanent
error which we can also change. It seemed at the time best to
simply fail quickly w/o core dumping.
I also return EMFILE in this case so that the error message returned
is slightly more descriptive than KRB5_KDC_UNREACH. You may very
well be able to reach KDCs, if you just had a few more fds..
Index: sendto_kdc.c
===================================================================
RCS file: /ms/dev/kerberos/mitkrb5/cvs-dirs/mitkrb5-1.4/mitkrb5/src/lib/krb5/os/sendto_kdc.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 sendto_kdc.c
--- sendto_kdc.c 16 Aug 2005 19:52:03 -0000 1.1.1.2
+++ sendto_kdc.c 7 Jan 2009 17:21:02 -0000
@@ -28,6 +28,25 @@
* as necessary.
*/
+/*
+ * We start out by upping the size of FD_SETSIZE. On rational operating
+ * systems, this is simple. One simply #defines FD_SETSIZE before including
+ * anything else. Linux of course does not support this because they are
+ * better than that. So, we special case things...
+ */
+
+#define DESIRED_FD_SETSIZE 8192
+#ifndef linux
+#define FD_SETSIZE DESIRED_FD_SETSIZE
+#else
+#include <features.h>
+#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
+#include <bits/types.h>
+#undef __FD_SETSIZE
+#define __FD_SETSIZE DESIRED_FD_SETSIZE
+#endif
+#endif
+
#define NEED_SOCKETS
#define NEED_LOWLEVEL_IO
#include "fake-addrinfo.h"
@@ -572,8 +591,16 @@
dprint("start_connection(@%p)\ngetting %s socket in family %d...", state,
ai->ai_socktype == SOCK_STREAM ? "stream" : "dgram", ai->ai_family);
fd = socket(ai->ai_family, ai->ai_socktype, 0);
+ if (fd >= FD_SETSIZE) {
+ close(fd);
+ state->err = EMFILE;
+ state->state = FAILED; /* XXXrcd: hmmm, is this permanent...? */
+ dprint("socket: %m creating with af %d\n", state->err, ai->ai_family);
+ return -1; /* try other hosts */
+ }
if (fd == INVALID_SOCKET) {
state->err = SOCKET_ERRNO;
+ state->state = FAILED; /* XXXrcd: hmmm, is this permanent...? */
dprint("socket: %m creating with af %d\n", state->err, ai->ai_family);
return -1; /* try other hosts */
}
@@ -1130,6 +1157,9 @@
if (sel_state->nfds == 0) {
/* No addresses? */
retval = KRB5_KDC_UNREACH;
+ for (host = 0; host < n_conns; host++)
+ if (conns[host].err == EMFILE)
+ retval = EMFILE;
goto egress;
}
if (e == 0 || winning_conn < 0) {
--
Roland Dowdeswell http://www.Imrryr.ORG/~elric/
More information about the krb5-bugs
mailing list