Re: [PATCH nf 3/3] netfilter: nf_conncount: speculative garbage collection on empty lists

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Dec 27, 2018 at 07:05:39PM +0100, Pablo Neira Ayuso wrote:
> On Thu, Dec 27, 2018 at 11:03:04AM -0600, Shawn Bohrer wrote:
> > On Wed, Dec 26, 2018 at 11:08:43PM +0100, Pablo Neira Ayuso wrote:
> [...]
> > > @@ -360,11 +340,6 @@ insert_tree(struct net *net,
> > >  				count = 0; /* hotdrop */
> > >  			} else if (ret == NF_CONNCOUNT_ADDED) {
> > >  				count = rbconn->list.count;
> > > -			} else {
> > > -				/* NF_CONNCOUNT_SKIP, rbconn is already
> > > -				 * reclaimed by gc, insert a new tree node
> > > -				 */
> > > -				node_found = false;
> > >  			}
> > >  			break;
> > >  		}
> > > @@ -451,11 +426,6 @@ count_tree(struct net *net,
> > >  				return 0; /* hotdrop */
> > >  			} else if (ret == NF_CONNCOUNT_ADDED) {
> > >  				return rbconn->list.count;
> > > -			} else {
> > > -				/* NF_CONNCOUNT_SKIP, rbconn is already
> > > -				 * reclaimed by gc, insert a new tree node
> > > -				 */
> > > -				break;
> > >  			}
> > >  		}
> > >  	}
> > 
> > The packet path can run concurrently on multiple CPUs correct?  If
> > yes, then there is a race where an empty node is about to be freed by
> > tree_nodes_free() which holds the rbconn->list.list_lock, while
> > nf_conncount_add() inside count_tree is waiting to acquire the lock.
> > Once tree_nodes_free() releases the lock nf_conncount_add() will add
> > the connection to the list, but it is too late the node has already
> > been rb_erased from the tree.
> 
> Right, if the CPU walking over nf_conncount_add() loses race, we have
> a connection object on a list that is gone.
> 
> > I think count_tree needs to break here if addit is true.  Then
> > insert_tree will handle calling nf_conncount_add() while holding both
> > the rbconn->list.list_lock and nf_conncount_locks.
> 
> Therefore we still need the NF_CONNCOUNT_SKIP handling (or rename it
> to NF_CONNCOUNT_LOCK as Florian suggested), so we can fall back on
> adding a new list in this case. It would be probably good to add a
> comment on this on the code.

I don't think you need NF_CONNCOUNT_SKIP or NF_CONNCOUNT_LOCK.  Just
don't call nf_conncount_add() from count_tree():

diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c
index b33df77bd7a3..aa74c9be89e3 100644
--- a/net/netfilter/nf_conncount.c
+++ b/net/netfilter/nf_conncount.c
@@ -420,13 +420,8 @@ count_tree(struct net *net,
 
 			if (!addit)
 				return rbconn->list.count;
-
-			ret = nf_conncount_add(&rbconn->list, tuple, zone);
-			if (ret == NF_CONNCOUNT_ERR) {
-				return 0; /* hotdrop */
-			} else if (ret == NF_CONNCOUNT_ADDED) {
-				return rbconn->list.count;
-			}
+			else
+				break;
 		}
 	}
 
insert_tree() and tree_nodes_free() can't race because they are both holding
nf_conncount_locks.

--
Shawn



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux