int police;
 };
 
-static inline void tcf_exts_init(struct tcf_exts *exts, int action, int police)
+static inline int tcf_exts_init(struct tcf_exts *exts, int action, int police)
 {
 #ifdef CONFIG_NET_CLS_ACT
        exts->type = 0;
        exts->nr_actions = 0;
        exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
                                GFP_KERNEL);
-       WARN_ON(!exts->actions); /* TODO: propagate the error to callers */
+       if (!exts->actions)
+               return -ENOMEM;
 #endif
        exts->action = action;
        exts->police = police;
+       return 0;
 }
 
 /**
 
        struct tcf_exts e;
        struct tcf_ematch_tree t;
 
-       tcf_exts_init(&e, TCA_BASIC_ACT, TCA_BASIC_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       err = tcf_exts_init(&e, TCA_BASIC_ACT, TCA_BASIC_POLICE);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       if (err < 0)
+               goto errout;
 
        err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &t);
        if (err < 0)
        if (!fnew)
                return -ENOBUFS;
 
-       tcf_exts_init(&fnew->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE);
+       err = tcf_exts_init(&fnew->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE);
+       if (err < 0)
+               goto errout;
+
        err = -EINVAL;
        if (handle) {
                fnew->handle = handle;
 
        return 0;
 errout:
+       tcf_exts_destroy(&fnew->exts);
        kfree(fnew);
        return err;
 }
 
        if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf))
                return -EINVAL;
 
-       tcf_exts_init(&exts, TCA_BPF_ACT, TCA_BPF_POLICE);
-       ret = tcf_exts_validate(net, tp, tb, est, &exts, ovr);
+       ret = tcf_exts_init(&exts, TCA_BPF_ACT, TCA_BPF_POLICE);
        if (ret < 0)
                return ret;
+       ret = tcf_exts_validate(net, tp, tb, est, &exts, ovr);
+       if (ret < 0)
+               goto errout;
 
        if (tb[TCA_BPF_FLAGS]) {
                u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]);
 
                if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT) {
-                       tcf_exts_destroy(&exts);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto errout;
                }
 
                have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
 
        ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
                       cls_bpf_prog_from_efd(tb, prog, tp);
-       if (ret < 0) {
-               tcf_exts_destroy(&exts);
-               return ret;
-       }
+       if (ret < 0)
+               goto errout;
 
        if (tb[TCA_BPF_CLASSID]) {
                prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]);
 
        tcf_exts_change(tp, &prog->exts, &exts);
        return 0;
+
+errout:
+       tcf_exts_destroy(&exts);
+       return ret;
 }
 
 static u32 cls_bpf_grab_new_handle(struct tcf_proto *tp,
        if (!prog)
                return -ENOBUFS;
 
-       tcf_exts_init(&prog->exts, TCA_BPF_ACT, TCA_BPF_POLICE);
+       ret = tcf_exts_init(&prog->exts, TCA_BPF_ACT, TCA_BPF_POLICE);
+       if (ret < 0)
+               goto errout;
 
        if (oldprog) {
                if (handle && oldprog->handle != handle) {
 
        *arg = (unsigned long) prog;
        return 0;
+
 errout:
+       tcf_exts_destroy(&prog->exts);
        kfree(prog);
-
        return ret;
 }
 
 
        if (!new)
                return -ENOBUFS;
 
-       tcf_exts_init(&new->exts, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
+       err = tcf_exts_init(&new->exts, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
+       if (err < 0)
+               goto errout;
        new->handle = handle;
        new->tp = tp;
        err = nla_parse_nested(tb, TCA_CGROUP_MAX, tca[TCA_OPTIONS],
        if (err < 0)
                goto errout;
 
-       tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
+       err = tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
        if (err < 0)
                goto errout;
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
+       if (err < 0) {
+               tcf_exts_destroy(&e);
+               goto errout;
+       }
 
        err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &t);
        if (err < 0) {
                call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
        return 0;
 errout:
+       tcf_exts_destroy(&new->exts);
        kfree(new);
        return err;
 }
 
                        return -EOPNOTSUPP;
        }
 
-       tcf_exts_init(&e, TCA_FLOW_ACT, TCA_FLOW_POLICE);
+       err = tcf_exts_init(&e, TCA_FLOW_ACT, TCA_FLOW_POLICE);
+       if (err < 0)
+               goto err1;
        err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
        if (err < 0)
-               return err;
+               goto err1;
 
        err = tcf_em_tree_validate(tp, tb[TCA_FLOW_EMATCHES], &t);
        if (err < 0)
        if (!fnew)
                goto err2;
 
-       tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
+       err = tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
+       if (err < 0)
+               goto err3;
 
        fold = (struct flow_filter *)*arg;
        if (fold) {
                err = -EINVAL;
                if (fold->handle != handle && handle)
-                       goto err2;
+                       goto err3;
 
                /* Copy fold into fnew */
                fnew->tp = fold->tp;
                if (tb[TCA_FLOW_MODE])
                        mode = nla_get_u32(tb[TCA_FLOW_MODE]);
                if (mode != FLOW_MODE_HASH && nkeys > 1)
-                       goto err2;
+                       goto err3;
 
                if (mode == FLOW_MODE_HASH)
                        perturb_period = fold->perturb_period;
                if (tb[TCA_FLOW_PERTURB]) {
                        if (mode != FLOW_MODE_HASH)
-                               goto err2;
+                               goto err3;
                        perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
                }
        } else {
                err = -EINVAL;
                if (!handle)
-                       goto err2;
+                       goto err3;
                if (!tb[TCA_FLOW_KEYS])
-                       goto err2;
+                       goto err3;
 
                mode = FLOW_MODE_MAP;
                if (tb[TCA_FLOW_MODE])
                        mode = nla_get_u32(tb[TCA_FLOW_MODE]);
                if (mode != FLOW_MODE_HASH && nkeys > 1)
-                       goto err2;
+                       goto err3;
 
                if (tb[TCA_FLOW_PERTURB]) {
                        if (mode != FLOW_MODE_HASH)
-                               goto err2;
+                               goto err3;
                        perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
                }
 
                call_rcu(&fold->rcu, flow_destroy_filter);
        return 0;
 
+err3:
+       tcf_exts_destroy(&fnew->exts);
 err2:
        tcf_em_tree_destroy(&t);
        kfree(fnew);
 
        struct tcf_exts e;
        int err;
 
-       tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
-       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       if (err < 0)
+               goto errout;
 
        if (tb[TCA_FLOWER_CLASSID]) {
                f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
        if (!fnew)
                return -ENOBUFS;
 
-       tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
+       err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
+       if (err < 0)
+               goto errout;
 
        if (!handle) {
                handle = fl_grab_new_handle(tp, head);
        return 0;
 
 errout:
+       tcf_exts_destroy(&fnew->exts);
        kfree(fnew);
        return err;
 }
 
        u32 mask;
        int err;
 
-       tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
+       err = tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
+       if (err < 0)
+               goto errout;
 
        if (tb[TCA_FW_CLASSID]) {
                f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]);
 #endif /* CONFIG_NET_CLS_IND */
                fnew->tp = f->tp;
 
-               tcf_exts_init(&fnew->exts, TCA_FW_ACT, TCA_FW_POLICE);
+               err = tcf_exts_init(&fnew->exts, TCA_FW_ACT, TCA_FW_POLICE);
+               if (err < 0) {
+                       kfree(fnew);
+                       return err;
+               }
 
                err = fw_change_attrs(net, tp, fnew, tb, tca, base, ovr);
                if (err < 0) {
+                       tcf_exts_destroy(&fnew->exts);
                        kfree(fnew);
                        return err;
                }
        if (f == NULL)
                return -ENOBUFS;
 
-       tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE);
+       err = tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE);
+       if (err < 0)
+               goto errout;
        f->id = handle;
        f->tp = tp;
 
        return 0;
 
 errout:
+       tcf_exts_destroy(&f->exts);
        kfree(f);
        return err;
 }
 
                            struct nlattr **tb, struct nlattr *est, int new,
                            bool ovr)
 {
-       int err;
        u32 id = 0, to = 0, nhandle = 0x8000;
        struct route4_filter *fp;
        unsigned int h1;
        struct route4_bucket *b;
        struct tcf_exts e;
+       int err;
 
-       tcf_exts_init(&e, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       err = tcf_exts_init(&e, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       if (err < 0)
+               goto errout;
 
        err = -EINVAL;
        if (tb[TCA_ROUTE4_TO]) {
        if (!f)
                goto errout;
 
-       tcf_exts_init(&f->exts, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE);
+       err = tcf_exts_init(&f->exts, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE);
+       if (err < 0)
+               goto errout;
+
        if (fold) {
                f->id = fold->id;
                f->iif = fold->iif;
        return 0;
 
 errout:
+       tcf_exts_destroy(&f->exts);
        kfree(f);
        return err;
 }
 
        if (err < 0)
                return err;
 
-       tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
+       err = tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
+       if (err < 0)
+               goto errout2;
 
        f = (struct rsvp_filter *)*arg;
        if (f) {
                        goto errout2;
                }
 
-               tcf_exts_init(&n->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
+               err = tcf_exts_init(&n->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
+               if (err < 0) {
+                       kfree(n);
+                       goto errout2;
+               }
 
                if (tb[TCA_RSVP_CLASSID]) {
                        n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
        if (f == NULL)
                goto errout2;
 
-       tcf_exts_init(&f->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
+       err = tcf_exts_init(&f->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE);
+       if (err < 0)
+               goto errout;
        h2 = 16;
        if (tb[TCA_RSVP_SRC]) {
                memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
        goto insert;
 
 errout:
+       tcf_exts_destroy(&f->exts);
        kfree(f);
 errout2:
        tcf_exts_destroy(&e);
 
        [TCA_TCINDEX_CLASSID]           = { .type = NLA_U32 },
 };
 
-static void tcindex_filter_result_init(struct tcindex_filter_result *r)
+static int tcindex_filter_result_init(struct tcindex_filter_result *r)
 {
        memset(r, 0, sizeof(*r));
-       tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
+       return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
 }
 
 static void __tcindex_partial_destroy(struct rcu_head *head)
        kfree(p);
 }
 
+static void tcindex_free_perfect_hash(struct tcindex_data *cp)
+{
+       int i;
+
+       for (i = 0; i < cp->hash; i++)
+               tcf_exts_destroy(&cp->perfect[i].exts);
+       kfree(cp->perfect);
+}
+
+static int tcindex_alloc_perfect_hash(struct tcindex_data *cp)
+{
+       int i, err = 0;
+
+       cp->perfect = kcalloc(cp->hash, sizeof(struct tcindex_filter_result),
+                             GFP_KERNEL);
+       if (!cp->perfect)
+               return -ENOMEM;
+
+       for (i = 0; i < cp->hash; i++) {
+               err = tcf_exts_init(&cp->perfect[i].exts,
+                                   TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
+               if (err < 0)
+                       goto errout;
+       }
+
+       return 0;
+
+errout:
+       tcindex_free_perfect_hash(cp);
+       return err;
+}
+
 static int
 tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
                  u32 handle, struct tcindex_data *p,
                  struct tcindex_filter_result *r, struct nlattr **tb,
                  struct nlattr *est, bool ovr)
 {
-       int err, balloc = 0;
        struct tcindex_filter_result new_filter_result, *old_r = r;
        struct tcindex_filter_result cr;
-       struct tcindex_data *cp, *oldp;
+       struct tcindex_data *cp = NULL, *oldp;
        struct tcindex_filter *f = NULL; /* make gcc behave */
+       int err, balloc = 0;
        struct tcf_exts e;
 
-       tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       err = tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       if (err < 0)
+               goto errout;
 
        err = -ENOMEM;
        /* tcindex_data attributes must look atomic to classifier/lookup so
        if (p->perfect) {
                int i;
 
-               cp->perfect = kmemdup(p->perfect,
-                                     sizeof(*r) * cp->hash, GFP_KERNEL);
-               if (!cp->perfect)
+               if (tcindex_alloc_perfect_hash(cp) < 0)
                        goto errout;
                for (i = 0; i < cp->hash; i++)
-                       tcf_exts_init(&cp->perfect[i].exts,
-                                     TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
+                       cp->perfect[i].res = p->perfect[i].res;
                balloc = 1;
        }
        cp->h = p->h;
 
-       tcindex_filter_result_init(&new_filter_result);
-       tcindex_filter_result_init(&cr);
+       err = tcindex_filter_result_init(&new_filter_result);
+       if (err < 0)
+               goto errout1;
+       err = tcindex_filter_result_init(&cr);
+       if (err < 0)
+               goto errout1;
        if (old_r)
                cr.res = r->res;
 
        err = -ENOMEM;
        if (!cp->perfect && !cp->h) {
                if (valid_perfect_hash(cp)) {
-                       int i;
-
-                       cp->perfect = kcalloc(cp->hash, sizeof(*r), GFP_KERNEL);
-                       if (!cp->perfect)
+                       if (tcindex_alloc_perfect_hash(cp) < 0)
                                goto errout_alloc;
-                       for (i = 0; i < cp->hash; i++)
-                               tcf_exts_init(&cp->perfect[i].exts,
-                                             TCA_TCINDEX_ACT,
-                                             TCA_TCINDEX_POLICE);
                        balloc = 1;
                } else {
                        struct tcindex_filter __rcu **hash;
                if (!f)
                        goto errout_alloc;
                f->key = handle;
-               tcindex_filter_result_init(&f->result);
                f->next = NULL;
+               err = tcindex_filter_result_init(&f->result);
+               if (err < 0) {
+                       kfree(f);
+                       goto errout_alloc;
+               }
        }
 
        if (tb[TCA_TCINDEX_CLASSID]) {
        else
                tcf_exts_change(tp, &cr.exts, &e);
 
-       if (old_r && old_r != r)
-               tcindex_filter_result_init(old_r);
+       if (old_r && old_r != r) {
+               err = tcindex_filter_result_init(old_r);
+               if (err < 0) {
+                       kfree(f);
+                       goto errout_alloc;
+               }
+       }
 
        oldp = p;
        r->res = cr.res;
 
 errout_alloc:
        if (balloc == 1)
-               kfree(cp->perfect);
+               tcindex_free_perfect_hash(cp);
        else if (balloc == 2)
                kfree(cp->h);
+errout1:
+       tcf_exts_destroy(&cr.exts);
+       tcf_exts_destroy(&new_filter_result.exts);
 errout:
        kfree(cp);
        tcf_exts_destroy(&e);
 
                         struct tc_u_knode *n, struct nlattr **tb,
                         struct nlattr *est, bool ovr)
 {
-       int err;
        struct tcf_exts e;
+       int err;
 
-       tcf_exts_init(&e, TCA_U32_ACT, TCA_U32_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       err = tcf_exts_init(&e, TCA_U32_ACT, TCA_U32_POLICE);
        if (err < 0)
                return err;
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
+       if (err < 0)
+               goto errout;
 
        err = -EINVAL;
        if (tb[TCA_U32_LINK]) {
        new->tp = tp;
        memcpy(&new->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key));
 
-       tcf_exts_init(&new->exts, TCA_U32_ACT, TCA_U32_POLICE);
+       if (tcf_exts_init(&new->exts, TCA_U32_ACT, TCA_U32_POLICE)) {
+               kfree(new);
+               return NULL;
+       }
 
        return new;
 }
        n->handle = handle;
        n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
        n->flags = flags;
-       tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE);
        n->tp = tp;
 
+       err = tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE);
+       if (err < 0)
+               goto errout;
+
 #ifdef CONFIG_CLS_U32_MARK
        n->pcpu_success = alloc_percpu(u32);
        if (!n->pcpu_success) {
 errhw:
 #ifdef CONFIG_CLS_U32_MARK
        free_percpu(n->pcpu_success);
-errout:
 #endif
 
+errout:
+       tcf_exts_destroy(&n->exts);
 #ifdef CONFIG_CLS_U32_PERF
        free_percpu(n->pf);
 #endif