Commit f0179410 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_conntrack_expect: use expect->helper



Use expect->helper in ctnetlink and /proc to dump the helper name.
Using nfct_help() without holding a reference to the master conntrack
is unsafe.

Use exp->master->helper in ctnetlink path if userspace does not provide
an explicit helper when creating an expectation to retain the existing
behaviour. The ctnetlink expectation path holds the reference on the
master conntrack and nf_conntrack_expect lock and the nfnetlink glue
path refers to the master ct that is attached to the skb.

Reported-by: default avatarHyunwoo Kim <imv4bel@gmail.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 9c42bc9d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -666,7 +666,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
	if (expect->flags & NF_CT_EXPECT_USERSPACE)
		seq_printf(s, "%sUSERSPACE", delim);

	helper = rcu_dereference(nfct_help(expect->master)->helper);
	helper = rcu_dereference(expect->helper);
	if (helper) {
		seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
		if (helper->expect_policy[expect->class].name[0])
+1 −5
Original line number Diff line number Diff line
@@ -395,14 +395,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);

static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
{
	struct nf_conn_help *help = nfct_help(exp->master);
	const struct nf_conntrack_helper *me = data;
	const struct nf_conntrack_helper *this;

	if (rcu_access_pointer(exp->helper) == me)
		return true;

	this = rcu_dereference_protected(help->helper,
	this = rcu_dereference_protected(exp->helper,
					 lockdep_is_held(&nf_conntrack_expect_lock));
	return this == me;
}
+10 −14
Original line number Diff line number Diff line
@@ -3012,7 +3012,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
{
	struct nf_conn *master = exp->master;
	long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
	struct nf_conn_help *help;
	struct nf_conntrack_helper *helper;
#if IS_ENABLED(CONFIG_NF_NAT)
	struct nlattr *nest_parms;
	struct nf_conntrack_tuple nat_tuple = {};
@@ -3057,15 +3057,12 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
	    nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
	    nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
		goto nla_put_failure;
	help = nfct_help(master);
	if (help) {
		struct nf_conntrack_helper *helper;

		helper = rcu_dereference(help->helper);
	helper = rcu_dereference(exp->helper);
	if (helper &&
	    nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
		goto nla_put_failure;
	}

	expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
	if (expfn != NULL &&
	    nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
@@ -3394,12 +3391,9 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
{
	struct nf_conntrack_helper *helper;
	const struct nf_conn_help *m_help;
	const char *name = data;

	m_help = nfct_help(exp->master);

	helper = rcu_dereference(m_help->helper);
	helper = rcu_dereference(exp->helper);
	if (!helper)
		return false;

@@ -3534,9 +3528,9 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
		       struct nf_conntrack_tuple *tuple,
		       struct nf_conntrack_tuple *mask)
{
	u_int32_t class = 0;
	struct nf_conntrack_expect *exp;
	struct nf_conn_help *help;
	u32 class = 0;
	int err;

	help = nfct_help(ct);
@@ -3573,6 +3567,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,

	exp->class = class;
	exp->master = ct;
	if (!helper)
		helper = rcu_dereference(help->helper);
	rcu_assign_pointer(exp->helper, helper);
	exp->tuple = *tuple;
	exp->mask.src.u3 = mask->src.u3;
+1 −1
Original line number Diff line number Diff line
@@ -924,7 +924,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
		exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);

		if (!exp || exp->master == ct ||
		    nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
		    exp->helper != nfct_help(ct)->helper ||
		    exp->class != class)
			break;
#if IS_ENABLED(CONFIG_NF_NAT)