Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Feb 2019 15:46:43 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r344278 - head/sys/kern
Message-ID:  <201902191546.x1JFkhZq032336@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201902191546.x1JFkhZq032336>