Index: sys/kern/sys_generic.c =================================================================== --- sys/kern/sys_generic.c +++ sys/kern/sys_generic.c @@ -116,7 +116,7 @@ static int pollrescan(struct thread *); static int selscan(struct thread *, fd_mask **, fd_mask **, int); static int selrescan(struct thread *, fd_mask **, fd_mask **); -static void selfdalloc(struct thread *, void *); +static void selfdalloc(struct thread *, struct file *, void *); static void selfdfree(struct seltd *, struct selfd *); static int dofileread(struct thread *, int, struct file *, struct uio *, off_t, int); @@ -156,6 +156,7 @@ struct mtx *sf_mtx; /* Pointer to selinfo mtx. */ struct seltd *sf_td; /* (k) owning seltd. */ void *sf_cookie; /* (k) fd or pollfd. */ + struct file *sf_fp; /* (k) fd file pointer */ u_int sf_refs; }; @@ -1220,27 +1221,29 @@ struct file *fp; fd_mask bit; int fd, ev, n, idx; - int error; fdp = td->td_proc->p_fd; stp = td->td_sel; n = 0; STAILQ_FOREACH_SAFE(sfp, &stp->st_selq, sf_link, sfn) { fd = (int)(uintptr_t)sfp->sf_cookie; + fp = sfp->sf_fp; si = sfp->sf_si; - selfdfree(stp, sfp); /* If the selinfo wasn't cleared the event didn't fire. */ - if (si != NULL) + if (si != NULL) { + selfdfree(stp, sfp); continue; - error = getselfd_cap(fdp, fd, &fp); - if (error) - return (error); + } + if (fdp->fd_ofiles[fd].fde_file != fp) { + selfdfree(stp, sfp); + return (EINVAL); + } idx = fd / NFDBITS; bit = (fd_mask)1 << (fd % NFDBITS); ev = fo_poll(fp, selflags(ibits, idx, bit), td->td_ucred, td); - fdrop(fp, td); if (ev != 0) n += selsetbits(ibits, obits, idx, bit, ev); + selfdfree(stp, sfp); } stp->st_flags = 0; td->td_retval[0] = n; @@ -1273,9 +1276,8 @@ error = getselfd_cap(fdp, fd, &fp); if (error) return (error); - selfdalloc(td, (void *)(uintptr_t)fd); + selfdalloc(td, fp, (void *)(uintptr_t)fd); ev = fo_poll(fp, flags, td->td_ucred, td); - fdrop(fp, td); if (ev != 0) n += selsetbits(ibits, obits, idx, bit, ev); } @@ -1442,24 +1444,20 @@ n = 0; fdp = td->td_proc->p_fd; stp = td->td_sel; - FILEDESC_SLOCK(fdp); STAILQ_FOREACH_SAFE(sfp, &stp->st_selq, sf_link, sfn) { + fp = sfp->sf_fp; fd = (struct pollfd *)sfp->sf_cookie; si = sfp->sf_si; - selfdfree(stp, sfp); /* If the selinfo wasn't cleared the event didn't fire. */ - if (si != NULL) + if (si != NULL) { + selfdfree(stp, sfp); continue; - fp = fdp->fd_ofiles[fd->fd].fde_file; -#ifdef CAPABILITIES - if (fp == NULL || - cap_check(cap_rights(fdp, fd->fd), &cap_event_rights) != 0) -#else - if (fp == NULL) -#endif - { + } + + if (fdp->fd_ofiles[fd->fd].fde_file != fp) { fd->revents = POLLNVAL; n++; + selfdfree(stp, sfp); continue; } @@ -1470,8 +1468,8 @@ fd->revents = fo_poll(fp, fd->events, td->td_ucred, td); if (fd->revents != 0) n++; + selfdfree(stp, sfp); } - FILEDESC_SUNLOCK(fdp); stp->st_flags = 0; td->td_retval[0] = n; return (0); @@ -1506,7 +1504,6 @@ struct file *fp; int i, n = 0; - FILEDESC_SLOCK(fdp); for (i = 0; i < nfd; i++, fds++) { if (fds->fd > fdp->fd_lastfile) { fds->revents = POLLNVAL; @@ -1514,14 +1511,9 @@ } else if (fds->fd < 0) { fds->revents = 0; } else { - fp = fdp->fd_ofiles[fds->fd].fde_file; -#ifdef CAPABILITIES - if (fp == NULL || - cap_check(cap_rights(fdp, fds->fd), &cap_event_rights) != 0) -#else - if (fp == NULL) -#endif - { + fget_unlocked(fdp, fds->fd, &cap_event_rights, &fp, NULL); + + if (fp == NULL) { fds->revents = POLLNVAL; n++; } else { @@ -1529,7 +1521,7 @@ * Note: backend also returns POLLHUP and * POLLERR if appropriate. */ - selfdalloc(td, fds); + selfdalloc(td, fp, fds); fds->revents = fo_poll(fp, fds->events, td->td_ucred, td); /* @@ -1544,7 +1536,6 @@ } } } - FILEDESC_SUNLOCK(fdp); td->td_retval[0] = n; return (0); } @@ -1589,7 +1580,7 @@ * Iterate until the timeout expires or the socket becomes ready. */ for (;;) { - selfdalloc(td, NULL); + selfdalloc(td, NULL, NULL); error = sopoll(so, events, NULL, td); /* error here is actually the ready events. */ if (error) @@ -1610,7 +1601,7 @@ * have two select sets, one for read and another for write. */ static void -selfdalloc(struct thread *td, void *cookie) +selfdalloc(struct thread *td, struct file *fp, void *cookie) { struct seltd *stp; @@ -1618,10 +1609,12 @@ if (stp->st_free1 == NULL) stp->st_free1 = uma_zalloc(selfd_zone, M_WAITOK|M_ZERO); stp->st_free1->sf_td = stp; + stp->st_free1->sf_fp = fp; stp->st_free1->sf_cookie = cookie; if (stp->st_free2 == NULL) stp->st_free2 = uma_zalloc(selfd_zone, M_WAITOK|M_ZERO); stp->st_free2->sf_td = stp; + stp->st_free2->sf_fp = fp; stp->st_free2->sf_cookie = cookie; } @@ -1637,6 +1630,8 @@ } mtx_unlock(sfp->sf_mtx); } + if (sfp->sf_fp) + fdrop(sfp->sf_fp, curthread); if (refcount_release(&sfp->sf_refs)) uma_zfree(selfd_zone, sfp); }