NetBSD Problem Report #50766
From www@NetBSD.org Wed Feb 3 23:38:17 2016
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.NetBSD.org [199.233.217.200])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id A528B7A140
for <gnats-bugs@gnats.NetBSD.org>; Wed, 3 Feb 2016 23:38:17 +0000 (UTC)
Message-Id: <20160203233815.D06297ACB3@mollari.NetBSD.org>
Date: Wed, 3 Feb 2016 23:38:15 +0000 (UTC)
From: zafer@aydogan.de
Reply-To: zafer@aydogan.de
To: gnats-bugs@NetBSD.org
Subject: panic in tcp_input.c on the banana pi (earm7hf) when trying to connect an ipv6 address through a gif ipv6 in ipv4 tunnel
X-Send-Pr-Version: www-1.0
>Number: 50766
>Category: kern
>Synopsis: panic in tcp_input.c on the banana pi (earm7hf) when trying to connect an ipv6 address through a gif ipv6 in ipv4 tunnel
>Confidential: no
>Severity: non-critical
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Feb 03 23:40:00 +0000 2016
>Last-Modified: Tue Nov 15 20:55:00 +0000 2016
>Originator: Zafer Aydogan
>Release: 7.0
>Organization:
>Environment:
NetBSD bpi 7.0.0_PATCH NetBSD 7.0.0_PATCH (BPI) #2: Wed Feb 3 22:33:20 UTC 2016 zafer@current:/data/objdir/sys/arch/evbarm/compile/BPI evbarm
>Description:
With a banana pi running NetBSD 7.0 following panic occurs when trying to connect to an ipv6 address through a gif ipv6 in ipv4 tunnel
panic: kernel diagnostic assertion "TCP_HDR_ALIGNED_P(th) failed: file /data/src/sys/netinet/tcp_input.c line 1344.
ping6 and traceroute6 on the other hand are working just fine. Panic happens only upon connect.
Also, I cross-checked this issue on amd64, where it does not appear.
You can connect just fine on amd64.
>How-To-Repeat:
Please enable pseudo device gif in the BPI kernel first,
then create a tunnel to an ipv6 enabled server.
I am using this script:
#!/bin/sh
ifconfig gif0 create
ifconfig gif0 tunnel 192.168.0.216 104.207.131.231
ifconfig gif0 inet6 2001:19f0:6c00:9089:8487:979e:c000:2 2001:19f0:6c00:9089:8487:979e:c000:1 prefixlen 128
route -n add -inet6 default 2001:19f0:6c00:9089:8487:979e:c000:1
where c000:2 and c000:1 are endpoints. 1 is the ipv6 enabled server and 2 is the banana pi at home. both endpoints are running NetBSD 7.0. The server is amd64.
I have applied following patches that show that nothing was misaligned prior to IP6_EXTHDR_GET in tcp_input.c on line 1298
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index 61a09aa..a4ed39e 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -57,6 +57,10 @@ __KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.64 2014/05/18 14:46:16 rmind Exp $");
#include <netinet/in_var.h>
#include <netinet/ip_encap.h>
#include <netinet/ip_ecn.h>
+#include <netinet/ip_private.h>
+#include <netinet/tcp_private.h>
+#include <netinet/udp_private.h>
+#include <netinet6/ip6_private.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -211,6 +215,11 @@ in_gif_input(struct mbuf *m, ...)
proto = va_arg(ap, int);
va_end(ap);
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
+ KASSERT(IP_HDR_ALIGNED_P(off));
+ KASSERT(IP6_HDR_ALIGNED_P(off));
+ KASSERT(TCP_HDR_ALIGNED_P(off));
+ KASSERT(UDP_HDR_ALIGNED_P(off));
ip = mtod(m, const struct ip *);
gifp = (struct ifnet *)encap_getarg(m);
@@ -230,6 +239,7 @@ in_gif_input(struct mbuf *m, ...)
otos = ip->ip_tos;
m_adj(m, off);
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
switch (proto) {
#ifdef INET
@@ -241,6 +251,7 @@ in_gif_input(struct mbuf *m, ...)
if ((m = m_pullup(m, sizeof(*xip))) == NULL)
return;
}
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
xip = mtod(m, struct ip *);
if (gifp->if_flags & IFF_LINK1)
ip_ecn_egress(ECN_ALLOWED, &otos, &xip->ip_tos);
@@ -259,6 +270,7 @@ in_gif_input(struct mbuf *m, ...)
if ((m = m_pullup(m, sizeof(*ip6))) == NULL)
return;
}
+ KASSERT(IP6_HDR_ALIGNED_P(mtod(m, void *)));
ip6 = mtod(m, struct ip6_hdr *);
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if (gifp->if_flags & IFF_LINK1)
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index cb80d94..7295941 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -407,12 +407,14 @@ ip_input(struct mbuf *m)
return;
}
}
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
ip = mtod(m, struct ip *);
if (ip->ip_v != IPVERSION) {
IP_STATINC(IP_STAT_BADVERS);
goto bad;
}
hlen = ip->ip_hl << 2;
+ KASSERT(IP_HDR_ALIGNED_P(hlen));
if (hlen < sizeof(struct ip)) { /* minimum header length */
IP_STATINC(IP_STAT_BADHLEN);
goto bad;
@@ -422,6 +424,7 @@ ip_input(struct mbuf *m)
IP_STATINC(IP_STAT_BADHLEN);
return;
}
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
ip = mtod(m, struct ip *);
}
@@ -526,8 +529,10 @@ ip_input(struct mbuf *m)
if (freed || m == NULL) {
return;
}
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
+ KASSERT(IP_HDR_ALIGNED_P(hlen));
/*
* XXX The setting of "srcrt" here is to prevent ip_forward()
@@ -736,8 +741,10 @@ ours:
* Reassembly is done, we have the final packet.
* Updated cached data in local variable(s).
*/
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
+ KASSERT(IP_HDR_ALIGNED_P(hlen));
}
#ifdef IPSEC
@@ -768,6 +775,9 @@ ours:
const int off = hlen, nh = ip->ip_p;
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
+ KASSERT(IP_HDR_ALIGNED_P(off));
+
SOFTNET_LOCK();
(*inetsw[ip_protox[nh]].pr_input)(m, off, nh);
SOFTNET_UNLOCK();
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 4362c99..88857227 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -212,6 +212,7 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.334.2.2 2015/07/24 07:30:40 martin E
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcp_private.h>
+#include <netinet/ip_private.h>
#include <netinet/tcpip.h>
#include <netinet/tcp_congctl.h>
#include <netinet/tcp_debug.h>
@@ -1237,6 +1238,11 @@ tcp_input(struct mbuf *m, ...)
(void)va_arg(ap, int); /* ignore value, advance ap */
va_end(ap);
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
+ KASSERT(IP_HDR_ALIGNED_P(toff));
+ KASSERT(TCP_HDR_ALIGNED_P(mtod(m, void *)));
+ KASSERT(TCP_HDR_ALIGNED_P(toff));
+
TCP_STATINC(TCP_STAT_RCVTOTAL);
memset(&opti, 0, sizeof(opti));
@@ -1267,6 +1273,7 @@ tcp_input(struct mbuf *m, ...)
* Get IP and TCP header.
* Note: IP leaves IP header in first mbuf.
*/
+ KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
ip = mtod(m, struct ip *);
switch (ip->ip_v) {
#ifdef INET
@@ -1276,12 +1283,15 @@ tcp_input(struct mbuf *m, ...)
#endif
af = AF_INET;
iphlen = sizeof(struct ip);
+ KASSERT(TCP_HDR_ALIGNED_P(mtod(m, void *)));
+ KASSERT(TCP_HDR_ALIGNED_P(toff));
IP6_EXTHDR_GET(th, struct tcphdr *, m, toff,
sizeof(struct tcphdr));
if (th == NULL) {
TCP_STATINC(TCP_STAT_RCVSHORT);
return;
}
+ KASSERT(TCP_HDR_ALIGNED_P(th));
/* We do the checksum after PCB lookup... */
len = ntohs(ip->ip_len);
tlen = len - toff;
@@ -1294,12 +1304,15 @@ tcp_input(struct mbuf *m, ...)
iphlen = sizeof(struct ip6_hdr);
af = AF_INET6;
ip6 = mtod(m, struct ip6_hdr *);
+ KASSERT(TCP_HDR_ALIGNED_P(mtod(m, void *)));
+ KASSERT(TCP_HDR_ALIGNED_P(toff));
IP6_EXTHDR_GET(th, struct tcphdr *, m, toff,
sizeof(struct tcphdr));
if (th == NULL) {
TCP_STATINC(TCP_STAT_RCVSHORT);
return;
}
+ KASSERT(TCP_HDR_ALIGNED_P(th));
/* Be proactive about malicious use of IPv4 mapped address */
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
>Fix:
>Audit-Trail:
From: Masanobu SAITOH <msaitoh@execsw.org>
To: gnats-bugs@NetBSD.org, kern-bug-people@netbsd.org,
gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Cc: msaitoh@execsw.org
Subject: Re: kern/50766: panic in tcp_input.c on the banana pi (earm7hf) when
trying to connect an ipv6 address through a gif ipv6 in ipv4 tunnel
Date: Thu, 4 Feb 2016 15:38:09 +0900
On 2016/02/04 8:40, zafer@aydogan.de wrote:
>> Number: 50766
>> Category: kern
>> Synopsis: panic in tcp_input.c on the banana pi (earm7hf) when trying to connect an ipv6 address through a gif ipv6 in ipv4 tunnel
>> Confidential: no
>> Severity: non-critical
>> Priority: high
>> Responsible: kern-bug-people
>> State: open
>> Class: sw-bug
>> Submitter-Id: net
>> Arrival-Date: Wed Feb 03 23:40:00 +0000 2016
>> Originator: Zafer Aydogan
>> Release: 7.0
>> Organization:
>> Environment:
> NetBSD bpi 7.0.0_PATCH NetBSD 7.0.0_PATCH (BPI) #2: Wed Feb 3 22:33:20 UTC 2016 zafer@current:/data/objdir/sys/arch/evbarm/compile/BPI evbarm
>> Description:
> With a banana pi running NetBSD 7.0 following panic occurs when trying to connect to an ipv6 address through a gif ipv6 in ipv4 tunnel
>
> panic: kernel diagnostic assertion "TCP_HDR_ALIGNED_P(th) failed: file /data/src/sys/netinet/tcp_input.c line 1344.
>
> ping6 and traceroute6 on the other hand are working just fine. Panic happens only upon connect.
>
> Also, I cross-checked this issue on amd64, where it does not appear.
> You can connect just fine on amd64.
One of possibility is that the Ethernet device driver passed unaligned mbuf.
>> How-To-Repeat:
> Please enable pseudo device gif in the BPI kernel first,
> then create a tunnel to an ipv6 enabled server.
> I am using this script:
>
> #!/bin/sh
> ifconfig gif0 create
> ifconfig gif0 tunnel 192.168.0.216 104.207.131.231
> ifconfig gif0 inet6 2001:19f0:6c00:9089:8487:979e:c000:2 2001:19f0:6c00:9089:8487:979e:c000:1 prefixlen 128
> route -n add -inet6 default 2001:19f0:6c00:9089:8487:979e:c000:1
>
> where c000:2 and c000:1 are endpoints. 1 is the ipv6 enabled server and 2 is the banana pi at home. both endpoints are running NetBSD 7.0. The server is amd64.
>
> I have applied following patches that show that nothing was misaligned prior to IP6_EXTHDR_GET in tcp_input.c on line 1298
>
>
> diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
> index 61a09aa..a4ed39e 100644
> --- a/sys/netinet/in_gif.c
> +++ b/sys/netinet/in_gif.c
> @@ -57,6 +57,10 @@ __KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.64 2014/05/18 14:46:16 rmind Exp $");
> #include <netinet/in_var.h>
> #include <netinet/ip_encap.h>
> #include <netinet/ip_ecn.h>
> +#include <netinet/ip_private.h>
> +#include <netinet/tcp_private.h>
> +#include <netinet/udp_private.h>
> +#include <netinet6/ip6_private.h>
>
> #ifdef INET6
> #include <netinet/ip6.h>
> @@ -211,6 +215,11 @@ in_gif_input(struct mbuf *m, ...)
> proto = va_arg(ap, int);
> va_end(ap);
>
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> + KASSERT(IP_HDR_ALIGNED_P(off));
> + KASSERT(IP6_HDR_ALIGNED_P(off));
> + KASSERT(TCP_HDR_ALIGNED_P(off));
> + KASSERT(UDP_HDR_ALIGNED_P(off));
At least, avobe checks aren't correct what you intended.
% grep _HDR_ALIGNED_P */*.h
netinet/icmp_private.h:#define ICMP_HDR_ALIGNED_P(ic) 1
netinet/icmp_private.h:#define ICMP_HDR_ALIGNED_P(ic) ((((vaddr_t) (ic)) & 3) == 0)
netinet/igmp_var.h:#define IGMP_HDR_ALIGNED_P(ig) 1
netinet/igmp_var.h:#define IGMP_HDR_ALIGNED_P(ig) ((((vaddr_t) (ig)) & 3) == 0)
netinet/ip_private.h:#define IP_HDR_ALIGNED_P(ip) 1
netinet/ip_private.h:#define IP_HDR_ALIGNED_P(ip) ((((vaddr_t) (ip)) & 3) == 0)
netinet/tcp_private.h:#define TCP_HDR_ALIGNED_P(th) 1
netinet/tcp_private.h:#define TCP_HDR_ALIGNED_P(th) ((((vaddr_t)(th)) & 3) == 0)
netinet/udp_private.h:#define UDP_HDR_ALIGNED_P(uh) 1
netinet/udp_private.h:#define UDP_HDR_ALIGNED_P(uh) ((((vaddr_t) (uh)) & 3) == 0)
netinet6/ip6_private.h:#define IP6_HDR_ALIGNED_P(ip) 1
netinet6/ip6_private.h:#define IP6_HDR_ALIGNED_P(ip) ((((vaddr_t) (ip)) & 3) == 0)
Each *_HDR_ALIGNED_P()'s argument takes the head of each protocol header.
> ip = mtod(m, const struct ip *);
>
> gifp = (struct ifnet *)encap_getarg(m);
> @@ -230,6 +239,7 @@ in_gif_input(struct mbuf *m, ...)
>
> otos = ip->ip_tos;
> m_adj(m, off);
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
>
> switch (proto) {
> #ifdef INET
> @@ -241,6 +251,7 @@ in_gif_input(struct mbuf *m, ...)
> if ((m = m_pullup(m, sizeof(*xip))) == NULL)
> return;
> }
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> xip = mtod(m, struct ip *);
> if (gifp->if_flags & IFF_LINK1)
> ip_ecn_egress(ECN_ALLOWED, &otos, &xip->ip_tos);
> @@ -259,6 +270,7 @@ in_gif_input(struct mbuf *m, ...)
> if ((m = m_pullup(m, sizeof(*ip6))) == NULL)
> return;
> }
> + KASSERT(IP6_HDR_ALIGNED_P(mtod(m, void *)));
> ip6 = mtod(m, struct ip6_hdr *);
> itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
> if (gifp->if_flags & IFF_LINK1)
> diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
> index cb80d94..7295941 100644
> --- a/sys/netinet/ip_input.c
> +++ b/sys/netinet/ip_input.c
> @@ -407,12 +407,14 @@ ip_input(struct mbuf *m)
> return;
> }
> }
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> ip = mtod(m, struct ip *);
> if (ip->ip_v != IPVERSION) {
> IP_STATINC(IP_STAT_BADVERS);
> goto bad;
> }
> hlen = ip->ip_hl << 2;
> + KASSERT(IP_HDR_ALIGNED_P(hlen));
> if (hlen < sizeof(struct ip)) { /* minimum header length */
> IP_STATINC(IP_STAT_BADHLEN);
> goto bad;
> @@ -422,6 +424,7 @@ ip_input(struct mbuf *m)
> IP_STATINC(IP_STAT_BADHLEN);
> return;
> }
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> ip = mtod(m, struct ip *);
> }
>
> @@ -526,8 +529,10 @@ ip_input(struct mbuf *m)
> if (freed || m == NULL) {
> return;
> }
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> ip = mtod(m, struct ip *);
> hlen = ip->ip_hl << 2;
> + KASSERT(IP_HDR_ALIGNED_P(hlen));
>
> /*
> * XXX The setting of "srcrt" here is to prevent ip_forward()
> @@ -736,8 +741,10 @@ ours:
> * Reassembly is done, we have the final packet.
> * Updated cached data in local variable(s).
> */
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> ip = mtod(m, struct ip *);
> hlen = ip->ip_hl << 2;
> + KASSERT(IP_HDR_ALIGNED_P(hlen));
> }
>
> #ifdef IPSEC
> @@ -768,6 +775,9 @@ ours:
>
> const int off = hlen, nh = ip->ip_p;
>
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> + KASSERT(IP_HDR_ALIGNED_P(off));
> +
> SOFTNET_LOCK();
> (*inetsw[ip_protox[nh]].pr_input)(m, off, nh);
> SOFTNET_UNLOCK();
> diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
> index 4362c99..88857227 100644
> --- a/sys/netinet/tcp_input.c
> +++ b/sys/netinet/tcp_input.c
> @@ -212,6 +212,7 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.334.2.2 2015/07/24 07:30:40 martin E
> #include <netinet/tcp_timer.h>
> #include <netinet/tcp_var.h>
> #include <netinet/tcp_private.h>
> +#include <netinet/ip_private.h>
> #include <netinet/tcpip.h>
> #include <netinet/tcp_congctl.h>
> #include <netinet/tcp_debug.h>
> @@ -1237,6 +1238,11 @@ tcp_input(struct mbuf *m, ...)
> (void)va_arg(ap, int); /* ignore value, advance ap */
> va_end(ap);
>
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> + KASSERT(IP_HDR_ALIGNED_P(toff));
> + KASSERT(TCP_HDR_ALIGNED_P(mtod(m, void *)));
> + KASSERT(TCP_HDR_ALIGNED_P(toff));
> +
> TCP_STATINC(TCP_STAT_RCVTOTAL);
>
> memset(&opti, 0, sizeof(opti));
> @@ -1267,6 +1273,7 @@ tcp_input(struct mbuf *m, ...)
> * Get IP and TCP header.
> * Note: IP leaves IP header in first mbuf.
> */
> + KASSERT(IP_HDR_ALIGNED_P(mtod(m, void *)));
> ip = mtod(m, struct ip *);
> switch (ip->ip_v) {
> #ifdef INET
> @@ -1276,12 +1283,15 @@ tcp_input(struct mbuf *m, ...)
> #endif
> af = AF_INET;
> iphlen = sizeof(struct ip);
> + KASSERT(TCP_HDR_ALIGNED_P(mtod(m, void *)));
> + KASSERT(TCP_HDR_ALIGNED_P(toff));
> IP6_EXTHDR_GET(th, struct tcphdr *, m, toff,
> sizeof(struct tcphdr));
> if (th == NULL) {
> TCP_STATINC(TCP_STAT_RCVSHORT);
> return;
> }
> + KASSERT(TCP_HDR_ALIGNED_P(th));
> /* We do the checksum after PCB lookup... */
> len = ntohs(ip->ip_len);
> tlen = len - toff;
> @@ -1294,12 +1304,15 @@ tcp_input(struct mbuf *m, ...)
> iphlen = sizeof(struct ip6_hdr);
> af = AF_INET6;
> ip6 = mtod(m, struct ip6_hdr *);
> + KASSERT(TCP_HDR_ALIGNED_P(mtod(m, void *)));
> + KASSERT(TCP_HDR_ALIGNED_P(toff));
> IP6_EXTHDR_GET(th, struct tcphdr *, m, toff,
> sizeof(struct tcphdr));
> if (th == NULL) {
> TCP_STATINC(TCP_STAT_RCVSHORT);
> return;
> }
> + KASSERT(TCP_HDR_ALIGNED_P(th));
>
> /* Be proactive about malicious use of IPv4 mapped address */
> if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
>
>
>
>
>
>> Fix:
>
--
-----------------------------------------------
SAITOH Masanobu (msaitoh@execsw.org
msaitoh@netbsd.org)
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc: zafer@aydogan.de
Subject: Re: kern/50766: panic in tcp_input.c on the banana pi (earm7hf) when trying to connect an ipv6 address through a gif ipv6 in ipv4 tunnel
Date: Thu, 4 Feb 2016 09:27:12 +0100
On Thu, Feb 04, 2016 at 06:40:01AM +0000, Masanobu SAITOH wrote:
> One of possibility is that the Ethernet device driver passed unaligned mbuf.
I would be suprised if that was the case (assuming it is awge0 on the BPI).
Martin
From: Nick Hudson <skrll@netbsd.org>
To: gnats-bugs@NetBSD.org, kern-bug-people@netbsd.org,
gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Cc:
Subject: Re: kern/50766: panic in tcp_input.c on the banana pi (earm7hf) when
trying to connect an ipv6 address through a gif ipv6 in ipv4 tunnel
Date: Wed, 10 Feb 2016 10:11:42 +0000
This is a multi-part message in MIME format.
--------------000108030809020100050007
Content-Type: text/plain; charset=windows-1252; format=flowed
Content-Transfer-Encoding: 7bit
I reproduced this on my bpi with
and got
panic: kernel diagnostic assertion "TCP_HDR_ALIGNED_P(th)" failed: file
"/wrk/bpi/src/sys/netinet/tcp_input.c", line 1358
Stopped in pid 0.3 (system) at netbsd:cpu_Debugger+0x4: bx r14
db{0}> t
0xbfee7d04: netbsd:vpanic+0xc
0xbfee7d1c: netbsd:__udivmoddi4
0xbfee7e8c: netbsd:tcp_input+0x2d14
0xbfee7ecc: netbsd:tcp6_input+0x11c
0xbfee7f4c: netbsd:ip6_input+0x9f4
0xbfee7f64: netbsd:ip6intr+0x74
0xbfee7fac: netbsd:softint_dispatch+0xd4
Bad frame pointer: 0xbf227e84
db{0}>
or
http://nxr.netbsd.org/xref/src/sys/netinet/tcp_input.c#1345
with HEAD
Nick
--------------000108030809020100050007
Content-Type: text/x-patch;
name="bpi.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="bpi.diff"
Index: sys/netinet/in_gif.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_gif.c,v
retrieving revision 1.75
diff -u -p -r1.75 in_gif.c
--- sys/netinet/in_gif.c 26 Jan 2016 06:00:10 -0000 1.75
+++ sys/netinet/in_gif.c 10 Feb 2016 10:10:02 -0000
@@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#include <netinet/ip_private.h>
#include <netinet/ip_var.h>
#include <netinet/in_gif.h>
#include <netinet/in_var.h>
@@ -200,6 +201,8 @@ in_gif_input(struct mbuf *m, int off, in
int af;
u_int8_t otos;
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(off));
ip = mtod(m, const struct ip *);
gifp = (struct ifnet *)encap_getarg(m);
@@ -226,6 +229,7 @@ in_gif_input(struct mbuf *m, int off, in
#endif
otos = ip->ip_tos;
m_adj(m, off);
+ ip_mbuf_align_check(m);
switch (proto) {
#ifdef INET
@@ -237,6 +241,7 @@ in_gif_input(struct mbuf *m, int off, in
if ((m = m_pullup(m, sizeof(*xip))) == NULL)
return;
}
+ ip_mbuf_align_check(m);
xip = mtod(m, struct ip *);
if (gifp->if_flags & IFF_LINK1)
ip_ecn_egress(ECN_ALLOWED, &otos, &xip->ip_tos);
@@ -255,6 +260,7 @@ in_gif_input(struct mbuf *m, int off, in
if ((m = m_pullup(m, sizeof(*ip6))) == NULL)
return;
}
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if (gifp->if_flags & IFF_LINK1)
@@ -271,6 +277,7 @@ in_gif_input(struct mbuf *m, int off, in
m_freem(m);
return;
}
+ ip_mbuf_align_check(m);
gif_input(m, af, gifp);
return;
}
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.328
diff -u -p -r1.328 ip_input.c
--- sys/netinet/ip_input.c 21 Jan 2016 15:41:30 -0000 1.328
+++ sys/netinet/ip_input.c 10 Feb 2016 10:10:02 -0000
@@ -411,12 +411,14 @@ ip_input(struct mbuf *m)
return;
}
}
+ ip_mbuf_align_check(m);
ip = mtod(m, struct ip *);
if (ip->ip_v != IPVERSION) {
IP_STATINC(IP_STAT_BADVERS);
goto bad;
}
hlen = ip->ip_hl << 2;
+ KASSERT(IP_HDR_ALIGNED_P(hlen));
if (hlen < sizeof(struct ip)) { /* minimum header length */
IP_STATINC(IP_STAT_BADHLEN);
goto bad;
@@ -426,6 +428,7 @@ ip_input(struct mbuf *m)
IP_STATINC(IP_STAT_BADHLEN);
return;
}
+ ip_mbuf_align_check(m);
ip = mtod(m, struct ip *);
}
@@ -530,6 +533,7 @@ ip_input(struct mbuf *m)
if (freed || m == NULL) {
return;
}
+ ip_mbuf_align_check(m);
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
@@ -744,6 +748,7 @@ ours:
* Reassembly is done, we have the final packet.
* Updated cached data in local variable(s).
*/
+ ip_mbuf_align_check(m);
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
}
@@ -775,6 +780,8 @@ ours:
IP_STATINC(IP_STAT_DELIVERED);
const int off = hlen, nh = ip->ip_p;
+ KASSERT(IP_HDR_ALIGNED_P(off));
+ ip_mbuf_align_check(m);
SOFTNET_LOCK();
(*inetsw[ip_protox[nh]].pr_input)(m, off, nh);
Index: sys/netinet/ip_private.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_private.h,v
retrieving revision 1.3
diff -u -p -r1.3 ip_private.h
--- sys/netinet/ip_private.h 28 Apr 2008 20:24:09 -0000 1.3
+++ sys/netinet/ip_private.h 10 Feb 2016 10:10:02 -0000
@@ -48,6 +48,20 @@ extern percpu_t *ipstat_percpu;
#else
#define IP_HDR_ALIGNED_P(ip) ((((vaddr_t) (ip)) & 3) == 0)
#endif
+
+#include <sys/mbuf.h>
+
+static inline void
+ip_mbuf_align_check(struct mbuf *m)
+{
+ unsigned i;
+
+ for (i = 0; m != NULL; m = m->m_next, i++) {
+ if (!IP_HDR_ALIGNED_P(m->m_data)) {
+ printf("mbuf chunk %u misaligned: %p\n", i, m->m_data);
+ }
+ }
+}
#endif /* _KERNEL */
#endif /* !_NETINET_IP_PRIVATE_H_ */
Index: sys/netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v
retrieving revision 1.344
diff -u -p -r1.344 tcp_input.c
--- sys/netinet/tcp_input.c 24 Aug 2015 22:21:26 -0000 1.344
+++ sys/netinet/tcp_input.c 10 Feb 2016 10:10:09 -0000
@@ -181,6 +181,7 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_input.c,
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#include <netinet/ip_private.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
@@ -820,6 +821,9 @@ tcp6_input(struct mbuf **mp, int *offp,
{
struct mbuf *m = *mp;
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(*offp));
+
/*
* draft-itojun-ipv6-tcp-to-anycast
* better place to put this in?
@@ -832,6 +836,7 @@ tcp6_input(struct mbuf **mp, int *offp,
return IPPROTO_DONE;
}
}
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR,
(char *)&ip6->ip6_dst - (char *)ip6);
@@ -1238,6 +1243,9 @@ tcp_input(struct mbuf *m, ...)
(void)va_arg(ap, int); /* ignore value, advance ap */
va_end(ap);
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(toff));
+
TCP_STATINC(TCP_STAT_RCVTOTAL);
memset(&opti, 0, sizeof(opti));
@@ -1268,6 +1276,7 @@ tcp_input(struct mbuf *m, ...)
* Get IP and TCP header.
* Note: IP leaves IP header in first mbuf.
*/
+ ip_mbuf_align_check(m);
ip = mtod(m, struct ip *);
switch (ip->ip_v) {
#ifdef INET
@@ -1283,6 +1292,8 @@ tcp_input(struct mbuf *m, ...)
TCP_STATINC(TCP_STAT_RCVSHORT);
return;
}
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(toff));
/* We do the checksum after PCB lookup... */
len = ntohs(ip->ip_len);
tlen = len - toff;
@@ -1301,6 +1312,8 @@ tcp_input(struct mbuf *m, ...)
TCP_STATINC(TCP_STAT_RCVSHORT);
return;
}
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(toff));
/* Be proactive about malicious use of IPv4 mapped address */
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
Index: sys/netinet6/ip6_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.155
diff -u -p -r1.155 ip6_input.c
--- sys/netinet6/ip6_input.c 4 Feb 2016 02:48:37 -0000 1.155
+++ sys/netinet6/ip6_input.c 10 Feb 2016 10:10:12 -0000
@@ -106,6 +106,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c,
#include <netinet/portalgo.h>
#include <netinet6/in6_var.h>
#include <netinet6/ip6_var.h>
+#include <netinet/ip_private.h>
#include <netinet6/ip6_private.h>
#include <netinet6/in6_pcb.h>
#include <netinet/icmp6.h>
@@ -308,6 +309,7 @@ ip6_input(struct mbuf *m)
}
}
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
@@ -347,6 +349,7 @@ ip6_input(struct mbuf *m)
return;
if (m == NULL)
return;
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
}
@@ -419,6 +422,7 @@ ip6_input(struct mbuf *m)
if (__predict_false(
m_makewritable(&m, 0, sizeof(struct ip6_hdr), M_DONTWAIT)))
goto bad;
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) {
IP6_STATINC(IP6_STAT_BADSCOPE); /* XXX */
@@ -597,6 +601,7 @@ ip6_input(struct mbuf *m)
}
/* adjust pointer */
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
/*
@@ -681,6 +686,7 @@ ip6_input(struct mbuf *m)
return;
}
+ ip_mbuf_align_check(m);
ip6 = mtod(m, struct ip6_hdr *);
/*
@@ -757,7 +763,11 @@ ip6_input(struct mbuf *m)
}
#endif /* IPSEC */
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(off));
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
+ ip_mbuf_align_check(m);
+ KASSERT(IP_HDR_ALIGNED_P(off));
}
return;
bad:
--------------000108030809020100050007--
From: Michael van Elst <mlelstv@serpens.de>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/50766 panic in tcp_input.c on the banana pi
Date: Sat, 5 Nov 2016 17:37:25 +0100
I just got the same on evbmips running -current and analyzed it a bit.
ip_input() and ip6_input() align the IP header by calling m_copyup when
necessary to enforce alignment.
However, the protocol input routines rely on m_pulldown() to achieve
the same. This assumption breaks when IP header and protocol header
(e.g. ICMP) are not contigous but in separate mbufs. There is no
guarantee that the second mbuf is aligned.
m_copyup() is part of the problem too. It copies the requested
header size but rounds it up to 60 bytes. For a simple packet
this copies part of the protocol header, which is therefore
aligned, and the following m_pullup coalesces remaining bytes.
But with ipv6-in-ipv4 encapsulation you have e.g.
20 bytes IPv4
40 bytes IPv6
20 bytes TCP
If this comes in aligned, everyone is happy.
If this comes in unaligned, then ip_input will m_copyup 60 bytes,
leaving the unaligned TCP header in the original mbuf.
ip6_input will then see that its header is already aligned and
do nothing regarding alignment.
tcp_input will fail because the header isn't aligned and m_pullup
doesn't change that.
I have locally patched the protocol routines to use m_copyup as well.
Greetings,
--
Michael van Elst
Internet: mlelstv@serpens.de
"A potential Snark may lurk in every tree."
From: "Michael van Elst" <mlelstv@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/50766 CVS commit: src/sys
Date: Tue, 15 Nov 2016 20:50:29 +0000
Module Name: src
Committed By: mlelstv
Date: Tue Nov 15 20:50:29 UTC 2016
Modified Files:
src/sys/netinet: tcp_input.c udp_usrreq.c
src/sys/netinet6: icmp6.c udp6_usrreq.c
Log Message:
Enforce alignment requirements that are violated in some cases.
For machines that don't need strict alignment (i386,amd64,vax,m68k) this
is a no-op.
Fixes PR kern/50766 but should be improved.
To generate a diff of this commit:
cvs rdiff -u -r1.347 -r1.348 src/sys/netinet/tcp_input.c
cvs rdiff -u -r1.227 -r1.228 src/sys/netinet/udp_usrreq.c
cvs rdiff -u -r1.200 -r1.201 src/sys/netinet6/icmp6.c
cvs rdiff -u -r1.124 -r1.125 src/sys/netinet6/udp6_usrreq.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.