Skip to content

Commit 7fa2e29

Browse files
ummakynesgregkh
authored andcommitted
netfilter: nf_tables: use timestamp to check for set element timeout
commit 7395dfa upstream. Add a timestamp field at the beginning of the transaction, store it in the nftables per-netns area. Update set backend .insert, .deactivate and sync gc path to use the timestamp, this avoids that an element expires while control plane transaction is still unfinished. .lookup and .update, which are used from packet path, still use the current time to check if the element has expired. And .get path and dump also since this runs lockless under rcu read size lock. Then, there is async gc which also needs to check the current time since it runs asynchronously from a workqueue. Fixes: c3e1b00 ("netfilter: nf_tables: add set element timeout support") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Jianqi Ren <jianqi.ren.cn@windriver.com> Signed-off-by: He Zhe <zhe.he@windriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 50b22a9 commit 7fa2e29

5 files changed

Lines changed: 42 additions & 15 deletions

File tree

include/net/netfilter/nf_tables.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,10 +826,16 @@ static inline struct nft_set_elem_expr *nft_set_ext_expr(const struct nft_set_ex
826826
return nft_set_ext(ext, NFT_SET_EXT_EXPRESSIONS);
827827
}
828828

829-
static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
829+
static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
830+
u64 tstamp)
830831
{
831832
return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
832-
time_is_before_eq_jiffies64(*nft_set_ext_expiration(ext));
833+
time_after_eq64(tstamp, *nft_set_ext_expiration(ext));
834+
}
835+
836+
static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
837+
{
838+
return __nft_set_elem_expired(ext, get_jiffies_64());
833839
}
834840

835841
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
@@ -1791,6 +1797,7 @@ struct nftables_pernet {
17911797
struct list_head notify_list;
17921798
struct mutex commit_mutex;
17931799
u64 table_handle;
1800+
u64 tstamp;
17941801
unsigned int base_seq;
17951802
unsigned int gc_seq;
17961803
u8 validate_state;
@@ -1803,6 +1810,11 @@ static inline struct nftables_pernet *nft_pernet(const struct net *net)
18031810
return net_generic(net, nf_tables_net_id);
18041811
}
18051812

1813+
static inline u64 nft_net_tstamp(const struct net *net)
1814+
{
1815+
return nft_pernet(net)->tstamp;
1816+
}
1817+
18061818
#define __NFT_REDUCE_READONLY 1UL
18071819
#define NFT_REDUCE_READONLY (void *)__NFT_REDUCE_READONLY
18081820

net/netfilter/nf_tables_api.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9963,6 +9963,7 @@ struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
99639963
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
99649964
{
99659965
struct nft_set_elem_catchall *catchall, *next;
9966+
u64 tstamp = nft_net_tstamp(gc->net);
99669967
const struct nft_set *set = gc->set;
99679968
struct nft_set_elem elem;
99689969
struct nft_set_ext *ext;
@@ -9972,7 +9973,7 @@ struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
99729973
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
99739974
ext = nft_set_elem_ext(set, catchall->elem);
99749975

9975-
if (!nft_set_elem_expired(ext))
9976+
if (!__nft_set_elem_expired(ext, tstamp))
99769977
continue;
99779978

99789979
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
@@ -10777,6 +10778,7 @@ static bool nf_tables_valid_genid(struct net *net, u32 genid)
1077710778
bool genid_ok;
1077810779

1077910780
mutex_lock(&nft_net->commit_mutex);
10781+
nft_net->tstamp = get_jiffies_64();
1078010782

1078110783
genid_ok = genid == 0 || nft_net->base_seq == genid;
1078210784
if (!genid_ok)

net/netfilter/nft_set_hash.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct nft_rhash_cmp_arg {
3737
const struct nft_set *set;
3838
const u32 *key;
3939
u8 genmask;
40+
u64 tstamp;
4041
};
4142

4243
static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed)
@@ -63,7 +64,7 @@ static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg,
6364
return 1;
6465
if (nft_set_elem_is_dead(&he->ext))
6566
return 1;
66-
if (nft_set_elem_expired(&he->ext))
67+
if (__nft_set_elem_expired(&he->ext, x->tstamp))
6768
return 1;
6869
if (!nft_set_elem_active(&he->ext, x->genmask))
6970
return 1;
@@ -88,6 +89,7 @@ bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
8889
.genmask = nft_genmask_cur(net),
8990
.set = set,
9091
.key = key,
92+
.tstamp = get_jiffies_64(),
9193
};
9294

9395
he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
@@ -106,6 +108,7 @@ static void *nft_rhash_get(const struct net *net, const struct nft_set *set,
106108
.genmask = nft_genmask_cur(net),
107109
.set = set,
108110
.key = elem->key.val.data,
111+
.tstamp = get_jiffies_64(),
109112
};
110113

111114
he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
@@ -129,6 +132,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
129132
.genmask = NFT_GENMASK_ANY,
130133
.set = set,
131134
.key = key,
135+
.tstamp = get_jiffies_64(),
132136
};
133137

134138
he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
@@ -172,6 +176,7 @@ static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
172176
.genmask = nft_genmask_next(net),
173177
.set = set,
174178
.key = elem->key.val.data,
179+
.tstamp = nft_net_tstamp(net),
175180
};
176181
struct nft_rhash_elem *prev;
177182

@@ -214,6 +219,7 @@ static void *nft_rhash_deactivate(const struct net *net,
214219
.genmask = nft_genmask_next(net),
215220
.set = set,
216221
.key = elem->key.val.data,
222+
.tstamp = nft_net_tstamp(net),
217223
};
218224

219225
rcu_read_lock();

net/netfilter/nft_set_pipapo.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
504504
* @set: nftables API set representation
505505
* @data: Key data to be matched against existing elements
506506
* @genmask: If set, check that element is active in given genmask
507+
* @tstamp: timestamp to check for expired elements
507508
*
508509
* This is essentially the same as the lookup function, except that it matches
509510
* key data against the uncommitted copy and doesn't use preallocated maps for
@@ -513,7 +514,8 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
513514
*/
514515
static struct nft_pipapo_elem *pipapo_get(const struct net *net,
515516
const struct nft_set *set,
516-
const u8 *data, u8 genmask)
517+
const u8 *data, u8 genmask,
518+
u64 tstamp)
517519
{
518520
struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
519521
struct nft_pipapo *priv = nft_set_priv(set);
@@ -568,7 +570,7 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
568570
goto out;
569571

570572
if (last) {
571-
if (nft_set_elem_expired(&f->mt[b].e->ext))
573+
if (__nft_set_elem_expired(&f->mt[b].e->ext, tstamp))
572574
goto next_match;
573575
if ((genmask &&
574576
!nft_set_elem_active(&f->mt[b].e->ext, genmask)))
@@ -605,7 +607,7 @@ static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
605607
const struct nft_set_elem *elem, unsigned int flags)
606608
{
607609
return pipapo_get(net, set, (const u8 *)elem->key.val.data,
608-
nft_genmask_cur(net));
610+
nft_genmask_cur(net), get_jiffies_64());
609611
}
610612

611613
/**
@@ -1199,6 +1201,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
11991201
struct nft_pipapo *priv = nft_set_priv(set);
12001202
struct nft_pipapo_match *m = priv->clone;
12011203
u8 genmask = nft_genmask_next(net);
1204+
u64 tstamp = nft_net_tstamp(net);
12021205
struct nft_pipapo_field *f;
12031206
const u8 *start_p, *end_p;
12041207
int i, bsize_max, err = 0;
@@ -1208,7 +1211,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
12081211
else
12091212
end = start;
12101213

1211-
dup = pipapo_get(net, set, start, genmask);
1214+
dup = pipapo_get(net, set, start, genmask, tstamp);
12121215
if (!IS_ERR(dup)) {
12131216
/* Check if we already have the same exact entry */
12141217
const struct nft_data *dup_key, *dup_end;
@@ -1230,7 +1233,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
12301233

12311234
if (PTR_ERR(dup) == -ENOENT) {
12321235
/* Look for partially overlapping entries */
1233-
dup = pipapo_get(net, set, end, nft_genmask_next(net));
1236+
dup = pipapo_get(net, set, end, nft_genmask_next(net), tstamp);
12341237
}
12351238

12361239
if (PTR_ERR(dup) != -ENOENT) {
@@ -1581,6 +1584,7 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
15811584
{
15821585
struct nft_pipapo *priv = nft_set_priv(set);
15831586
struct net *net = read_pnet(&set->net);
1587+
u64 tstamp = nft_net_tstamp(net);
15841588
int rules_f0, first_rule = 0;
15851589
struct nft_pipapo_elem *e;
15861590
struct nft_trans_gc *gc;
@@ -1615,7 +1619,7 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
16151619
/* synchronous gc never fails, there is no need to set on
16161620
* NFT_SET_ELEM_DEAD_BIT.
16171621
*/
1618-
if (nft_set_elem_expired(&e->ext)) {
1622+
if (__nft_set_elem_expired(&e->ext, tstamp)) {
16191623
priv->dirty = true;
16201624

16211625
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
@@ -1786,7 +1790,7 @@ static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
17861790
{
17871791
struct nft_pipapo_elem *e;
17881792

1789-
e = pipapo_get(net, set, data, nft_genmask_next(net));
1793+
e = pipapo_get(net, set, data, nft_genmask_next(net), nft_net_tstamp(net));
17901794
if (IS_ERR(e))
17911795
return NULL;
17921796

net/netfilter/nft_set_rbtree.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
314314
struct nft_rbtree *priv = nft_set_priv(set);
315315
u8 cur_genmask = nft_genmask_cur(net);
316316
u8 genmask = nft_genmask_next(net);
317+
u64 tstamp = nft_net_tstamp(net);
317318
int d;
318319

319320
/* Descend the tree to search for an existing element greater than the
@@ -361,7 +362,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
361362
/* perform garbage collection to avoid bogus overlap reports
362363
* but skip new elements in this transaction.
363364
*/
364-
if (nft_set_elem_expired(&rbe->ext) &&
365+
if (__nft_set_elem_expired(&rbe->ext, tstamp) &&
365366
nft_set_elem_active(&rbe->ext, cur_genmask)) {
366367
const struct nft_rbtree_elem *removed_end;
367368

@@ -553,6 +554,7 @@ static void *nft_rbtree_deactivate(const struct net *net,
553554
const struct rb_node *parent = priv->root.rb_node;
554555
struct nft_rbtree_elem *rbe, *this = elem->priv;
555556
u8 genmask = nft_genmask_next(net);
557+
u64 tstamp = nft_net_tstamp(net);
556558
int d;
557559

558560
while (parent != NULL) {
@@ -573,7 +575,7 @@ static void *nft_rbtree_deactivate(const struct net *net,
573575
nft_rbtree_interval_end(this)) {
574576
parent = parent->rb_right;
575577
continue;
576-
} else if (nft_set_elem_expired(&rbe->ext)) {
578+
} else if (__nft_set_elem_expired(&rbe->ext, tstamp)) {
577579
break;
578580
} else if (!nft_set_elem_active(&rbe->ext, genmask)) {
579581
parent = parent->rb_left;
@@ -632,9 +634,10 @@ static void nft_rbtree_gc(struct nft_set *set)
632634
struct nft_rbtree *priv = nft_set_priv(set);
633635
struct nft_rbtree_elem *rbe, *rbe_end = NULL;
634636
struct nftables_pernet *nft_net;
637+
struct net *net = read_pnet(&set->net);
638+
u64 tstamp = nft_net_tstamp(net);
635639
struct rb_node *node, *next;
636640
struct nft_trans_gc *gc;
637-
struct net *net;
638641

639642
set = nft_set_container_of(priv);
640643
net = read_pnet(&set->net);
@@ -657,7 +660,7 @@ static void nft_rbtree_gc(struct nft_set *set)
657660
rbe_end = rbe;
658661
continue;
659662
}
660-
if (!nft_set_elem_expired(&rbe->ext))
663+
if (!__nft_set_elem_expired(&rbe->ext, tstamp))
661664
continue;
662665

663666
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);

0 commit comments

Comments
 (0)