xfrm: Fix wraparound in xfrm_policy_addr_delta()

[ Upstream commit da64ae2d35d3673233f0403b035d4c6acbf71965 ]

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: 9cf545ebd5 ("xfrm: policy: store inexact policies in a tree ordered by destination address")
Signed-off-by: Visa Hankala <[email protected]>
Acked-by: Florian Westphal <[email protected]>
Signed-off-by: Steffen Klassert <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
This commit is contained in:
Visa Hankala 2020-12-30 16:15:53 +00:00 • committed by Greg Kroah-Hartman
commit 78fc9ef35d
2 changed files with 61 additions and 8 deletions

View file

@ -790,15 +790,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;
@ -809,10 +816,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: