Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Fix warnings suspicious rcu usage when handling base chain
   statistics, from Taehee Yoo.

2) Refetch pointer to tcp header from nf_ct_sack_adjust() since
   skb_make_writable() may reallocate data area, reported by Google
   folks patch from Florian.

3) Incorrect netlink nest end after previous cancellation from error
   path in ipset, from Pan Bian.

4) Use dst_hold_safe() from nf_xfrm_me_harder(), from Florian.

5) Use rb_link_node_rcu() for rcu-protected rbtree node in
   nf_conncount, from Taehee Yoo.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-12-12 21:36:12 -08:00
commit 18330c58e3
7 changed files with 22 additions and 27 deletions

View File

@ -62,18 +62,6 @@ static inline bool lockdep_nfnl_is_held(__u8 subsys_id)
}
#endif /* CONFIG_PROVE_LOCKING */
/*
* nfnl_dereference - fetch RCU pointer when updates are prevented by subsys mutex
*
* @p: The pointer to read, prior to dereferencing
* @ss: The nfnetlink subsystem ID
*
* Return the value of the specified RCU-protected pointer, but omit
* the READ_ONCE(), because caller holds the NFNL subsystem mutex.
*/
#define nfnl_dereference(p, ss) \
rcu_dereference_protected(p, lockdep_nfnl_is_held(ss))
#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))

View File

@ -531,8 +531,8 @@ nla_put_failure:
ret = -EMSGSIZE;
} else {
cb->args[IPSET_CB_ARG0] = i;
ipset_nest_end(skb, atd);
}
ipset_nest_end(skb, atd);
out:
rcu_read_unlock();
return ret;

View File

@ -427,7 +427,7 @@ insert_tree(struct net *net,
count = 1;
rbconn->list.count = count;
rb_link_node(&rbconn->node, parent, rbnode);
rb_link_node_rcu(&rbconn->node, parent, rbnode);
rb_insert_color(&rbconn->node, root);
out_unlock:
spin_unlock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]);

View File

@ -115,12 +115,12 @@ static void nf_ct_sack_block_adjust(struct sk_buff *skb,
/* TCP SACK sequence number adjustment */
static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
unsigned int protoff,
struct tcphdr *tcph,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
unsigned int dir, optoff, optend;
struct tcphdr *tcph = (void *)skb->data + protoff;
struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
unsigned int dir, optoff, optend;
optoff = protoff + sizeof(struct tcphdr);
optend = protoff + tcph->doff * 4;
@ -128,6 +128,7 @@ static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
if (!skb_make_writable(skb, optend))
return 0;
tcph = (void *)skb->data + protoff;
dir = CTINFO2DIR(ctinfo);
while (optoff < optend) {
@ -207,7 +208,7 @@ int nf_ct_seq_adjust(struct sk_buff *skb,
ntohl(newack));
tcph->ack_seq = newack;
res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo);
res = nf_ct_sack_adjust(skb, protoff, ct, ctinfo);
out:
spin_unlock_bh(&ct->lock);

View File

@ -117,7 +117,8 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
dst = skb_dst(skb);
if (dst->xfrm)
dst = ((struct xfrm_dst *)dst)->route;
dst_hold(dst);
if (!dst_hold_safe(dst))
return -EHOSTUNREACH;
if (sk && !net_eq(net, sock_net(sk)))
sk = NULL;

View File

@ -1216,7 +1216,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
goto nla_put_failure;
if (basechain->stats && nft_dump_stats(skb, basechain->stats))
if (rcu_access_pointer(basechain->stats) &&
nft_dump_stats(skb, rcu_dereference(basechain->stats)))
goto nla_put_failure;
}
@ -1392,7 +1393,8 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
return newstats;
}
static void nft_chain_stats_replace(struct nft_base_chain *chain,
static void nft_chain_stats_replace(struct net *net,
struct nft_base_chain *chain,
struct nft_stats __percpu *newstats)
{
struct nft_stats __percpu *oldstats;
@ -1400,8 +1402,9 @@ static void nft_chain_stats_replace(struct nft_base_chain *chain,
if (newstats == NULL)
return;
if (chain->stats) {
oldstats = nfnl_dereference(chain->stats, NFNL_SUBSYS_NFTABLES);
if (rcu_access_pointer(chain->stats)) {
oldstats = rcu_dereference_protected(chain->stats,
lockdep_commit_lock_is_held(net));
rcu_assign_pointer(chain->stats, newstats);
synchronize_rcu();
free_percpu(oldstats);
@ -1439,9 +1442,10 @@ static void nf_tables_chain_destroy(struct nft_ctx *ctx)
struct nft_base_chain *basechain = nft_base_chain(chain);
module_put(basechain->type->owner);
free_percpu(basechain->stats);
if (basechain->stats)
if (rcu_access_pointer(basechain->stats)) {
static_branch_dec(&nft_counters_enabled);
free_percpu(rcu_dereference_raw(basechain->stats));
}
kfree(chain->name);
kfree(basechain);
} else {
@ -1590,7 +1594,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
kfree(basechain);
return PTR_ERR(stats);
}
basechain->stats = stats;
rcu_assign_pointer(basechain->stats, stats);
static_branch_inc(&nft_counters_enabled);
}
@ -6180,7 +6184,8 @@ static void nft_chain_commit_update(struct nft_trans *trans)
return;
basechain = nft_base_chain(trans->ctx.chain);
nft_chain_stats_replace(basechain, nft_trans_chain_stats(trans));
nft_chain_stats_replace(trans->ctx.net, basechain,
nft_trans_chain_stats(trans));
switch (nft_trans_chain_policy(trans)) {
case NF_DROP:

View File

@ -101,7 +101,7 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain,
struct nft_stats *stats;
base_chain = nft_base_chain(chain);
if (!base_chain->stats)
if (!rcu_access_pointer(base_chain->stats))
return;
local_bh_disable();