Commit 3a926b0e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tcp-rfc-6056'



Eric Dumazet says:

====================
tcp: RFC 6056 induced changes

This is based on a report from David Dworken.

First patch implements RFC 6056 3.3.4 proposal.

Second patch is adding a little bit of noise to make
attacker life a bit harder.
===================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1edb5cbf c579bd1b
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -709,6 +709,17 @@ void inet_unhash(struct sock *sk)
}
EXPORT_SYMBOL_GPL(inet_unhash);

/* RFC 6056 3.3.4.  Algorithm 4: Double-Hash Port Selection Algorithm
 * Note that we use 32bit integers (vs RFC 'short integers')
 * because 2^16 is not a multiple of num_ephemeral and this
 * property might be used by clever attacker.
 * RFC claims using TABLE_LENGTH=10 buckets gives an improvement,
 * we use 256 instead to really give more isolation and
 * privacy, this only consumes 1 KB of kernel memory.
 */
#define INET_TABLE_PERTURB_SHIFT 8
static u32 table_perturb[1 << INET_TABLE_PERTURB_SHIFT];

int __inet_hash_connect(struct inet_timewait_death_row *death_row,
		struct sock *sk, u32 port_offset,
		int (*check_established)(struct inet_timewait_death_row *,
@@ -722,8 +733,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
	struct inet_bind_bucket *tb;
	u32 remaining, offset;
	int ret, i, low, high;
	static u32 hint;
	int l3mdev;
	u32 index;

	if (port) {
		head = &hinfo->bhash[inet_bhashfn(net, port,
@@ -750,7 +761,10 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
	if (likely(remaining > 1))
		remaining &= ~1U;

	offset = (hint + port_offset) % remaining;
	net_get_random_once(table_perturb, sizeof(table_perturb));
	index = hash_32(port_offset, INET_TABLE_PERTURB_SHIFT);

	offset = (READ_ONCE(table_perturb[index]) + port_offset) % remaining;
	/* In first pass we try ports of @low parity.
	 * inet_csk_get_port() does the opposite choice.
	 */
@@ -804,7 +818,12 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
	return -EADDRNOTAVAIL;

ok:
	hint += i + 2;
	/* If our first attempt found a candidate, skip next candidate
	 * in 1/16 of cases to add some noise.
	 */
	if (!i && !(prandom_u32() % 16))
		i = 2;
	WRITE_ONCE(table_perturb[index], READ_ONCE(table_perturb[index]) + i + 2);

	/* Head lock still held and bh's disabled */
	inet_bind_hash(sk, tb, port);