Skip to content

Commit 78222ba

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: cttimeout: decouple unlink and free on netns destruction
Make it so netns pre_exit unlinks the objects from the pernet list, so they cannot be found anymore. netns core issues a synchronize_rcu() before calling the exit hooks so any the time the exit hooks run unconfirmed nf_conn entries have been free'd or they have been committed to the hashtable. The exit hook still tags unconfirmed entries as dying, this can now be removed in a followup change. Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 1397af5 commit 78222ba

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

include/net/netfilter/nf_conntrack_timeout.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@ struct nf_ct_timeout {
1717
char data[];
1818
};
1919

20-
struct ctnl_timeout {
21-
struct list_head head;
22-
struct rcu_head rcu_head;
23-
refcount_t refcnt;
24-
char name[CTNL_TIMEOUT_NAME_MAX];
25-
struct nf_ct_timeout timeout;
26-
};
27-
2820
struct nf_conn_timeout {
2921
struct nf_ct_timeout __rcu *timeout;
3022
};

net/netfilter/nfnetlink_cttimeout.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,19 @@
3333

3434
static unsigned int nfct_timeout_id __read_mostly;
3535

36+
struct ctnl_timeout {
37+
struct list_head head;
38+
struct rcu_head rcu_head;
39+
refcount_t refcnt;
40+
char name[CTNL_TIMEOUT_NAME_MAX];
41+
struct nf_ct_timeout timeout;
42+
43+
struct list_head free_head;
44+
};
45+
3646
struct nfct_timeout_pernet {
3747
struct list_head nfct_timeout_list;
48+
struct list_head nfct_timeout_freelist;
3849
};
3950

4051
MODULE_LICENSE("GPL");
@@ -574,10 +585,24 @@ static int __net_init cttimeout_net_init(struct net *net)
574585
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
575586

576587
INIT_LIST_HEAD(&pernet->nfct_timeout_list);
588+
INIT_LIST_HEAD(&pernet->nfct_timeout_freelist);
577589

578590
return 0;
579591
}
580592

593+
static void __net_exit cttimeout_net_pre_exit(struct net *net)
594+
{
595+
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
596+
struct ctnl_timeout *cur, *tmp;
597+
598+
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list, head) {
599+
list_del_rcu(&cur->head);
600+
list_add(&cur->free_head, &pernet->nfct_timeout_freelist);
601+
}
602+
603+
/* core calls synchronize_rcu() after this */
604+
}
605+
581606
static void __net_exit cttimeout_net_exit(struct net *net)
582607
{
583608
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
@@ -586,8 +611,8 @@ static void __net_exit cttimeout_net_exit(struct net *net)
586611
nf_ct_unconfirmed_destroy(net);
587612
nf_ct_untimeout(net, NULL);
588613

589-
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list, head) {
590-
list_del_rcu(&cur->head);
614+
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_freelist, head) {
615+
list_del(&cur->free_head);
591616

592617
if (refcount_dec_and_test(&cur->refcnt))
593618
kfree_rcu(cur, rcu_head);
@@ -596,6 +621,7 @@ static void __net_exit cttimeout_net_exit(struct net *net)
596621

597622
static struct pernet_operations cttimeout_ops = {
598623
.init = cttimeout_net_init,
624+
.pre_exit = cttimeout_net_pre_exit,
599625
.exit = cttimeout_net_exit,
600626
.id = &nfct_timeout_id,
601627
.size = sizeof(struct nfct_timeout_pernet),

0 commit comments

Comments
 (0)