Skip to content

Commit 615efed

Browse files
committed
Merge tag 'nf-23-09-13' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
netfilter pull request 23-09-13 ==================== The following patchset contains Netfilter fixes for net: 1) Do not permit to remove rules from chain binding, otherwise double rule release is possible, triggering UaF. This rule deletion support does not make sense and userspace does not use this. Problem exists since the introduction of chain binding support. 2) rbtree GC worker only collects the elements that have expired. This operation is not destructive, therefore, turn write into read spinlock to avoid datapath contention due to GC worker run. This was not fixed in the recent GC fix batch in the 6.5 cycle. 3) pipapo set backend performs sync GC, therefore, catchall elements must use sync GC queue variant. This bug was introduced in the 6.5 cycle with the recent GC fixes. 4) Stop GC run if memory allocation fails in pipapo set backend, otherwise access to NULL pointer to GC transaction object might occur. This bug was introduced in the 6.5 cycle with the recent GC fixes. 5) rhash GC run uses an iterator that might hit EAGAIN to rewind, triggering double-collection of the same element. This bug was introduced in the 6.5 cycle with the recent GC fixes. 6) Do not permit to remove elements in anonymous sets, this type of sets are populated once and then bound to rules. This fix is similar to the chain binding patch coming first in this batch. API permits since the very beginning but it has no use case from userspace. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 350db8a + e8dbde5 commit 615efed

File tree

11 files changed

+338
-38
lines changed

11 files changed

+338
-38
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,8 +1700,9 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans);
17001700

17011701
void nft_trans_gc_elem_add(struct nft_trans_gc *gc, void *priv);
17021702

1703-
struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
1704-
unsigned int gc_seq);
1703+
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
1704+
unsigned int gc_seq);
1705+
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc);
17051706

17061707
void nft_setelem_data_deactivate(const struct net *net,
17071708
const struct nft_set *set,

net/netfilter/nf_conntrack_extend.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ static const u8 nf_ct_ext_type_len[NF_CT_EXT_NUM] = {
4040
[NF_CT_EXT_ECACHE] = sizeof(struct nf_conntrack_ecache),
4141
#endif
4242
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
43-
[NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_acct),
43+
[NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_tstamp),
4444
#endif
4545
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
46-
[NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_tstamp),
46+
[NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_timeout),
4747
#endif
4848
#ifdef CONFIG_NF_CONNTRACK_LABELS
4949
[NF_CT_EXT_LABELS] = sizeof(struct nf_conn_labels),

net/netfilter/nf_tables_api.c

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
14321432
if (!nft_is_active_next(ctx->net, chain))
14331433
continue;
14341434

1435-
if (nft_chain_is_bound(chain))
1435+
if (nft_chain_binding(chain))
14361436
continue;
14371437

14381438
ctx->chain = chain;
@@ -1446,8 +1446,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
14461446
if (!nft_is_active_next(ctx->net, set))
14471447
continue;
14481448

1449-
if (nft_set_is_anonymous(set) &&
1450-
!list_empty(&set->bindings))
1449+
if (nft_set_is_anonymous(set))
14511450
continue;
14521451

14531452
err = nft_delset(ctx, set);
@@ -1477,7 +1476,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
14771476
if (!nft_is_active_next(ctx->net, chain))
14781477
continue;
14791478

1480-
if (nft_chain_is_bound(chain))
1479+
if (nft_chain_binding(chain))
14811480
continue;
14821481

14831482
ctx->chain = chain;
@@ -2910,6 +2909,9 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
29102909
return PTR_ERR(chain);
29112910
}
29122911

2912+
if (nft_chain_binding(chain))
2913+
return -EOPNOTSUPP;
2914+
29132915
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
29142916

29152917
if (nla[NFTA_CHAIN_HOOK]) {
@@ -3449,6 +3451,8 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
34493451
struct net *net = sock_net(skb->sk);
34503452
const struct nft_rule *rule, *prule;
34513453
unsigned int s_idx = cb->args[0];
3454+
unsigned int entries = 0;
3455+
int ret = 0;
34523456
u64 handle;
34533457

34543458
prule = NULL;
@@ -3471,20 +3475,22 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
34713475
NFT_MSG_NEWRULE,
34723476
NLM_F_MULTI | NLM_F_APPEND,
34733477
table->family,
3474-
table, chain, rule, handle, reset) < 0)
3475-
return 1;
3476-
3478+
table, chain, rule, handle, reset) < 0) {
3479+
ret = 1;
3480+
break;
3481+
}
3482+
entries++;
34773483
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
34783484
cont:
34793485
prule = rule;
34803486
cont_skip:
34813487
(*idx)++;
34823488
}
34833489

3484-
if (reset && *idx)
3485-
audit_log_rule_reset(table, cb->seq, *idx);
3490+
if (reset && entries)
3491+
audit_log_rule_reset(table, cb->seq, entries);
34863492

3487-
return 0;
3493+
return ret;
34883494
}
34893495

34903496
static int nf_tables_dump_rules(struct sk_buff *skb,
@@ -3971,6 +3977,11 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
39713977
}
39723978

39733979
if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
3980+
if (nft_chain_binding(chain)) {
3981+
err = -EOPNOTSUPP;
3982+
goto err_destroy_flow_rule;
3983+
}
3984+
39743985
err = nft_delrule(&ctx, old_rule);
39753986
if (err < 0)
39763987
goto err_destroy_flow_rule;
@@ -4078,7 +4089,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
40784089
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
40794090
return PTR_ERR(chain);
40804091
}
4081-
if (nft_chain_is_bound(chain))
4092+
if (nft_chain_binding(chain))
40824093
return -EOPNOTSUPP;
40834094
}
40844095

@@ -4112,7 +4123,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
41124123
list_for_each_entry(chain, &table->chains, list) {
41134124
if (!nft_is_active_next(net, chain))
41144125
continue;
4115-
if (nft_chain_is_bound(chain))
4126+
if (nft_chain_binding(chain))
41164127
continue;
41174128

41184129
ctx.chain = chain;
@@ -7183,8 +7194,10 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
71837194
if (IS_ERR(set))
71847195
return PTR_ERR(set);
71857196

7186-
if (!list_empty(&set->bindings) &&
7187-
(set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS)))
7197+
if (nft_set_is_anonymous(set))
7198+
return -EOPNOTSUPP;
7199+
7200+
if (!list_empty(&set->bindings) && (set->flags & NFT_SET_CONSTANT))
71887201
return -EBUSY;
71897202

71907203
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
@@ -9605,8 +9618,9 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
96059618
call_rcu(&trans->rcu, nft_trans_gc_trans_free);
96069619
}
96079620

9608-
struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
9609-
unsigned int gc_seq)
9621+
static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
9622+
unsigned int gc_seq,
9623+
bool sync)
96109624
{
96119625
struct nft_set_elem_catchall *catchall;
96129626
const struct nft_set *set = gc->set;
@@ -9622,7 +9636,11 @@ struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
96229636

96239637
nft_set_elem_dead(ext);
96249638
dead_elem:
9625-
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
9639+
if (sync)
9640+
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
9641+
else
9642+
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
9643+
96269644
if (!gc)
96279645
return NULL;
96289646

@@ -9632,6 +9650,17 @@ struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
96329650
return gc;
96339651
}
96349652

9653+
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9654+
unsigned int gc_seq)
9655+
{
9656+
return nft_trans_gc_catchall(gc, gc_seq, false);
9657+
}
9658+
9659+
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
9660+
{
9661+
return nft_trans_gc_catchall(gc, 0, true);
9662+
}
9663+
96359664
static void nf_tables_module_autoload_cleanup(struct net *net)
96369665
{
96379666
struct nftables_pernet *nft_net = nft_pernet(net);
@@ -11054,7 +11083,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
1105411083
ctx.family = table->family;
1105511084
ctx.table = table;
1105611085
list_for_each_entry(chain, &table->chains, list) {
11057-
if (nft_chain_is_bound(chain))
11086+
if (nft_chain_binding(chain))
1105811087
continue;
1105911088

1106011089
ctx.chain = chain;

net/netfilter/nft_set_hash.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,9 @@ static void nft_rhash_gc(struct work_struct *work)
338338

339339
while ((he = rhashtable_walk_next(&hti))) {
340340
if (IS_ERR(he)) {
341-
if (PTR_ERR(he) != -EAGAIN) {
342-
nft_trans_gc_destroy(gc);
343-
gc = NULL;
344-
goto try_later;
345-
}
346-
continue;
341+
nft_trans_gc_destroy(gc);
342+
gc = NULL;
343+
goto try_later;
347344
}
348345

349346
/* Ruleset has been updated, try later. */
@@ -372,7 +369,7 @@ static void nft_rhash_gc(struct work_struct *work)
372369
nft_trans_gc_elem_add(gc, he);
373370
}
374371

375-
gc = nft_trans_gc_catchall(gc, gc_seq);
372+
gc = nft_trans_gc_catchall_async(gc, gc_seq);
376373

377374
try_later:
378375
/* catchall list iteration requires rcu read side lock. */

net/netfilter/nft_set_pipapo.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,7 +1596,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
15961596

15971597
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
15981598
if (!gc)
1599-
break;
1599+
return;
16001600

16011601
nft_pipapo_gc_deactivate(net, set, e);
16021602
pipapo_drop(m, rulemap);
@@ -1610,7 +1610,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
16101610
}
16111611
}
16121612

1613-
gc = nft_trans_gc_catchall(gc, 0);
1613+
gc = nft_trans_gc_catchall_sync(gc);
16141614
if (gc) {
16151615
nft_trans_gc_queue_sync_done(gc);
16161616
priv->last_gc = jiffies;

net/netfilter/nft_set_rbtree.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,7 @@ static void nft_rbtree_gc(struct work_struct *work)
622622
if (!gc)
623623
goto done;
624624

625-
write_lock_bh(&priv->lock);
626-
write_seqcount_begin(&priv->count);
625+
read_lock_bh(&priv->lock);
627626
for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
628627

629628
/* Ruleset has been updated, try later. */
@@ -670,11 +669,10 @@ static void nft_rbtree_gc(struct work_struct *work)
670669
nft_trans_gc_elem_add(gc, rbe);
671670
}
672671

673-
gc = nft_trans_gc_catchall(gc, gc_seq);
672+
gc = nft_trans_gc_catchall_async(gc, gc_seq);
674673

675674
try_later:
676-
write_seqcount_end(&priv->count);
677-
write_unlock_bh(&priv->lock);
675+
read_unlock_bh(&priv->lock);
678676

679677
if (gc)
680678
nft_trans_gc_queue_async_done(gc);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
nf-queue
33
connect_close
4+
audit_logread

tools/testing/selftests/netfilter/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
66
nft_concat_range.sh nft_conntrack_helper.sh \
77
nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
88
ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \
9-
conntrack_vrf.sh nft_synproxy.sh rpath.sh
9+
conntrack_vrf.sh nft_synproxy.sh rpath.sh nft_audit.sh
1010

1111
HOSTPKG_CONFIG := pkg-config
1212

1313
CFLAGS += $(shell $(HOSTPKG_CONFIG) --cflags libmnl 2>/dev/null)
1414
LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)
1515

16-
TEST_GEN_FILES = nf-queue connect_close
16+
TEST_GEN_FILES = nf-queue connect_close audit_logread
1717

1818
include ../lib.mk

0 commit comments

Comments
 (0)