Author: markj
Date: Tue Feb 19 15:46:43 2019
New Revision: 344278
URL: https://svnweb.freebsd.org/changeset/base/344278

Log:
  Move a racy assertion in filt_pipewrite().
  
  EVFILT_WRITE knotes for pipes live on the knlist for the other end of the
  pipe.  Since they do not hold a reference on the corresponding file
  structure, they may be removed from the knlist by pipeclose() while still
  remaining active.  In this case, there is no knlist lock acquired before
  filt_pipewrite() is called, so the assertion fails.
  
  Fix the problem by first checking whether that end of the pipe has been
  closed.  These checks are memory safe since the knote holds a reference
  on one end of the pipe, and the pipe structure is not freed until both
  ends are closed.  The checks are not racy since PIPE_EOF is never cleared
  after being set, and pipe_present is never set back to PIPE_ACTIVE after
  pipeclose() has been called.
  
  PR:           235640
  Reported and tested by:       pho
  Reviewed by:  kib
  MFC after:    2 weeks
  Sponsored by: The FreeBSD Foundation
  Differential Revision:        https://reviews.freebsd.org/D19224

Modified:
  head/sys/kern/sys_pipe.c

Modified: head/sys/kern/sys_pipe.c
==============================================================================
--- head/sys/kern/sys_pipe.c    Tue Feb 19 12:45:37 2019        (r344277)
+++ head/sys/kern/sys_pipe.c    Tue Feb 19 15:46:43 2019        (r344278)
@@ -1741,15 +1741,19 @@ static int
 filt_pipewrite(struct knote *kn, long hint)
 {
        struct pipe *wpipe;
-   
+
+       /*
+        * If this end of the pipe is closed, the knote was removed from the
+        * knlist and the list lock (i.e., the pipe lock) is therefore not held.
+        */
        wpipe = kn->kn_hook;
-       PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
        if (wpipe->pipe_present != PIPE_ACTIVE ||
            (wpipe->pipe_state & PIPE_EOF)) {
                kn->kn_data = 0;
                kn->kn_flags |= EV_EOF;
                return (1);
        }
+       PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
        kn->kn_data = (wpipe->pipe_buffer.size > 0) ?
            (wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) : PIPE_BUF;
        if (wpipe->pipe_state & PIPE_DIRECTW)
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to