[PATCH net] vlan: prevent unsigned underflow in VLAN MTU calculation over MACsec
From: Yizhou Zhao
Date: Fri May 29 2026 - 02:27:16 EST
When a VLAN device is created on top of a MACsec device (where
`netif_reduces_vlan_mtu()` returns true) and the underlying device's MTU
is smaller than `VLAN_HLEN` (4 bytes), subtracting `VLAN_HLEN` from the
device MTU can underflow an unsigned integer. This wraps `max_mtu` to a
value near `UINT_MAX`, bypassing MTU checks and allowing an invalidly
large MTU on the VLAN device.
The same underflow exists in `vlan_newlink()` where the ternary
expression `real_dev->mtu - VLAN_HLEN` can wrap if the real device's MTU
is smaller than `VLAN_HLEN`.
Fix both locations by first verifying that `real_dev->mtu >= VLAN_HLEN`
before performing the subtraction. If the underlying device's MTU is too
small, return an appropriate error:
- `vlan_dev_change_mtu()`: return `-ERANGE`
- `vlan_newlink()`: return `-EINVAL`
This ensures no invalid MTU values are set on VLAN devices when the
underlying MACsec device is too small.
Fixes: 18d3df3eab23 ("vlan: use a valid default mtu value for vlan over macsec")
Reported-by: Yizhou Zhao <zhaoyz24@xxxxxxxxxxxxxxxxxxxxx>
Reported-by: Yuxiang Yang <yangyx22@xxxxxxxxxxxxxxxxxxxxx>
Reported-by: Ao Wang <wangao@xxxxxxxxxx>
Reported-by: Xuewei Feng <fengxw06@xxxxxxx>
Reported-by: Qi Li <qli01@xxxxxxxxxxxxxxx>
Reported-by: Ke Xu <xuke@xxxxxxxxxxxxxxx>
Assisted-by: GLM:GLM-5.1
---
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index c40f7d5..19c838c 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -145,8 +145,11 @@ static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
unsigned int max_mtu = real_dev->mtu;
- if (netif_reduces_vlan_mtu(real_dev))
+ if (netif_reduces_vlan_mtu(real_dev)) {
+ if (max_mtu < VLAN_HLEN)
+ return -ERANGE;
+ max_mtu -= VLAN_HLEN;
+ }
if (max_mtu < new_mtu)
return -ERANGE;
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index a000b1e..52a47d2 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -178,8 +178,13 @@ static int vlan_newlink(struct net_device *dev,
if (err < 0)
return err;
- max_mtu = netif_reduces_vlan_mtu(real_dev) ? real_dev->mtu - VLAN_HLEN :
- real_dev->mtu;
+ if (netif_reduces_vlan_mtu(real_dev)) {
+ if (real_dev->mtu < VLAN_HLEN)
+ return -EINVAL;
+ max_mtu = real_dev->mtu - VLAN_HLEN;
+ } else {
+ max_mtu = real_dev->mtu;
+ }
if (!tb[IFLA_MTU])
dev->mtu = max_mtu;
else if (dev->mtu > max_mtu)
dev->mtu = max_mtu;