]> git.itanic.dy.fi Git - linux-stable/commitdiff
net: sched: cls_bpf: Undo tcf_bind_filter in case of an error
authorVictor Nogueira <victor@mojatatu.com>
Thu, 13 Jul 2023 18:05:13 +0000 (15:05 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jul 2023 06:47:00 +0000 (08:47 +0200)
[ Upstream commit 26a22194927e8521e304ed75c2f38d8068d55fc7 ]

If cls_bpf_offload errors out, we must also undo tcf_bind_filter that
was done before the error.

Fix that by calling tcf_unbind_filter in errout_parms.

Fixes: eadb41489fd2 ("net: cls_bpf: add support for marking filters as hardware-only")
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Pedro Tammela <pctammela@mojatatu.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/sched/cls_bpf.c

index df19a847829e8a14246070f1f9ff658f095c8877..b7c46a93a41215feeff5f1abba40a6014f16ff5d 100644 (file)
@@ -402,56 +402,6 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
        return 0;
 }
 
-static int cls_bpf_set_parms(struct net *net, struct tcf_proto *tp,
-                            struct cls_bpf_prog *prog, unsigned long base,
-                            struct nlattr **tb, struct nlattr *est, u32 flags,
-                            struct netlink_ext_ack *extack)
-{
-       bool is_bpf, is_ebpf, have_exts = false;
-       u32 gen_flags = 0;
-       int ret;
-
-       is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS];
-       is_ebpf = tb[TCA_BPF_FD];
-       if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf))
-               return -EINVAL;
-
-       ret = tcf_exts_validate(net, tp, tb, est, &prog->exts, flags,
-                               extack);
-       if (ret < 0)
-               return ret;
-
-       if (tb[TCA_BPF_FLAGS]) {
-               u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]);
-
-               if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT)
-                       return -EINVAL;
-
-               have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
-       }
-       if (tb[TCA_BPF_FLAGS_GEN]) {
-               gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]);
-               if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS ||
-                   !tc_flags_valid(gen_flags))
-                       return -EINVAL;
-       }
-
-       prog->exts_integrated = have_exts;
-       prog->gen_flags = gen_flags;
-
-       ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
-                      cls_bpf_prog_from_efd(tb, prog, gen_flags, tp);
-       if (ret < 0)
-               return ret;
-
-       if (tb[TCA_BPF_CLASSID]) {
-               prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]);
-               tcf_bind_filter(tp, &prog->res, base);
-       }
-
-       return 0;
-}
-
 static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                          struct tcf_proto *tp, unsigned long base,
                          u32 handle, struct nlattr **tca,
@@ -459,9 +409,12 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                          struct netlink_ext_ack *extack)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
+       bool is_bpf, is_ebpf, have_exts = false;
        struct cls_bpf_prog *oldprog = *arg;
        struct nlattr *tb[TCA_BPF_MAX + 1];
+       bool bound_to_filter = false;
        struct cls_bpf_prog *prog;
+       u32 gen_flags = 0;
        int ret;
 
        if (tca[TCA_OPTIONS] == NULL)
@@ -500,11 +453,51 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                goto errout;
        prog->handle = handle;
 
-       ret = cls_bpf_set_parms(net, tp, prog, base, tb, tca[TCA_RATE], flags,
-                               extack);
+       is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS];
+       is_ebpf = tb[TCA_BPF_FD];
+       if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf)) {
+               ret = -EINVAL;
+               goto errout_idr;
+       }
+
+       ret = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &prog->exts,
+                               flags, extack);
+       if (ret < 0)
+               goto errout_idr;
+
+       if (tb[TCA_BPF_FLAGS]) {
+               u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]);
+
+               if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT) {
+                       ret = -EINVAL;
+                       goto errout_idr;
+               }
+
+               have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
+       }
+       if (tb[TCA_BPF_FLAGS_GEN]) {
+               gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]);
+               if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS ||
+                   !tc_flags_valid(gen_flags)) {
+                       ret = -EINVAL;
+                       goto errout_idr;
+               }
+       }
+
+       prog->exts_integrated = have_exts;
+       prog->gen_flags = gen_flags;
+
+       ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
+               cls_bpf_prog_from_efd(tb, prog, gen_flags, tp);
        if (ret < 0)
                goto errout_idr;
 
+       if (tb[TCA_BPF_CLASSID]) {
+               prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]);
+               tcf_bind_filter(tp, &prog->res, base);
+               bound_to_filter = true;
+       }
+
        ret = cls_bpf_offload(tp, prog, oldprog, extack);
        if (ret)
                goto errout_parms;
@@ -526,6 +519,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
        return 0;
 
 errout_parms:
+       if (bound_to_filter)
+               tcf_unbind_filter(tp, &prog->res);
        cls_bpf_free_parms(prog);
 errout_idr:
        if (!oldprog)