ndisc_snoop: Avoid misaligned read of IPv6 address

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>
This commit is contained in:
Jouni Malinen 2015-07-07 15:51:05 +03:00
parent e9ed7d9898
commit cf6fd19b34

View file

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