Commit 63cad4c7 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'inet-exceptions-less-predictable'



Eric Dumazet says:

====================
inet: make exception handling less predictible

This second round of patches is addressing Keyu Man recommendations
to make linux hosts more robust against a class of brute force attacks.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9dfa859d 67d6d681
Loading
Loading
Loading
Loading
+30 −16
Original line number Diff line number Diff line
@@ -587,18 +587,25 @@ static void fnhe_flush_routes(struct fib_nh_exception *fnhe)
	}
}

static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
static void fnhe_remove_oldest(struct fnhe_hash_bucket *hash)
{
	struct fib_nh_exception *fnhe, *oldest;
	struct fib_nh_exception __rcu **fnhe_p, **oldest_p;
	struct fib_nh_exception *fnhe, *oldest = NULL;

	oldest = rcu_dereference(hash->chain);
	for (fnhe = rcu_dereference(oldest->fnhe_next); fnhe;
	     fnhe = rcu_dereference(fnhe->fnhe_next)) {
		if (time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp))
	for (fnhe_p = &hash->chain; ; fnhe_p = &fnhe->fnhe_next) {
		fnhe = rcu_dereference_protected(*fnhe_p,
						 lockdep_is_held(&fnhe_lock));
		if (!fnhe)
			break;
		if (!oldest ||
		    time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp)) {
			oldest = fnhe;
			oldest_p = fnhe_p;
		}
	}
	fnhe_flush_routes(oldest);
	return oldest;
	*oldest_p = oldest->fnhe_next;
	kfree_rcu(oldest, rcu);
}

static u32 fnhe_hashfun(__be32 daddr)
@@ -677,16 +684,21 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
		if (rt)
			fill_route_from_fnhe(rt, fnhe);
	} else {
		if (depth > FNHE_RECLAIM_DEPTH)
			fnhe = fnhe_oldest(hash);
		else {
		/* Randomize max depth to avoid some side channels attacks. */
		int max_depth = FNHE_RECLAIM_DEPTH +
				prandom_u32_max(FNHE_RECLAIM_DEPTH);

		while (depth > max_depth) {
			fnhe_remove_oldest(hash);
			depth--;
		}

		fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC);
		if (!fnhe)
			goto out_unlock;

		fnhe->fnhe_next = hash->chain;
			rcu_assign_pointer(hash->chain, fnhe);
		}

		fnhe->fnhe_genid = genid;
		fnhe->fnhe_daddr = daddr;
		fnhe->fnhe_gw = gw;
@@ -694,6 +706,8 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
		fnhe->fnhe_mtu_locked = lock;
		fnhe->fnhe_expires = max(1UL, expires);

		rcu_assign_pointer(hash->chain, fnhe);

		/* Exception created; mark the cached routes for the nexthop
		 * stale, so anyone caching it rechecks if this exception
		 * applies to them.
+4 −1
Original line number Diff line number Diff line
@@ -1657,6 +1657,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,
	struct in6_addr *src_key = NULL;
	struct rt6_exception *rt6_ex;
	struct fib6_nh *nh = res->nh;
	int max_depth;
	int err = 0;

	spin_lock_bh(&rt6_exception_lock);
@@ -1711,7 +1712,9 @@ static int rt6_insert_exception(struct rt6_info *nrt,
	bucket->depth++;
	net->ipv6.rt6_stats->fib_rt_cache++;

	if (bucket->depth > FIB6_MAX_DEPTH)
	/* Randomize max depth to avoid some side channels attacks. */
	max_depth = FIB6_MAX_DEPTH + prandom_u32_max(FIB6_MAX_DEPTH);
	while (bucket->depth > max_depth)
		rt6_exception_remove_oldest(bucket);

out: