Subject: Re: sys_select() EBADF bug
To: David Laight <david@l8s.co.uk>
From: Greg A. Woods <woods@weird.com>
List: tech-kern
Date: 11/16/2002 15:11:11
[ On Saturday, November 16, 2002 at 10:01:44 (+0000), David Laight wrote: ]
> Subject: Re: sys_select() EBADF bug
>
> On Sat, Nov 16, 2002 at 01:08:11AM +0100, der Mouse wrote:
> > 
> > Well, FD_SETSIZE is not a constant system-wide.  As the manpage for
> > select(2) notes, if you define FD_SETSIZE as a larger-than-default
> > value before your includes, you can raise the effective limit and still
> > use the FD_* macros without the code having to know anything about the
> > format of an fd_set.
> 
> Absolutely true - makes it tricky to detect the nfds > FD_SETSIZE
> error outside that compilation unit though.

Sure, but that doesn't really matter -- anyone who doesn't consistently
define FD_SETSIZE across all the code that cares is asking for trouble.
That's just a normal C programming issue.

> Remember, as well as the non-obvious implementations of fd_set,
> using one byte per fd is valid.

How does that cause breakage?  NFDBITS declares how wide an fd is.
Isn't that sufficient?

>  As is including a count as the
> first member (which FD_ZERO would set and select use to perform
> the nfds > FD_SETSIZE, it could also be used to stop FD_SET
> overwriting random memory).

I'm not so sure that would be a "valid" implementation.

> Mr Woods bin/18955 is similarly broken (the freebsd webcvs doesn't
> contain this version of the slect code).

FYI the fd_grow() and related changes are from OpenBSD, not FreeBSD.

> The only really safe way to support fds > (the default) FD_SETSIZE
> is to convert the programs to use poll().

Well, portably, anyway I suppose, though even saying that is somewhat
facetious since of course poll() isn't really portable.

Stevens noted the original problem with the comment about FD_SETSIZE
maleability in <sys/types.h> in his "UNIX Network Programming, 2nd
Edition", Volume 1, Page 155:

    This makes us think that we can just #define FD_SETSIZE to some
    larger value before including this head to increase the size of
    the descriptor sets used by select().  Unfortunately, this
    normally does not work.

      To see what is wrong, notice that Figure 16.53 of TCPv2 declares
      three descriptor sets within the kernel and also uses the kernel's
      definition of FD_SETSIZE as the upper limit.  The only way to
      increase the size of the descriptor sets is to increase the value
      of FD_SETSIZE and then recompile the kernel.  Changing the value
      without recompiling the kernel is inadequate.

    Some vendors are changing their implementation of select() to allow
    the process to define FD_SETSIZE to larger than the default value.
    BSD/OS has changed the kernel implementation to allow larger
    descriptor sets, and it also provides four new FD_xxx macros to
    dynamically allocate and manipulate these larger sets.  From a
    portability standpoint, however, beware of using large descriptor
    sets.

If I'm not mistaken NetBSD was also "fixed" to allow fd_set arrays of
more than FD_SETSIZE back in revision 1.25 of sys/sys_generic.c, though
the BSD/OS macros mentioned were apparently not borrowed, thus the
fd_grow() I borrowed from OpenBSD.

-- 
								Greg A. Woods

+1 416 218-0098;            <g.a.woods@ieee.org>;           <woods@robohack.ca>
Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>