Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Kernel panic related to pipe



> Date: Mon, 05 Oct 2026 17:57:25 +0700
> From: Robert Elz <kre%munnari.OZ.AU@localhost>
> References: <asN1qORaELZUHaDN%big-apple.aprisoft.de@localhost> <877bjwlcbw.fsf%castella.elements.tetera.org@localhost> <asNzOSWNKvzPAmxu%big-apple.aprisoft.de@localhost>
> 
>     Date:        Mon, 5 Oct 2026 12:02:16 +0200
>     From:        Martin Husemann <martin%duskware.de@localhost>
>     Message-ID:  <asN1qORaELZUHaDN%big-apple.aprisoft.de@localhost>
> 
>   | Taylor: it crashes in the
>   |
>   | 	KASSERT(mutex_owned(pipe->pipe_lock));
>   |
>   | with a NULL deref as apparently "pipe" is NULL.
> 
> Try with src/sys/kern/sys_pipe.c 1.178  (from about 20 mins ago).

Thanks, but while this stop-gap measure will help to unblock others,
it cannot be correct on its own.  Here's the context of the change:

@@ -507,62 +507,64 @@ again:
 
 		/*
 		 * Detect EOF condition.
 		 * Read returns 0 on EOF, no need to set error.
 		 *
 		 * XXX Why rpipe->pipe_state and not wpipe->pipe_state?
 		 * XXX Distinguish reader-closed from writer-closed?
 		 */
 		if (rpipe->pipe_state & PIPE_EOF)
 			break;
...
 		/*
 		 * If the "write-side" is blocked, wake it up now.
 		 */
 		wpipe = rpipe->pipe_peer;
-		pipeselwakeup(wpipe, POLL_OUT);
-		cv_broadcast(&wpipe->pipe_wcv);
+		if (wpipe != NULL) {
+			pipeselwakeup(wpipe, POLL_OUT);
+			cv_broadcast(&wpipe->pipe_wcv);
+		}

In the ellipsis, the pipe->pipe_lock (it's the same for the reader and
the writer) is not released.  (You'll also find a call to a function
`pipeunlock', but that just changes a flag bit under that lock and
signals a condvar; it doesn't mutex_exit.)  And the transition from
pipe->pipe_peer != NULL to pipe->pipe_peer == NULL only happens

(a) under the lock, and
(b) after PIPE_EOF has been set on both sides of the pipe:

   1049 	pipe->pipe_state |= PIPE_EOF;
   1050 	if ((ppipe = pipe->pipe_peer) != NULL) {
...
   1064 		ppipe->pipe_state |= PIPE_EOF;
   1065 		if (ppipe->pipe_busy) {
   1066 			cv_broadcast(&ppipe->pipe_rcv);
   1067 			cv_broadcast(&ppipe->pipe_wcv);
   1068 			while (ppipe->pipe_busy)
   1069 				cv_wait(&ppipe->pipe_draincv, lock);
   1070 		}
   1071 		ppipe->pipe_peer = NULL;
   1072 	}

https://nxr.netbsd.org/xref/src/sys/kern/sys_pipe.c?r=1.177#1049

Hence, if, in the context of your change, PIPE_EOF has been set in
rpipe->pipe_state, then rpipe->pipe_peer is supposed to be nonnull.

So:

1. there is something else going wrong here, and
2. we don't have an adequate automatic test for it.


Home | Main Index | Thread Index | Old Index