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

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
...@@ -587,18 +587,25 @@ static void fnhe_flush_routes(struct fib_nh_exception *fnhe) ...@@ -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_p = &hash->chain; ; fnhe_p = &fnhe->fnhe_next) {
for (fnhe = rcu_dereference(oldest->fnhe_next); fnhe; fnhe = rcu_dereference_protected(*fnhe_p,
fnhe = rcu_dereference(fnhe->fnhe_next)) { lockdep_is_held(&fnhe_lock));
if (time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp)) if (!fnhe)
break;
if (!oldest ||
time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp)) {
oldest = fnhe; oldest = fnhe;
oldest_p = fnhe_p;
}
} }
fnhe_flush_routes(oldest); fnhe_flush_routes(oldest);
return oldest; *oldest_p = oldest->fnhe_next;
kfree_rcu(oldest, rcu);
} }
static u32 fnhe_hashfun(__be32 daddr) static u32 fnhe_hashfun(__be32 daddr)
...@@ -677,16 +684,21 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr, ...@@ -677,16 +684,21 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
if (rt) if (rt)
fill_route_from_fnhe(rt, fnhe); fill_route_from_fnhe(rt, fnhe);
} else { } else {
if (depth > FNHE_RECLAIM_DEPTH) /* Randomize max depth to avoid some side channels attacks. */
fnhe = fnhe_oldest(hash); int max_depth = FNHE_RECLAIM_DEPTH +
else { prandom_u32_max(FNHE_RECLAIM_DEPTH);
fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC);
if (!fnhe) while (depth > max_depth) {
goto out_unlock; fnhe_remove_oldest(hash);
depth--;
fnhe->fnhe_next = hash->chain;
rcu_assign_pointer(hash->chain, fnhe);
} }
fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC);
if (!fnhe)
goto out_unlock;
fnhe->fnhe_next = hash->chain;
fnhe->fnhe_genid = genid; fnhe->fnhe_genid = genid;
fnhe->fnhe_daddr = daddr; fnhe->fnhe_daddr = daddr;
fnhe->fnhe_gw = gw; fnhe->fnhe_gw = gw;
...@@ -694,6 +706,8 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr, ...@@ -694,6 +706,8 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
fnhe->fnhe_mtu_locked = lock; fnhe->fnhe_mtu_locked = lock;
fnhe->fnhe_expires = max(1UL, expires); fnhe->fnhe_expires = max(1UL, expires);
rcu_assign_pointer(hash->chain, fnhe);
/* Exception created; mark the cached routes for the nexthop /* Exception created; mark the cached routes for the nexthop
* stale, so anyone caching it rechecks if this exception * stale, so anyone caching it rechecks if this exception
* applies to them. * applies to them.
......
...@@ -1657,6 +1657,7 @@ static int rt6_insert_exception(struct rt6_info *nrt, ...@@ -1657,6 +1657,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,
struct in6_addr *src_key = NULL; struct in6_addr *src_key = NULL;
struct rt6_exception *rt6_ex; struct rt6_exception *rt6_ex;
struct fib6_nh *nh = res->nh; struct fib6_nh *nh = res->nh;
int max_depth;
int err = 0; int err = 0;
spin_lock_bh(&rt6_exception_lock); spin_lock_bh(&rt6_exception_lock);
...@@ -1711,7 +1712,9 @@ static int rt6_insert_exception(struct rt6_info *nrt, ...@@ -1711,7 +1712,9 @@ static int rt6_insert_exception(struct rt6_info *nrt,
bucket->depth++; bucket->depth++;
net->ipv6.rt6_stats->fib_rt_cache++; 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); rt6_exception_remove_oldest(bucket);
out: out:
......
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