Source-Changes-HG archive

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

[src/trunk]: src/sys/kern In uipc_usrreq(PRU_ACCEPT), grab the unp_streamlock...



details:   https://anonhg.NetBSD.org/src/rev/05cc5e606ac4
branches:  trunk
changeset: 746986:05cc5e606ac4
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Wed Aug 26 22:34:47 2009 +0000

description:
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

diffstat:

 sys/kern/uipc_usrreq.c |  22 ++++++++++++++++++++--
 1 files changed, 20 insertions(+), 2 deletions(-)

diffs (65 lines):

diff -r a5fc799082fa -r 05cc5e606ac4 sys/kern/uipc_usrreq.c
--- a/sys/kern/uipc_usrreq.c    Wed Aug 26 22:33:38 2009 +0000
+++ b/sys/kern/uipc_usrreq.c    Wed Aug 26 22:34:47 2009 +0000
@@ -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:



Home | Main Index | Thread Index | Old Index