Subject: kern/36051: Incorect handling of cached SPs in FAST_IPSEC]
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Karl Knutsson <karl.knutsson@ericsson.com>
List: netbsd-bugs
Date: 03/21/2007 15:30:00
>Number:         36051
>Category:       kern
>Synopsis:       Incorect handling of cached SPs in FAST_IPSEC
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Mar 21 15:30:00 +0000 2007
>Originator:     Karl Knutsson <karl.knutsson@ericsson.com>
>Release:        NetBSD 3.0
>Organization:
LM Ericsson
>Environment:
System: System: NetBSD zuul 3.0.0_STABLE NetBSD 3.0.0_STABLE (SPEED) #0: Mon Sep 18 16:59:06 CEST 2006
Architecture: i386 
Machine: i386
>Description:
Incorrect usage of cached policies on unconnected sockets may result in that
the wrong policy is applied to a packet. The fact that a packet matches 
a cached rule isn't enough reason to apply it since there might be policies
with higher priority, e.i. a policy that where inserted before the cached 
policy, that matches the packet.
>How-To-Repeat:
Insert the following policies. 192.168.66.2 is the address of a local interface
on the machine. Enable the udp echo server in inetd.conf
# cat setkey.conf
spdadd 192.168.70.1[1234] 192.168.66.2 any -P in none;
spdadd 192.168.70.0/24  192.168.66.2 any -P in discard;
# setkey -f setkey.conf
# setkey -DP
192.168.70.1[1234] 192.168.66.2[any] any
        in none
        spid=1 seq=2 pid=108
        refcnt=1
192.168.70.0/24[any] 192.168.66.2[any] any
        in discard
        spid=2 seq=1 pid=108
        refcnt=1

Send a UDP packet from 192.168.70.1[1234] to 192.168.66.2[7]. 
tcpdump will display the following (expected) output:
14:28:59.460960 IP 192.168.70.1.1234 > 192.168.66.2.7: UDP, length: 64
14:28:59.461152 IP 192.168.66.2.7 > 192.168.70.1.1234: UDP, length: 64

Next send a packet from an address that will get blocked by the second 
policy. 
tcpdump displays: 
14:31:20.480938 IP 192.168.70.2.1234 > 192.168.66.2.7: UDP, length: 64
14:31:20.481035 IP 192.168.66.2 > 192.168.70.2: icmp 36: host 192.168.66.2 unreachable - admin prohibited filter

Finally send a packet that should match the first policy again, that is 
from 192.168.70.1[1234].
tcpdump shows that cached policy of the previous packet is applied rather than
the first policy, which has a higher priorioty. 
14:33:14.172468 IP 192.168.70.1.1234 > 192.168.66.2.7: UDP, length: 64
14:33:14.172565 IP 192.168.66.2 > 192.168.70.1: icmp 36: host 192.168.66.2 unreachable - admin prohibited filter

>Fix:
Index: ipsec.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec.c,v
retrieving revision 1.15
diff -u -r1.15 ipsec.c
--- ipsec.c	26 Feb 2005 22:45:13 -0000	1.15
+++ ipsec.c	16 Mar 2007 09:48:16 -0000
@@ -275,13 +275,16 @@
 			return NULL;
 		if (ipsec_setspidx(m, &spidx, 1) != 0)
 			return NULL;
+		
+		/*
+		 * We have to make an exact match here since the cached rule
+		 * might have lower priority than a rule that would otherwise
+		 * have matched the packet. 
+		 */
 		if (bcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx,
-			 sizeof(spidx))) {
-			if (!key_cmpspidx_withmask(&pcbsp->sp_cache[dir].cachesp->spidx,
-			    &spidx))
-				return NULL;
-			pcbsp->sp_cache[dir].cacheidx = spidx;
-		}
+			 sizeof(spidx))) 
+			return NULL;
+
 	} else {
 		/*
 		 * The pcb is connected, and the L4 code is sure that: