Change unp_mtx to supporting recursion, and do not drop the unp_mtx over

sonewconn() in unp_connect().  This avoids a race that occurs due to
v_socket being an uncounted reference, as the lock was being released in
order to call sonewconn(), which otherwise recurses into the UNIX domain
socket code via pru_attach, as well as holding the lock over a sleeping
memory allocation in uipc_attach().  Switch to a non-sleeping memory
allocation during UNIX domain socket attach.

This fix non-ideal in that it requires enabling recursion, but is a much
smaller change than moving to using true references for v_socket.  The
reported panic occurs in unp_connect() following the return of
sonewconn().

Update copyright year.

Panic reported by:      jhb
This commit is contained in:
Robert Watson 2007-02-14 12:22:11 +00:00
parent 1a681311da
commit 46a1d9bfe8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166708

View File

@ -1,7 +1,7 @@
/*-
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California.
* Copyright (c) 2004-2006 Robert N. M. Watson
* Copyright (c) 2004-2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -161,7 +161,7 @@ SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, "");
*/
static struct mtx unp_mtx;
#define UNP_LOCK_INIT() \
mtx_init(&unp_mtx, "unp", NULL, MTX_DEF)
mtx_init(&unp_mtx, "unp", NULL, MTX_DEF | MTX_RECURSE)
#define UNP_LOCK() mtx_lock(&unp_mtx)
#define UNP_UNLOCK() mtx_unlock(&unp_mtx)
#define UNP_LOCK_ASSERT() mtx_assert(&unp_mtx, MA_OWNED)
@ -278,7 +278,7 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
if (error)
return (error);
}
unp = uma_zalloc(unp_zone, M_WAITOK | M_ZERO);
unp = uma_zalloc(unp_zone, M_NOWAIT | M_ZERO);
if (unp == NULL)
return (ENOBUFS);
LIST_INIT(&unp->unp_refs);
@ -988,17 +988,9 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
goto bad2;
}
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
if (so2->so_options & SO_ACCEPTCONN) {
/*
* NB: drop locks here so unp_attach is entered w/o
* locks; this avoids a recursive lock of the head
* and holding sleep locks across a (potentially)
* blocking malloc.
*/
UNP_UNLOCK();
if (so2->so_options & SO_ACCEPTCONN)
so3 = sonewconn(so2, 0);
UNP_LOCK();
} else
else
so3 = NULL;
if (so3 == NULL) {
error = ECONNREFUSED;