Skip to content

Commit

Permalink
net: sched: use temporary variable for actions indexes
Browse files Browse the repository at this point in the history
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: 0190c1d ("net: sched: atomically check-allocate action")
Signed-off-by: Dmytro Linkin <dmitrolin@mellanox.com>
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dmytro Linkin authored and David S. Miller committed Aug 5, 2019
1 parent 7fb5a71 commit 7be8ef2
Show file tree
Hide file tree
Showing 18 changed files with 100 additions and 75 deletions.
9 changes: 5 additions & 4 deletions net/sched/act_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,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;
Expand All @@ -298,13 +299,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;
}

Expand Down
9 changes: 5 additions & 4 deletions net/sched/act_connmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
struct tcf_connmark_info *ci;
struct tc_connmark *parm;
int ret = 0, err;
u32 index;

if (!nla)
return -EINVAL;
Expand All @@ -116,13 +117,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;
}

Expand Down
9 changes: 5 additions & 4 deletions net/sched/act_csum.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,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;
Expand All @@ -64,13 +65,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;
Expand Down
9 changes: 5 additions & 4 deletions net/sched/act_ct.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
struct tc_ct *parm;
struct tcf_ct *c;
int err, res = 0;
u32 index;

if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Ct requires attributes to be passed");
Expand All @@ -681,16 +682,16 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
parm = nla_data(tb[TCA_CT_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 < 0)
return err;

if (!err) {
err = tcf_idr_create(tn, parm->index, est, a,
err = tcf_idr_create(tn, index, est, a,
&act_ct_ops, bind, true);
if (err) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
return err;
}
res = ACT_P_CREATED;
Expand Down
9 changes: 5 additions & 4 deletions net/sched/act_ctinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
struct netlink_ext_ack *extack)
{
struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
u32 dscpmask = 0, dscpstatemask, index;
struct nlattr *tb[TCA_CTINFO_MAX + 1];
struct tcf_ctinfo_params *cp_new;
struct tcf_chain *goto_ch = NULL;
u32 dscpmask = 0, dscpstatemask;
struct tc_ctinfo *actparm;
struct tcf_ctinfo *ci;
u8 dscpmaskshift;
Expand Down Expand Up @@ -206,12 +206,13 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
}

/* done the validation:now to the actual action allocation */
err = tcf_idr_check_alloc(tn, &actparm->index, a, bind);
index = actparm->index;
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
ret = tcf_idr_create(tn, actparm->index, est, a,
ret = tcf_idr_create(tn, index, est, a,
&act_ctinfo_ops, bind, false);
if (ret) {
tcf_idr_cleanup(tn, actparm->index);
tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
Expand Down
8 changes: 5 additions & 3 deletions net/sched/act_gact.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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;
Expand All @@ -77,6 +78,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)
Expand All @@ -94,12 +96,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;
Expand Down
8 changes: 5 additions & 3 deletions net/sched/act_ife.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,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) {
Expand Down Expand Up @@ -507,7 +508,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;
Expand All @@ -519,10 +521,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;
}
Expand Down
13 changes: 7 additions & 6 deletions net/sched/act_mirred.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
struct net_device *dev;
bool exists = false;
int ret, err;
u32 index;

if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed");
Expand All @@ -118,8 +119,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
parm = nla_data(tb[TCA_MIRRED_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 < 0)
return err;
exists = err;
Expand All @@ -136,21 +137,21 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option");
return -EINVAL;
}

if (!exists) {
if (!parm->ifindex) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
return -EINVAL;
}
ret = tcf_idr_create(tn, parm->index, est, a,
ret = tcf_idr_create(tn, index, est, a,
&act_mirred_ops, bind, true);
if (ret) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
Expand Down
8 changes: 5 additions & 3 deletions net/sched/act_mpls.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
struct tcf_mpls *m;
int ret = 0, err;
u8 mpls_ttl = 0;
u32 index;

if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Missing netlink attributes");
Expand All @@ -153,6 +154,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
parm = nla_data(tb[TCA_MPLS_PARMS]);
index = parm->index;

/* Verify parameters against action type. */
switch (parm->m_action) {
Expand Down Expand Up @@ -209,18 +211,18 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}

err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
if (exists && bind)
return 0;

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

Expand Down
9 changes: 5 additions & 4 deletions net/sched/act_nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
struct tc_nat *parm;
int ret = 0, err;
struct tcf_nat *p;
u32 index;

if (nla == NULL)
return -EINVAL;
Expand All @@ -56,13 +57,13 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
if (tb[TCA_NAT_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_NAT_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_nat_ops, bind, false);
if (ret) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
Expand Down
10 changes: 6 additions & 4 deletions net/sched/act_pedit.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
struct tcf_pedit *p;
int ret = 0, err;
int ksize;
u32 index;

if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Pedit requires attributes to be passed");
Expand Down Expand Up @@ -179,18 +180,19 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
if (IS_ERR(keys_ex))
return PTR_ERR(keys_ex);

err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
index = parm->index;
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
if (!parm->nkeys) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
ret = -EINVAL;
goto out_free;
}
ret = tcf_idr_create(tn, parm->index, est, a,
ret = tcf_idr_create(tn, index, est, a,
&act_pedit_ops, bind, false);
if (ret) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
goto out_free;
}
ret = ACT_P_CREATED;
Expand Down
8 changes: 5 additions & 3 deletions net/sched/act_police.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
struct tc_action_net *tn = net_generic(net, police_net_id);
struct tcf_police_params *new;
bool exists = false;
u32 index;

if (nla == NULL)
return -EINVAL;
Expand All @@ -73,18 +74,19 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
return -EINVAL;

parm = nla_data(tb[TCA_POLICE_TBF]);
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)
return err;
exists = err;
if (exists && bind)
return 0;

if (!exists) {
ret = tcf_idr_create(tn, parm->index, NULL, a,
ret = tcf_idr_create(tn, index, NULL, a,
&act_police_ops, bind, true);
if (ret) {
tcf_idr_cleanup(tn, parm->index);
tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
Expand Down
Loading

0 comments on commit 7be8ef2

Please sign in to comment.