VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46153

CVE-2026-46153

Description

In the Linux kernel, the following vulnerability has been resolved:

8021q: delete cleared egress QoS mappings

vlan_dev_set_egress_priority() currently keeps cleared egress priority mappings in the hash as tombstones. Repeated set/clear cycles with distinct skb priorities therefore accumulate mapping nodes until device teardown and leak memory.

Delete mappings when vlan_prio is cleared instead of keeping tombstones. Now that the egress mapping lists are RCU protected, the node can be unlinked safely and freed after a grace period.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A memory leak in the Linux kernel's 8021q VLAN module occurs when repeatedly setting and clearing egress QoS mappings, as cleared mappings are kept as tombstones.

Vulnerability

In the Linux kernel's 8021q VLAN module, the function vlan_dev_set_egress_priority() keeps cleared egress priority mappings in the hash as tombstones. This means that when a mapping is cleared (vlan_prio set to zero), the node is not removed from the list. Repeated set/clear cycles with distinct skb priorities accumulate mapping nodes until device teardown, leading to a memory leak. The vulnerability affects all kernel versions that include this code path; the fix is applied in commit a52e122c9e4d [1].

Exploitation

An attacker would need the ability to trigger repeated calls to vlan_dev_set_egress_priority() with distinct skb priorities, followed by clearing those mappings. This could be achieved through local access to a system with VLAN interfaces configured, or via a privileged process that can manipulate egress QoS mappings. No special network position is required beyond local user access that can interact with VLAN device configuration.

Impact

The impact is a memory leak, which over time can exhaust kernel memory, leading to system instability or denial of service. The attacker does not gain code execution or privilege escalation directly, but the leak can degrade system performance and availability.

Mitigation

The fix is included in the Linux kernel stable commit a52e122c9e4d [1]. Users should update to a kernel version containing this commit. As a workaround, avoid repeatedly setting and clearing egress priority mappings on VLAN interfaces. The vulnerability is not listed in CISA's Known Exploited Vulnerabilities (KEV) catalog as of the publication date.

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

4
7dddc74af369

8021q: delete cleared egress QoS mappings

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitLongxuan YuApr 20, 2026Fixed in 7.1-rc1via kernel-cna
2 files changed · +14 11
  • net/8021q/vlan_dev.c+14 6 modified
    diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
    index a5340932b657a6..7aa3af8b10ead0 100644
    --- a/net/8021q/vlan_dev.c
    +++ b/net/8021q/vlan_dev.c
    @@ -172,26 +172,34 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
     				 u32 skb_prio, u16 vlan_prio)
     {
     	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    +	struct vlan_priority_tci_mapping __rcu **mpp;
     	struct vlan_priority_tci_mapping *mp;
     	struct vlan_priority_tci_mapping *np;
     	u32 bucket = skb_prio & 0xF;
     	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
     
     	/* See if a priority mapping exists.. */
    -	mp = rtnl_dereference(vlan->egress_priority_map[bucket]);
    +	mpp = &vlan->egress_priority_map[bucket];
    +	mp = rtnl_dereference(*mpp);
     	while (mp) {
     		if (mp->priority == skb_prio) {
    -			if (mp->vlan_qos && !vlan_qos)
    +			if (!vlan_qos) {
    +				rcu_assign_pointer(*mpp, rtnl_dereference(mp->next));
     				vlan->nr_egress_mappings--;
    -			else if (!mp->vlan_qos && vlan_qos)
    -				vlan->nr_egress_mappings++;
    -			WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +				kfree_rcu(mp, rcu);
    +			} else {
    +				WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +			}
     			return 0;
     		}
    -		mp = rtnl_dereference(mp->next);
    +		mpp = &mp->next;
    +		mp = rtnl_dereference(*mpp);
     	}
     
     	/* Create a new mapping then. */
    +	if (!vlan_qos)
    +		return 0;
    +
     	np = kmalloc_obj(struct vlan_priority_tci_mapping);
     	if (!np)
     		return -ENOBUFS;
    
  • net/8021q/vlan_netlink.c+0 5 modified
    diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
    index a5b16833e2ceeb..368d53ca7d8709 100644
    --- a/net/8021q/vlan_netlink.c
    +++ b/net/8021q/vlan_netlink.c
    @@ -263,10 +263,6 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
     			for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm;
     			     pm = rcu_dereference_rtnl(pm->next)) {
     				u16 vlan_qos = READ_ONCE(pm->vlan_qos);
    -
    -				if (!vlan_qos)
    -					continue;
    -
     				m.from = pm->priority;
     				m.to   = (vlan_qos >> 13) & 0x7;
     				if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
    -- 
    cgit 1.3-korg
    
    
    
a52e122c9e4d

8021q: delete cleared egress QoS mappings

2 files changed · +14 11
  • net/8021q/vlan_dev.c+14 6 modified
    diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
    index a5340932b657a6..7aa3af8b10ead0 100644
    --- a/net/8021q/vlan_dev.c
    +++ b/net/8021q/vlan_dev.c
    @@ -172,26 +172,34 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
     				 u32 skb_prio, u16 vlan_prio)
     {
     	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    +	struct vlan_priority_tci_mapping __rcu **mpp;
     	struct vlan_priority_tci_mapping *mp;
     	struct vlan_priority_tci_mapping *np;
     	u32 bucket = skb_prio & 0xF;
     	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
     
     	/* See if a priority mapping exists.. */
    -	mp = rtnl_dereference(vlan->egress_priority_map[bucket]);
    +	mpp = &vlan->egress_priority_map[bucket];
    +	mp = rtnl_dereference(*mpp);
     	while (mp) {
     		if (mp->priority == skb_prio) {
    -			if (mp->vlan_qos && !vlan_qos)
    +			if (!vlan_qos) {
    +				rcu_assign_pointer(*mpp, rtnl_dereference(mp->next));
     				vlan->nr_egress_mappings--;
    -			else if (!mp->vlan_qos && vlan_qos)
    -				vlan->nr_egress_mappings++;
    -			WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +				kfree_rcu(mp, rcu);
    +			} else {
    +				WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +			}
     			return 0;
     		}
    -		mp = rtnl_dereference(mp->next);
    +		mpp = &mp->next;
    +		mp = rtnl_dereference(*mpp);
     	}
     
     	/* Create a new mapping then. */
    +	if (!vlan_qos)
    +		return 0;
    +
     	np = kmalloc_obj(struct vlan_priority_tci_mapping);
     	if (!np)
     		return -ENOBUFS;
    
  • net/8021q/vlan_netlink.c+0 5 modified
    diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
    index a5b16833e2ceeb..368d53ca7d8709 100644
    --- a/net/8021q/vlan_netlink.c
    +++ b/net/8021q/vlan_netlink.c
    @@ -263,10 +263,6 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
     			for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm;
     			     pm = rcu_dereference_rtnl(pm->next)) {
     				u16 vlan_qos = READ_ONCE(pm->vlan_qos);
    -
    -				if (!vlan_qos)
    -					continue;
    -
     				m.from = pm->priority;
     				m.to   = (vlan_qos >> 13) & 0x7;
     				if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
    -- 
    cgit 1.3-korg
    
    
    
7dddc74af369

8021q: delete cleared egress QoS mappings

2 files changed · +14 11
  • net/8021q/vlan_dev.c+14 6 modified
    diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
    index a5340932b657a6..7aa3af8b10ead0 100644
    --- a/net/8021q/vlan_dev.c
    +++ b/net/8021q/vlan_dev.c
    @@ -172,26 +172,34 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
     				 u32 skb_prio, u16 vlan_prio)
     {
     	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    +	struct vlan_priority_tci_mapping __rcu **mpp;
     	struct vlan_priority_tci_mapping *mp;
     	struct vlan_priority_tci_mapping *np;
     	u32 bucket = skb_prio & 0xF;
     	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
     
     	/* See if a priority mapping exists.. */
    -	mp = rtnl_dereference(vlan->egress_priority_map[bucket]);
    +	mpp = &vlan->egress_priority_map[bucket];
    +	mp = rtnl_dereference(*mpp);
     	while (mp) {
     		if (mp->priority == skb_prio) {
    -			if (mp->vlan_qos && !vlan_qos)
    +			if (!vlan_qos) {
    +				rcu_assign_pointer(*mpp, rtnl_dereference(mp->next));
     				vlan->nr_egress_mappings--;
    -			else if (!mp->vlan_qos && vlan_qos)
    -				vlan->nr_egress_mappings++;
    -			WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +				kfree_rcu(mp, rcu);
    +			} else {
    +				WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +			}
     			return 0;
     		}
    -		mp = rtnl_dereference(mp->next);
    +		mpp = &mp->next;
    +		mp = rtnl_dereference(*mpp);
     	}
     
     	/* Create a new mapping then. */
    +	if (!vlan_qos)
    +		return 0;
    +
     	np = kmalloc_obj(struct vlan_priority_tci_mapping);
     	if (!np)
     		return -ENOBUFS;
    
  • net/8021q/vlan_netlink.c+0 5 modified
    diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
    index a5b16833e2ceeb..368d53ca7d8709 100644
    --- a/net/8021q/vlan_netlink.c
    +++ b/net/8021q/vlan_netlink.c
    @@ -263,10 +263,6 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
     			for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm;
     			     pm = rcu_dereference_rtnl(pm->next)) {
     				u16 vlan_qos = READ_ONCE(pm->vlan_qos);
    -
    -				if (!vlan_qos)
    -					continue;
    -
     				m.from = pm->priority;
     				m.to   = (vlan_qos >> 13) & 0x7;
     				if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
    -- 
    cgit 1.3-korg
    
    
    
a52e122c9e4d

8021q: delete cleared egress QoS mappings

2 files changed · +14 11
  • net/8021q/vlan_dev.c+14 6 modified
    diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
    index a5340932b657a6..7aa3af8b10ead0 100644
    --- a/net/8021q/vlan_dev.c
    +++ b/net/8021q/vlan_dev.c
    @@ -172,26 +172,34 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
     				 u32 skb_prio, u16 vlan_prio)
     {
     	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    +	struct vlan_priority_tci_mapping __rcu **mpp;
     	struct vlan_priority_tci_mapping *mp;
     	struct vlan_priority_tci_mapping *np;
     	u32 bucket = skb_prio & 0xF;
     	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
     
     	/* See if a priority mapping exists.. */
    -	mp = rtnl_dereference(vlan->egress_priority_map[bucket]);
    +	mpp = &vlan->egress_priority_map[bucket];
    +	mp = rtnl_dereference(*mpp);
     	while (mp) {
     		if (mp->priority == skb_prio) {
    -			if (mp->vlan_qos && !vlan_qos)
    +			if (!vlan_qos) {
    +				rcu_assign_pointer(*mpp, rtnl_dereference(mp->next));
     				vlan->nr_egress_mappings--;
    -			else if (!mp->vlan_qos && vlan_qos)
    -				vlan->nr_egress_mappings++;
    -			WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +				kfree_rcu(mp, rcu);
    +			} else {
    +				WRITE_ONCE(mp->vlan_qos, vlan_qos);
    +			}
     			return 0;
     		}
    -		mp = rtnl_dereference(mp->next);
    +		mpp = &mp->next;
    +		mp = rtnl_dereference(*mpp);
     	}
     
     	/* Create a new mapping then. */
    +	if (!vlan_qos)
    +		return 0;
    +
     	np = kmalloc_obj(struct vlan_priority_tci_mapping);
     	if (!np)
     		return -ENOBUFS;
    
  • net/8021q/vlan_netlink.c+0 5 modified
    diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
    index a5b16833e2ceeb..368d53ca7d8709 100644
    --- a/net/8021q/vlan_netlink.c
    +++ b/net/8021q/vlan_netlink.c
    @@ -263,10 +263,6 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
     			for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm;
     			     pm = rcu_dereference_rtnl(pm->next)) {
     				u16 vlan_qos = READ_ONCE(pm->vlan_qos);
    -
    -				if (!vlan_qos)
    -					continue;
    -
     				m.from = pm->priority;
     				m.to   = (vlan_qos >> 13) & 0x7;
     				if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing deletion of egress priority mapping nodes when the VLAN priority is cleared, causing tombstone nodes to accumulate and leak memory."

Attack vector

An attacker with the ability to set and clear VLAN egress priority mappings (e.g., via netlink `IFLA_VLAN_QOS_MAPPING` operations) can repeatedly call `vlan_dev_set_egress_priority()` with distinct `skb_prio` values and a zero `vlan_prio`. Before the fix, each clear operation left a "tombstone" node in the hash list instead of removing it. Repeated set/clear cycles with different `skb_prio` values accumulate these nodes, causing a memory leak that persists until the VLAN device is torn down [patch_id=2898239].

Affected code

The vulnerability is in `net/8021q/vlan_dev.c`, function `vlan_dev_set_egress_priority()`. The egress priority mappings are stored in a hash table (`vlan->egress_priority_map[]`) as a linked list of `vlan_priority_tci_mapping` nodes. A secondary change in `net/8021q/vlan_netlink.c` removes a skip of zero-QoS entries in `vlan_fill_info()`.

What the fix does

The patch modifies `vlan_dev_set_egress_priority()` in `net/8021q/vlan_dev.c` to delete the mapping node when `vlan_prio` is cleared (zero). When a matching node is found and `vlan_qos` is zero, the node is unlinked from the list via `rcu_assign_pointer(*mpp, rtnl_dereference(mp->next))` and freed with `kfree_rcu(mp, rcu)`. Additionally, a new early-return guard (`if (!vlan_qos) return 0;`) prevents allocation of a new node when the caller is trying to clear a non-existent mapping. The change in `net/8021q/vlan_netlink.c` removes the `if (!vlan_qos) continue;` skip, since zero-QoS entries no longer exist in the list [patch_id=2898239].

Preconditions

  • authThe attacker must be able to issue netlink commands to set/clear VLAN egress priority mappings on a VLAN netdevice.
  • inputThe attacker must be able to specify distinct skb_priority values across repeated operations to accumulate nodes.

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.