[PATCH openEuler-1.0-LTS 0/2] xfrm: fix stale skb->prev UAF in validate_xmit_xfrm() for async crypto GSO segments
From: Dong Chenchen <dongchenchen2@huawei.com> CVE: CVE-2026-68426 Reference: https://atomgit.com/src-openeuler/kernel/issues/17032 This series fixes CVE-2026-68426, a use-after-free in validate_xmit_xfrm(): when async crypto steals GSO segments (->xmit() returns -EINPROGRESS), the returned segment list head keeps skb->prev pointing at a stolen (crypto-owned) segment. validate_xmit_skb_list() later does tail = skb->prev and tail->next = skb, writing through the stale pointer. Patch 1 is a prerequisite backport of upstream d1d17a359ce6 ("esp: remove the skb from the chain when it's enqueued in cryptd_wq", v5.6). It introduces the pskb tracking of the last retained segment and properly unlinks stolen segments from the chain. Without it the CVE fix commit cannot be applied faithfully: its skb->prev repoint logic builds directly on the pskb variable and the unlinking behaviour introduced there. Patch 2 is the mainline fix for CVE-2026-68426, 3f4c3919baf0944ad96580467c302bc6c7758b00 (v7.2-rc4): repoint skb->prev at the last retained segment before returning, so validate_xmit_skb_list() never chains onto a segment now owned by the crypto engine. Both patches are adapted to the 4.19-based openEuler-1.0-LTS code base, which still uses the original do-while loop form of validate_xmit_xfrm() (the upstream skb_list_walk_safe refactor c3b18e0d9254 is a pure refactor and is not backported). The target's "return skb" semantics are kept (upstream's ERR_PTR(-EINPROGRESS) return comes from the unrelated later commit 6860b467f569 and is not needed for this fix). Note: this series is based on f702ec806ef8 and supersedes the incomplete single-commit adaptation 0026e6ba24b0 ("xfrm: fix stale skb->prev after async crypto steals a GSO segment"), which tracked pskb without the prerequisite chain-unlink fix. Petr Wozniak (1): xfrm: fix stale skb->prev after async crypto steals a GSO segment Xin Long (1): esp: remove the skb from the chain when it's enqueued in cryptd_wq net/xfrm/xfrm_device.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) -- 2.43.0
From: Xin Long <lucien.xin@gmail.com> mainline inclusion from mainline-v5.6 commit d1d17a359ce6901545c075d7401c10179d9cedfd category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17032 CVE: CVE-2026-68426 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Xiumei found a panic in esp offload: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 RIP: 0010:esp_output_done+0x101/0x160 [esp4] Call Trace: ? esp_output+0x180/0x180 [esp4] cryptd_aead_crypt+0x4c/0x90 cryptd_queue_worker+0x6e/0xa0 process_one_work+0x1a7/0x3b0 worker_thread+0x30/0x390 ? create_worker+0x1a0/0x1a0 kthread+0x112/0x130 ? kthread_flush_work_fn+0x10/0x10 ret_from_fork+0x35/0x40 It was caused by that skb secpath is used in esp_output_done() after it's been released elsewhere. The tx path for esp offload is: __dev_queue_xmit()-> validate_xmit_skb_list()-> validate_xmit_xfrm()-> esp_xmit()-> esp_output_tail()-> aead_request_set_callback(esp_output_done) <--[1] crypto_aead_encrypt() <--[2] In [1], .callback is set, and in [2] it will trigger the worker schedule, later on a kernel thread will call .callback(esp_output_done), as the call trace shows. But in validate_xmit_xfrm(): skb_list_walk_safe(skb, skb2, nskb) { ... err = x->type_offload->xmit(x, skb2, esp_features); [esp_xmit] ... } When the err is -EINPROGRESS, which means this skb2 will be enqueued and later gets encrypted and sent out by .callback later in a kernel thread, skb2 should be removed fromt skb chain. Otherwise, it will get processed again outside validate_xmit_xfrm(), which could release skb secpath, and cause the panic above. This patch is to remove the skb from the chain when it's enqueued in cryptd_wq. While at it, remove the unnecessary 'if (!skb)' check. Fixes: 3dca3f38cfb8 ("xfrm: Separate ESP handling from segmentation for GRO packets.") Reported-by: Xiumei Mu <xmu@redhat.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Conflicts: net/xfrm/xfrm_device.c [commit c3b18e0d9254 ("net: xfrm: use skb_list_walk_safe helper for gso segments") is not backport, which lead to conflicts; adapted to the 4.19-style do-while loop with goto skip_push: track the last retained segment in pskb and bridge pskb->next around segments stolen by async crypto, replacing the "if (!skb) return NULL" bail-out, preserving the upstream semantics on the target's control flow] Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> --- net/xfrm/xfrm_device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 8a9f02997067..e63da1ff17bf 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -28,7 +28,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur int err; unsigned long flags; struct xfrm_state *x; - struct sk_buff *skb2; + struct sk_buff *skb2, *pskb = NULL; struct softnet_data *sd; netdev_features_t esp_features = features; struct xfrm_offload *xo = xfrm_offload(skb); @@ -119,14 +119,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur } else { if (skb == skb2) skb = nskb; - - if (!skb) - return NULL; + else + pskb->next = nskb; goto skip_push; } skb_push(skb2, skb2->data - skb_mac_header(skb2)); + pskb = skb2; skip_push: skb2 = nskb; -- 2.43.0
From: Petr Wozniak <petr.wozniak@gmail.com> mainline inclusion from mainline-v7.2-rc4 commit 3f4c3919baf0944ad96580467c302bc6c7758b00 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17032 CVE: CVE-2026-68426 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- skb_gso_segment() leaves the segment list head with ->prev pointing at the last segment, an invariant validate_xmit_skb_list() relies on when it sets its tail pointer (tail = skb->prev). When validate_xmit_xfrm() walks a GSO list and some segments are stolen by async crypto (->xmit() returns -EINPROGRESS), those segments are unlinked from the list but the head ->prev is never updated. If the last segment is the one stolen, the returned head still has ->prev pointing at it, even though it is now owned by the crypto engine and may be freed. validate_xmit_skb_list() later does tail->next = skb, writing through that stale pointer -- a use-after-free. Repoint skb->prev at the last retained segment before returning. Fixes: f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.") Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Conflicts: net/xfrm/xfrm_device.c [commit 6860b467f569 ("xfrm: propagate -EINPROGRESS from validate_xmit_xfrm()") is not backport, which lead to conflicts; kept the target's "return skb" (NULL still means stolen to the 4.19 validate_xmit_skb_list() caller) and added the skb->prev repoint to the last retained segment after the do-while loop] Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> --- net/xfrm/xfrm_device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index e63da1ff17bf..b24472911f8c 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -132,6 +132,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur skb2 = nskb; } while (skb2); + /* skb_gso_segment() set skb->prev to the last segment, but async + * crypto may have stolen it above without updating ->prev. Repoint + * it at the last retained segment so validate_xmit_skb_list() does + * not chain onto a segment now owned by the crypto engine. + */ + if (skb) + skb->prev = pskb; + return skb; } EXPORT_SYMBOL_GPL(validate_xmit_xfrm); -- 2.43.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/29450 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6SE... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/29450 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6SE...
participants (2)
-
patchwork bot -
superdcc97@163.com