diff options
author | markj <markj@FreeBSD.org> | 2016-08-31 21:35:51 +0000 |
---|---|---|
committer | markj <markj@FreeBSD.org> | 2016-08-31 21:35:51 +0000 |
commit | f5388b59e2ab29e05e2ffb7cbccc9536a14ee97a (patch) | |
tree | dce419f17c83494106319a400e55cc84ced8eaca /sys/kern | |
parent | 1f035a616d39dfdb3e0a7cd2ef7741d68b896a4a (diff) | |
download | FreeBSD-src-f5388b59e2ab29e05e2ffb7cbccc9536a14ee97a.zip FreeBSD-src-f5388b59e2ab29e05e2ffb7cbccc9536a14ee97a.tar.gz |
MFC 303855:
Handle races with listening socket close when connecting a unix socket.
PR: 211531
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/uipc_usrreq.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index feead8a..ed9817c 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -429,6 +429,8 @@ uipc_attach(struct socket *so, int proto, struct thread *td) unp->unp_socket = so; so->so_pcb = unp; unp->unp_refcount = 1; + if (so->so_head != NULL) + unp->unp_flags |= UNP_NASCENT; UNP_LIST_LOCK(); unp->unp_gencnt = ++unp_gencnt; @@ -651,14 +653,22 @@ uipc_detach(struct socket *so) unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); - UNP_LINK_WLOCK(); + vp = NULL; + local_unp_rights = 0; + UNP_LIST_LOCK(); - UNP_PCB_LOCK(unp); LIST_REMOVE(unp, unp_link); unp->unp_gencnt = ++unp_gencnt; --unp_count; UNP_LIST_UNLOCK(); + if ((unp->unp_flags & UNP_NASCENT) != 0) { + UNP_PCB_LOCK(unp); + goto teardown; + } + UNP_LINK_WLOCK(); + UNP_PCB_LOCK(unp); + /* * XXXRW: Should assert vp->v_socket == so. */ @@ -686,6 +696,7 @@ uipc_detach(struct socket *so) } local_unp_rights = unp_rights; UNP_LINK_WUNLOCK(); +teardown: unp->unp_socket->so_pcb = NULL; saved_unp_addr = unp->unp_addr; unp->unp_addr = NULL; @@ -1441,6 +1452,7 @@ unp_connect2(struct socket *so, struct socket *so2, int req) if (so2->so_type != so->so_type) return (EPROTOTYPE); + unp2->unp_flags &= ~UNP_NASCENT; unp->unp_conn = unp2; switch (so->so_type) { |