Module Name: src
Committed By: snj
Date: Sun Nov 8 21:47:45 UTC 2009
Modified Files:
src/sys/kern [netbsd-5]: uipc_usrreq.c
Log Message:
Pull up following revision(s) (requested by bouyer in ticket #932):
sys/kern/uipc_usrreq.c: revision 1.127
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.119.4.2 -r1.119.4.3 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.119.4.2 src/sys/kern/uipc_usrreq.c:1.119.4.3
--- src/sys/kern/uipc_usrreq.c:1.119.4.2 Wed Mar 18 05:33:23 2009
+++ src/sys/kern/uipc_usrreq.c Sun Nov 8 21:47:45 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: uipc_usrreq.c,v 1.119.4.2 2009/03/18 05:33:23 snj Exp $ */
+/* $NetBSD: uipc_usrreq.c,v 1.119.4.3 2009/11/08 21:47:45 snj 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.119.4.2 2009/03/18 05:33:23 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.119.4.3 2009/11/08 21:47:45 snj Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -251,6 +251,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);
}
@@ -327,6 +332,7 @@
struct unpcb *unp;
bool ext;
+ KASSERT(solocked(so));
unp = sotounpcb(so);
ext = false;
@@ -443,7 +449,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
@@ -454,6 +470,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: