1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

gnrc_ipv6_nib: fix acquire race on gnrc_ipv6_nib_get_next_hop_l2addr()

When two threads use `gnrc_ipv6_nib_get_next_hop_l2addr()` to determine
a next hop (e.g. when there is both an IPv6 sender and a 6LoWPAN
fragment forwarder), a race condition may happen, where one thread
acquires the NIB and the other acquires the network interface resulting
in a deadlock. By releasing the NIB (if acquired) before trying to
acquire the network interface and re-acquiring the NIB after the network
interface is acquired, this is fixed.
This commit is contained in:
Martine Lenders 2021-05-05 17:48:24 +02:00
parent 6e4434a760
commit 4b4eaf3b76
No known key found for this signature in database
GPG Key ID: CCD317364F63286F

View File

@ -186,6 +186,18 @@ static bool _on_link(const ipv6_addr_t *dst, unsigned *iface)
return ipv6_addr_is_link_local(dst);
}
static gnrc_netif_t *_acquire_new_iface(unsigned iface)
{
gnrc_netif_t *netif = gnrc_netif_get_by_pid(iface);
/* release NIB, in case other thread calls a NIB function while we wait for
* the netif */
_nib_release();
gnrc_netif_acquire(netif);
/* re-acquire NIB */
_nib_acquire();
return netif;
}
int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
gnrc_netif_t *netif, gnrc_pktsnip_t *pkt,
gnrc_ipv6_nib_nc_t *nce)
@ -208,10 +220,9 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
/* on-link prefixes return their interface */
if (!ipv6_addr_is_link_local(dst) && (iface != 0)) {
/* release preassumed interface */
/* release pre-assumed netif */
gnrc_netif_release(netif);
netif = gnrc_netif_get_by_pid(iface);
gnrc_netif_acquire(netif);
netif = _acquire_new_iface(iface);
}
if ((netif == NULL) ||
!_resolve_addr(dst, netif, pkt, nce, node)) {
@ -259,13 +270,12 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
}
}
if ((netif != NULL) && (netif->pid != (int)route.iface)) {
/* drop pre-assumed netif */
/* release pre-assumed netif */
gnrc_netif_release(netif);
}
if ((netif == NULL) || (netif->pid != (int)route.iface)) {
/* get actual netif */
netif = gnrc_netif_get_by_pid(route.iface);
gnrc_netif_acquire(netif);
netif = _acquire_new_iface(route.iface);
}
node = _nib_onl_get(&route.next_hop,
(netif != NULL) ? netif->pid : 0);