diff options
author | markj <markj@FreeBSD.org> | 2016-09-02 00:14:28 +0000 |
---|---|---|
committer | markj <markj@FreeBSD.org> | 2016-09-02 00:14:28 +0000 |
commit | a80af232a432914d0c8e6a0c45184d0efcbf1a98 (patch) | |
tree | 2dbfbfd4ea4c0bdeb3e429a1c59472bb0a31aa02 /sys/kern/uipc_socket.c | |
parent | a79616dbee6ff950597905ba262f9d753ad202d3 (diff) | |
download | FreeBSD-src-a80af232a432914d0c8e6a0c45184d0efcbf1a98.zip FreeBSD-src-a80af232a432914d0c8e6a0c45184d0efcbf1a98.tar.gz |
MFC r285522:
Fix cleanup race between unp_dispose and unp_gc.
This change modifies the original commit to avoid changing the
domain_dispose KPI.
Tested by: Oliver Pinter
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r-- | sys/kern/uipc_socket.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 23acdf7..eb83617 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -741,8 +741,12 @@ sofree(struct socket *so) ACCEPT_UNLOCK(); 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); + if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL) { + if (pr->pr_domain->dom_family == AF_LOCAL) + unp_dispose_so(so); + else + (*pr->pr_domain->dom_dispose)(so->so_rcv.sb_mb); + } if (pr->pr_usrreqs->pru_detach != NULL) (*pr->pr_usrreqs->pru_detach)(so); @@ -2290,7 +2294,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); @@ -2315,8 +2319,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)); @@ -2324,12 +2329,16 @@ 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); + if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL) { + if (pr->pr_domain->dom_family == AF_LOCAL) + unp_dispose_so(&aso); + else + (*pr->pr_domain->dom_dispose)(aso.so_rcv.sb_mb); + } + sbrelease_internal(&aso.so_rcv, so); } /* |