NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

port-evbarm/49020: Writing to tap device may cause panic on RPI



>Number:         49020
>Category:       port-evbarm
>Synopsis:       Writing to tap device may cause panic on RPI
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-evbarm-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 18 21:25:00 +0000 2014
>Originator:     Takahiro HAYASHI
>Release:        NetBSD 6.99.47 2014-07-18 11:57:12 UTC
>Organization:
>Environment:
System: NetBSD raspi 6.99.47 NetBSD 6.99.47 (MYRPI) #13: Fri Jul 18 20:50:08 
JST 2014  root@halt:/build/head/obj.evbarm/sys/arch/evbarm/compile/MYRPI evbarm
Architecture: earmhf
Machine: evbarm
>Description:
        Writing to tap device may cause panic on Raspberry-Pi.

        tap(4) needs to be written data with ethernet link-level header,
        whose length is 14.  It means payload is not aligned.
        ip6_input() tries to adjust alignment but does not do because
        __NO_STRICT_ALIGNMENT is defined in arm/types.h on RPI.
        This causes ip6->ip6_dst not aligned and copying struct
        > sin6->sin6_addr = *addr;
        in sockaddr_in6_init1() (this is inline func in in6.h) fails.

# ./a.out
writing data 0x212e0 len 70 to tap0 (f2:0b:a4:61:b0:fb)
data_abort_handler: data_aborts fsr=0x1 far=0xdbf1fa5e
Fatal kernel mode data abort: 'Alignment Fault 1'
trapframe: 0xdbf2be98
FSR=00000001, FAR=dbf1fa5e, spsr=80000013
r0 =00000000, r1 =00000000, r2 =00000018, r3 =0000001c
r4 =c0489444, r5 =00000000, r6 =dbf1fa46, r7 =dbf1fa5e
r8 =dbf1fa4e, r9 =00000004, r10=00000010, r11=dbf2bf4c
r12=00000000, ssp=dbf2bee8, slr=dbf2bf0c, pc =c00c4914

Stopped in pid 0.3 (system) at  netbsd:ip6_input+0x7d0: ldmia   r7, {r0-r3}
db> bt
0xdbf2bf4c: netbsd:ip6_input+0xc
0xdbf2bf64: netbsd:ip6intr+0x6c
0xdbf2bfac: netbsd:softint_dispatch+0xec
Bad frame pointer: 0xdb98bd34

>How-To-Repeat:
        Enable tap* devices in your kernel and
        configure tap0 and run this program.
        > ifconfig tap0 create up
        > ./a.out

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <err.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_ether.h>
#include <net/if_tap.h>

static struct ether_addr *getmyenaddr(char *);

/* total_len 0t70 (14+40+16)
  * ether 00:16:3e:00:00:01 -> 0:0:0:0:0:0 (filled later)
  * IP6 (hlim 64, next-header ICMPv6 (58) payload length: 16)
  *   2001:db8::2 > 2001:db8::1: ICMP6, echo reply, seq 0
  */
static uint8_t data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,             /* ether_dhost */
0x00, 0x16, 0x3e, 0x00, 0x00, 0x01,             /* ether_shost */
0x86, 0xdd,                                     /* ETHERTYPE_IPV6 */
0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x3a, 0x40, /* plen 16 ICMPv6 hlim 64 */
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, /* src */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, /* dst */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x81, 0x00, 0x11, 0x0c, 0x12, 0x34, 0x00, 0x00, /* echo-reply */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

int
main(int ac, char **av)
{
        int fd;
        struct ifreq ifr;
        struct ether_addr *ea;

        if ((fd = open("/dev/tap0", O_RDWR, 0)) < 0)
                err(1, "tapopen");

        memset(&ifr, 0, sizeof ifr);
        if (ioctl(fd, TAPGIFNAME, &ifr) != 0)
                err(1, "TAPGIFNAME");

        if ((ea = getmyenaddr(ifr.ifr_name)) == NULL)
                err(1, "getmyenaddr");
        memcpy(&data[0], ea, ETHER_ADDR_LEN);
        printf("writing data %p len %zd to %s (%s)\n",
            data, sizeof data, ifr.ifr_name, ether_ntoa(ea));
        fflush(stdout);
        usleep(100000);

        write(fd, data, sizeof data);

        close(fd);
}

static struct ether_addr *
getmyenaddr(char *ifname)
{
        struct ifaddrs *ifap0, *ifap;
        struct ether_addr *ea = NULL;
        static struct ether_addr ea0;

        if (getifaddrs(&ifap0) == -1) {
                perror("getifaddrs");
                return NULL;
        }

        for (ifap = ifap0; ifap; ifap = ifap->ifa_next) {
                if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ))
                        continue;
                if (ifap->ifa_addr->sa_family != AF_LINK)
                        continue;
                ea = (struct ether_addr *)
                    LLADDR((struct sockaddr_dl *)ifap->ifa_addr);
                memcpy(&ea0, ea, sizeof(ea0));
                freeifaddrs(ifap0);
                return &ea0;
        }
        freeifaddrs(ifap0);
        return NULL;
}
__EOF__

>Fix:
        To avoid this issue, comment out __NO_STRICT_ALIGNMENT in types.h.

        Is it a good idea that tap_dev_write() puts data on mbuf
        ETHER_ALIGN (2) bytes later for padding and do m_adj(m, 2) ?

-- 
t-hash



Home | Main Index | Thread Index | Old Index