Skip to content

Commit

Permalink
xfrm: Fix wraparound in xfrm_policy_addr_delta()
Browse files Browse the repository at this point in the history
Use three-way comparison for address components to avoid integer
wraparound in the result of xfrm_policy_addr_delta(). This ensures
that the search trees are built and traversed correctly.

Treat IPv4 and IPv6 similarly by returning 0 when prefixlen == 0.
Prefix /0 has only one equivalence class.

Fixes: 9cf545e ("xfrm: policy: store inexact policies in a tree ordered by destination address")
Signed-off-by: Visa Hankala <visa@hankala.org>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
  • Loading branch information
Visa Hankala authored and Steffen Klassert committed Jan 4, 2021
1 parent f6e9ceb commit da64ae2
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
26 changes: 18 additions & 8 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,15 +793,22 @@ static int xfrm_policy_addr_delta(const xfrm_address_t *a,
const xfrm_address_t *b,
u8 prefixlen, u16 family)
{
u32 ma, mb, mask;
unsigned int pdw, pbi;
int delta = 0;

switch (family) {
case AF_INET:
if (sizeof(long) == 4 && prefixlen == 0)
return ntohl(a->a4) - ntohl(b->a4);
return (ntohl(a->a4) & ((~0UL << (32 - prefixlen)))) -
(ntohl(b->a4) & ((~0UL << (32 - prefixlen))));
if (prefixlen == 0)
return 0;
mask = ~0U << (32 - prefixlen);
ma = ntohl(a->a4) & mask;
mb = ntohl(b->a4) & mask;
if (ma < mb)
delta = -1;
else if (ma > mb)
delta = 1;
break;
case AF_INET6:
pdw = prefixlen >> 5;
pbi = prefixlen & 0x1f;
Expand All @@ -812,10 +819,13 @@ static int xfrm_policy_addr_delta(const xfrm_address_t *a,
return delta;
}
if (pbi) {
u32 mask = ~0u << (32 - pbi);

delta = (ntohl(a->a6[pdw]) & mask) -
(ntohl(b->a6[pdw]) & mask);
mask = ~0U << (32 - pbi);
ma = ntohl(a->a6[pdw]) & mask;
mb = ntohl(b->a6[pdw]) & mask;
if (ma < mb)
delta = -1;
else if (ma > mb)
delta = 1;
}
break;
default:
Expand Down
43 changes: 43 additions & 0 deletions tools/testing/selftests/net/xfrm_policy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,47 @@ check_hthresh_repeat()
return 0
}

# insert non-overlapping policies in a random order and check that
# all of them can be fetched using the traffic selectors.
check_random_order()
{
local ns=$1
local log=$2

for i in $(seq 100); do
ip -net $ns xfrm policy flush
for j in $(seq 0 16 255 | sort -R); do
ip -net $ns xfrm policy add dst $j.0.0.0/24 dir out priority 10 action allow
done
for j in $(seq 0 16 255); do
if ! ip -net $ns xfrm policy get dst $j.0.0.0/24 dir out > /dev/null; then
echo "FAIL: $log" 1>&2
return 1
fi
done
done

for i in $(seq 100); do
ip -net $ns xfrm policy flush
for j in $(seq 0 16 255 | sort -R); do
local addr=$(printf "e000:0000:%02x00::/56" $j)
ip -net $ns xfrm policy add dst $addr dir out priority 10 action allow
done
for j in $(seq 0 16 255); do
local addr=$(printf "e000:0000:%02x00::/56" $j)
if ! ip -net $ns xfrm policy get dst $addr dir out > /dev/null; then
echo "FAIL: $log" 1>&2
return 1
fi
done
done

ip -net $ns xfrm policy flush

echo "PASS: $log"
return 0
}

#check for needed privileges
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
Expand Down Expand Up @@ -438,6 +479,8 @@ check_exceptions "exceptions and block policies after htresh change to normal"

check_hthresh_repeat "policies with repeated htresh change"

check_random_order ns3 "policies inserted in random order"

for i in 1 2 3 4;do ip netns del ns$i;done

exit $ret

0 comments on commit da64ae2

Please sign in to comment.