svn commit: r334185 - head/sys/kern
Matt Macy
mmacy at FreeBSD.org
Thu May 24 21:13:47 UTC 2018
Author: mmacy
Date: Thu May 24 21:13:46 2018
New Revision: 334185
URL: https://svnweb.freebsd.org/changeset/base/334185
Log:
AF_UNIX: It is possible for UNIX datagram sockets to be connected
to themselves. The updated code assumed that that could not happen
and would try to lock the unp mutex twice.
There may be a lingering issue here but this fixes it for the
reporter.
PR: 228458
Reported by: marieheleneka at gmail.com
Modified:
head/sys/kern/uipc_usrreq.c
Modified: head/sys/kern/uipc_usrreq.c
==============================================================================
--- head/sys/kern/uipc_usrreq.c Thu May 24 21:11:38 2018 (r334184)
+++ head/sys/kern/uipc_usrreq.c Thu May 24 21:13:46 2018 (r334185)
@@ -722,7 +722,9 @@ uipc_close(struct socket *so)
}
unp2 = unp->unp_conn;
unp_pcb_hold(unp);
- if (unp2 != NULL) {
+ if (__predict_false(unp == unp2)) {
+ unp_disconnect(unp, unp2);
+ } else if (unp2 != NULL) {
unp_pcb_hold(unp2);
unp_pcb_owned_lock2(unp, unp2, freed);
unp_disconnect(unp, unp2);
@@ -747,9 +749,13 @@ uipc_connect2(struct socket *so1, struct socket *so2)
KASSERT(unp != NULL, ("uipc_connect2: unp == NULL"));
unp2 = so2->so_pcb;
KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL"));
- unp_pcb_lock2(unp, unp2);
+ if (unp != unp2)
+ unp_pcb_lock2(unp, unp2);
+ else
+ UNP_PCB_LOCK(unp);
error = unp_connect2(so1, so2, PRU_CONNECT2);
- UNP_PCB_UNLOCK(unp2);
+ if (unp != unp2)
+ UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
return (error);
}
@@ -783,29 +789,30 @@ uipc_detach(struct socket *so)
mtx_lock(vplock);
}
UNP_PCB_LOCK(unp);
- if ((unp2 = unp->unp_conn) != NULL) {
- unp_pcb_owned_lock2(unp, unp2, freeunp);
- if (freeunp)
- unp2 = NULL;
- }
if (unp->unp_vnode != vp &&
unp->unp_vnode != NULL) {
if (vplock)
mtx_unlock(vplock);
UNP_PCB_UNLOCK(unp);
- if (unp2)
- UNP_PCB_UNLOCK(unp2);
goto restart;
}
if ((unp->unp_flags & UNP_NASCENT) != 0) {
- if (unp2)
- UNP_PCB_UNLOCK(unp2);
goto teardown;
}
if ((vp = unp->unp_vnode) != NULL) {
VOP_UNP_DETACH(vp);
unp->unp_vnode = NULL;
}
+ if (__predict_false(unp == unp->unp_conn)) {
+ unp_disconnect(unp, unp);
+ unp2 = NULL;
+ goto connect_self;
+ }
+ if ((unp2 = unp->unp_conn) != NULL) {
+ unp_pcb_owned_lock2(unp, unp2, freeunp);
+ if (freeunp)
+ unp2 = NULL;
+ }
unp_pcb_hold(unp);
if (unp2 != NULL) {
unp_pcb_hold(unp2);
@@ -813,6 +820,7 @@ uipc_detach(struct socket *so)
if (unp_pcb_rele(unp2) == 0)
UNP_PCB_UNLOCK(unp2);
}
+ connect_self:
UNP_PCB_UNLOCK(unp);
UNP_REF_LIST_LOCK();
while (!LIST_EMPTY(&unp->unp_refs)) {
@@ -864,6 +872,10 @@ uipc_disconnect(struct socket *so)
UNP_PCB_UNLOCK(unp);
return (0);
}
+ if (unp == unp2) {
+ if (unp_pcb_rele(unp) == 0)
+ UNP_PCB_UNLOCK(unp);
+ }
unp_pcb_owned_lock2(unp, unp2, freed);
if (__predict_false(freed)) {
UNP_PCB_UNLOCK(unp);
@@ -1925,7 +1937,9 @@ unp_drop(struct unpcb *unp)
if (so)
so->so_error = ECONNRESET;
unp2 = unp->unp_conn;
- if (unp2 != NULL) {
+ if (unp2 == unp) {
+ unp_disconnect(unp, unp2);
+ } else if (unp2 != NULL) {
unp_pcb_hold(unp2);
unp_pcb_owned_lock2(unp, unp2, freed);
unp_disconnect(unp, unp2);
More information about the svn-src-all
mailing list