Skip to content

Commit fc14f9c

Browse files
committed
Merge tag 'nf-25-03-06' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Fix racy non-atomic read-then-increment operation with PREEMPT_RT in nft_ct, from Sebastian Andrzej Siewior. 2) GC is not skipped when jiffies wrap around in nf_conncount, from Nicklas Bo Jensen. 3) flush_work() on nf_tables_destroy_work waits for the last queued instance, this could be an instance that is different from the one that we must wait for, then make destruction work queue. * tag 'nf-25-03-06' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: make destruction work queue pernet netfilter: nf_conncount: garbage collection is not skipped when jiffies wrap around netfilter: nft_ct: Use __refcount_inc() for per-CPU nft_ct_pcpu_template. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 115ef44 + fb82865 commit fc14f9c

File tree

5 files changed

+27
-19
lines changed

5 files changed

+27
-19
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1891,7 +1891,7 @@ void nft_chain_filter_fini(void);
18911891
void __init nft_chain_route_init(void);
18921892
void nft_chain_route_fini(void);
18931893

1894-
void nf_tables_trans_destroy_flush_work(void);
1894+
void nf_tables_trans_destroy_flush_work(struct net *net);
18951895

18961896
int nf_msecs_to_jiffies64(const struct nlattr *nla, u64 *result);
18971897
__be64 nf_jiffies64_to_msecs(u64 input);
@@ -1905,6 +1905,7 @@ static inline int nft_request_module(struct net *net, const char *fmt, ...) { re
19051905
struct nftables_pernet {
19061906
struct list_head tables;
19071907
struct list_head commit_list;
1908+
struct list_head destroy_list;
19081909
struct list_head commit_set_list;
19091910
struct list_head binding_list;
19101911
struct list_head module_list;
@@ -1915,6 +1916,7 @@ struct nftables_pernet {
19151916
unsigned int base_seq;
19161917
unsigned int gc_seq;
19171918
u8 validate_state;
1919+
struct work_struct destroy_work;
19181920
};
19191921

19201922
extern unsigned int nf_tables_net_id;

net/netfilter/nf_conncount.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ static int __nf_conncount_add(struct net *net,
132132
struct nf_conn *found_ct;
133133
unsigned int collect = 0;
134134

135-
if (time_is_after_eq_jiffies((unsigned long)list->last_gc))
135+
if ((u32)jiffies == list->last_gc)
136136
goto add_new_node;
137137

138138
/* check the saved connections */
@@ -234,7 +234,7 @@ bool nf_conncount_gc_list(struct net *net,
234234
bool ret = false;
235235

236236
/* don't bother if we just did GC */
237-
if (time_is_after_eq_jiffies((unsigned long)READ_ONCE(list->last_gc)))
237+
if ((u32)jiffies == READ_ONCE(list->last_gc))
238238
return false;
239239

240240
/* don't bother if other cpu is already doing GC */

net/netfilter/nf_tables_api.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ unsigned int nf_tables_net_id __read_mostly;
3434
static LIST_HEAD(nf_tables_expressions);
3535
static LIST_HEAD(nf_tables_objects);
3636
static LIST_HEAD(nf_tables_flowtables);
37-
static LIST_HEAD(nf_tables_destroy_list);
3837
static LIST_HEAD(nf_tables_gc_list);
3938
static DEFINE_SPINLOCK(nf_tables_destroy_list_lock);
4039
static DEFINE_SPINLOCK(nf_tables_gc_list_lock);
@@ -125,7 +124,6 @@ static void nft_validate_state_update(struct nft_table *table, u8 new_validate_s
125124
table->validate_state = new_validate_state;
126125
}
127126
static void nf_tables_trans_destroy_work(struct work_struct *w);
128-
static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work);
129127

130128
static void nft_trans_gc_work(struct work_struct *work);
131129
static DECLARE_WORK(trans_gc_work, nft_trans_gc_work);
@@ -10006,11 +10004,12 @@ static void nft_commit_release(struct nft_trans *trans)
1000610004

1000710005
static void nf_tables_trans_destroy_work(struct work_struct *w)
1000810006
{
10007+
struct nftables_pernet *nft_net = container_of(w, struct nftables_pernet, destroy_work);
1000910008
struct nft_trans *trans, *next;
1001010009
LIST_HEAD(head);
1001110010

1001210011
spin_lock(&nf_tables_destroy_list_lock);
10013-
list_splice_init(&nf_tables_destroy_list, &head);
10012+
list_splice_init(&nft_net->destroy_list, &head);
1001410013
spin_unlock(&nf_tables_destroy_list_lock);
1001510014

1001610015
if (list_empty(&head))
@@ -10024,9 +10023,11 @@ static void nf_tables_trans_destroy_work(struct work_struct *w)
1002410023
}
1002510024
}
1002610025

10027-
void nf_tables_trans_destroy_flush_work(void)
10026+
void nf_tables_trans_destroy_flush_work(struct net *net)
1002810027
{
10029-
flush_work(&trans_destroy_work);
10028+
struct nftables_pernet *nft_net = nft_pernet(net);
10029+
10030+
flush_work(&nft_net->destroy_work);
1003010031
}
1003110032
EXPORT_SYMBOL_GPL(nf_tables_trans_destroy_flush_work);
1003210033

@@ -10484,11 +10485,11 @@ static void nf_tables_commit_release(struct net *net)
1048410485

1048510486
trans->put_net = true;
1048610487
spin_lock(&nf_tables_destroy_list_lock);
10487-
list_splice_tail_init(&nft_net->commit_list, &nf_tables_destroy_list);
10488+
list_splice_tail_init(&nft_net->commit_list, &nft_net->destroy_list);
1048810489
spin_unlock(&nf_tables_destroy_list_lock);
1048910490

1049010491
nf_tables_module_autoload_cleanup(net);
10491-
schedule_work(&trans_destroy_work);
10492+
schedule_work(&nft_net->destroy_work);
1049210493

1049310494
mutex_unlock(&nft_net->commit_mutex);
1049410495
}
@@ -11853,7 +11854,7 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
1185311854

1185411855
gc_seq = nft_gc_seq_begin(nft_net);
1185511856

11856-
nf_tables_trans_destroy_flush_work();
11857+
nf_tables_trans_destroy_flush_work(net);
1185711858
again:
1185811859
list_for_each_entry(table, &nft_net->tables, list) {
1185911860
if (nft_table_has_owner(table) &&
@@ -11895,6 +11896,7 @@ static int __net_init nf_tables_init_net(struct net *net)
1189511896

1189611897
INIT_LIST_HEAD(&nft_net->tables);
1189711898
INIT_LIST_HEAD(&nft_net->commit_list);
11899+
INIT_LIST_HEAD(&nft_net->destroy_list);
1189811900
INIT_LIST_HEAD(&nft_net->commit_set_list);
1189911901
INIT_LIST_HEAD(&nft_net->binding_list);
1190011902
INIT_LIST_HEAD(&nft_net->module_list);
@@ -11903,6 +11905,7 @@ static int __net_init nf_tables_init_net(struct net *net)
1190311905
nft_net->base_seq = 1;
1190411906
nft_net->gc_seq = 0;
1190511907
nft_net->validate_state = NFT_VALIDATE_SKIP;
11908+
INIT_WORK(&nft_net->destroy_work, nf_tables_trans_destroy_work);
1190611909

1190711910
return 0;
1190811911
}
@@ -11931,14 +11934,17 @@ static void __net_exit nf_tables_exit_net(struct net *net)
1193111934
if (!list_empty(&nft_net->module_list))
1193211935
nf_tables_module_autoload_cleanup(net);
1193311936

11937+
cancel_work_sync(&nft_net->destroy_work);
1193411938
__nft_release_tables(net);
1193511939

1193611940
nft_gc_seq_end(nft_net, gc_seq);
1193711941

1193811942
mutex_unlock(&nft_net->commit_mutex);
11943+
1193911944
WARN_ON_ONCE(!list_empty(&nft_net->tables));
1194011945
WARN_ON_ONCE(!list_empty(&nft_net->module_list));
1194111946
WARN_ON_ONCE(!list_empty(&nft_net->notify_list));
11947+
WARN_ON_ONCE(!list_empty(&nft_net->destroy_list));
1194211948
}
1194311949

1194411950
static void nf_tables_exit_batch(struct list_head *net_exit_list)
@@ -12029,10 +12035,8 @@ static void __exit nf_tables_module_exit(void)
1202912035
unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
1203012036
nft_chain_filter_fini();
1203112037
nft_chain_route_fini();
12032-
nf_tables_trans_destroy_flush_work();
1203312038
unregister_pernet_subsys(&nf_tables_net_ops);
1203412039
cancel_work_sync(&trans_gc_work);
12035-
cancel_work_sync(&trans_destroy_work);
1203612040
rcu_barrier();
1203712041
rhltable_destroy(&nft_objname_ht);
1203812042
nf_tables_core_module_exit();

net/netfilter/nft_compat.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,15 +228,15 @@ static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
228228
return 0;
229229
}
230230

231-
static void nft_compat_wait_for_destructors(void)
231+
static void nft_compat_wait_for_destructors(struct net *net)
232232
{
233233
/* xtables matches or targets can have side effects, e.g.
234234
* creation/destruction of /proc files.
235235
* The xt ->destroy functions are run asynchronously from
236236
* work queue. If we have pending invocations we thus
237237
* need to wait for those to finish.
238238
*/
239-
nf_tables_trans_destroy_flush_work();
239+
nf_tables_trans_destroy_flush_work(net);
240240
}
241241

242242
static int
@@ -262,7 +262,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
262262

263263
nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
264264

265-
nft_compat_wait_for_destructors();
265+
nft_compat_wait_for_destructors(ctx->net);
266266

267267
ret = xt_check_target(&par, size, proto, inv);
268268
if (ret < 0) {
@@ -515,7 +515,7 @@ __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
515515

516516
nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
517517

518-
nft_compat_wait_for_destructors();
518+
nft_compat_wait_for_destructors(ctx->net);
519519

520520
return xt_check_match(&par, size, proto, inv);
521521
}

net/netfilter/nft_ct.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr,
230230
enum ip_conntrack_info ctinfo;
231231
u16 value = nft_reg_load16(&regs->data[priv->sreg]);
232232
struct nf_conn *ct;
233+
int oldcnt;
233234

234235
ct = nf_ct_get(skb, &ctinfo);
235236
if (ct) /* already tracked */
@@ -250,10 +251,11 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr,
250251

251252
ct = this_cpu_read(nft_ct_pcpu_template);
252253

253-
if (likely(refcount_read(&ct->ct_general.use) == 1)) {
254-
refcount_inc(&ct->ct_general.use);
254+
__refcount_inc(&ct->ct_general.use, &oldcnt);
255+
if (likely(oldcnt == 1)) {
255256
nf_ct_zone_add(ct, &zone);
256257
} else {
258+
refcount_dec(&ct->ct_general.use);
257259
/* previous skb got queued to userspace, allocate temporary
258260
* one until percpu template can be reused.
259261
*/

0 commit comments

Comments
 (0)