Skip to content

Commit 8938fc0

Browse files
author
Paolo Abeni
committed
Merge tag 'nf-23-08-23' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Florian Westphal says: ==================== netfilter updates for net This PR contains nf_tables updates for your *net* tree. First patch fixes table validation, I broke this in 6.4 when tracking validation state per table, reported by Pablo, fixup from myself. Second patch makes sure objects waiting for memory release have been released, this was broken in 6.1, patch from Pablo Neira Ayuso. Patch three is a fix-for-fix from previous PR: In case a transaction gets aborted, gc sequence counter needs to be incremented so pending gc requests are invalidated, from Pablo. Same for patch 4: gc list needs to use gc list lock, not destroy lock, also from Pablo. Patch 5 fixes a UaF in a set backend, but this should only occur when failslab is enabled for GFP_KERNEL allocations, broken since feature was added in 5.6, from myself. Patch 6 fixes a double-free bug that was also added via previous PR: We must not schedule gc work if the previous batch is still queued. netfilter pull request 2023-08-23 * tag 'nf-23-08-23' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: defer gc run if previous batch is still pending netfilter: nf_tables: fix out of memory error handling netfilter: nf_tables: use correct lock to protect gc_list netfilter: nf_tables: GC transaction race with abort path netfilter: nf_tables: flush pending destroy work before netlink notifier netfilter: nf_tables: validate all pending tables ==================== Link: https://lore.kernel.org/r/20230823152711.15279-1-fw@strlen.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents b251610 + 8e51830 commit 8938fc0

File tree

5 files changed

+37
-11
lines changed

5 files changed

+37
-11
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,11 @@ static inline void *nft_set_priv(const struct nft_set *set)
587587
return (void *)set->data;
588588
}
589589

590+
static inline bool nft_set_gc_is_pending(const struct nft_set *s)
591+
{
592+
return refcount_read(&s->refs) != 1;
593+
}
594+
590595
static inline struct nft_set *nft_set_container_of(const void *priv)
591596
{
592597
return (void *)priv - offsetof(struct nft_set, data);
@@ -1729,6 +1734,7 @@ struct nftables_pernet {
17291734
u64 table_handle;
17301735
unsigned int base_seq;
17311736
unsigned int gc_seq;
1737+
u8 validate_state;
17321738
};
17331739

17341740
extern unsigned int nf_tables_net_id;

net/netfilter/nf_tables_api.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,7 +1373,7 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
13731373
if (table == NULL)
13741374
goto err_kzalloc;
13751375

1376-
table->validate_state = NFT_VALIDATE_SKIP;
1376+
table->validate_state = nft_net->validate_state;
13771377
table->name = nla_strdup(attr, GFP_KERNEL_ACCOUNT);
13781378
if (table->name == NULL)
13791379
goto err_strdup;
@@ -9051,9 +9051,8 @@ static int nf_tables_validate(struct net *net)
90519051
return -EAGAIN;
90529052

90539053
nft_validate_state_update(table, NFT_VALIDATE_SKIP);
9054+
break;
90549055
}
9055-
9056-
break;
90579056
}
90589057

90599058
return 0;
@@ -9457,9 +9456,9 @@ static void nft_trans_gc_work(struct work_struct *work)
94579456
struct nft_trans_gc *trans, *next;
94589457
LIST_HEAD(trans_gc_list);
94599458

9460-
spin_lock(&nf_tables_destroy_list_lock);
9459+
spin_lock(&nf_tables_gc_list_lock);
94619460
list_splice_init(&nf_tables_gc_list, &trans_gc_list);
9462-
spin_unlock(&nf_tables_destroy_list_lock);
9461+
spin_unlock(&nf_tables_gc_list_lock);
94639462

94649463
list_for_each_entry_safe(trans, next, &trans_gc_list, list) {
94659464
list_del(&trans->list);
@@ -9799,8 +9798,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
97999798
}
98009799

98019800
/* 0. Validate ruleset, otherwise roll back for error reporting. */
9802-
if (nf_tables_validate(net) < 0)
9801+
if (nf_tables_validate(net) < 0) {
9802+
nft_net->validate_state = NFT_VALIDATE_DO;
98039803
return -EAGAIN;
9804+
}
98049805

98059806
err = nft_flow_rule_offload_commit(net);
98069807
if (err < 0)
@@ -10059,6 +10060,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
1005910060
nf_tables_commit_audit_log(&adl, nft_net->base_seq);
1006010061

1006110062
nft_gc_seq_end(nft_net, gc_seq);
10063+
nft_net->validate_state = NFT_VALIDATE_SKIP;
1006210064
nf_tables_commit_release(net);
1006310065

1006410066
return 0;
@@ -10335,8 +10337,12 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb,
1033510337
enum nfnl_abort_action action)
1033610338
{
1033710339
struct nftables_pernet *nft_net = nft_pernet(net);
10338-
int ret = __nf_tables_abort(net, action);
10340+
unsigned int gc_seq;
10341+
int ret;
1033910342

10343+
gc_seq = nft_gc_seq_begin(nft_net);
10344+
ret = __nf_tables_abort(net, action);
10345+
nft_gc_seq_end(nft_net, gc_seq);
1034010346
mutex_unlock(&nft_net->commit_mutex);
1034110347

1034210348
return ret;
@@ -11071,7 +11077,7 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
1107111077
gc_seq = nft_gc_seq_begin(nft_net);
1107211078

1107311079
if (!list_empty(&nf_tables_destroy_list))
11074-
rcu_barrier();
11080+
nf_tables_trans_destroy_flush_work();
1107511081
again:
1107611082
list_for_each_entry(table, &nft_net->tables, list) {
1107711083
if (nft_table_has_owner(table) &&
@@ -11115,6 +11121,7 @@ static int __net_init nf_tables_init_net(struct net *net)
1111511121
mutex_init(&nft_net->commit_mutex);
1111611122
nft_net->base_seq = 1;
1111711123
nft_net->gc_seq = 0;
11124+
nft_net->validate_state = NFT_VALIDATE_SKIP;
1111811125

1111911126
return 0;
1112011127
}

net/netfilter/nft_set_hash.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ static void nft_rhash_gc(struct work_struct *work)
326326
nft_net = nft_pernet(net);
327327
gc_seq = READ_ONCE(nft_net->gc_seq);
328328

329+
if (nft_set_gc_is_pending(set))
330+
goto done;
331+
329332
gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL);
330333
if (!gc)
331334
goto done;

net/netfilter/nft_set_pipapo.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -902,12 +902,14 @@ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f)
902902
static int pipapo_insert(struct nft_pipapo_field *f, const uint8_t *k,
903903
int mask_bits)
904904
{
905-
int rule = f->rules++, group, ret, bit_offset = 0;
905+
int rule = f->rules, group, ret, bit_offset = 0;
906906

907-
ret = pipapo_resize(f, f->rules - 1, f->rules);
907+
ret = pipapo_resize(f, f->rules, f->rules + 1);
908908
if (ret)
909909
return ret;
910910

911+
f->rules++;
912+
911913
for (group = 0; group < f->groups; group++) {
912914
int i, v;
913915
u8 mask;
@@ -1052,7 +1054,9 @@ static int pipapo_expand(struct nft_pipapo_field *f,
10521054
step++;
10531055
if (step >= len) {
10541056
if (!masks) {
1055-
pipapo_insert(f, base, 0);
1057+
err = pipapo_insert(f, base, 0);
1058+
if (err < 0)
1059+
return err;
10561060
masks = 1;
10571061
}
10581062
goto out;
@@ -1235,6 +1239,9 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
12351239
else
12361240
ret = pipapo_expand(f, start, end, f->groups * f->bb);
12371241

1242+
if (ret < 0)
1243+
return ret;
1244+
12381245
if (f->bsize > bsize_max)
12391246
bsize_max = f->bsize;
12401247

net/netfilter/nft_set_rbtree.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,9 @@ static void nft_rbtree_gc(struct work_struct *work)
611611
nft_net = nft_pernet(net);
612612
gc_seq = READ_ONCE(nft_net->gc_seq);
613613

614+
if (nft_set_gc_is_pending(set))
615+
goto done;
616+
614617
gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL);
615618
if (!gc)
616619
goto done;

0 commit comments

Comments
 (0)