On Mon, Dec 06, 2021 at 05:17:21PM +0000, Visa Hankala wrote:
> This patch adjusts the EVFILT_EXCEPT code of sockets and FIFOs so that
> it would raise the HUP condition only when the channel has been closed
> from both sides. This should match better with the POLLHUP case of
> soo_poll() and fifo_poll().
> 
> The "poll index ... unclaimed" error seen by some was related to this.
> With pfd[i].events = 0, the EVFILT_EXCEPT filter triggered prematurely
> when the socket was only half-closed.
> 
> When comparing the code, note that POLL_NOHUP was set by the old
> select(2) code with writefds. The kqueue-based code achieves the same
> effect with FIFOs by not raising HUP in filt_fifowrite().
> 
> The resulting code is possibly overly contrived. The SS_CANTRCVMORE
> condition alone is irrelevant for poll and select. It could be removed
> to simplify the code, but then socket and FIFO's EVFILT_EXCEPT would
> behave inconsistently relative to EV_EOF. However, only NOTE_OOB has
> been documented and it skips SS_CANTRCVMORE...

Here is a revised patch for EVFILT_EXCEPT handlers. Changes:

* Disallow use of EVFILT_EXCEPT through kevent(2) with FIFOs and pipes.
  These file types do not implement out-of-band data that userspace
  could query.

* Do not return EOF condition to userspace from EVFILT_EXCEPT code.
  The relevant code blocks are now conditional to __EV_POLL and only
  set __EV_HUP.

These items prevent unintended "leakage" of functionality to userspace.

Also note that ptys and sockets can now return both NOTE_OOB and __EV_HUP
at the same time. This was present in the initial revision.

OK?

Index: kern/sys_pipe.c
===================================================================
RCS file: src/sys/kern/sys_pipe.c,v
retrieving revision 1.131
diff -u -p -r1.131 sys_pipe.c
--- kern/sys_pipe.c     8 Dec 2021 13:03:52 -0000       1.131
+++ kern/sys_pipe.c     11 Dec 2021 12:36:06 -0000
@@ -927,6 +927,11 @@ pipe_kqfilter(struct file *fp, struct kn
                        error = EPERM;
                        break;
                }
+               if ((kn->kn_flags & __EV_POLL) == 0) {
+                       /* Disallow usage through kevent(2). */
+                       error = EINVAL;
+                       break;
+               }
                kn->kn_fop = &pipe_efiltops;
                kn->kn_hook = rpipe;
                klist_insert_locked(&rpipe->pipe_sel.si_note, kn);
@@ -1074,19 +1079,20 @@ int
 filt_pipeexcept_common(struct knote *kn, struct pipe *rpipe)
 {
        struct pipe *wpipe;
+       int active = 0;
 
        rw_assert_wrlock(rpipe->pipe_lock);
 
        wpipe = pipe_peer(rpipe);
 
-       if ((rpipe->pipe_state & PIPE_EOF) || wpipe == NULL) {
-               kn->kn_flags |= EV_EOF;
-               if (kn->kn_flags & __EV_POLL)
+       if (kn->kn_flags & __EV_POLL) {
+               if ((rpipe->pipe_state & PIPE_EOF) || wpipe == NULL) {
                        kn->kn_flags |= __EV_HUP;
-               return (1);
+                       active = 1;
+               }
        }
 
-       return (0);
+       return (active);
 }
 
 int
Index: kern/tty_pty.c
===================================================================
RCS file: src/sys/kern/tty_pty.c,v
retrieving revision 1.110
diff -u -p -r1.110 tty_pty.c
--- kern/tty_pty.c      24 Oct 2021 00:02:25 -0000      1.110
+++ kern/tty_pty.c      11 Dec 2021 12:36:06 -0000
@@ -727,6 +734,7 @@ filt_ptcexcept(struct knote *kn, long hi
 {
        struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
        struct tty *tp;
+       int active = 0;
 
        tp = pti->pt_tty;
 
@@ -736,18 +744,18 @@ filt_ptcexcept(struct knote *kn, long hi
                    ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)) {
                        kn->kn_fflags |= NOTE_OOB;
                        kn->kn_data = 1;
-                       return (1);
+                       active = 1;
                }
-               return (0);
        }
-       if (!ISSET(tp->t_state, TS_CARR_ON)) {
-               kn->kn_flags |= EV_EOF;
-               if (kn->kn_flags & __EV_POLL)
+
+       if (kn->kn_flags & __EV_POLL) {
+               if (!ISSET(tp->t_state, TS_CARR_ON)) {
                        kn->kn_flags |= __EV_HUP;
-               return (1);
+                       active = 1;
+               }
        }
 
-       return (0);
+       return (active);
 }
 
 const struct filterops ptcread_filtops = {
Index: kern/uipc_socket.c
===================================================================
RCS file: src/sys/kern/uipc_socket.c,v
retrieving revision 1.269
diff -u -p -r1.269 uipc_socket.c
--- kern/uipc_socket.c  11 Nov 2021 16:35:09 -0000      1.269
+++ kern/uipc_socket.c  11 Dec 2021 12:36:06 -0000
@@ -2263,14 +2263,13 @@ filt_soexcept_common(struct knote *kn, s
                        kn->kn_data -= so->so_oobmark;
                        rv = 1;
                }
-       } else if (so->so_state & SS_CANTRCVMORE) {
-               kn->kn_flags |= EV_EOF;
-               if (kn->kn_flags & __EV_POLL) {
-                       if (so->so_state & SS_ISDISCONNECTED)
-                               kn->kn_flags |= __EV_HUP;
+       }
+
+       if (kn->kn_flags & __EV_POLL) {
+               if (so->so_state & SS_ISDISCONNECTED) {
+                       kn->kn_flags |= __EV_HUP;
+                       rv = 1;
                }
-               kn->kn_fflags = so->so_error;
-               rv = 1;
        }
 
        return rv;
Index: miscfs/fifofs/fifo_vnops.c
===================================================================
RCS file: src/sys/miscfs/fifofs/fifo_vnops.c,v
retrieving revision 1.87
diff -u -p -r1.87 fifo_vnops.c
--- miscfs/fifofs/fifo_vnops.c  11 Dec 2021 09:28:26 -0000      1.87
+++ miscfs/fifofs/fifo_vnops.c  11 Dec 2021 12:36:06 -0000
@@ -544,6 +544,10 @@ fifo_kqfilter(void *v)
                        /* Prevent triggering exceptfds. */
                        return (EPERM);
                }
+               if ((ap->a_kn->kn_flags & __EV_POLL) == 0) {
+                       /* Disallow usage through kevent(2). */
+                       return (EINVAL);
+               }
                ap->a_kn->kn_fop = &fifoexcept_filtops;
                so = fip->fi_readsock;
                sb = &so->so_rcv;
@@ -704,13 +708,11 @@ filt_fifoexcept_common(struct knote *kn,
 
        soassertlocked(so);
 
-       if (so->so_state & SS_CANTRCVMORE) {
-               kn->kn_flags |= EV_EOF;
-               if (kn->kn_flags & __EV_POLL) {
-                       if (so->so_state & SS_ISDISCONNECTED)
-                               kn->kn_flags |= __EV_HUP;
+       if (kn->kn_flags & __EV_POLL) {
+               if (so->so_state & SS_ISDISCONNECTED) {
+                       kn->kn_flags |= __EV_HUP;
+                       rv = 1;
                }
-               rv = 1;
        }
 
        return (rv);

Reply via email to