Subject: kern/22715: Port-specific TCP IPsec security policies don't work
To: None <gnats-bugs@gnats.netbsd.org>
From: None <michael.eriksson@era-t.ericsson.se>
List: netbsd-bugs
Date: 09/07/2003 23:18:38
>Number:         22715
>Category:       kern
>Synopsis:       Port-specific TCP IPsec security policies don't work
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Sep 07 21:19:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     Michael Eriksson
>Release:        NetBSD 1.6X
>Organization:
Ericsson Research
>Environment:
>Description:

It is sometimes useful to have IPsec security policies that is just
for a particular transport protocol port, e.g., to protect NFS
traffic. Due to a kernel bug, port-specific TCP policies don't work.

>How-To-Repeat:

datan$ setkey -f - <<EOF
spdadd 0.0.0.0/0[any] 10.11.0.0/16[2049] any
        -P out ipsec esp/transport//require;
spdadd 10.11.0.0/16[2049] 0.0.0.0/0[any] any
        -P in ipsec esp/transport//require;
EOF
datan$ telnet 10.11.0.3 2049

Use tcpdump to see the traffic go unencrypted.

>Fix:

The basic problem is that the IPsec policy is chosen very early, long
before ip_output() is called. Early in tcp_output(), tcp_segsize() is
called. tcp_segsize() indirectly uses tp->t_template to pick a
security policy (which is cached). tp->t_template's IP header length
is not initialised, which makes ipsec4_get_ulp() read the port numbers
from the wrong place in memory (at the start of the IP header).

Index: tcp_subr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.150
diff -u -r1.150 tcp_subr.c
--- tcp_subr.c	2003/08/22 22:27:07	1.150
+++ tcp_subr.c	2003/09/07 20:58:12
@@ -462,6 +462,7 @@
 	    {
 		struct ipovly *ipov;
 		mtod(m, struct ip *)->ip_v = 4;
+		mtod(m, struct ip *)->ip_hl = hlen >> 2;
 		ipov = mtod(m, struct ipovly *);
 		ipov->ih_pr = IPPROTO_TCP;
 		ipov->ih_len = htons(sizeof(struct tcphdr));

>Release-Note:
>Audit-Trail:
>Unformatted: