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: