diff options
author | Florian Westphal <fw@strlen.de> | 2019-04-01 07:08:54 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2019-04-15 01:31:44 -0400 |
commit | 3c79107631db1f7fd32cf3f7368e4672004a3010 (patch) | |
tree | e8eb82a458ef088d823e96d66d6ee2ff40e70774 /net | |
parent | 0261ea1bd1eb0da5c0792a9119b8655cf33c80a3 (diff) |
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: 3583240249ef ("[NETFILTER]: nf_conntrack_expect: kill unique ID")
Fixes: 7f85f914721f ("[NETFILTER]: nf_conntrack: kill unique ID")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 35 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 34 |
2 files changed, 64 insertions, 5 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index a137d4e7f218..3c48d44d6fff 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/random.h> | 26 | #include <linux/random.h> |
27 | #include <linux/jhash.h> | 27 | #include <linux/jhash.h> |
28 | #include <linux/siphash.h> | ||
28 | #include <linux/err.h> | 29 | #include <linux/err.h> |
29 | #include <linux/percpu.h> | 30 | #include <linux/percpu.h> |
30 | #include <linux/moduleparam.h> | 31 | #include <linux/moduleparam.h> |
@@ -449,6 +450,40 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, | |||
449 | } | 450 | } |
450 | EXPORT_SYMBOL_GPL(nf_ct_invert_tuple); | 451 | EXPORT_SYMBOL_GPL(nf_ct_invert_tuple); |
451 | 452 | ||
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 | |||
452 | static void | 487 | static void |
453 | clean_from_lists(struct nf_conn *ct) | 488 | clean_from_lists(struct nf_conn *ct) |
454 | { | 489 | { |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 66c596d287a5..d7f61b0547c6 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/siphash.h> | ||
32 | 33 | ||
33 | #include <linux/netfilter.h> | 34 | #include <linux/netfilter.h> |
34 | #include <net/netlink.h> | 35 | #include <net/netlink.h> |
@@ -485,7 +486,9 @@ nla_put_failure: | |||
485 | 486 | ||
486 | static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) | 487 | static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) |
487 | { | 488 | { |
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)) | ||
489 | goto nla_put_failure; | 492 | goto nla_put_failure; |
490 | return 0; | 493 | return 0; |
491 | 494 | ||
@@ -1286,8 +1289,9 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, | |||
1286 | } | 1289 | } |
1287 | 1290 | ||
1288 | if (cda[CTA_ID]) { | 1291 | if (cda[CTA_ID]) { |
1289 | u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID])); | 1292 | __be32 id = nla_get_be32(cda[CTA_ID]); |
1290 | if (id != (u32)(unsigned long)ct) { | 1293 | |
1294 | if (id != (__force __be32)nf_ct_get_id(ct)) { | ||
1291 | nf_ct_put(ct); | 1295 | nf_ct_put(ct); |
1292 | return -ENOENT; | 1296 | return -ENOENT; |
1293 | } | 1297 | } |
@@ -2692,6 +2696,25 @@ nla_put_failure: | |||
2692 | 2696 | ||
2693 | static const union nf_inet_addr any_addr; | 2697 | static const union nf_inet_addr any_addr; |
2694 | 2698 | ||
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 | |||
2695 | static int | 2718 | static int |
2696 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 2719 | ctnetlink_exp_dump_expect(struct sk_buff *skb, |
2697 | const struct nf_conntrack_expect *exp) | 2720 | const struct nf_conntrack_expect *exp) |
@@ -2739,7 +2762,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
2739 | } | 2762 | } |
2740 | #endif | 2763 | #endif |
2741 | if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) || | 2764 | 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)) || |
2743 | nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) || | 2766 | nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) || |
2744 | nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class))) | 2767 | nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class))) |
2745 | goto nla_put_failure; | 2768 | goto nla_put_failure; |
@@ -3044,7 +3067,8 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl, | |||
3044 | 3067 | ||
3045 | if (cda[CTA_EXPECT_ID]) { | 3068 | if (cda[CTA_EXPECT_ID]) { |
3046 | __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]); | 3069 | __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)) { | ||
3048 | nf_ct_expect_put(exp); | 3072 | nf_ct_expect_put(exp); |
3049 | return -ENOENT; | 3073 | return -ENOENT; |
3050 | } | 3074 | } |