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:
parent
1a681311da
commit
46a1d9bfe8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166708
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user