]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/sched/act_tunnel_key.c
net/sched: act_tunnel_key: fix NULL dereference when 'goto chain' is used
[mirror_ubuntu-bionic-kernel.git] / net / sched / act_tunnel_key.c
index 30c96274c63826520eec062a6a5609b141bab307..cd51f2ed55fabf98b3780cc14e49f8cb878e31a3 100644 (file)
@@ -36,7 +36,7 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
 
        tcf_lastuse_update(&t->tcf_tm);
        bstats_cpu_update(this_cpu_ptr(t->common.cpu_bstats), skb);
-       action = params->action;
+       action = READ_ONCE(t->tcf_action);
 
        switch (params->tcft_action) {
        case TCA_TUNNEL_KEY_ACT_RELEASE:
@@ -153,6 +153,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
                metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;
                break;
        default:
+               ret = -EINVAL;
                goto err_out;
        }
 
@@ -181,7 +182,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
 
        params_old = rtnl_dereference(t->params);
 
-       params_new->action = parm->action;
+       t->tcf_action = parm->action;
        params_new->tcft_action = parm->t_action;
        params_new->tcft_enc_metadata = metadata;
 
@@ -207,11 +208,12 @@ static void tunnel_key_release(struct tc_action *a, int bind)
        struct tcf_tunnel_key_params *params;
 
        params = rcu_dereference_protected(t->params, 1);
+       if (params) {
+               if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
+                       dst_release(&params->tcft_enc_metadata->dst);
 
-       if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
-               dst_release(&params->tcft_enc_metadata->dst);
-
-       kfree_rcu(params, rcu);
+               kfree_rcu(params, rcu);
+       }
 }
 
 static int tunnel_key_dump_addresses(struct sk_buff *skb,
@@ -252,13 +254,13 @@ static int tunnel_key_dump(struct sk_buff *skb, struct tc_action *a,
                .index    = t->tcf_index,
                .refcnt   = t->tcf_refcnt - ref,
                .bindcnt  = t->tcf_bindcnt - bind,
+               .action   = t->tcf_action,
        };
        struct tcf_t tm;
 
        params = rtnl_dereference(t->params);
 
        opt.t_action = params->tcft_action;
-       opt.action = params->action;
 
        if (nla_put(skb, TCA_TUNNEL_KEY_PARMS, sizeof(opt), &opt))
                goto nla_put_failure;