CVE-2026-46323
Description
Linux kernel GRO vulnerability allows UAF by mishandling zerocopy skbs, potentially leading to system instability.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Linux kernel GRO vulnerability allows UAF by mishandling zerocopy skbs, potentially leading to system instability.
Vulnerability
The Linux kernel's Generic Receive Offload (GRO) functionality contains a vulnerability where skb_gro_receive() can copy fragments between source and GRO skbs without checking the zerocopy status or the SKBFL_MANAGED_FRAG_REFS flag. This can occur when either the last skb in the GRO chain or the source skb is zerocopy. Affected versions are not explicitly listed but the fix is present in the provided kernel commits.
Exploitation
An attacker could exploit this vulnerability by sending specially crafted network packets that trigger the GRO merging logic. If the conditions involving zerocopy skbs and the SKBFL_MANAGED_FRAG_REFS flag are met, the kernel may attempt to merge skbs without properly managing page reference counts.
Impact
Successful exploitation can lead to a Use-After-Free (UAF) condition. This UAF vulnerability can result in system instability, crashes, and potentially allow an attacker to gain elevated privileges or execute arbitrary code within the kernel context.
Mitigation
The vulnerability has been resolved in the Linux kernel. The fix involves ensuring that zerocopy skbs are not merged when the SKBFL_MANAGED_FRAG_REFS flag is set. Users should update to a kernel version containing the fix, which is available in the commits referenced [1][2][3][4]. No workarounds are described, and the EOL status or KEV listing are not mentioned in the available references.
AI Insight generated on Jun 9, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
101f9c82855641net: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 0a9d4a3bb104d..1555e6bb5c9d7 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -110,6 +110,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
479084ae0e1dnet: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index f5c80c2f69df7..e4cebf162efb7 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -108,6 +108,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
e334cbf3388fnet: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 867611d171dbb..b5f790a643d49 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -109,6 +109,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
44bea2032af0net: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 9f8960789b2cf..a847539834679 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -109,6 +109,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
4db79a322db8net: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 9f8960789b2cf..a847539834679 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -109,6 +109,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
1f9c82855641net: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 0a9d4a3bb104d..1555e6bb5c9d7 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -110,6 +110,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
44bea2032af0net: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 9f8960789b2cf..a847539834679 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -109,6 +109,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
479084ae0e1dnet: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index f5c80c2f69df7..e4cebf162efb7 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -108,6 +108,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
4db79a322db8net: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 9f8960789b2cf..a847539834679 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -109,6 +109,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
e334cbf3388fnet: gro: don't merge zcopy skbs
1 file changed · +3 −1
net/core/gro.c+3 −1 modifieddiff --git a/net/core/gro.c b/net/core/gro.c index 867611d171dbb..b5f790a643d49 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -109,6 +109,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) if (p->pp_recycle != skb->pp_recycle) return -ETOOMANYREFS; + if (skb_zcopy(p) || skb_zcopy(skb)) + return -ETOOMANYREFS; + if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || NAPI_GRO_CB(skb)->flush)) return -E2BIG; -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"The skb_gro_receive function incorrectly merges "zerocopy" skbs without properly managing page reference counts, leading to a use-after-free."
Attack vector
An attacker can trigger this vulnerability by sending specially crafted network packets that are processed by the GRO (Generic Receive Offload) mechanism. The function `skb_gro_receive` is called during this process. If either the GRO skb or the source skb is a "zerocopy" skb, and the SKBFL_MANAGED_FRAG_REFS flag is set, the vulnerability can be triggered.
Affected code
The vulnerability exists within the `skb_gro_receive` function in `net/core/gro.c`. Specifically, the code path that copies fragments between skbs without checking their zerocopy status is at fault. The fix introduces a check for zerocopy status before proceeding with the merge operation [patch_id=5354487].
What the fix does
The patch adds a check at the beginning of the `skb_gro_receive` function to determine if either the GRO skb (`p`) or the incoming skb (`skb`) is a zerocopy skb using `skb_zcopy()`. If either is true, the function returns early with an error code, preventing the merge operation. This stops the incorrect copying of fragments from zerocopy skbs, thereby avoiding the potential use-after-free condition by ensuring page reference counts are not mishandled [patch_id=5354487].
Preconditions
- configThe network interface must support and have GRO enabled.
- inputSpecially crafted network packets that trigger the GRO processing.
Generated on Jun 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/1f9c828556416fbe3f49386708ce999fc4d4da06nvd
- git.kernel.org/stable/c/44bea2032af0425e4ce6d26a8af0ede79db49ec1nvd
- git.kernel.org/stable/c/479084ae0e1d9cb7929cb4298d35623de189f80anvd
- git.kernel.org/stable/c/4db79a322db8c97f7b73b8a347395ef4d685eb40nvd
- git.kernel.org/stable/c/e334cbf3388fd9334503a778a82d9e9f14dd2f71nvd
News mentions
1- Linux Kernel: 25 Vulnerabilities Disclosed in Single Batch on June 8-9, 2026Vypr Intelligence · Jun 9, 2026