提交 3f7c72bc 编写于 作者: V Vlad Buslov 提交者: David S. Miller

net: sched: always take reference to action

Without rtnl lock protection it is no longer safe to use pointer to tc
action without holding reference to it. (it can be destroyed concurrently)

Remove unsafe action idr lookup function. Instead of it, implement safe tcf
idr check function that atomically looks up action in idr and increments
its reference and bind counters. Implement both action search and check
using new safe function

Reference taken by idr check is temporal and should not be accounted by
userspace clients (both logically and to preserver current API behavior).
Subtract temporal reference when dumping action to userspace using existing
tca_get_fill function arguments.
Reviewed-by: NMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: NVlad Buslov <vladbu@mellanox.com>
Signed-off-by: NJiri Pirko <jiri@mellanox.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 789871bb
...@@ -284,44 +284,38 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, ...@@ -284,44 +284,38 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
} }
EXPORT_SYMBOL(tcf_generic_walker); EXPORT_SYMBOL(tcf_generic_walker);
static struct tc_action *tcf_idr_lookup(u32 index, struct tcf_idrinfo *idrinfo) static bool __tcf_idr_check(struct tc_action_net *tn, u32 index,
struct tc_action **a, int bind)
{ {
struct tc_action *p = NULL; struct tcf_idrinfo *idrinfo = tn->idrinfo;
struct tc_action *p;
spin_lock(&idrinfo->lock); spin_lock(&idrinfo->lock);
p = idr_find(&idrinfo->action_idr, index); p = idr_find(&idrinfo->action_idr, index);
if (p) {
refcount_inc(&p->tcfa_refcnt);
if (bind)
atomic_inc(&p->tcfa_bindcnt);
}
spin_unlock(&idrinfo->lock); spin_unlock(&idrinfo->lock);
return p; if (p) {
*a = p;
return true;
}
return false;
} }
int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index) int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
{ {
struct tcf_idrinfo *idrinfo = tn->idrinfo; return __tcf_idr_check(tn, index, a, 0);
struct tc_action *p = tcf_idr_lookup(index, idrinfo);
if (p) {
*a = p;
return 1;
}
return 0;
} }
EXPORT_SYMBOL(tcf_idr_search); EXPORT_SYMBOL(tcf_idr_search);
bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a, bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
int bind) int bind)
{ {
struct tcf_idrinfo *idrinfo = tn->idrinfo; return __tcf_idr_check(tn, index, a, bind);
struct tc_action *p = tcf_idr_lookup(index, idrinfo);
if (index && p) {
if (bind)
atomic_inc(&p->tcfa_bindcnt);
refcount_inc(&p->tcfa_refcnt);
*a = p;
return true;
}
return false;
} }
EXPORT_SYMBOL(tcf_idr_check); EXPORT_SYMBOL(tcf_idr_check);
...@@ -932,7 +926,7 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, ...@@ -932,7 +926,7 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
if (!skb) if (!skb)
return -ENOBUFS; return -ENOBUFS;
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event,
0, 0) <= 0) { 0, 1) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action"); NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action");
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
...@@ -1072,7 +1066,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, ...@@ -1072,7 +1066,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
return -ENOBUFS; return -ENOBUFS;
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION, if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
0, 1) <= 0) { 0, 2) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink TC action attributes"); NL_SET_ERR_MSG(extack, "Failed to fill netlink TC action attributes");
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
...@@ -1131,14 +1125,14 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -1131,14 +1125,14 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
if (event == RTM_GETACTION) if (event == RTM_GETACTION)
ret = tcf_get_notify(net, portid, n, &actions, event, extack); ret = tcf_get_notify(net, portid, n, &actions, event, extack);
else { /* delete */ else { /* delete */
cleanup_a(&actions, 1); /* lookup took reference */
ret = tcf_del_notify(net, n, &actions, portid, attr_size, extack); ret = tcf_del_notify(net, n, &actions, portid, attr_size, extack);
if (ret) if (ret)
goto err; goto err;
return ret; return ret;
} }
err: err:
if (event != RTM_GETACTION) tcf_action_destroy(&actions, 0);
tcf_action_destroy(&actions, 0);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册