Use three-way comparison for address elements to avoid integer
wraparound in the result of xfrm_policy_addr_delta().

This ensures that the search trees are built and traversed correctly
when the difference between compared address elements is larger
than INT_MAX.

Fixes: 9cf545ebd591d ("xfrm: policy: store inexact policies in a tree ordered 
by destination address")
Signed-off-by: Visa Hankala <v...@hankala.org>

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index d622c2548d22..d74902f11dde 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -793,15 +793,20 @@ 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))));
+               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;
@@ -812,10 +817,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:
asd

Reply via email to