Skip to content

Commit 3c79107

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: ctnetlink: don't use conntrack/expect object addresses as id
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: 3583240 ("[NETFILTER]: nf_conntrack_expect: kill unique ID") Fixes: 7f85f91 ("[NETFILTER]: nf_conntrack: kill unique ID") Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 0261ea1 commit 3c79107

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed

include/net/netfilter/nf_conntrack.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net,
316316
gfp_t flags);
317317
void nf_ct_tmpl_free(struct nf_conn *tmpl);
318318

319+
u32 nf_ct_get_id(const struct nf_conn *ct);
320+
319321
static inline void
320322
nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info)
321323
{

net/netfilter/nf_conntrack_core.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/slab.h>
2626
#include <linux/random.h>
2727
#include <linux/jhash.h>
28+
#include <linux/siphash.h>
2829
#include <linux/err.h>
2930
#include <linux/percpu.h>
3031
#include <linux/moduleparam.h>
@@ -449,6 +450,40 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
449450
}
450451
EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
451452

453+
/* Generate a almost-unique pseudo-id for a given conntrack.
454+
*
455+
* intentionally doesn't re-use any of the seeds used for hash
456+
* table location, we assume id gets exposed to userspace.
457+
*
458+
* Following nf_conn items do not change throughout lifetime
459+
* of the nf_conn after it has been committed to main hash table:
460+
*
461+
* 1. nf_conn address
462+
* 2. nf_conn->ext address
463+
* 3. nf_conn->master address (normally NULL)
464+
* 4. tuple
465+
* 5. the associated net namespace
466+
*/
467+
u32 nf_ct_get_id(const struct nf_conn *ct)
468+
{
469+
static __read_mostly siphash_key_t ct_id_seed;
470+
unsigned long a, b, c, d;
471+
472+
net_get_random_once(&ct_id_seed, sizeof(ct_id_seed));
473+
474+
a = (unsigned long)ct;
475+
b = (unsigned long)ct->master ^ net_hash_mix(nf_ct_net(ct));
476+
c = (unsigned long)ct->ext;
477+
d = (unsigned long)siphash(&ct->tuplehash, sizeof(ct->tuplehash),
478+
&ct_id_seed);
479+
#ifdef CONFIG_64BIT
480+
return siphash_4u64((u64)a, (u64)b, (u64)c, (u64)d, &ct_id_seed);
481+
#else
482+
return siphash_4u32((u32)a, (u32)b, (u32)c, (u32)d, &ct_id_seed);
483+
#endif
484+
}
485+
EXPORT_SYMBOL_GPL(nf_ct_get_id);
486+
452487
static void
453488
clean_from_lists(struct nf_conn *ct)
454489
{

net/netfilter/nf_conntrack_netlink.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/spinlock.h>
3030
#include <linux/interrupt.h>
3131
#include <linux/slab.h>
32+
#include <linux/siphash.h>
3233

3334
#include <linux/netfilter.h>
3435
#include <net/netlink.h>
@@ -485,7 +486,9 @@ static int ctnetlink_dump_ct_synproxy(struct sk_buff *skb, struct nf_conn *ct)
485486

486487
static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
487488
{
488-
if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct)))
489+
__be32 id = (__force __be32)nf_ct_get_id(ct);
490+
491+
if (nla_put_be32(skb, CTA_ID, id))
489492
goto nla_put_failure;
490493
return 0;
491494

@@ -1286,8 +1289,9 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
12861289
}
12871290

12881291
if (cda[CTA_ID]) {
1289-
u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID]));
1290-
if (id != (u32)(unsigned long)ct) {
1292+
__be32 id = nla_get_be32(cda[CTA_ID]);
1293+
1294+
if (id != (__force __be32)nf_ct_get_id(ct)) {
12911295
nf_ct_put(ct);
12921296
return -ENOENT;
12931297
}
@@ -2692,6 +2696,25 @@ static int ctnetlink_exp_dump_mask(struct sk_buff *skb,
26922696

26932697
static const union nf_inet_addr any_addr;
26942698

2699+
static __be32 nf_expect_get_id(const struct nf_conntrack_expect *exp)
2700+
{
2701+
static __read_mostly siphash_key_t exp_id_seed;
2702+
unsigned long a, b, c, d;
2703+
2704+
net_get_random_once(&exp_id_seed, sizeof(exp_id_seed));
2705+
2706+
a = (unsigned long)exp;
2707+
b = (unsigned long)exp->helper;
2708+
c = (unsigned long)exp->master;
2709+
d = (unsigned long)siphash(&exp->tuple, sizeof(exp->tuple), &exp_id_seed);
2710+
2711+
#ifdef CONFIG_64BIT
2712+
return (__force __be32)siphash_4u64((u64)a, (u64)b, (u64)c, (u64)d, &exp_id_seed);
2713+
#else
2714+
return (__force __be32)siphash_4u32((u32)a, (u32)b, (u32)c, (u32)d, &exp_id_seed);
2715+
#endif
2716+
}
2717+
26952718
static int
26962719
ctnetlink_exp_dump_expect(struct sk_buff *skb,
26972720
const struct nf_conntrack_expect *exp)
@@ -2739,7 +2762,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
27392762
}
27402763
#endif
27412764
if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
2742-
nla_put_be32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)) ||
2765+
nla_put_be32(skb, CTA_EXPECT_ID, nf_expect_get_id(exp)) ||
27432766
nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
27442767
nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
27452768
goto nla_put_failure;
@@ -3044,7 +3067,8 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
30443067

30453068
if (cda[CTA_EXPECT_ID]) {
30463069
__be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
3047-
if (ntohl(id) != (u32)(unsigned long)exp) {
3070+
3071+
if (id != nf_expect_get_id(exp)) {
30483072
nf_ct_expect_put(exp);
30493073
return -ENOENT;
30503074
}

0 commit comments

Comments
 (0)