netfilter: nft_compat: use call_rcu for nfnl_compat_get

Just use .call_rcu instead.  We can drop the rcu read lock
after obtaining a reference and re-acquire on return.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Florian Westphal 2018-05-27 11:20:48 +02:00 committed by Pablo Neira Ayuso
parent 88491c11b0
commit eb1fb1479b

View File

@ -611,10 +611,10 @@ nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
return -1; return -1;
} }
static int nfnl_compat_get(struct net *net, struct sock *nfnl, static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[], const struct nlattr * const tb[],
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
int ret = 0, target; int ret = 0, target;
struct nfgenmsg *nfmsg; struct nfgenmsg *nfmsg;
@ -653,16 +653,21 @@ static int nfnl_compat_get(struct net *net, struct sock *nfnl,
return -EINVAL; return -EINVAL;
} }
if (!try_module_get(THIS_MODULE))
return -EINVAL;
rcu_read_unlock();
try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name, try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
rev, target, &ret), rev, target, &ret),
fmt, name); fmt, name);
if (ret < 0) if (ret < 0)
return ret; goto out_put;
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb2 == NULL) if (skb2 == NULL) {
return -ENOMEM; ret = -ENOMEM;
goto out_put;
}
/* include the best revision for this extension in the message */ /* include the best revision for this extension in the message */
if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid, if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
@ -672,14 +677,16 @@ static int nfnl_compat_get(struct net *net, struct sock *nfnl,
nfmsg->nfgen_family, nfmsg->nfgen_family,
name, ret, target) <= 0) { name, ret, target) <= 0) {
kfree_skb(skb2); kfree_skb(skb2);
return -ENOSPC; goto out_put;
} }
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT); MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
out_put:
rcu_read_lock();
module_put(THIS_MODULE);
return ret == -EAGAIN ? -ENOBUFS : ret; return ret == -EAGAIN ? -ENOBUFS : ret;
} }
@ -691,7 +698,7 @@ static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
}; };
static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = { static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
[NFNL_MSG_COMPAT_GET] = { .call = nfnl_compat_get, [NFNL_MSG_COMPAT_GET] = { .call_rcu = nfnl_compat_get_rcu,
.attr_count = NFTA_COMPAT_MAX, .attr_count = NFTA_COMPAT_MAX,
.policy = nfnl_compat_policy_get }, .policy = nfnl_compat_policy_get },
}; };