net_sched: hold netns refcnt for each action
authorCong Wang <xiyou.wangcong@gmail.com>
Wed, 1 Nov 2017 17:23:50 +0000 (10:23 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 3 Nov 2017 01:30:38 +0000 (10:30 +0900)
TC actions have been destroyed asynchronously for a long time,
previously in a RCU callback and now in a workqueue. If we
don't hold a refcnt for its netns, we could use the per netns
data structure, struct tcf_idrinfo, after it has been freed by
netns workqueue.

Hold refcnt to ensure netns destroy happens after all actions
are gone.

Fixes: ddf97ccdd7cb ("net_sched: add network namespace support for tc actions")
Reported-by: Lucas Bates <lucasb@mojatatu.com>
Tested-by: Lucas Bates <lucasb@mojatatu.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
18 files changed:
include/net/act_api.h
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_connmark.c
net/sched/act_csum.c
net/sched/act_gact.c
net/sched/act_ife.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/act_skbmod.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c

index 5072446d5f06f0935dc4e506635c4bee317ac4c4..c6855125503269b8217af4d8dace963ad1b0fb4c 100644 (file)
@@ -13,6 +13,7 @@
 struct tcf_idrinfo {
        spinlock_t      lock;
        struct idr      action_idr;
+       struct net      *net;
 };
 
 struct tc_action_ops;
@@ -104,7 +105,7 @@ struct tc_action_net {
 
 static inline
 int tc_action_net_init(struct tc_action_net *tn,
-                      const struct tc_action_ops *ops)
+                      const struct tc_action_ops *ops, struct net *net)
 {
        int err = 0;
 
@@ -112,6 +113,7 @@ int tc_action_net_init(struct tc_action_net *tn,
        if (!tn->idrinfo)
                return -ENOMEM;
        tn->ops = ops;
+       tn->idrinfo->net = net;
        spin_lock_init(&tn->idrinfo->lock);
        idr_init(&tn->idrinfo->action_idr);
        return err;
index 8f2c635149561e741bda88163df063f8cc70f957..ca2ff0b3123f9d37e4b0549e55254bf46efb5e1a 100644 (file)
@@ -78,6 +78,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
        spin_lock_bh(&idrinfo->lock);
        idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
        spin_unlock_bh(&idrinfo->lock);
+       put_net(idrinfo->net);
        gen_kill_estimator(&p->tcfa_rate_est);
        free_tcf(p);
 }
@@ -336,6 +337,7 @@ err3:
        p->idrinfo = idrinfo;
        p->ops = ops;
        INIT_LIST_HEAD(&p->list);
+       get_net(idrinfo->net);
        *a = p;
        return 0;
 }
index c0c707eb2c962520fbc6da655c8b4151bf8a4462..9bce8cc84cbb9cd99fa1812ef0ac99a4405a995a 100644 (file)
@@ -398,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, bpf_net_id);
 
-       return tc_action_net_init(tn, &act_bpf_ops);
+       return tc_action_net_init(tn, &act_bpf_ops, net);
 }
 
 static void __net_exit bpf_exit_net(struct net *net)
index 10b7a8855a6c754640c66b21af3df1e4b17de63d..34e52d01a5dde25ab4432979eaac01c730d733fd 100644 (file)
@@ -206,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, connmark_net_id);
 
-       return tc_action_net_init(tn, &act_connmark_ops);
+       return tc_action_net_init(tn, &act_connmark_ops, net);
 }
 
 static void __net_exit connmark_exit_net(struct net *net)
index 1c40caadcff959ba0c6cec6b8e32f7b459c42cfa..35171df2ebef38776dfd2f9fe2603de86d341872 100644 (file)
@@ -626,7 +626,7 @@ static __net_init int csum_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, csum_net_id);
 
-       return tc_action_net_init(tn, &act_csum_ops);
+       return tc_action_net_init(tn, &act_csum_ops, net);
 }
 
 static void __net_exit csum_exit_net(struct net *net)
index e29a48ef7fc348aefdc720cf08d1509ac5b53559..ef7f7f39d26d27cff31f929f84dfed549ccb843d 100644 (file)
@@ -232,7 +232,7 @@ static __net_init int gact_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, gact_net_id);
 
-       return tc_action_net_init(tn, &act_gact_ops);
+       return tc_action_net_init(tn, &act_gact_ops, net);
 }
 
 static void __net_exit gact_exit_net(struct net *net)
index 8ccd35825b6b97f48311c1060f88a41a34f18f9a..f65e4b5058e0803d4e2f9a67f2cb1f7978ffc656 100644 (file)
@@ -818,7 +818,7 @@ static __net_init int ife_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ife_net_id);
 
-       return tc_action_net_init(tn, &act_ife_ops);
+       return tc_action_net_init(tn, &act_ife_ops, net);
 }
 
 static void __net_exit ife_exit_net(struct net *net)
index d9e399a7e3d59c8ec53e46e0862e2ca3c83988bc..dbdf3b2470d53bebbd2f75f32889d4fda47e19fb 100644 (file)
@@ -334,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ipt_net_id);
 
-       return tc_action_net_init(tn, &act_ipt_ops);
+       return tc_action_net_init(tn, &act_ipt_ops, net);
 }
 
 static void __net_exit ipt_exit_net(struct net *net)
@@ -384,7 +384,7 @@ static __net_init int xt_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, xt_net_id);
 
-       return tc_action_net_init(tn, &act_xt_ops);
+       return tc_action_net_init(tn, &act_xt_ops, net);
 }
 
 static void __net_exit xt_exit_net(struct net *net)
index 416627c66f081f26ff9284de86411c3e05390b8e..84759cfd5a3398555cba7012d0cc949b7b7e6033 100644 (file)
@@ -343,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, mirred_net_id);
 
-       return tc_action_net_init(tn, &act_mirred_ops);
+       return tc_action_net_init(tn, &act_mirred_ops, net);
 }
 
 static void __net_exit mirred_exit_net(struct net *net)
index c365d01b99c8b7892c16e43742a88744d7d84e54..7eeaaf9217b69faa356a091409bbaa2c70f95242 100644 (file)
@@ -307,7 +307,7 @@ static __net_init int nat_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, nat_net_id);
 
-       return tc_action_net_init(tn, &act_nat_ops);
+       return tc_action_net_init(tn, &act_nat_ops, net);
 }
 
 static void __net_exit nat_exit_net(struct net *net)
index 491fe5deb09ee7f38a6c0f892c43ffe0bce79fd1..b3d82c334a5f5285ad7309e5eb9b573e2f84e229 100644 (file)
@@ -450,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, pedit_net_id);
 
-       return tc_action_net_init(tn, &act_pedit_ops);
+       return tc_action_net_init(tn, &act_pedit_ops, net);
 }
 
 static void __net_exit pedit_exit_net(struct net *net)
index 3bb2ebf9e9aec2743033ecdc4f5763ce601bf653..9ec42b26e4b97d298392e60ed7ca0a1eb427b6ea 100644 (file)
@@ -331,7 +331,7 @@ static __net_init int police_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, police_net_id);
 
-       return tc_action_net_init(tn, &act_police_ops);
+       return tc_action_net_init(tn, &act_police_ops, net);
 }
 
 static void __net_exit police_exit_net(struct net *net)
index 8b5abcd2f32faeaa2a283bcc8fb388201f7a86e2..e69a1e3a39bf700a5a729bd9234132397c7e55c7 100644 (file)
@@ -240,7 +240,7 @@ static __net_init int sample_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, sample_net_id);
 
-       return tc_action_net_init(tn, &act_sample_ops);
+       return tc_action_net_init(tn, &act_sample_ops, net);
 }
 
 static void __net_exit sample_exit_net(struct net *net)
index e7b57e5071a365743de9d2c5aaa22dca445fa0d9..a8d0ea95f89454826e9d782846543f054a0dc5e5 100644 (file)
@@ -201,7 +201,7 @@ static __net_init int simp_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, simp_net_id);
 
-       return tc_action_net_init(tn, &act_simp_ops);
+       return tc_action_net_init(tn, &act_simp_ops, net);
 }
 
 static void __net_exit simp_exit_net(struct net *net)
index 59949d61f20da1031b8b47712f817c991c6bed60..fbac62472e09cf72c5aac1731f9065843b48455e 100644 (file)
@@ -238,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, skbedit_net_id);
 
-       return tc_action_net_init(tn, &act_skbedit_ops);
+       return tc_action_net_init(tn, &act_skbedit_ops, net);
 }
 
 static void __net_exit skbedit_exit_net(struct net *net)
index b642ad3d39dd414d392e492bae091995b01cbd77..8e12d8897d2ff6449a410e037652a1aa95c63d35 100644 (file)
@@ -263,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, skbmod_net_id);
 
-       return tc_action_net_init(tn, &act_skbmod_ops);
+       return tc_action_net_init(tn, &act_skbmod_ops, net);
 }
 
 static void __net_exit skbmod_exit_net(struct net *net)
index 30c96274c63826520eec062a6a5609b141bab307..c33faa373cf2221c2798509a5f1f70c8bce69240 100644 (file)
@@ -322,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 
-       return tc_action_net_init(tn, &act_tunnel_key_ops);
+       return tc_action_net_init(tn, &act_tunnel_key_ops, net);
 }
 
 static void __net_exit tunnel_key_exit_net(struct net *net)
index 16eb067a8d8fa20c17894db8047571789c0b96e8..115fc33cc6d8b321f9c02febf861b93fe9a85740 100644 (file)
@@ -269,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, vlan_net_id);
 
-       return tc_action_net_init(tn, &act_vlan_ops);
+       return tc_action_net_init(tn, &act_vlan_ops, net);
 }
 
 static void __net_exit vlan_exit_net(struct net *net)