Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131837512
D3044.id6845.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D3044.id6845.diff
View Options
Index: sys/kern/uipc_socket.c
===================================================================
--- sys/kern/uipc_socket.c
+++ sys/kern/uipc_socket.c
@@ -805,7 +805,7 @@
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 @@
{
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 @@
* 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 @@
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);
}
/*
Index: sys/kern/uipc_usrreq.c
===================================================================
--- sys/kern/uipc_usrreq.c
+++ sys/kern/uipc_usrreq.c
@@ -278,6 +278,7 @@
static int unp_connect2(struct socket *so, struct socket *so2, int);
static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2);
static void unp_dispose(struct mbuf *);
+static void unp_dispose_so(struct socket *so);
static void unp_shutdown(struct unpcb *);
static void unp_drop(struct unpcb *, int);
static void unp_gc(__unused void *, int);
@@ -334,7 +335,7 @@
.dom_name = "local",
.dom_init = unp_init,
.dom_externalize = unp_externalize,
- .dom_dispose = unp_dispose,
+ .dom_dispose = unp_dispose_so,
.dom_protosw = localsw,
.dom_protoswNPROTOSW = &localsw[sizeof(localsw)/sizeof(localsw[0])]
};
@@ -2193,8 +2194,7 @@
struct socket *so;
struct file *fp;
- /* Already processed. */
- if (unp->unp_gcflag & UNPGC_SCANNED)
+ if (unp->unp_gcflag & (UNPGC_SCANNED | UNPGC_IGNORE))
return;
fp = unp->unp_file;
@@ -2252,11 +2252,11 @@
unp_taskcount++;
UNP_LIST_LOCK();
/*
- * First clear all gc flags from previous runs.
+ * First clear all gc flags from previous runs, apart from UNPGC_IGNORE.
*/
for (head = heads; *head != NULL; head++)
LIST_FOREACH(unp, *head, unp_link)
- unp->unp_gcflag = 0;
+ unp->unp_gcflag = unp->unp_gcflag & UNPGC_IGNORE;
/*
* Scan marking all reachable sockets with UNPGC_REF. Once a socket
@@ -2333,6 +2333,21 @@
unp_scan(m, unp_freerights);
}
+/*
+ * Synchronize against unp_gc, which can trip over data as we are freeing it.
+ */
+static void
+unp_dispose_so(struct socket *so)
+{
+ struct unpcb *unp;
+
+ unp = sotounpcb(so);
+ UNP_LIST_LOCK();
+ unp->unp_gcflag |= UNPGC_IGNORE;
+ UNP_LIST_UNLOCK();
+ unp_dispose(so->so_rcv.sb_mb);
+}
+
static void
unp_scan(struct mbuf *m0, void (*op)(struct filedescent **, int))
{
Index: sys/sys/domain.h
===================================================================
--- sys/sys/domain.h
+++ sys/sys/domain.h
@@ -42,6 +42,7 @@
*/
struct mbuf;
struct ifnet;
+struct socket;
struct domain {
int dom_family; /* AF_xxx */
@@ -53,7 +54,7 @@
int (*dom_externalize) /* externalize access rights */
(struct mbuf *, struct mbuf **, int);
void (*dom_dispose) /* dispose of internalized rights */
- (struct mbuf *);
+ (struct socket *);
struct protosw *dom_protosw, *dom_protoswNPROTOSW;
struct domain *dom_next;
int (*dom_rtattach) /* initialize routing table */
Index: sys/sys/unpcb.h
===================================================================
--- sys/sys/unpcb.h
+++ sys/sys/unpcb.h
@@ -106,6 +106,7 @@
#define UNPGC_REF 0x1 /* unpcb has external ref. */
#define UNPGC_DEAD 0x2 /* unpcb might be dead. */
#define UNPGC_SCANNED 0x4 /* Has been scanned. */
+#define UNPGC_IGNORE 0x8 /* Someone will clear it. */
/*
* These flags are used to handle non-atomicity in connect() and bind()
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Oct 12, 2:29 PM (23 m, 45 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23626526
Default Alt Text
D3044.id6845.diff (4 KB)
Attached To
Mode
D3044: PR 194264: Fix race between unp_dispose and unp_gc
Attached
Detach File
Event Timeline
Log In to Comment