Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51d240a1 authored by Dmytro Linkin's avatar Dmytro Linkin Committed by Greg Kroah-Hartman
Browse files

net: sched: use temporary variable for actions indexes



[ Upstream commit 7be8ef2cdbfe41a2e524b7c6cc3f8e6cfaa906e4 ]

Currently init call of all actions (except ipt) init their 'parm'
structure as a direct pointer to nla data in skb. This leads to race
condition when some of the filter actions were initialized successfully
(and were assigned with idr action index that was written directly
into nla data), but then were deleted and retried (due to following
action module missing or classifier-initiated retry), in which case
action init code tries to insert action to idr with index that was
assigned on previous iteration. During retry the index can be reused
by another action that was inserted concurrently, which causes
unintended action sharing between filters.
To fix described race condition, save action idr index to temporary
stack-allocated variable instead on nla data.

Fixes: 0190c1d4 ("net: sched: atomically check-allocate action")
Signed-off-by: default avatarDmytro Linkin <dmitrolin@mellanox.com>
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Acked-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cb20f741
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
	struct tcf_bpf *prog;
	bool is_bpf, is_ebpf;
	int ret, res = 0;
	u32 index;

	if (!nla)
		return -EINVAL;
@@ -299,13 +300,13 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
		return -EINVAL;

	parm = nla_data(tb[TCA_ACT_BPF_PARMS]);

	ret = tcf_idr_check_alloc(tn, &parm->index, act, bind);
	index = parm->index;
	ret = tcf_idr_check_alloc(tn, &index, act, bind);
	if (!ret) {
		ret = tcf_idr_create(tn, parm->index, est, act,
		ret = tcf_idr_create(tn, index, est, act,
				     &act_bpf_ops, bind, true);
		if (ret < 0) {
			tcf_idr_cleanup(tn, parm->index);
			tcf_idr_cleanup(tn, index);
			return ret;
		}

+5 −4
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
	struct tcf_connmark_info *ci;
	struct tc_connmark *parm;
	int ret = 0;
	u32 index;

	if (!nla)
		return -EINVAL;
@@ -117,13 +118,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
		return -EINVAL;

	parm = nla_data(tb[TCA_CONNMARK_PARMS]);

	ret = tcf_idr_check_alloc(tn, &parm->index, a, bind);
	index = parm->index;
	ret = tcf_idr_check_alloc(tn, &index, a, bind);
	if (!ret) {
		ret = tcf_idr_create(tn, parm->index, est, a,
		ret = tcf_idr_create(tn, index, est, a,
				     &act_connmark_ops, bind, false);
		if (ret) {
			tcf_idr_cleanup(tn, parm->index);
			tcf_idr_cleanup(tn, index);
			return ret;
		}

+5 −4
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
	struct tc_csum *parm;
	struct tcf_csum *p;
	int ret = 0, err;
	u32 index;

	if (nla == NULL)
		return -EINVAL;
@@ -66,13 +67,13 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
	if (tb[TCA_CSUM_PARMS] == NULL)
		return -EINVAL;
	parm = nla_data(tb[TCA_CSUM_PARMS]);

	err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
	index = parm->index;
	err = tcf_idr_check_alloc(tn, &index, a, bind);
	if (!err) {
		ret = tcf_idr_create(tn, parm->index, est, a,
		ret = tcf_idr_create(tn, index, est, a,
				     &act_csum_ops, bind, true);
		if (ret) {
			tcf_idr_cleanup(tn, parm->index);
			tcf_idr_cleanup(tn, index);
			return ret;
		}
		ret = ACT_P_CREATED;
+5 −3
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
	struct tc_gact *parm;
	struct tcf_gact *gact;
	int ret = 0;
	u32 index;
	int err;
#ifdef CONFIG_GACT_PROB
	struct tc_gact_p *p_parm = NULL;
@@ -79,6 +80,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
	if (tb[TCA_GACT_PARMS] == NULL)
		return -EINVAL;
	parm = nla_data(tb[TCA_GACT_PARMS]);
	index = parm->index;

#ifndef CONFIG_GACT_PROB
	if (tb[TCA_GACT_PROB] != NULL)
@@ -91,12 +93,12 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
	}
#endif

	err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
	err = tcf_idr_check_alloc(tn, &index, a, bind);
	if (!err) {
		ret = tcf_idr_create(tn, parm->index, est, a,
		ret = tcf_idr_create(tn, index, est, a,
				     &act_gact_ops, bind, true);
		if (ret) {
			tcf_idr_cleanup(tn, parm->index);
			tcf_idr_cleanup(tn, index);
			return ret;
		}
		ret = ACT_P_CREATED;
+5 −3
Original line number Diff line number Diff line
@@ -482,6 +482,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
	u8 *saddr = NULL;
	bool exists = false;
	int ret = 0;
	u32 index;
	int err;

	if (!nla) {
@@ -509,7 +510,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
	if (!p)
		return -ENOMEM;

	err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
	index = parm->index;
	err = tcf_idr_check_alloc(tn, &index, a, bind);
	if (err < 0) {
		kfree(p);
		return err;
@@ -521,10 +523,10 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
	}

	if (!exists) {
		ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
		ret = tcf_idr_create(tn, index, est, a, &act_ife_ops,
				     bind, true);
		if (ret) {
			tcf_idr_cleanup(tn, parm->index);
			tcf_idr_cleanup(tn, index);
			kfree(p);
			return ret;
		}
Loading