CVE-2026-46322
Description
Linux kernel tun module vulnerability leads to memory leaks when build_skb fails in tun_xdp_one(), potentially causing denial of service.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Linux kernel tun module vulnerability leads to memory leaks when build_skb fails in tun_xdp_one(), potentially causing denial of service.
Vulnerability
In the Linux kernel's tun module, specifically within the tun_xdp_one() function, a vulnerability exists where a page allocated for a frame is not freed when the build_skb() function fails due to an out-of-memory condition. This occurs because the function jumps to an error label without releasing the page, and the calling function vhost_net_build_xdp() proceeds as if successful, leading to a page leak for each build_skb() failure within a batch. This issue affects versions of the Linux kernel where this code path is present.
Exploitation
An attacker would need to trigger a scenario where build_skb() repeatedly fails within the tun_xdp_one() function, likely by overwhelming the system's memory resources or by crafting specific network traffic that triggers this failure path. The vulnerability is triggered when tun_sendmsg() discards per-buffer errors and returns success, allowing vhost_tx_batch() to proceed without recognizing the underlying page allocation failure. No specific network position or authentication is mentioned as required, but the context implies interaction with the tun/vhost subsystem.
Impact
Each failure of build_skb() in tun_xdp_one() results in a leak of one page-frag chunk. Repeated exploitation of this vulnerability can lead to a gradual depletion of system memory. This memory exhaustion can degrade system performance and potentially lead to a denial-of-service (DoS) condition, rendering the system unstable or unresponsive.
Mitigation
This vulnerability has been resolved by freeing the page before taking the error path in tun_xdp_one(), aligning with existing error exit paths that perform put_page(). The fix is available in the Linux kernel at commit aa308e9dbb9acb17cacdbbce9e4504f69bac8385 [1]. Specific patched kernel versions are not detailed in the provided references, but users should update to the latest stable kernel that incorporates this fix.
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
8aa8963fdce66tun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index f594360d66d65..9e7744eb57a32 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2439,6 +2439,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
d16e38fac09atun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index 19c33d21bab94..d53e60823bf1b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2505,6 +2505,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
aa308e9dbb9atun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index afba37965ce3b..9a767da38c71e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2437,6 +2437,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
4fefc6156a16tun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8154d18a2a235..ca0ae5df73af7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2437,6 +2437,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
4fefc6156a16tun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8154d18a2a235..ca0ae5df73af7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2437,6 +2437,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
aa308e9dbb9atun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index afba37965ce3b..9a767da38c71e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2437,6 +2437,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
aa8963fdce66tun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index f594360d66d65..9e7744eb57a32 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2439,6 +2439,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
d16e38fac09atun: free page on build_skb failure in tun_xdp_one()
1 file changed · +1 −1
drivers/net/tun.c+1 −1 modifieddiff --git a/drivers/net/tun.c b/drivers/net/tun.c index 19c33d21bab94..d53e60823bf1b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2505,6 +2505,7 @@ static int tun_xdp_one(struct tun_struct *tun, build: skb = build_skb(xdp->data_hard_start, buflen); if (!skb) { + put_page(virt_to_head_page(xdp->data)); ret = -ENOMEM; goto out; } -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"A page allocated for an XDP frame is not freed when build_skb() fails."
Attack vector
An attacker can trigger this vulnerability by sending a batch of XDP frames to the tun device. If the build_skb() function fails for any of these frames, the allocated page will not be freed. This can occur repeatedly within a batch, leading to a page leak. The tun_sendmsg() function discards per-buffer errors and returns success, allowing vhost_tx_batch() to proceed without freeing the page [patch_id=5354477].
Affected code
The vulnerability exists in the tun_xdp_one() function within the drivers/net/tun.c file. Specifically, the issue occurs when the build_skb() function fails to allocate an skb. The code then jumps to the 'out' label without freeing the page that was previously allocated for the frame.
What the fix does
The patch adds a call to put_page() immediately after build_skb() fails and returns -ENOMEM [patch_id=5354477]. This ensures that the page allocated by vhost_net_build_xdp() is freed when build_skb() encounters an error, preventing the page leak. This change aligns the error handling with other existing error exit paths in tun_xdp_one() that already perform page freeing.
Preconditions
- configThe tun device must be configured to use XDP.
Generated on Jun 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
1- Linux Kernel: 25 Vulnerabilities Disclosed in Single Batch on June 8-9, 2026Vypr Intelligence · Jun 9, 2026