Commit c9c3b681 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: conntrack: make max chain length random

Similar to commit 67d6d681
("ipv4: make exception cache less predictible"):

Use a random drop length to make it harder to detect when entries were
hashed to same bucket list.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 310e2d43
...@@ -77,7 +77,8 @@ static __read_mostly bool nf_conntrack_locks_all; ...@@ -77,7 +77,8 @@ static __read_mostly bool nf_conntrack_locks_all;
#define GC_SCAN_INTERVAL (120u * HZ) #define GC_SCAN_INTERVAL (120u * HZ)
#define GC_SCAN_MAX_DURATION msecs_to_jiffies(10) #define GC_SCAN_MAX_DURATION msecs_to_jiffies(10)
#define MAX_CHAINLEN 64u #define MIN_CHAINLEN 8u
#define MAX_CHAINLEN (32u - MIN_CHAINLEN)
static struct conntrack_gc_work conntrack_gc_work; static struct conntrack_gc_work conntrack_gc_work;
...@@ -842,6 +843,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) ...@@ -842,6 +843,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
unsigned int hash, reply_hash; unsigned int hash, reply_hash;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n; struct hlist_nulls_node *n;
unsigned int max_chainlen;
unsigned int chainlen = 0; unsigned int chainlen = 0;
unsigned int sequence; unsigned int sequence;
int err = -EEXIST; int err = -EEXIST;
...@@ -857,13 +859,15 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) ...@@ -857,13 +859,15 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
&ct->tuplehash[IP_CT_DIR_REPLY].tuple); &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
} while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
max_chainlen = MIN_CHAINLEN + prandom_u32_max(MAX_CHAINLEN);
/* See if there's one in the list already, including reverse */ /* See if there's one in the list already, including reverse */
hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[hash], hnnode) { hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[hash], hnnode) {
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
zone, net)) zone, net))
goto out; goto out;
if (chainlen++ > MAX_CHAINLEN) if (chainlen++ > max_chainlen)
goto chaintoolong; goto chaintoolong;
} }
...@@ -873,7 +877,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) ...@@ -873,7 +877,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
zone, net)) zone, net))
goto out; goto out;
if (chainlen++ > MAX_CHAINLEN) if (chainlen++ > max_chainlen)
goto chaintoolong; goto chaintoolong;
} }
...@@ -1103,8 +1107,8 @@ nf_ct_resolve_clash(struct sk_buff *skb, struct nf_conntrack_tuple_hash *h, ...@@ -1103,8 +1107,8 @@ nf_ct_resolve_clash(struct sk_buff *skb, struct nf_conntrack_tuple_hash *h,
int int
__nf_conntrack_confirm(struct sk_buff *skb) __nf_conntrack_confirm(struct sk_buff *skb)
{ {
unsigned int chainlen = 0, sequence, max_chainlen;
const struct nf_conntrack_zone *zone; const struct nf_conntrack_zone *zone;
unsigned int chainlen = 0, sequence;
unsigned int hash, reply_hash; unsigned int hash, reply_hash;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct; struct nf_conn *ct;
...@@ -1168,6 +1172,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) ...@@ -1168,6 +1172,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
goto dying; goto dying;
} }
max_chainlen = MIN_CHAINLEN + prandom_u32_max(MAX_CHAINLEN);
/* See if there's one in the list already, including reverse: /* See if there's one in the list already, including reverse:
NAT could have grabbed it without realizing, since we're NAT could have grabbed it without realizing, since we're
not in the hash. If there is, we lost race. */ not in the hash. If there is, we lost race. */
...@@ -1175,7 +1180,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) ...@@ -1175,7 +1180,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
zone, net)) zone, net))
goto out; goto out;
if (chainlen++ > MAX_CHAINLEN) if (chainlen++ > max_chainlen)
goto chaintoolong; goto chaintoolong;
} }
...@@ -1184,7 +1189,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) ...@@ -1184,7 +1189,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
zone, net)) zone, net))
goto out; goto out;
if (chainlen++ > MAX_CHAINLEN) { if (chainlen++ > max_chainlen) {
chaintoolong: chaintoolong:
nf_ct_add_to_dying_list(ct); nf_ct_add_to_dying_list(ct);
NF_CT_STAT_INC(net, chaintoolong); NF_CT_STAT_INC(net, chaintoolong);
......
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