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.

NetBSD Home
NetBSD PR Database Search

(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.