kern/143029: poll() can return too large a number

John Plevyak jplevyak at apache.org
Wed Jan 20 19:20:08 UTC 2010


>Number:         143029
>Category:       kern
>Synopsis:       poll() can return too large a number
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan 20 19:20:08 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     John Plevyak
>Release:        8.0-RELEASE
>Organization:
Apache.org
>Environment:
FreeBSD jplevyak2.hsd1.ca.comcast.net. 8.0-RELEASE FreeBSD 8.0-RELEASE #0: Sat Nov 21 15:02:08 UTC 2009     root at mason.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64

>Description:
I am calling poll() and the result is 2 while only one
of the revent fields is non-zero.

This is inside of libev where it results in a SEGV.
I have talked to the libev maintainers who suggested
that I talk to you.

This is on FreeBSD 8.

Inspection of the code in sys_generic.c
and uipc_socket.c indicates that selrecord is being called
twice for poll sockets and that pollrescan is counting
the number of td->td_sel entries which are ready and
returning the result. I am concerned that there are 2
entries for the poll socket because of the comments
in selsetbits (sys_generic.c) which are:

* XXX Check for a duplicate set. This can occur because a
* socket calls selrecord() twice for each poll() call
* resulting in two selfds per real fd. selrescan() will
* call selsetbits twice as a result.


This check is not being done for poll().

>How-To-Repeat:
Simple tests do not show the problem since the pollscan() does not have
the problem so if it returns a result the problem is not evident.

I can reproduce in the context of the apache.org trafficserver
linked with libev.  I can provide build and setup instructions or
a login to a VM with the required setup.

>Fix:
selsetbits uses the conditional:

                /*
                 * XXX Check for a duplicate set.  This can occur because a
                 * socket calls selrecord() twice for each poll() call
                 * resulting in two selfds per real fd.  selrescan() will
                 * call selsetbits twice as a result.
                 */
                if ((obits[msk][idx] & bit) != 0)
                        continue;

however looking at the code I think perhaps changing pollrescan to:

                /*
                 * Note: backend also returns POLLHUP and
                 * POLLERR if appropriate.
                 */
                int old_revents = fd->revents;
                fd->revents = fo_poll(fp, fd->events, td->td_ucred, td);
                if (!old_revents && fd->revents != 0)
                        n++;

or something similar might fix the problem.

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list