Commit ae7b03f6 authored by Florian Westphal's avatar Florian Westphal Committed by Khalid Elmously

netfilter: ctnetlink: don't use conntrack/expect object addresses as id

BugLink: https://bugs.launchpad.net/bugs/1845036

commit 3c791076 upstream.

else, we leak the addresses to userspace via ctnetlink events
and dumps.

Compute an ID on demand based on the immutable parts of nf_conn struct.

Another advantage compared to using an address is that there is no
immediate re-use of the same ID in case the conntrack entry is freed and
reallocated again immediately.

Fixes: 35832402 ("[NETFILTER]: nf_conntrack_expect: kill unique ID")
Fixes: 7f85f914 ("[NETFILTER]: nf_conntrack: kill unique ID")
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
[bwh: Backported to 4.4: adjust context]
Signed-off-by: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarConnor Kuehl <connor.kuehl@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent 70ef81e7
...@@ -297,6 +297,8 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net, ...@@ -297,6 +297,8 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net,
gfp_t flags); gfp_t flags);
void nf_ct_tmpl_free(struct nf_conn *tmpl); void nf_ct_tmpl_free(struct nf_conn *tmpl);
u32 nf_ct_get_id(const struct nf_conn *ct);
#define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count) #define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count)
#define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count) #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/jhash.h> #include <linux/jhash.h>
#include <linux/siphash.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -234,6 +235,40 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, ...@@ -234,6 +235,40 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
} }
EXPORT_SYMBOL_GPL(nf_ct_invert_tuple); EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
/* Generate a almost-unique pseudo-id for a given conntrack.
*
* intentionally doesn't re-use any of the seeds used for hash
* table location, we assume id gets exposed to userspace.
*
* Following nf_conn items do not change throughout lifetime
* of the nf_conn after it has been committed to main hash table:
*
* 1. nf_conn address
* 2. nf_conn->ext address
* 3. nf_conn->master address (normally NULL)
* 4. tuple
* 5. the associated net namespace
*/
u32 nf_ct_get_id(const struct nf_conn *ct)
{
static __read_mostly siphash_key_t ct_id_seed;
unsigned long a, b, c, d;
net_get_random_once(&ct_id_seed, sizeof(ct_id_seed));
a = (unsigned long)ct;
b = (unsigned long)ct->master ^ net_hash_mix(nf_ct_net(ct));
c = (unsigned long)ct->ext;
d = (unsigned long)siphash(&ct->tuplehash, sizeof(ct->tuplehash),
&ct_id_seed);
#ifdef CONFIG_64BIT
return siphash_4u64((u64)a, (u64)b, (u64)c, (u64)d, &ct_id_seed);
#else
return siphash_4u32((u32)a, (u32)b, (u32)c, (u32)d, &ct_id_seed);
#endif
}
EXPORT_SYMBOL_GPL(nf_ct_get_id);
static void static void
clean_from_lists(struct nf_conn *ct) clean_from_lists(struct nf_conn *ct)
{ {
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/siphash.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <net/netlink.h> #include <net/netlink.h>
...@@ -451,7 +452,9 @@ ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) ...@@ -451,7 +452,9 @@ ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, const struct nf_conn *ct)
static inline int static inline int
ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
{ {
if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct))) __be32 id = (__force __be32)nf_ct_get_id(ct);
if (nla_put_be32(skb, CTA_ID, id))
goto nla_put_failure; goto nla_put_failure;
return 0; return 0;
...@@ -1159,8 +1162,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ...@@ -1159,8 +1162,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (cda[CTA_ID]) { if (cda[CTA_ID]) {
u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID])); __be32 id = nla_get_be32(cda[CTA_ID]);
if (id != (u32)(unsigned long)ct) {
if (id != (__force __be32)nf_ct_get_id(ct)) {
nf_ct_put(ct); nf_ct_put(ct);
return -ENOENT; return -ENOENT;
} }
...@@ -2480,6 +2484,25 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb, ...@@ -2480,6 +2484,25 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb,
static const union nf_inet_addr any_addr; static const union nf_inet_addr any_addr;
static __be32 nf_expect_get_id(const struct nf_conntrack_expect *exp)
{
static __read_mostly siphash_key_t exp_id_seed;
unsigned long a, b, c, d;
net_get_random_once(&exp_id_seed, sizeof(exp_id_seed));
a = (unsigned long)exp;
b = (unsigned long)exp->helper;
c = (unsigned long)exp->master;
d = (unsigned long)siphash(&exp->tuple, sizeof(exp->tuple), &exp_id_seed);
#ifdef CONFIG_64BIT
return (__force __be32)siphash_4u64((u64)a, (u64)b, (u64)c, (u64)d, &exp_id_seed);
#else
return (__force __be32)siphash_4u32((u32)a, (u32)b, (u32)c, (u32)d, &exp_id_seed);
#endif
}
static int static int
ctnetlink_exp_dump_expect(struct sk_buff *skb, ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct nf_conntrack_expect *exp) const struct nf_conntrack_expect *exp)
...@@ -2527,7 +2550,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, ...@@ -2527,7 +2550,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
} }
#endif #endif
if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) || if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
nla_put_be32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)) || nla_put_be32(skb, CTA_EXPECT_ID, nf_expect_get_id(exp)) ||
nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) || nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class))) nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
goto nla_put_failure; goto nla_put_failure;
...@@ -2824,7 +2847,8 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, ...@@ -2824,7 +2847,8 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (cda[CTA_EXPECT_ID]) { if (cda[CTA_EXPECT_ID]) {
__be32 id = nla_get_be32(cda[CTA_EXPECT_ID]); __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
if (ntohl(id) != (u32)(unsigned long)exp) {
if (id != nf_expect_get_id(exp)) {
nf_ct_expect_put(exp); nf_ct_expect_put(exp);
return -ENOENT; return -ENOENT;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment