Use neighbour lock when copying MAC address from neighbour data struct in dst_fetch_ha. When not using the lock, it is possible for the function to race with neigh_update, causing it to copy an invalid MAC address. It is possible to provoke this error by calling rdma_resolve_addr in a tight loop, while deleting the corresponding ARP entry in another tight loop. This will cause the race shown it the following sample trace: rdma_resolve_addr() rdma_resolve_ip() addr_resolve() addr_resolve_neigh() fetch_ha() dst_fetch_ha() n->nud_state == NUD_VALID and net_ioctl() arp_ioctl() arp_rec_delete() arp_invalidate() neigh_update() __neigh_update() neigh->nud_state = new; Signed-off-by: Dag Moxnes <dag.moxnes@xxxxxxxxxx> Signed-off-by: Håkon Bugge <haakon.bugge@xxxxxxxxxx> Reviewed-by: Parav Pandit <parav@xxxxxxxxxxxx> --- v1 -> v2: * Modified implementation to improve readability v2 -> v3: * Added sample trace as suggested by Parav Pandit * Added Reviewed-by --- drivers/infiniband/core/addr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 2f7d141598..51323ffbc5 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -333,11 +333,14 @@ static int dst_fetch_ha(const struct dst_entry *dst, if (!n) return -ENODATA; - if (!(n->nud_state & NUD_VALID)) { + read_lock_bh(&n->lock); + if (n->nud_state & NUD_VALID) { + memcpy(dev_addr->dst_dev_addr, n->ha, MAX_ADDR_LEN); + read_unlock_bh(&n->lock); + } else { + read_unlock_bh(&n->lock); neigh_event_send(n, NULL); ret = -ENODATA; - } else { - memcpy(dev_addr->dst_dev_addr, n->ha, MAX_ADDR_LEN); } neigh_release(n); -- 2.20.1