Module Name:    src
Committed By:   bouyer
Date:           Wed Aug 26 22:34:47 UTC 2009

Modified Files:
        src/sys/kern: uipc_usrreq.c

Log Message:
In uipc_usrreq(PRU_ACCEPT), grab the unp_streamlock before unp_setpeerlocks().
This fixes a race where, for a short period of time, so->so_lock and
so2->so_lock are not sync. This makes solocked2() and solocked()
unreliable and cause DIAGNOSTIC kernel panics. This also fixes a possible
panic in unp_setaddr() which expects the socket locked.
Should fix kern/38968, fix proposed in
http://mail-index.netbsd.org/tech-kern/2009/08/17/msg005863.html


To generate a diff of this commit:
cvs rdiff -u -r1.126 -r1.127 src/sys/kern/uipc_usrreq.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/uipc_usrreq.c
diff -u src/sys/kern/uipc_usrreq.c:1.126 src/sys/kern/uipc_usrreq.c:1.127
--- src/sys/kern/uipc_usrreq.c:1.126	Sun May 24 21:41:26 2009
+++ src/sys/kern/uipc_usrreq.c	Wed Aug 26 22:34:47 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_usrreq.c,v 1.126 2009/05/24 21:41:26 ad Exp $	*/
+/*	$NetBSD: uipc_usrreq.c,v 1.127 2009/08/26 22:34:47 bouyer Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2004, 2008, 2009 The NetBSD Foundation, Inc.
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.126 2009/05/24 21:41:26 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.127 2009/08/26 22:34:47 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -252,6 +252,11 @@
 	unp->unp_streamlock = NULL;
 	mutex_obj_hold(lock);
 	membar_exit();
+	/*
+	 * possible race if lock is not held - see comment in
+	 * uipc_usrreq(PRU_ACCEPT).
+	 */
+	KASSERT(mutex_owned(lock));
 	solockreset(so, lock);
 	solockreset(so2, lock);
 }
@@ -328,6 +333,7 @@
 	struct unpcb *unp;
 	bool ext;
 
+	KASSERT(solocked(so));
 	unp = sotounpcb(so);
 	ext = false;
 
@@ -444,7 +450,17 @@
 		 * If the connection is fully established, break the
 		 * association with uipc_lock and give the connected
 		 * pair a seperate lock to share.
+		 * There is a race here: sotounpcb(so2)->unp_streamlock
+		 * is not locked, so when changing so2->so_lock
+		 * another thread can grab it while so->so_lock is still
+		 * pointing to the (locked) uipc_lock.
+		 * this should be harmless, exept that this makes
+		 * solocked2() and solocked() unreliable.
+		 * Another problem is that unp_setaddr() expects the
+		 * the socket locked. Grabing sotounpcb(so2)->unp_streamlock
+		 * fixes both issues.
 		 */
+		mutex_enter(sotounpcb(so2)->unp_streamlock);
 		unp_setpeerlocks(so2, so);
 		/*
 		 * Only now return peer's address, as we may need to
@@ -455,6 +471,8 @@
 		 * error == 0 and sun_noname as the peer address.
 		 */
 		unp_setaddr(so, nam, true);
+		/* so_lock now points to unp_streamlock */
+		mutex_exit(so2->so_lock);
 		break;
 
 	case PRU_SHUTDOWN:

Reply via email to