kern/155606: commit references a PR

dfilter service dfilter at FreeBSD.ORG
Sun Nov 13 10:30:13 UTC 2011


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

From: dfilter at FreeBSD.ORG (dfilter service)
To: bug-followup at FreeBSD.org
Cc:  
Subject: Re: kern/155606: commit references a PR
Date: Sun, 13 Nov 2011 10:28:15 +0000 (UTC)

 Author: kib
 Date: Sun Nov 13 10:28:01 2011
 New Revision: 227485
 URL: http://svn.freebsd.org/changeset/base/227485
 
 Log:
   To limit amount of the kernel memory allocated, and to optimize the
   iteration over the fdsets, kern_select() limits the length of the
   fdsets copied in by the last valid file descriptor index. If any bit
   is set in a mask above the limit, current implementation ignores the
   filedescriptor, instead of returning EBADF.
   
   Fix the issue by scanning the tails of fdset before entering the
   select loop and returning EBADF if any bit above last valid
   filedescriptor index is set. The performance impact of the additional
   check is only imposed on the (somewhat) buggy applications that pass
   bad file descriptors to select(2) or pselect(2).
   
   PR:	kern/155606, kern/162379
   Discussed with:	cognet, glebius
   Tested by:	andreast (powerpc, all 64/32bit ABI combinations, big-endian),
          marius (sparc64, big-endian)
   MFC after:    2 weeks
 
 Modified:
   head/sys/kern/sys_generic.c
 
 Modified: head/sys/kern/sys_generic.c
 ==============================================================================
 --- head/sys/kern/sys_generic.c	Sun Nov 13 06:39:49 2011	(r227484)
 +++ head/sys/kern/sys_generic.c	Sun Nov 13 10:28:01 2011	(r227485)
 @@ -831,6 +831,54 @@ sys_select(struct thread *td, struct sel
  	    NFDBITS));
  }
  
 +/*
 + * In the unlikely case when user specified n greater then the last
 + * open file descriptor, check that no bits are set after the last
 + * valid fd.  We must return EBADF if any is set.
 + *
 + * There are applications that rely on the behaviour.
 + *
 + * nd is fd_lastfile + 1.
 + */
 +static int
 +select_check_badfd(fd_set *fd_in, int nd, int ndu, int abi_nfdbits)
 +{
 +	char *addr, *oaddr;
 +	int b, i, res;
 +	uint8_t bits;
 +
 +	if (nd >= ndu || fd_in == NULL)
 +		return (0);
 +
 +	oaddr = NULL;
 +	bits = 0; /* silence gcc */
 +	for (i = nd; i < ndu; i++) {
 +		b = i / NBBY;
 +#if BYTE_ORDER == LITTLE_ENDIAN
 +		addr = (char *)fd_in + b;
 +#else
 +		addr = (char *)fd_in;
 +		if (abi_nfdbits == NFDBITS) {
 +			addr += rounddown(b, sizeof(fd_mask)) +
 +			    sizeof(fd_mask) - 1 - b % sizeof(fd_mask);
 +		} else {
 +			addr += rounddown(b, sizeof(uint32_t)) +
 +			    sizeof(uint32_t) - 1 - b % sizeof(uint32_t);
 +		}
 +#endif
 +		if (addr != oaddr) {
 +			res = fubyte(addr);
 +			if (res == -1)
 +				return (EFAULT);
 +			oaddr = addr;
 +			bits = res;
 +		}
 +		if ((bits & (1 << (i % NBBY))) != 0)
 +			return (EBADF);
 +	}
 +	return (0);
 +}
 +
  int
  kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
      fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits)
 @@ -845,14 +893,26 @@ kern_select(struct thread *td, int nd, f
  	fd_mask s_selbits[howmany(2048, NFDBITS)];
  	fd_mask *ibits[3], *obits[3], *selbits, *sbp;
  	struct timeval atv, rtv, ttv;
 -	int error, timo;
 +	int error, lf, ndu, timo;
  	u_int nbufbytes, ncpbytes, ncpubytes, nfdbits;
  
  	if (nd < 0)
  		return (EINVAL);
  	fdp = td->td_proc->p_fd;
 -	if (nd > fdp->fd_lastfile + 1)
 -		nd = fdp->fd_lastfile + 1;
 +	ndu = nd;
 +	lf = fdp->fd_lastfile;
 +	if (nd > lf + 1)
 +		nd = lf + 1;
 +
 +	error = select_check_badfd(fd_in, nd, ndu, abi_nfdbits);
 +	if (error != 0)
 +		return (error);
 +	error = select_check_badfd(fd_ou, nd, ndu, abi_nfdbits);
 +	if (error != 0)
 +		return (error);
 +	error = select_check_badfd(fd_ex, nd, ndu, abi_nfdbits);
 +	if (error != 0)
 +		return (error);
  
  	/*
  	 * Allocate just enough bits for the non-null fd_sets.  Use the
 _______________________________________________
 svn-src-all at freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
 


More information about the freebsd-bugs mailing list