svn commit: r319685 - head/sys/kern

Gleb Smirnoff glebius at FreeBSD.org
Thu Jun 8 06:16:48 UTC 2017


Author: glebius
Date: Thu Jun  8 06:16:47 2017
New Revision: 319685
URL: https://svnweb.freebsd.org/changeset/base/319685

Log:
  Fix a degenerate case when soisdisconnected() would call soisconnected().
  
  This happens when closing a socket with upcall, and trace is: soclose()->
  ... protocol ... -> soisdisconnected() -> socantrcvmore_locked() ->
  sowakeup() -> soisconnected().
  
  Right now this case is innocent for two reasons.  First, soisconnected()
  doesn't clear SS_ISDISCONNECTED flag.  Second, the mutex to lock the
  socket is the socket receive buffer mutex, and sodisconnected() first
  disables the receive buffer. But in future code, the mutex to lock
  socket is different to buffer mutex, and we would get undesired mutex
  recursion.
  
  The fix is to check SS_ISDISCONNECTED flag before calling upcall.

Modified:
  head/sys/kern/uipc_sockbuf.c

Modified: head/sys/kern/uipc_sockbuf.c
==============================================================================
--- head/sys/kern/uipc_sockbuf.c	Thu Jun  8 06:13:53 2017	(r319684)
+++ head/sys/kern/uipc_sockbuf.c	Thu Jun  8 06:16:47 2017	(r319685)
@@ -322,7 +322,7 @@ sowakeup(struct socket *so, struct sockbuf *sb)
 		wakeup(&sb->sb_acc);
 	}
 	KNOTE_LOCKED(&sb->sb_sel.si_note, 0);
-	if (sb->sb_upcall != NULL) {
+	if (sb->sb_upcall != NULL && !(so->so_state & SS_ISDISCONNECTED)) {
 		ret = sb->sb_upcall(so, sb->sb_upcallarg, M_NOWAIT);
 		if (ret == SU_ISCONNECTED) {
 			KASSERT(sb == &so->so_rcv,


More information about the svn-src-all mailing list