]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
ndisc_snoop: Avoid misaligned read of IPv6 address
authorJouni Malinen <j@w1.fi>
Tue, 7 Jul 2015 12:51:05 +0000 (15:51 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 7 Jul 2015 13:25:06 +0000 (16:25 +0300)
The IPv6 address in the frame buffer may not be 32-bit aligned, so use a
local copy to align this before reading the address with 32-bit reads
(s6_addr32[]).

Signed-off-by: Jouni Malinen <j@w1.fi>
src/ap/ndisc_snoop.c

index 0adcc97d702a084f9b4d52cac3fd849acec33437..4a87721e2ecfce3f65e070c3fd3e22077f3f2cab 100644 (file)
@@ -98,7 +98,7 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
 {
        struct hostapd_data *hapd = ctx;
        struct icmpv6_ndmsg *msg;
-       struct in6_addr *saddr;
+       struct in6_addr saddr;
        struct sta_info *sta;
        int res;
        char addrtxt[INET6_ADDRSTRLEN + 1];
@@ -113,25 +113,30 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
                if (msg->opt_type != SOURCE_LL_ADDR)
                        return;
 
-               saddr = &msg->ipv6h.ip6_src;
-               if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
-                     saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
+               /*
+                * IPv6 header may not be 32-bit aligned in the buffer, so use
+                * a local copy to avoid unaligned reads.
+                */
+               os_memcpy(&saddr, &msg->ipv6h.ip6_src, sizeof(saddr));
+               if (!(saddr.s6_addr32[0] == 0 && saddr.s6_addr32[1] == 0 &&
+                     saddr.s6_addr32[2] == 0 && saddr.s6_addr32[3] == 0)) {
                        if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
                                return;
                        sta = ap_get_sta(hapd, msg->opt_lladdr);
                        if (!sta)
                                return;
 
-                       if (sta_has_ip6addr(sta, saddr))
+                       if (sta_has_ip6addr(sta, &saddr))
                                return;
 
-                       if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
-                           == NULL)
+                       if (inet_ntop(AF_INET6, &saddr, addrtxt,
+                                     sizeof(addrtxt)) == NULL)
                                addrtxt[0] = '\0';
                        wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
                                   MACSTR, addrtxt, MAC2STR(sta->addr));
-                       hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
-                       res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
+                       hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &saddr);
+                       res = hostapd_drv_br_add_ip_neigh(hapd, 6,
+                                                         (u8 *) &saddr,
                                                          128, sta->addr);
                        if (res) {
                                wpa_printf(MSG_ERROR,
@@ -140,7 +145,7 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
                                return;
                        }
 
-                       if (sta_ip6addr_add(sta, saddr))
+                       if (sta_ip6addr_add(sta, &saddr))
                                return;
                }
                break;