netfilter: nft_set_rbtree: Add missing expired checks
authorPhil Sutter <phil@nwl.cc>
Mon, 11 May 2020 13:31:41 +0000 (15:31 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 May 2020 06:20:25 +0000 (08:20 +0200)
[ Upstream commit 340eaff651160234bdbce07ef34b92a8e45cd540 ]

Expired intervals would still match and be dumped to user space until
garbage collection wiped them out. Make sure they stop matching and
disappear (from users' perspective) as soon as they expire.

Fixes: 8d8540c4f5e03 ("netfilter: nft_set_rbtree: add timeout support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/netfilter/nft_set_rbtree.c

index 95fcba34bfd35e34da2d31fa25dfab75fa003b81..ee7c29e0a9d7b5320ea55f9e7c6d209f8c6561e0 100644 (file)
@@ -79,6 +79,10 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
                                parent = rcu_dereference_raw(parent->rb_left);
                                continue;
                        }
+
+                       if (nft_set_elem_expired(&rbe->ext))
+                               return false;
+
                        if (nft_rbtree_interval_end(rbe)) {
                                if (nft_set_is_anonymous(set))
                                        return false;
@@ -94,6 +98,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
 
        if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
            nft_set_elem_active(&interval->ext, genmask) &&
+           !nft_set_elem_expired(&interval->ext) &&
            nft_rbtree_interval_start(interval)) {
                *ext = &interval->ext;
                return true;
@@ -154,6 +159,9 @@ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set,
                                continue;
                        }
 
+                       if (nft_set_elem_expired(&rbe->ext))
+                               return false;
+
                        if (!nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) ||
                            (*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END) ==
                            (flags & NFT_SET_ELEM_INTERVAL_END)) {
@@ -170,6 +178,7 @@ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set,
 
        if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
            nft_set_elem_active(&interval->ext, genmask) &&
+           !nft_set_elem_expired(&interval->ext) &&
            ((!nft_rbtree_interval_end(interval) &&
              !(flags & NFT_SET_ELEM_INTERVAL_END)) ||
             (nft_rbtree_interval_end(interval) &&
@@ -355,6 +364,8 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
 
                if (iter->count < iter->skip)
                        goto cont;
+               if (nft_set_elem_expired(&rbe->ext))
+                       goto cont;
                if (!nft_set_elem_active(&rbe->ext, iter->genmask))
                        goto cont;