Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfrm: Fix wraparound in xfrm_policy_addr_delta()

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: 9cf545ebd591d ("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>

authored by

Visa Hankala and committed by
Steffen Klassert
da64ae2d f6e9ceb7

+61 -8
+18 -8
net/xfrm/xfrm_policy.c
··· 793 793 const xfrm_address_t *b, 794 794 u8 prefixlen, u16 family) 795 795 { 796 + u32 ma, mb, mask; 796 797 unsigned int pdw, pbi; 797 798 int delta = 0; 798 799 799 800 switch (family) { 800 801 case AF_INET: 801 - if (sizeof(long) == 4 && prefixlen == 0) 802 - return ntohl(a->a4) - ntohl(b->a4); 803 - return (ntohl(a->a4) & ((~0UL << (32 - prefixlen)))) - 804 - (ntohl(b->a4) & ((~0UL << (32 - prefixlen)))); 802 + if (prefixlen == 0) 803 + return 0; 804 + mask = ~0U << (32 - prefixlen); 805 + ma = ntohl(a->a4) & mask; 806 + mb = ntohl(b->a4) & mask; 807 + if (ma < mb) 808 + delta = -1; 809 + else if (ma > mb) 810 + delta = 1; 811 + break; 805 812 case AF_INET6: 806 813 pdw = prefixlen >> 5; 807 814 pbi = prefixlen & 0x1f; ··· 819 812 return delta; 820 813 } 821 814 if (pbi) { 822 - u32 mask = ~0u << (32 - pbi); 823 - 824 - delta = (ntohl(a->a6[pdw]) & mask) - 825 - (ntohl(b->a6[pdw]) & mask); 815 + mask = ~0U << (32 - pbi); 816 + ma = ntohl(a->a6[pdw]) & mask; 817 + mb = ntohl(b->a6[pdw]) & mask; 818 + if (ma < mb) 819 + delta = -1; 820 + else if (ma > mb) 821 + delta = 1; 826 822 } 827 823 break; 828 824 default:
+43
tools/testing/selftests/net/xfrm_policy.sh
··· 287 287 return 0 288 288 } 289 289 290 + # insert non-overlapping policies in a random order and check that 291 + # all of them can be fetched using the traffic selectors. 292 + check_random_order() 293 + { 294 + local ns=$1 295 + local log=$2 296 + 297 + for i in $(seq 100); do 298 + ip -net $ns xfrm policy flush 299 + for j in $(seq 0 16 255 | sort -R); do 300 + ip -net $ns xfrm policy add dst $j.0.0.0/24 dir out priority 10 action allow 301 + done 302 + for j in $(seq 0 16 255); do 303 + if ! ip -net $ns xfrm policy get dst $j.0.0.0/24 dir out > /dev/null; then 304 + echo "FAIL: $log" 1>&2 305 + return 1 306 + fi 307 + done 308 + done 309 + 310 + for i in $(seq 100); do 311 + ip -net $ns xfrm policy flush 312 + for j in $(seq 0 16 255 | sort -R); do 313 + local addr=$(printf "e000:0000:%02x00::/56" $j) 314 + ip -net $ns xfrm policy add dst $addr dir out priority 10 action allow 315 + done 316 + for j in $(seq 0 16 255); do 317 + local addr=$(printf "e000:0000:%02x00::/56" $j) 318 + if ! ip -net $ns xfrm policy get dst $addr dir out > /dev/null; then 319 + echo "FAIL: $log" 1>&2 320 + return 1 321 + fi 322 + done 323 + done 324 + 325 + ip -net $ns xfrm policy flush 326 + 327 + echo "PASS: $log" 328 + return 0 329 + } 330 + 290 331 #check for needed privileges 291 332 if [ "$(id -u)" -ne 0 ];then 292 333 echo "SKIP: Need root privileges" ··· 478 437 check_exceptions "exceptions and block policies after htresh change to normal" 479 438 480 439 check_hthresh_repeat "policies with repeated htresh change" 440 + 441 + check_random_order ns3 "policies inserted in random order" 481 442 482 443 for i in 1 2 3 4;do ip netns del ns$i;done 483 444