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
1 changed files with 15 additions and 10 deletions

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 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;