GHSA-MQXQ-XQ56-PCHW
Vulnerability from github – Published: 2026-07-19 15:30 – Updated: 2026-07-20 15:31In the Linux kernel, the following vulnerability has been resolved:
esp: fix page frag reference leak on skb_to_sgvec failure
In esp_output_tail(), when esp->inplace is false, the old skb page frags are replaced with a new page from the xfrm page_frag cache. The source scatterlist (sg) is built from the old frags before the replacement, and esp_ssg_unref() is responsible for releasing the old page references after the crypto operation completes.
However, if the second skb_to_sgvec() call (which builds the destination scatterlist from the new page) fails, the code jumps to error_free which only calls kfree(tmp). The old page frag references captured in the source scatterlist are never released:
- sg[] is built from old frags via skb_to_sgvec() (no extra get_page)
- nr_frags is set to 1 and frag[0] is replaced with the new page
- Second skb_to_sgvec() fails -> goto error_free
- kfree(tmp) frees the sg[] memory but old frags are not unref'd
- kfree_skb() only releases frag[0] (the new page), not the old ones
Fix this by adding a bool parameter to esp_ssg_unref() that, when true, unconditionally unrefs the source scatterlist frags without checking req->src and req->dst, since those fields are not yet initialized by aead_request_set_crypt() at the point of the error. Existing callers pass false to preserve the original behavior.
The same issue exists in both esp4 and esp6 as the code is identical.
{
"affected": [],
"aliases": [
"CVE-2026-63872"
],
"database_specific": {
"cwe_ids": [],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-19T15:16:54Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nesp: fix page frag reference leak on skb_to_sgvec failure\n\nIn esp_output_tail(), when esp-\u003einplace is false, the old skb page frags\nare replaced with a new page from the xfrm page_frag cache. The source\nscatterlist (sg) is built from the old frags before the replacement, and\nesp_ssg_unref() is responsible for releasing the old page references\nafter the crypto operation completes.\n\nHowever, if the second skb_to_sgvec() call (which builds the destination\nscatterlist from the new page) fails, the code jumps to error_free which\nonly calls kfree(tmp). The old page frag references captured in the\nsource scatterlist are never released:\n\n 1. sg[] is built from old frags via skb_to_sgvec() (no extra get_page)\n 2. nr_frags is set to 1 and frag[0] is replaced with the new page\n 3. Second skb_to_sgvec() fails -\u003e goto error_free\n 4. kfree(tmp) frees the sg[] memory but old frags are not unref\u0027d\n 5. kfree_skb() only releases frag[0] (the new page), not the old ones\n\nFix this by adding a bool parameter to esp_ssg_unref() that, when true,\nunconditionally unrefs the source scatterlist frags without checking\nreq-\u003esrc and req-\u003edst, since those fields are not yet initialized by\naead_request_set_crypt() at the point of the error. Existing callers\npass false to preserve the original behavior.\n\nThe same issue exists in both esp4 and esp6 as the code is identical.",
"id": "GHSA-mqxq-xq56-pchw",
"modified": "2026-07-20T15:31:49Z",
"published": "2026-07-19T15:30:28Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-63872"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/2982e599fff6faa21c8df147d96fc7af6c1a2f24"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/e705b8ff4dd38fb8fe4e6fdc5378a86acea4feb5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.