NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/47886: IPSEC_NAT_T enabled kernels may access outdated pointers and pass ESP data to UPD-sockets
>Number: 47886
>Category: kern
>Synopsis: IPSEC_NAT_T enabled kernels may access outdated pointers and
>pass ESP data to UPD-sockets
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jun 04 14:05:00 +0000 2013
>Originator: Dr. Wolfgang Stukenbrock
>Release: NetBSD 6.1
>Organization:
Dr. Nagler & Company GmbH
>Environment:
System: NetBSD s012 4.0 NetBSD 4.0 (NSW-S012) #12: Tue Jun 19 11:15:19 CEST
2012 ncadmin@s012:/usr/src/sys/arch/amd64/compile/NSW-S012 amd64
Architecture: x86_64
Machine: amd64
>Description:
If IPSEC_NAT_T is enabled, it may happen that the mbuf chain gets
changed by m_pullup().
So it is no good idea to use a pointer to the IP-header that is based
on the old one.
A second strange thing is, that we strip off the UPD header during
processing and set the type to ESP, but still
processing this packet as UPD packet, if we fail to duplicate the
packet or to allocate a packet tag.
I'm not shure what can happen in udp6_realinput() and/or udp4_sendup()
when called with ESP-packets.
As far as I can see, this may inject any data into the UPD-stack while
bypassing ipfilter rules.
Also returning the 1 byte keep-alive packets to the UPD processing may
end up in passing it to IPv6
UPD sockets, if it has been send to a multicast address.
Same may happen with "normal" NAT-T packets send to Multicast addresses.
(May be some kind of DOS attack when running without ipfilter setup ???)
>How-To-Repeat:
Found while validating private patches agains 6.1 release while
preparing upgrade to 6.1.
>Fix:
The following patch to src/sys/netinet/udp_usrreq.c will fix the
problem:
- avoid any UDP processing of NAT-T-keep-alive packets
- avoid any UDP processing after stripping of the UPD header
(this makes the duplication of the packet obsolete and speeds up
processing.)
- recalculate the pointer to the IP header if the UPD packets is
returned to upd_input() for futher processing.
--- udp_usrreq.c 2013/06/04 12:07:05 1.1
+++ udp_usrreq.c 2013/06/04 13:18:57
@@ -412,6 +412,11 @@
UDP_STATINC(UDP_STAT_HDROPS);
return;
}
+#ifdef IPSEC_NAT_T
+ if (m == NULL) return; /* packet has been processed by ESP stuff - e.g.
dropped NAT-T-keep-alive-packet ... */
+// need to refresch pointer to ip-header, mbuf may have changed after pullup
...
+ ip = mtod(m, struct ip *);
+#endif
#ifdef INET6
if (IN_MULTICAST(ip->ip_dst.s_addr) || n == 0) {
struct sockaddr_in6 src6, dst6;
@@ -1493,7 +1498,6 @@
size_t minlen;
size_t iphdrlen;
struct ip *ip;
- struct mbuf *n;
struct m_tag *tag;
struct udphdr *udphdr;
u_int16_t sport, dport;
@@ -1521,6 +1525,8 @@
/* Ignore keepalive packets */
if ((len == 1) && (*(unsigned char *)data == 0xff)) {
+ m_free(m);
+ *mp = NULL; /* avoid any further processiong by caller ... */
return 1;
}
@@ -1578,16 +1584,7 @@
ip = mtod(m, struct ip *);
ip->ip_len = htons(ntohs(ip->ip_len) - skip);
ip->ip_p = IPPROTO_ESP;
-
- /*
- * Copy the mbuf to avoid multiple free, as both
- * esp4_input (which we call) and udp_input (which
- * called us) free the mbuf.
- */
- if ((n = m_dup(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
- printf("udp4_espinudp: m_dup failed\n");
- return 0;
- }
+// remark: we have modified the packet - it is now ESP, so we should not
return to UDP processing ...
/*
* Add a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember
@@ -1598,20 +1595,21 @@
if ((tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS,
sizeof(sport) + sizeof(dport), M_DONTWAIT)) == NULL) {
printf("udp4_espinudp: m_tag_get failed\n");
- m_freem(n);
- return 0;
+ m_freem(m); /* must free mbuf when returning -1 ... */
+ return -1;
}
((u_int16_t *)(tag + 1))[0] = sport;
((u_int16_t *)(tag + 1))[1] = dport;
- m_tag_prepend(n, tag);
+ m_tag_prepend(m, tag);
#ifdef FAST_IPSEC
- ipsec4_common_input(n, iphdrlen, IPPROTO_ESP);
+ ipsec4_common_input(m, iphdrlen, IPPROTO_ESP);
#else
- esp4_input(n, iphdrlen);
+ esp4_input(m, iphdrlen);
#endif
/* We handled it, it shouldn't be handled by UDP */
+ *mp = NULL; /* avoid free by caller ... */
return 1;
}
#endif
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index