Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

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

The following patchset contains Netfilter fixes for your net tree,
they are:

1) Missing TCP header sanity check in TCPMSS target, from Eric Dumazet.

2) Incorrect event message type for related conntracks created via
   ctnetlink, from Liping Zhang.

3) Fix incorrect rcu locking when handling helpers from ctnetlink,
   from Gao feng.

4) Fix missing rcu locking when updating helper, from Liping Zhang.

5) Fix missing read_lock_bh when iterating over list of device addresses
   from TPROXY and redirect, also from Liping.

6) Fix crash when trying to dump expectations from conntrack with no
   helper via ctnetlink, from Liping.

7) Missing RCU protection to expecation list update given ctnetlink
   iterates over the list under rcu read lock side, from Liping too.

8) Don't dump autogenerated seed in nft_hash to userspace, this is
   very confusing to the user, again from Liping.

9) Fix wrong conntrack netns module refcount in ipt_CLUSTERIP,
   from Gao feng.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 14, 2017
2 parents 14cf4a7 + fe50543 commit f4c13c8
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 25 deletions.
2 changes: 1 addition & 1 deletion net/ipv4/netfilter/ipt_CLUSTERIP.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)

clusterip_config_put(cipinfo->config);

nf_ct_netns_get(par->net, par->family);
nf_ct_netns_put(par->net, par->family);
}

#ifdef CONFIG_COMPAT
Expand Down
4 changes: 2 additions & 2 deletions net/netfilter/nf_conntrack_expect.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
hlist_del_rcu(&exp->hnode);
net->ct.expect_count--;

hlist_del(&exp->lnode);
hlist_del_rcu(&exp->lnode);
master_help->expecting[exp->class]--;

nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
Expand Down Expand Up @@ -363,7 +363,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
/* two references : one for hash insert, one for the timer */
atomic_add(2, &exp->use);

hlist_add_head(&exp->lnode, &master_help->expectations);
hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
master_help->expecting[exp->class]++;

hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
Expand Down
17 changes: 12 additions & 5 deletions net/netfilter/nf_conntrack_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,25 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
{
struct nf_conntrack_helper *h;

rcu_read_lock();

h = __nf_conntrack_helper_find(name, l3num, protonum);
#ifdef CONFIG_MODULES
if (h == NULL) {
if (request_module("nfct-helper-%s", name) == 0)
rcu_read_unlock();
if (request_module("nfct-helper-%s", name) == 0) {
rcu_read_lock();
h = __nf_conntrack_helper_find(name, l3num, protonum);
} else {
return h;
}
}
#endif
if (h != NULL && !try_module_get(h->me))
h = NULL;

rcu_read_unlock();

return h;
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
Expand Down Expand Up @@ -311,38 +320,36 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);

/* Caller should hold the rcu lock */
struct nf_ct_helper_expectfn *
nf_ct_helper_expectfn_find_by_name(const char *name)
{
struct nf_ct_helper_expectfn *cur;
bool found = false;

rcu_read_lock();
list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
if (!strcmp(cur->name, name)) {
found = true;
break;
}
}
rcu_read_unlock();
return found ? cur : NULL;
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);

/* Caller should hold the rcu lock */
struct nf_ct_helper_expectfn *
nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
{
struct nf_ct_helper_expectfn *cur;
bool found = false;

rcu_read_lock();
list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
if (cur->expectfn == symbol) {
found = true;
break;
}
}
rcu_read_unlock();
return found ? cur : NULL;
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
Expand Down
41 changes: 29 additions & 12 deletions net/netfilter/nf_conntrack_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1488,11 +1488,16 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
* treat the second attempt as a no-op instead of returning
* an error.
*/
if (help && help->helper &&
!strcmp(help->helper->name, helpname))
return 0;
else
return -EBUSY;
err = -EBUSY;
if (help) {
rcu_read_lock();
helper = rcu_dereference(help->helper);
if (helper && !strcmp(helper->name, helpname))
err = 0;
rcu_read_unlock();
}

return err;
}

if (!strcmp(helpname, "")) {
Expand Down Expand Up @@ -1929,9 +1934,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,

err = 0;
if (test_bit(IPS_EXPECTED_BIT, &ct->status))
events = IPCT_RELATED;
events = 1 << IPCT_RELATED;
else
events = IPCT_NEW;
events = 1 << IPCT_NEW;

if (cda[CTA_LABELS] &&
ctnetlink_attach_labels(ct, cda) == 0)
Expand Down Expand Up @@ -2675,8 +2680,8 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
last = (struct nf_conntrack_expect *)cb->args[1];
for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
restart:
hlist_for_each_entry(exp, &nf_ct_expect_hash[cb->args[0]],
hnode) {
hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
hnode) {
if (l3proto && exp->tuple.src.l3num != l3proto)
continue;

Expand Down Expand Up @@ -2727,7 +2732,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock();
last = (struct nf_conntrack_expect *)cb->args[1];
restart:
hlist_for_each_entry(exp, &help->expectations, lnode) {
hlist_for_each_entry_rcu(exp, &help->expectations, lnode) {
if (l3proto && exp->tuple.src.l3num != l3proto)
continue;
if (cb->args[1]) {
Expand Down Expand Up @@ -2789,6 +2794,12 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
return -ENOENT;

ct = nf_ct_tuplehash_to_ctrack(h);
/* No expectation linked to this connection tracking. */
if (!nfct_help(ct)) {
nf_ct_put(ct);
return 0;
}

c.data = ct;

err = netlink_dump_start(ctnl, skb, nlh, &c);
Expand Down Expand Up @@ -3133,23 +3144,27 @@ ctnetlink_create_expect(struct net *net,
return -ENOENT;
ct = nf_ct_tuplehash_to_ctrack(h);

rcu_read_lock();
if (cda[CTA_EXPECT_HELP_NAME]) {
const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);

helper = __nf_conntrack_helper_find(helpname, u3,
nf_ct_protonum(ct));
if (helper == NULL) {
rcu_read_unlock();
#ifdef CONFIG_MODULES
if (request_module("nfct-helper-%s", helpname) < 0) {
err = -EOPNOTSUPP;
goto err_ct;
}
rcu_read_lock();
helper = __nf_conntrack_helper_find(helpname, u3,
nf_ct_protonum(ct));
if (helper) {
err = -EAGAIN;
goto err_ct;
goto err_rcu;
}
rcu_read_unlock();
#endif
err = -EOPNOTSUPP;
goto err_ct;
Expand All @@ -3159,11 +3174,13 @@ ctnetlink_create_expect(struct net *net,
exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
if (IS_ERR(exp)) {
err = PTR_ERR(exp);
goto err_ct;
goto err_rcu;
}

err = nf_ct_expect_related_report(exp, portid, report);
nf_ct_expect_put(exp);
err_rcu:
rcu_read_unlock();
err_ct:
nf_ct_put(ct);
return err;
Expand Down
2 changes: 2 additions & 0 deletions net/netfilter/nf_nat_redirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,13 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
rcu_read_lock();
idev = __in6_dev_get(skb->dev);
if (idev != NULL) {
read_lock_bh(&idev->lock);
list_for_each_entry(ifa, &idev->addr_list, if_list) {
newdst = ifa->addr;
addr = true;
break;
}
read_unlock_bh(&idev->lock);
}
rcu_read_unlock();

Expand Down
10 changes: 7 additions & 3 deletions net/netfilter/nft_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct nft_hash {
enum nft_registers sreg:8;
enum nft_registers dreg:8;
u8 len;
bool autogen_seed:1;
u32 modulus;
u32 seed;
u32 offset;
Expand Down Expand Up @@ -82,10 +83,12 @@ static int nft_hash_init(const struct nft_ctx *ctx,
if (priv->offset + priv->modulus - 1 < priv->offset)
return -EOVERFLOW;

if (tb[NFTA_HASH_SEED])
if (tb[NFTA_HASH_SEED]) {
priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
else
} else {
priv->autogen_seed = true;
get_random_bytes(&priv->seed, sizeof(priv->seed));
}

return nft_validate_register_load(priv->sreg, len) &&
nft_validate_register_store(ctx, priv->dreg, NULL,
Expand All @@ -105,7 +108,8 @@ static int nft_hash_dump(struct sk_buff *skb,
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
if (!priv->autogen_seed &&
nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
goto nla_put_failure;
if (priv->offset != 0)
if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
Expand Down
6 changes: 5 additions & 1 deletion net/netfilter/xt_TCPMSS.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ tcpmss_mangle_packet(struct sk_buff *skb,
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
tcp_hdrlen = tcph->doff * 4;

if (len < tcp_hdrlen)
if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr))
return -1;

if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
Expand Down Expand Up @@ -152,6 +152,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
if (len > tcp_hdrlen)
return 0;

/* tcph->doff has 4 bits, do not wrap it to 0 */
if (tcp_hdrlen >= 15 * 4)
return 0;

/*
* MSS Option not found ?! add it..
*/
Expand Down
5 changes: 4 additions & 1 deletion net/netfilter/xt_TPROXY.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,14 +393,17 @@ tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,

rcu_read_lock();
indev = __in6_dev_get(skb->dev);
if (indev)
if (indev) {
read_lock_bh(&indev->lock);
list_for_each_entry(ifa, &indev->addr_list, if_list) {
if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
continue;

laddr = &ifa->addr;
break;
}
read_unlock_bh(&indev->lock);
}
rcu_read_unlock();

return laddr ? laddr : daddr;
Expand Down

0 comments on commit f4c13c8

Please sign in to comment.