Sashiko reported that if ___neigh_create() is called outside of
RCU, it could create a new entry for dev in a different netns
while __dev_change_net_namespace() is running concurrently:
creator
ipv6_neigh_create(dev, ...)
tbl = nd_table(dev_net(dev)) <- old netns
<preempted>
__dev_change_net_namespace()
NETDEV_UNREGISTER
rcu_barrier()
dev_net_set(dev, new_net)
NETDEV_REGISTER <- new in6_dev
creator resumes
neigh_create(old_tbl, ...)
ndisc_constructor()
in6_dev_get(dev) <- new in6_dev, live parms
Let's check n->parms->tbl under tbl->lock.
Fixes: cda2962b6e2b ("neighbour: Namespacify neigh_tables.")
Reported-by: netdev-bot+sashiko@kernel.org
Closes: https://lore.kernel.org/netdev/179090663305.434549.17214258093385242325@kernel.org/ (local)
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/core/neighbour.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0d883c043956..90335895b415 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -690,7 +690,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey,
hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
- if (n->parms->dead) {
+ if (n->parms->dead || n->parms->tbl != tbl) {
rc = ERR_PTR(-EINVAL);
goto out_tbl_unlock;
}--
2.56.0.rc1.315.gc6ed9934b7-goog