kern/143029: [libc] poll(2) can return too large a number

Kostik Belousov kostikbel at gmail.com
Thu Aug 26 20:20:12 UTC 2010


The following reply was made to PR kern/143029; it has been noted by GNATS.

From: Kostik Belousov <kostikbel at gmail.com>
To: bug-followup at FreeBSD.org, jplevyak at apache.org
Cc:  
Subject: Re: kern/143029: [libc] poll(2) can return too large a number
Date: Thu, 26 Aug 2010 23:16:33 +0300

 I believe the issue happens because for some file descriptors, select
 code registers two selfd structures. E.g., for socket, when specified
 POLLIN|POLLOUT in events, you would have one selfd registered for
 receiving socket buffer, and one for sending. Now, if both events
 are not ready to fire at the time of the initial scan, but are
 simultaneously ready after the sleep, pollrescan() would iterate
 over the pollfd struct twice. It is not harmful by itself, but
 pollfd gets accounted twice.
 
 The crusial part is the simultaneous firing of read and write ready
 events after the sleep, due to
 		/* If the selinfo wasn't cleared the event didn't fire. */
 		if (si != NULL)
 			continue;
 code in the pollrescan() loop. In the simple case when only one event
 fired, no double-accounting happen.
 
 Patch below should fix it. Could you, please, confirm ?
 
 diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
 index a1a7086..2b05faf 100644
 --- a/sys/kern/sys_generic.c
 +++ b/sys/kern/sys_generic.c
 @@ -76,7 +76,8 @@ static MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer");
  static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
  MALLOC_DEFINE(M_IOV, "iov", "large iov's");
  
 -static int	pollout(struct pollfd *, struct pollfd *, u_int);
 +static int	pollout(struct thread *, struct pollfd *, struct pollfd *,
 +		    u_int);
  static int	pollscan(struct thread *, struct pollfd *, u_int);
  static int	pollrescan(struct thread *);
  static int	selscan(struct thread *, fd_mask **, fd_mask **, int);
 @@ -1207,7 +1208,7 @@ done:
  	if (error == EWOULDBLOCK)
  		error = 0;
  	if (error == 0) {
 -		error = pollout(bits, uap->fds, nfds);
 +		error = pollout(td, bits, uap->fds, nfds);
  		if (error)
  			goto out;
  	}
 @@ -1262,22 +1263,27 @@ pollrescan(struct thread *td)
  
  
  static int
 -pollout(fds, ufds, nfd)
 +pollout(td, fds, ufds, nfd)
 +	struct thread *td; 
  	struct pollfd *fds;
  	struct pollfd *ufds;
  	u_int nfd;
  {
  	int error = 0;
  	u_int i = 0;
 +	u_int n = 0;
  
  	for (i = 0; i < nfd; i++) {
  		error = copyout(&fds->revents, &ufds->revents,
  		    sizeof(ufds->revents));
  		if (error)
  			return (error);
 +		if (fds->revents != 0)
 +			n++;
  		fds++;
  		ufds++;
  	}
 +	td->td_retval[0] = n;
  	return (0);
  }
  


More information about the freebsd-bugs mailing list