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
This commit is contained in:
parent
c9172fb4f1
commit
18a7de663b
@ -1741,15 +1741,19 @@ static int
|
|||||||
filt_pipewrite(struct knote *kn, long hint)
|
filt_pipewrite(struct knote *kn, long hint)
|
||||||
{
|
{
|
||||||
struct pipe *wpipe;
|
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;
|
wpipe = kn->kn_hook;
|
||||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
|
|
||||||
if (wpipe->pipe_present != PIPE_ACTIVE ||
|
if (wpipe->pipe_present != PIPE_ACTIVE ||
|
||||||
(wpipe->pipe_state & PIPE_EOF)) {
|
(wpipe->pipe_state & PIPE_EOF)) {
|
||||||
kn->kn_data = 0;
|
kn->kn_data = 0;
|
||||||
kn->kn_flags |= EV_EOF;
|
kn->kn_flags |= EV_EOF;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
|
||||||
kn->kn_data = (wpipe->pipe_buffer.size > 0) ?
|
kn->kn_data = (wpipe->pipe_buffer.size > 0) ?
|
||||||
(wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) : PIPE_BUF;
|
(wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) : PIPE_BUF;
|
||||||
if (wpipe->pipe_state & PIPE_DIRECTW)
|
if (wpipe->pipe_state & PIPE_DIRECTW)
|
||||||
|
Loading…
Reference in New Issue
Block a user