mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-01-23 15:12:55 +01:00
netfilter: ctnetlink: remove refcounting in expectation dumpers
Same pattern as previous patch: do not keep the expectation object alive via refcount, only store a cookie value and then use that as the skip hint for dump resumption. AFAICS this has the same issue as the one resolved in the conntrack dumper, when we do if (!refcount_inc_not_zero(&exp->use)) to increment the refcount, there is a chance that exp == last, which causes a double-increment of the refcount and subsequent memory leak. Fixes:cf6994c2b9("[NETFILTER]: nf_conntrack_netlink: sync expectation dumping with conntrack table dumping") Fixes:e844a92843("netfilter: ctnetlink: allow to dump expectation per master conntrack") Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
committed by
Pablo Neira Ayuso
parent
de788b2e62
commit
1492e3dcb2
@@ -3170,23 +3170,27 @@ errout:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static int ctnetlink_exp_done(struct netlink_callback *cb)
|
||||
|
||||
static unsigned long ctnetlink_exp_id(const struct nf_conntrack_expect *exp)
|
||||
{
|
||||
if (cb->args[1])
|
||||
nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);
|
||||
return 0;
|
||||
unsigned long id = (unsigned long)exp;
|
||||
|
||||
id += nf_ct_get_id(exp->master);
|
||||
id += exp->class;
|
||||
|
||||
return id ? id : 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct nf_conntrack_expect *exp, *last;
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
|
||||
u_int8_t l3proto = nfmsg->nfgen_family;
|
||||
unsigned long last_id = cb->args[1];
|
||||
struct nf_conntrack_expect *exp;
|
||||
|
||||
rcu_read_lock();
|
||||
last = (struct nf_conntrack_expect *)cb->args[1];
|
||||
for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
|
||||
restart:
|
||||
hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
|
||||
@@ -3198,7 +3202,7 @@ restart:
|
||||
continue;
|
||||
|
||||
if (cb->args[1]) {
|
||||
if (exp != last)
|
||||
if (ctnetlink_exp_id(exp) != last_id)
|
||||
continue;
|
||||
cb->args[1] = 0;
|
||||
}
|
||||
@@ -3207,9 +3211,7 @@ restart:
|
||||
cb->nlh->nlmsg_seq,
|
||||
IPCTNL_MSG_EXP_NEW,
|
||||
exp) < 0) {
|
||||
if (!refcount_inc_not_zero(&exp->use))
|
||||
continue;
|
||||
cb->args[1] = (unsigned long)exp;
|
||||
cb->args[1] = ctnetlink_exp_id(exp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -3220,32 +3222,30 @@ restart:
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
if (last)
|
||||
nf_ct_expect_put(last);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int
|
||||
ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct nf_conntrack_expect *exp, *last;
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
|
||||
struct nf_conn *ct = cb->data;
|
||||
struct nf_conn_help *help = nfct_help(ct);
|
||||
u_int8_t l3proto = nfmsg->nfgen_family;
|
||||
unsigned long last_id = cb->args[1];
|
||||
struct nf_conntrack_expect *exp;
|
||||
|
||||
if (cb->args[0])
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
last = (struct nf_conntrack_expect *)cb->args[1];
|
||||
|
||||
restart:
|
||||
hlist_for_each_entry_rcu(exp, &help->expectations, lnode) {
|
||||
if (l3proto && exp->tuple.src.l3num != l3proto)
|
||||
continue;
|
||||
if (cb->args[1]) {
|
||||
if (exp != last)
|
||||
if (ctnetlink_exp_id(exp) != last_id)
|
||||
continue;
|
||||
cb->args[1] = 0;
|
||||
}
|
||||
@@ -3253,9 +3253,7 @@ restart:
|
||||
cb->nlh->nlmsg_seq,
|
||||
IPCTNL_MSG_EXP_NEW,
|
||||
exp) < 0) {
|
||||
if (!refcount_inc_not_zero(&exp->use))
|
||||
continue;
|
||||
cb->args[1] = (unsigned long)exp;
|
||||
cb->args[1] = ctnetlink_exp_id(exp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -3266,9 +3264,6 @@ restart:
|
||||
cb->args[0] = 1;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
if (last)
|
||||
nf_ct_expect_put(last);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
@@ -3287,7 +3282,6 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
|
||||
struct nf_conntrack_zone zone;
|
||||
struct netlink_dump_control c = {
|
||||
.dump = ctnetlink_exp_ct_dump_table,
|
||||
.done = ctnetlink_exp_done,
|
||||
};
|
||||
|
||||
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER,
|
||||
@@ -3337,7 +3331,6 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
|
||||
else {
|
||||
struct netlink_dump_control c = {
|
||||
.dump = ctnetlink_exp_dump_table,
|
||||
.done = ctnetlink_exp_done,
|
||||
};
|
||||
return netlink_dump_start(info->sk, skb, info->nlh, &c);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user