* [PATCH net v4 1/2] vxlan: reject adding a remote to a nexthop fdb entry
@ 2026-10-27 10:47 Henry Martin
2026-10-27 10:47 ` [PATCH net v4 2/2] vxlan: reject VNI add when the default fdb entry is nexthop-backed Henry Martin
0 siblings, 1 reply; 2+ messages in thread
From: Henry Martin @ 2026-10-27 10:47 UTC (permalink / raw)
To: Ido Schimmel, Ilya Maximets, David S . Miller, Jakub Kicinski,
Eric Dumazet, Paolo Abeni, Andrew Lunn, Simon Horman,
Kuniyuki Iwashima, Petr Machata, Ferruh Yigit, Antoine Tenart,
Seungwon Bae
Cc: netdev, linux-kernel, Henry Martin, stable
FDB entries backed by a nexthop group must not carry a remote
destination list. vxlan_fdb_update_existing() currently appends a
remote via vxlan_fdb_append() on an NLM_F_APPEND request with a
multicast or zero MAC even when the entry is backed by a nexthop,
breaking that invariant through three different callers:
- "bridge fdb append" with a dst on a nexthop entry;
- "ip link set dev vx0 type vxlan remote <ip>" (vxlan_changelink());
- "bridge vni add" on a vnifilter device
(vxlan_update_default_fdb_entry()); this includes a plain
"bridge vni add vni N" without a group, which falls back to the
device's default remote, and a unicast group.
All three reach the append block with nhid == 0 and a PERMANENT
state, so they pass the earlier nexthop checks.
There is no crash and no leak: the appended remote is freed with the
entry, and the transmit path ignores it (vxlan_xmit() follows the
nexthop whenever f->nh is set). But the stray remote changes
deletion semantics: __vxlan_fdb_delete() destroys the whole fdb entry
when the matched remote is the only one on the list, so removing it
via "bridge fdb del ... dst <remote>" or "ip link set ... remote
0.0.0.0" tears down the nexthop entry, not just the stray remote.
The entry state is also misreported: vxlan_fdb_notify(), RTM_GETNEIGH
dumps and the switchdev FDB programming all prefer the remote list
over the nexthop, so user space sees the dead remote while the
datapath follows the nexthop group.
Reject the combination at the top of vxlan_fdb_update_existing(),
next to the existing nexthop guards, so a refused request has no side
effects.
Also move the non-unicast NLM_F_REPLACE rejection to the same place;
it previously returned -EOPNOTSUPP only after the entry state and
flags had been rewritten, skipping both the notification pass and
the err_notify rollback.
Note the resulting behavior change for the rtnetlink callers:
operations that previously succeeded while silently attaching a
remote to a nexthop entry now fail with extack
"Cannot add a remote to a nexthop fdb entry".
Add test cases to fib_nexthops.sh in the same fashion as the sibling
fix, commit 98fc57d16744 ("vxlan: reject dynamic fdb entries that
reference a nexthop id").
This issue was discovered by Tencent CodeBuddy Security.
Cc: stable@vger.kernel.org
Fixes: 1274e1cc4226 ("vxlan: ecmp support for mac fdb entries")
Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
---
v4: Also move the non-unicast REPLACE rejection before the entry is
modified (the same half-update class, pre-existing), describe the
stray remote's effect on __vxlan_fdb_delete() instead of calling
it "unused", and note that a plain "bridge vni add" or a unicast
group hits the check too (sashiko review of v2).
v3: Describe the actual consequence and add fib_nexthops.sh test
cases as requested by Ilya Maximets.
v2: Move the check before the entry state/flags update, next to the
other nexthop guards (reported by sashiko, confirmed by Jakub).
drivers/net/vxlan/vxlan_core.c | 26 +++++++++++++--------------
tools/testing/selftests/net/fib_nexthops.sh | 18 ++++++++++++++++++
2 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 3390e341d1e58..13143085065f6 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1002,6 +1016,22 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
return -EOPNOTSUPP;
}
+ if (rcu_access_pointer(f->nh) &&
+ (flags & NLM_F_APPEND) &&
+ (is_multicast_ether_addr(f->key.eth_addr) ||
+ is_zero_ether_addr(f->key.eth_addr))) {
+ NL_SET_ERR_MSG(extack,
+ "Cannot add a remote to a nexthop fdb entry");
+ return -EOPNOTSUPP;
+ }
+
+ if ((flags & NLM_F_REPLACE) &&
+ (is_multicast_ether_addr(f->key.eth_addr) ||
+ is_zero_ether_addr(f->key.eth_addr))) {
+ NL_SET_ERR_MSG(extack, "Cannot replace non-unicast fdb entries");
+ return -EOPNOTSUPP;
+ }
+
/* Do not allow an externally learned entry to take over an entry added
* by the user.
*/
@@ -1018,22 +1048,18 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
}
if ((flags & NLM_F_REPLACE)) {
- /* Only change unicasts */
- if (!(is_multicast_ether_addr(f->key.eth_addr) ||
- is_zero_ether_addr(f->key.eth_addr))) {
- if (nhid) {
- rc = vxlan_fdb_nh_update(vxlan, f, nhid, extack);
- if (rc < 0)
- return rc;
- } else {
- rc = vxlan_fdb_replace(f, ip, port, vni,
- ifindex, &oldrd);
- }
- notify |= rc;
+ /* Only change unicasts; non-unicast replace is rejected
+ * before any state is modified.
+ */
+ if (nhid) {
+ rc = vxlan_fdb_nh_update(vxlan, f, nhid, extack);
+ if (rc < 0)
+ return rc;
} else {
- NL_SET_ERR_MSG(extack, "Cannot replace non-unicast fdb entries");
- return -EOPNOTSUPP;
+ rc = vxlan_fdb_replace(f, ip, port, vni,
+ ifindex, &oldrd);
}
+ notify |= rc;
}
if ((flags & NLM_F_APPEND) &&
(is_multicast_ether_addr(f->key.eth_addr) ||
diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
index 431d7bed76224..bdc23205bde4c 100755
--- a/tools/testing/selftests/net/fib_nexthops.sh
+++ b/tools/testing/selftests/net/fib_nexthops.sh
@@ -547,6 +547,15 @@ ipv6_fdb_grp_fcnal()
run_cmd "$BRIDGE fdb append 02:02:00:00:00:17 dev vx10 dst 2001:db8:91::11 self dynamic"
log_test $? 255 "Fdb mac append with nexthop group and dynamic state"
+ # fdb entries with a nexthop group cannot take a remote append
+ run_cmd "$BRIDGE fdb add 00:00:00:00:00:00 dev vx10 nhid 102 self static"
+ run_cmd "$BRIDGE fdb append 00:00:00:00:00:00 dev vx10 dst 2001:db8:91::11 self"
+ log_test $? 255 "Fdb append with nexthop group"
+
+ # fdb entries with a nexthop group cannot be replaced with a non-unicast MAC
+ run_cmd "$BRIDGE fdb replace 00:00:00:00:00:00 dev vx10 dst 2001:db8:91::11 self permanent"
+ log_test $? 255 "Fdb replace with nexthop group"
+
run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 66"
log_test $? 2 "Route add with fdb nexthop"
@@ -697,6 +706,15 @@ ipv4_fdb_grp_fcnal()
run_cmd "$BRIDGE fdb append 02:02:00:00:00:17 dev vx10 dst 10.0.0.3 self dynamic"
log_test $? 255 "Fdb mac append with nexthop group and dynamic state"
+ # fdb entries with a nexthop group cannot take a remote append
+ run_cmd "$BRIDGE fdb add 00:00:00:00:00:00 dev vx10 nhid 102 self static"
+ run_cmd "$BRIDGE fdb append 00:00:00:00:00:00 dev vx10 dst 10.0.0.3 self"
+ log_test $? 255 "Fdb append with nexthop group"
+
+ # fdb entries with a nexthop group cannot be replaced with a non-unicast MAC
+ run_cmd "$BRIDGE fdb replace 00:00:00:00:00:00 dev vx10 dst 10.0.0.3 self permanent"
+ log_test $? 255 "Fdb replace with nexthop group"
+
run_cmd "$IP ro add 172.16.0.0/22 nhid 16"
log_test $? 2 "Route add with fdb nexthop"
--
2.43.7
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH net v4 2/2] vxlan: reject VNI add when the default fdb entry is nexthop-backed
2026-10-27 10:47 [PATCH net v4 1/2] vxlan: reject adding a remote to a nexthop fdb entry Henry Martin
@ 2026-10-27 10:47 ` Henry Martin
0 siblings, 0 replies; 2+ messages in thread
From: Henry Martin @ 2026-10-27 10:47 UTC (permalink / raw)
To: Ido Schimmel, Ilya Maximets, David S . Miller, Jakub Kicinski,
Eric Dumazet, Paolo Abeni, Andrew Lunn, Simon Horman,
Kuniyuki Iwashima, Petr Machata, Ferruh Yigit, Antoine Tenart,
Seungwon Bae
Cc: netdev, linux-kernel, Henry Martin, stable
vxlan_vni_add() installs the new VNI - hash table insert, group list,
socket attach and the RTM_NEWTUNNEL notification - before calling
vxlan_vni_update_group(), which in turn calls
vxlan_update_default_fdb_entry() to store the group (or the device's
default remote) into the all-zeros fdb entry of that VNI.
Now that vxlan_fdb_update_existing() rejects appending a remote to a
nexthop-backed default entry, the group store can fail with
-EOPNOTSUPP after the VNI has already been installed and announced,
leaving it half-installed: present in the tables and announced, but
with no remote stored and no multicast join.
Check whether the default fdb entry for the VNI is backed by a
nexthop before installing the VNI, and reject the add up front.
Note: the missing unwind in vxlan_vni_add() predates this series;
this check avoids giving user space a deterministic way to reach it.
Cc: stable@vger.kernel.org
Fixes: 1274e1cc4226 ("vxlan: ecmp support for mac fdb entries")
Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
---
v4: new patch; the failure path was made reachable by patch 1, so
guard it before the VNI is installed (sashiko review of v2).
drivers/net/vxlan/vxlan_core.c | 14 ++++++++++++++
drivers/net/vxlan/vxlan_private.h | 2 ++
drivers/net/vxlan/vxlan_vnifilter.c | 14 ++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 3390e341d1e58..13143085065f6 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -422,6 +422,20 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
return f;
}
+bool vxlan_fdb_entry_nh_backed(struct vxlan_dev *vxlan, const u8 *mac,
+ __be32 vni)
+{
+ struct vxlan_fdb *f;
+ bool ret;
+
+ spin_lock_bh(&vxlan->hash_lock);
+ f = vxlan_find_mac(vxlan, mac, vni);
+ ret = f && rcu_access_pointer(f->nh);
+ spin_unlock_bh(&vxlan->hash_lock);
+
+ return ret;
+}
+
/* caller should hold vxlan->hash_lock */
static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
union vxlan_addr *ip, __be16 port,
diff --git a/drivers/net/vxlan/vxlan_private.h b/drivers/net/vxlan/vxlan_private.h
index b1eec22163608..0454689965aeb 100644
--- a/drivers/net/vxlan/vxlan_private.h
+++ b/drivers/net/vxlan/vxlan_private.h
@@ -11,6 +11,8 @@
extern unsigned int vxlan_net_id;
extern const u8 all_zeros_mac[ETH_ALEN + 2];
+bool vxlan_fdb_entry_nh_backed(struct vxlan_dev *vxlan,
+ const u8 *mac, __be32 vni);
extern const struct rhashtable_params vxlan_vni_rht_params;
#define PORT_HASH_BITS 8
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index dd94085e08865..f07ae2a6a59ed 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -737,6 +737,20 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan,
return err;
}
+ /* A default fdb entry that is backed by a nexthop group can
+ * never take a remote; reject before the VNI is installed,
+ * otherwise a failure in vxlan_vni_update_group() would leave
+ * the VNI half-installed.
+ */
+ if ((group && !vxlan_addr_any(group)) ||
+ !vxlan_addr_any(&vxlan->cfg.remote_ip)) {
+ if (vxlan_fdb_entry_nh_backed(vxlan, all_zeros_mac, v)) {
+ NL_SET_ERR_MSG(extack,
+ "Cannot add a remote to a nexthop fdb entry");
+ return -EOPNOTSUPP;
+ }
+ }
+
vninode = vxlan_vni_alloc(vxlan, v);
if (!vninode)
return -ENOMEM;
--
2.43.7
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-27 10:47 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-27 10:47 [PATCH net v4 1/2] vxlan: reject adding a remote to a nexthop fdb entry Henry Martin
2026-10-27 10:47 ` [PATCH net v4 2/2] vxlan: reject VNI add when the default fdb entry is nexthop-backed Henry Martin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®