diff --git a/SOURCES/1102-net-skbuff-propagate-shared-frag-marker.patch b/SOURCES/1102-net-skbuff-propagate-shared-frag-marker.patch index 849b2be32..ff51dce5b 100644 --- a/SOURCES/1102-net-skbuff-propagate-shared-frag-marker.patch +++ b/SOURCES/1102-net-skbuff-propagate-shared-frag-marker.patch @@ -1,20 +1,23 @@ -From: Eduard Abdullin +From: Andrew Lukoshko Subject: [PATCH AlmaLinux 9] net: skbuff: propagate shared-frag marker through frag-transfer helpers -Backport of upstream v3 patch posted at -https://lore.kernel.org/all/agW4vC0r8QOUKtRT@v4bel/ +Backport of upstream v5 patch posted at +https://lore.kernel.org/all/ageeJfJHwgzmKXbh@v4bel/ (sibling to upstream commit f4c50a4034e6 "xfrm: esp: avoid in-place decrypt on shared skb frags"). Three frag-transfer helpers in net/core/skbuff.c -(__pskb_copy_fclone(), skb_try_coalesce(), skb_shift()) and the -GRO accumulator path in net/core/gro.c (skb_gro_receive()) and the -UDP GRO list helper in net/ipv4/udp_offload.c -(skb_gro_receive_list(), kept as a static helper on AlmaLinux 9) -fail to propagate the SKBFL_SHARED_FRAG bit in skb_shinfo()->flags -when moving frag descriptors from source to destination. As a -result, the destination skb keeps a reference to the same -externally-owned or page-cache-backed pages while reporting +(__pskb_copy_fclone(), skb_try_coalesce(), skb_shift()), the GRO +accumulator path in net/core/gro.c (skb_gro_receive()) and the UDP +GRO list helper in net/ipv4/udp_offload.c (skb_gro_receive_list(), +kept as a static helper on AlmaLinux 9) fail to propagate the +SKBFL_SHARED_FRAG bit in skb_shinfo()->flags when moving frag +descriptors from source to destination. In addition, skb_segment() +folds only head_skb's flag into nskb on the per-iteration flag +merge, and the inner switch that rebinds frag_skb to list_skb on +head_skb-frags exhaustion does not fold the new frag_skb's flag +into nskb. As a result, the destination skb keeps a reference to +the same externally-owned or page-cache-backed pages while reporting skb_has_shared_frag() as false. The mismatch is harmful in any in-place writer that uses @@ -31,6 +34,8 @@ were actually moved from the source. skb_copy() and skb_copy_expand() share skb_copy_header() too but linearize all paged data into freshly allocated head storage and emerge with nr_frags == 0, so skb_has_shared_frag() returns false on its own; they need no change. +tcp_clone_payload() does not exist in 5.14; no equivalent hunk +applies. The same omission exists in skb_gro_receive() and skb_gro_receive_list(). The former moves the incoming skb's frag @@ -42,31 +47,79 @@ reuses each sub-skb's shinfo as the nskb -- both p and lp must carry the marker. Tree adaptation: - * Upstream v3 places skb_gro_receive_list() in net/core/gro.c. + * Upstream v5 places skb_gro_receive_list() in net/core/gro.c. AlmaLinux 9 still keeps it as a static helper in net/ipv4/udp_offload.c (it has not been promoted to a global GRO helper in this tree). Apply the propagation hunk there instead. - * Upstream skb_shift() uses skb_len_add() helpers (introduced in - v5.16); AlmaLinux 9 still has the open-coded - `skb->len -= shiftlen; ...` block. The insertion point (right - after both ip_summed assignments) is the same. + * Upstream tcp_clone_payload() was added in v6.5 (commit + 808599b88c93); 5.14 has no such helper, so the corresponding v5 + hunk is omitted. Fixes: cef401de7be8 ("net: fix possible wrong checksum generation") Fixes: f4c50a4034e6 ("xfrm: esp: avoid in-place decrypt on shared skb frags") Reported-by: Sultan Alsawaf Reported-by: William Bowling Reported-by: Hyunwoo Kim -Signed-off-by: Eduard Abdullin +Signed-off-by: Andrew Lukoshko --- - net/core/gro.c | 2 ++ - net/core/skbuff.c | 6 ++++++ - net/ipv4/udp_offload.c | 2 ++ - 3 files changed, 10 insertions(+) + net/core/gro.c | 2 ++ + net/core/skbuff.c | 12 ++++++++++++ + net/ipv4/udp_offload.c | 2 ++ + 3 files changed, 16 insertions(+) ---- a/net/core/gro.c -+++ b/net/core/gro.c -@@ -222,10 +222,12 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) +--- a/net/core/skbuff.c 2026-05-28 12:54:14.127155793 +0200 ++++ b/net/core/skbuff.c 2026-05-28 12:57:03.811526691 +0200 +@@ -2027,6 +2027,7 @@ + skb_frag_ref(skb, i); + } + skb_shinfo(n)->nr_frags = i; ++ skb_shinfo(n)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; + } + + if (skb_has_frag_list(skb)) { +@@ -4029,6 +4030,8 @@ + tgt->ip_summed = CHECKSUM_PARTIAL; + skb->ip_summed = CHECKSUM_PARTIAL; + ++ skb_shinfo(tgt)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; ++ + /* Yak, is it really working this way? Some helper please? */ + skb->len -= shiftlen; + skb->data_len -= shiftlen; +@@ -4604,7 +4607,8 @@ + skb_copy_from_linear_data_offset(head_skb, offset, + skb_put(nskb, hsize), hsize); + +- skb_shinfo(nskb)->flags |= skb_shinfo(head_skb)->flags & ++ skb_shinfo(nskb)->flags |= (skb_shinfo(head_skb)->flags | ++ skb_shinfo(frag_skb)->flags) & + SKBFL_SHARED_FRAG; + + if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) +@@ -4621,6 +4625,10 @@ + nfrags = skb_shinfo(list_skb)->nr_frags; + frag = skb_shinfo(list_skb)->frags; + frag_skb = list_skb; ++ ++ skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & ++ SKBFL_SHARED_FRAG; ++ + if (!skb_headlen(list_skb)) { + BUG_ON(!nfrags); + } else { +@@ -5741,6 +5749,8 @@ + from_shinfo->frags, + from_shinfo->nr_frags * sizeof(skb_frag_t)); + to_shinfo->nr_frags += from_shinfo->nr_frags; ++ if (from_shinfo->nr_frags) ++ to_shinfo->flags |= from_shinfo->flags & SKBFL_SHARED_FRAG; + + if (!skb_cloned(from)) + from_shinfo->nr_frags = 0; +--- a/net/core/gro.c 2026-05-28 12:54:14.126244251 +0200 ++++ b/net/core/gro.c 2026-05-28 12:57:12.210673266 +0200 +@@ -222,10 +222,12 @@ p->data_len += len; p->truesize += delta_truesize; p->len += len; @@ -79,44 +132,14 @@ Signed-off-by: Eduard Abdullin } NAPI_GRO_CB(skb)->same_flow = 1; return 0; ---- a/net/core/skbuff.c -+++ b/net/core/skbuff.c -@@ -2026,6 +2026,7 @@ struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom, - skb_frag_ref(skb, i); - } - skb_shinfo(n)->nr_frags = i; -+ skb_shinfo(n)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; - } - - if (skb_has_frag_list(skb)) { -@@ -4029,6 +4030,8 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) - tgt->ip_summed = CHECKSUM_PARTIAL; - skb->ip_summed = CHECKSUM_PARTIAL; - -+ skb_shinfo(tgt)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; -+ - /* Yak, is it really working this way? Some helper please? */ - skb->len -= shiftlen; - skb->data_len -= shiftlen; -@@ -5740,6 +5743,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, - from_shinfo->frags, - from_shinfo->nr_frags * sizeof(skb_frag_t)); - to_shinfo->nr_frags += from_shinfo->nr_frags; -+ if (from_shinfo->nr_frags) -+ to_shinfo->flags |= from_shinfo->flags & SKBFL_SHARED_FRAG; - - if (!skb_cloned(from)) - from_shinfo->nr_frags = 0; ---- a/net/ipv4/udp_offload.c -+++ b/net/ipv4/udp_offload.c -@@ -487,6 +487,8 @@ static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) +--- a/net/ipv4/udp_offload.c 2026-05-28 12:54:14.556608350 +0200 ++++ b/net/ipv4/udp_offload.c 2026-05-28 12:57:19.503137455 +0200 +@@ -487,6 +487,8 @@ p->truesize += skb->truesize; p->len += skb->len; - + + skb_shinfo(p)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; + NAPI_GRO_CB(skb)->same_flow = 1; - + return 0; --- -2.43.0 diff --git a/SOURCES/1105-smb-client-reject-userspace-cifs.spnego-descriptions.patch b/SOURCES/1105-smb-client-reject-userspace-cifs.spnego-descriptions.patch new file mode 100644 index 000000000..4fbab3c28 --- /dev/null +++ b/SOURCES/1105-smb-client-reject-userspace-cifs.spnego-descriptions.patch @@ -0,0 +1,66 @@ +From 3da1fdf4efbc490041eb4f836bf596201203f8f2 Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Sat, 16 May 2026 21:15:39 +0000 +Subject: smb: client: reject userspace cifs.spnego descriptions + +cifs.spnego key descriptions contain authority-bearing fields such as +pid, uid, creduid, and upcall_target that cifs.upcall treats as +kernel-originating inputs. However, userspace can also create keys of +this type through request_key(2) or add_key(2), allowing those fields to +be supplied without CIFS origin. + +Only accept cifs.spnego descriptions while CIFS is using its private +spnego_cred to request the key. + +Fixes: f1d662a7d5e5 ("[CIFS] Add upcall files for cifs to use spnego/kerberos") +Assisted-by: avom-custom-harness:gpt-5.5-qwen3.6-mod-mix +Reviewed-by: David Howells +Signed-off-by: Asim Viladi Oglu Manizada +Signed-off-by: Steve French +--- + fs/smb/client/cifs_spnego.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/fs/smb/client/cifs_spnego.c b/fs/smb/client/cifs_spnego.c +index 3a41bbada04c76..44c40727568042 100644 +--- a/fs/smb/client/cifs_spnego.c ++++ b/fs/smb/client/cifs_spnego.c +@@ -8,6 +8,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -40,12 +41,27 @@ cifs_spnego_key_destroy(struct key *key) + kfree(key->payload.data[0]); + } + ++static int ++cifs_spnego_key_vet_description(const char *description) ++{ ++ /* ++ * cifs.spnego descriptions are authority-bearing inputs to cifs.upcall. ++ * They are only valid when produced by CIFS while using the private ++ * spnego_cred installed below. Do not let userspace create this type ++ * of key through request_key(2)/add_key(2), since the helper treats ++ * pid/uid/creduid/upcall_target as kernel-originating fields. ++ */ ++ if (current_cred() != spnego_cred) ++ return -EPERM; ++ return 0; ++} + + /* + * keytype for CIFS spnego keys + */ + struct key_type cifs_spnego_key_type = { + .name = "cifs.spnego", ++ .vet_description = cifs_spnego_key_vet_description, + .instantiate = cifs_spnego_key_instantiate, + .destroy = cifs_spnego_key_destroy, + .describe = user_describe, +-- +cgit 1.3-korg + diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec index ed4593c46..0973f0aa7 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec @@ -182,7 +182,7 @@ Summary: The Linux kernel # This is needed to do merge window version magic %define patchlevel 14 # This allows pkg_release to have configurable %%{?dist} tag -%define specrelease 687.5.3%{?buildid}%{?dist} +%define specrelease 687.5.4%{?buildid}%{?dist} # This defines the kabi tarball version %define kabiversion 5.14.0-687.5.1.el9_8 @@ -979,6 +979,7 @@ Patch1101: 1101-rxrpc-linearize-paged-frags.patch Patch1102: 1102-net-skbuff-propagate-shared-frag-marker.patch Patch1103: 1103-ptrace-require-cap-on-mm-less-task.patch Patch1104: 1104-CVE-2026-31431-crypto-Copy-Fail-fixes.patch +Patch1105: 1105-smb-client-reject-userspace-cifs.spnego-descriptions.patch Patch11111: ppc64le-kvm-support.patch @@ -1730,6 +1731,7 @@ ApplyPatch 1101-rxrpc-linearize-paged-frags.patch ApplyPatch 1102-net-skbuff-propagate-shared-frag-marker.patch ApplyPatch 1103-ptrace-require-cap-on-mm-less-task.patch ApplyPatch 1104-CVE-2026-31431-crypto-Copy-Fail-fixes.patch +ApplyPatch 1105-smb-client-reject-userspace-cifs.spnego-descriptions.patch # END OF PATCH APPLICATIONS @@ -3805,6 +3807,13 @@ fi # # %changelog +* Thu May 28 2026 Andrew Lukoshko - 5.14.0-687.5.4 +- net: skbuff: propagate shared-frag marker through frag-transfer helpers + (refresh to upstream v5: now also covers skb_segment(); CVE-2026-46300 + "Fragnesia") +- smb: client: reject userspace cifs.spnego descriptions (upstream commit + 3da1fdf4efbc) + * Tue May 19 2026 Andrew Lukoshko - 5.14.0-687.5.3 - xfrm: esp: avoid in-place decrypt on shared skb frags (CVE-2026-43284) - rxrpc: linearize incoming DATA packet when it has paged frags (CVE-2026-43500)