summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_socket.c
diff options
context:
space:
mode:
authorcem <cem@FreeBSD.org>2015-07-14 02:00:50 +0000
committercem <cem@FreeBSD.org>2015-07-14 02:00:50 +0000
commit576619e564618bca3675db57580d8e1f76bd2ac7 (patch)
tree739399a2fae275099b377fb3967997e0a672d3b6 /sys/kern/uipc_socket.c
parent05a0acba04631454bc202315fdcc3a3cd8119838 (diff)
downloadFreeBSD-src-576619e564618bca3675db57580d8e1f76bd2ac7.zip
FreeBSD-src-576619e564618bca3675db57580d8e1f76bd2ac7.tar.gz
Fix cleanup race between unp_dispose and unp_gc
unp_dispose and unp_gc could race to teardown the same mbuf chains, which can lead to dereferencing freed filedesc pointers. This patch adds an IGNORE_RIGHTS flag on unpcbs marking the unpcb's RIGHTS as invalid/freed. The flag is protected by UNP_LIST_LOCK. To serialize against unp_gc, unp_dispose needs the socket object. Change the dom_dispose() KPI to take a socket object instead of an mbuf chain directly. PR: 194264 Differential Revision: https://reviews.freebsd.org/D3044 Reviewed by: mjg (earlier version) Approved by: markj (mentor) Obtained from: mjg MFC after: 1 month Sponsored by: EMC / Isilon Storage Division
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r--sys/kern/uipc_socket.c17
1 files changed, 9 insertions, 8 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index a431b4b..c9d8179 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -805,7 +805,7 @@ sofree(struct socket *so)
VNET_SO_ASSERT(so);
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL)
- (*pr->pr_domain->dom_dispose)(so->so_rcv.sb_mb);
+ (*pr->pr_domain->dom_dispose)(so);
if (pr->pr_usrreqs->pru_detach != NULL)
(*pr->pr_usrreqs->pru_detach)(so);
@@ -2356,7 +2356,7 @@ sorflush(struct socket *so)
{
struct sockbuf *sb = &so->so_rcv;
struct protosw *pr = so->so_proto;
- struct sockbuf asb;
+ struct socket aso;
VNET_SO_ASSERT(so);
@@ -2381,8 +2381,9 @@ sorflush(struct socket *so)
* and mutex data unchanged.
*/
SOCKBUF_LOCK(sb);
- bzero(&asb, offsetof(struct sockbuf, sb_startzero));
- bcopy(&sb->sb_startzero, &asb.sb_startzero,
+ bzero(&aso, sizeof(aso));
+ aso.so_pcb = so->so_pcb;
+ bcopy(&sb->sb_startzero, &aso.so_rcv.sb_startzero,
sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
bzero(&sb->sb_startzero,
sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
@@ -2390,12 +2391,12 @@ sorflush(struct socket *so)
sbunlock(sb);
/*
- * Dispose of special rights and flush the socket buffer. Don't call
- * any unsafe routines (that rely on locks being initialized) on asb.
+ * Dispose of special rights and flush the copied socket. Don't call
+ * any unsafe routines (that rely on locks being initialized) on aso.
*/
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL)
- (*pr->pr_domain->dom_dispose)(asb.sb_mb);
- sbrelease_internal(&asb, so);
+ (*pr->pr_domain->dom_dispose)(&aso);
+ sbrelease_internal(&aso.so_rcv, so);
}
/*
OpenPOWER on IntegriCloud