Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Sep 2018 19:00:29 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r338571 - in head/sys: netinet netinet6
Message-ID:  <201809101900.w8AJ0TAQ055228@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Mon Sep 10 19:00:29 2018
New Revision: 338571
URL: https://svnweb.freebsd.org/changeset/base/338571

Log:
  Fix synchronization of LB group access.
  
  Lookups are protected by an epoch section, so the LB group linkage must
  be a CK_LIST rather than a plain LIST.  Furthermore, we were not
  deferring LB group frees, so in_pcbremlbgrouphash() could race with
  readers and cause a use-after-free.
  
  Reviewed by:	sbruno, Johannes Lundberg <johalun0@gmail.com>
  Tested by:	gallatin
  Approved by:	re (gjb)
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D17031

Modified:
  head/sys/netinet/in_pcb.c
  head/sys/netinet/in_pcb.h
  head/sys/netinet6/in6_pcb.c

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c	Mon Sep 10 18:59:23 2018	(r338570)
+++ head/sys/netinet/in_pcb.c	Mon Sep 10 19:00:29 2018	(r338571)
@@ -235,18 +235,28 @@ in_pcblbgroup_alloc(struct inpcblbgrouphead *hdr, u_ch
 	grp->il_lport = port;
 	grp->il_dependladdr = *addr;
 	grp->il_inpsiz = size;
-	LIST_INSERT_HEAD(hdr, grp, il_list);
+	CK_LIST_INSERT_HEAD(hdr, grp, il_list);
 	return (grp);
 }
 
 static void
-in_pcblbgroup_free(struct inpcblbgroup *grp)
+in_pcblbgroup_free_deferred(epoch_context_t ctx)
 {
+	struct inpcblbgroup *grp;
 
-	LIST_REMOVE(grp, il_list);
+	grp = __containerof(ctx, struct inpcblbgroup, il_epoch_ctx);
 	free(grp, M_PCB);
 }
 
+static void
+in_pcblbgroup_free(struct inpcblbgroup *grp)
+{
+
+	CK_LIST_REMOVE(grp, il_list);
+	epoch_call(net_epoch_preempt, &grp->il_epoch_ctx,
+	    in_pcblbgroup_free_deferred);
+}
+
 static struct inpcblbgroup *
 in_pcblbgroup_resize(struct inpcblbgrouphead *hdr,
     struct inpcblbgroup *old_grp, int size)
@@ -347,7 +357,7 @@ in_pcbinslbgrouphash(struct inpcb *inp)
 	hdr = &pcbinfo->ipi_lbgrouphashbase[
 	    INP_PCBLBGROUP_PORTHASH(inp->inp_lport,
 	        pcbinfo->ipi_lbgrouphashmask)];
-	LIST_FOREACH(grp, hdr, il_list) {
+	CK_LIST_FOREACH(grp, hdr, il_list) {
 		if (grp->il_vflag == inp->inp_vflag &&
 		    grp->il_lport == inp->inp_lport &&
 		    memcmp(&grp->il_dependladdr,
@@ -409,7 +419,7 @@ in_pcbremlbgrouphash(struct inpcb *inp)
 	    INP_PCBLBGROUP_PORTHASH(inp->inp_lport,
 	        pcbinfo->ipi_lbgrouphashmask)];
 
-	LIST_FOREACH(grp, hdr, il_list) {
+	CK_LIST_FOREACH(grp, hdr, il_list) {
 		for (i = 0; i < grp->il_inpcnt; ++i) {
 			if (grp->il_inp[i] != inp)
 				continue;
@@ -1972,7 +1982,7 @@ in_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo,
 	 * - Load balanced group does not contain IPv4 mapped INET6 wild sockets
 	 */
 	local_wild = NULL;
-	LIST_FOREACH(grp, hdr, il_list) {
+	CK_LIST_FOREACH(grp, hdr, il_list) {
 #ifdef INET6
 		if (!(grp->il_vflag & INP_IPV4))
 			continue;

Modified: head/sys/netinet/in_pcb.h
==============================================================================
--- head/sys/netinet/in_pcb.h	Mon Sep 10 18:59:23 2018	(r338570)
+++ head/sys/netinet/in_pcb.h	Mon Sep 10 19:00:29 2018	(r338571)
@@ -70,6 +70,7 @@
  */
 CK_LIST_HEAD(inpcbhead, inpcb);
 CK_LIST_HEAD(inpcbporthead, inpcbport);
+CK_LIST_HEAD(inpcblbgrouphead, inpcblbgroup);
 typedef	uint64_t	inp_gen_t;
 
 /*
@@ -566,7 +567,8 @@ struct inpcbgroup {
  * is dynamically resized as processes bind/unbind to that specific group.
  */
 struct inpcblbgroup {
-	LIST_ENTRY(inpcblbgroup) il_list;
+	CK_LIST_ENTRY(inpcblbgroup) il_list;
+	struct epoch_context il_epoch_ctx;
 	uint16_t	il_lport;			/* (c) */
 	u_char		il_vflag;			/* (c) */
 	u_char		il_pad;
@@ -578,7 +580,6 @@ struct inpcblbgroup {
 	uint32_t	il_inpcnt; /* cur count in il_inp[] (h) */
 	struct inpcb	*il_inp[];			/* (h) */
 };
-LIST_HEAD(inpcblbgrouphead, inpcblbgroup);
 
 #define INP_LOCK_INIT(inp, d, t) \
 	rw_init_flags(&(inp)->inp_lock, (t), RW_RECURSE |  RW_DUPOK)

Modified: head/sys/netinet6/in6_pcb.c
==============================================================================
--- head/sys/netinet6/in6_pcb.c	Mon Sep 10 18:59:23 2018	(r338570)
+++ head/sys/netinet6/in6_pcb.c	Mon Sep 10 19:00:29 2018	(r338571)
@@ -889,7 +889,7 @@ in6_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo,
 	 * - Load balanced group does not contain jailed sockets.
 	 * - Load balanced does not contain IPv4 mapped INET6 wild sockets.
 	 */
-	LIST_FOREACH(grp, hdr, il_list) {
+	CK_LIST_FOREACH(grp, hdr, il_list) {
 #ifdef INET
 		if (!(grp->il_vflag & INP_IPV6))
 			continue;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201809101900.w8AJ0TAQ055228>