Commit f4c13c8e authored by David S. Miller's avatar David S. Miller
Browse files


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: default avatarDavid S. Miller <davem@davemloft.net>
parents 14cf4a77 fe50543c
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -461,7 +461,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)


	clusterip_config_put(cipinfo->config);
	clusterip_config_put(cipinfo->config);


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


#ifdef CONFIG_COMPAT
#ifdef CONFIG_COMPAT
+2 −2
Original line number Original line Diff line number Diff line
@@ -57,7 +57,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
	hlist_del_rcu(&exp->hnode);
	hlist_del_rcu(&exp->hnode);
	net->ct.expect_count--;
	net->ct.expect_count--;


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


	nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
	nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
@@ -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 */
	/* two references : one for hash insert, one for the timer */
	atomic_add(2, &exp->use);
	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]++;
	master_help->expecting[exp->class]++;


	hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
	hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
+12 −5
Original line number Original line Diff line number Diff line
@@ -158,16 +158,25 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
{
{
	struct nf_conntrack_helper *h;
	struct nf_conntrack_helper *h;


	rcu_read_lock();

	h = __nf_conntrack_helper_find(name, l3num, protonum);
	h = __nf_conntrack_helper_find(name, l3num, protonum);
#ifdef CONFIG_MODULES
#ifdef CONFIG_MODULES
	if (h == NULL) {
	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);
			h = __nf_conntrack_helper_find(name, l3num, protonum);
		} else {
			return h;
		}
	}
	}
#endif
#endif
	if (h != NULL && !try_module_get(h->me))
	if (h != NULL && !try_module_get(h->me))
		h = NULL;
		h = NULL;


	rcu_read_unlock();

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


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


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


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


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

		return err;
	}
	}


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


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


			if (cda[CTA_LABELS] &&
			if (cda[CTA_LABELS] &&
			    ctnetlink_attach_labels(ct, cda) == 0)
			    ctnetlink_attach_labels(ct, cda) == 0)
@@ -2675,7 +2680,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
	last = (struct nf_conntrack_expect *)cb->args[1];
	last = (struct nf_conntrack_expect *)cb->args[1];
	for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
	for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
restart:
restart:
		hlist_for_each_entry(exp, &nf_ct_expect_hash[cb->args[0]],
		hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
					 hnode) {
					 hnode) {
			if (l3proto && exp->tuple.src.l3num != l3proto)
			if (l3proto && exp->tuple.src.l3num != l3proto)
				continue;
				continue;
@@ -2727,7 +2732,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
	rcu_read_lock();
	rcu_read_lock();
	last = (struct nf_conntrack_expect *)cb->args[1];
	last = (struct nf_conntrack_expect *)cb->args[1];
restart:
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)
		if (l3proto && exp->tuple.src.l3num != l3proto)
			continue;
			continue;
		if (cb->args[1]) {
		if (cb->args[1]) {
@@ -2789,6 +2794,12 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
		return -ENOENT;
		return -ENOENT;


	ct = nf_ct_tuplehash_to_ctrack(h);
	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;
	c.data = ct;


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


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


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


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


Loading