From babc364632800c1302255ce3cd081b3e2d0cbc4a Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Sat, 17 May 2025 11:59:26 +0000 Subject: [PATCH 01/17] Update PPC KVM support patch --- files/ppc64le-kvm-support.patch | 203 +++++++++++++++++++++++--------- 1 file changed, 147 insertions(+), 56 deletions(-) diff --git a/files/ppc64le-kvm-support.patch b/files/ppc64le-kvm-support.patch index 4f8883f..a185147 100644 --- a/files/ppc64le-kvm-support.patch +++ b/files/ppc64le-kvm-support.patch @@ -1,31 +1,55 @@ -From 524ab50336b1190547ceb8074260a1fbebfee0be Mon Sep 17 00:00:00 2001 -From: Sean Christopherson -Date: Mon, 6 Dec 2021 20:54:14 +0100 -Subject: [PATCH 1/3] KVM: PPC: Avoid referencing userspace memory region in - memslot updates +From 3c806e795bf954e4dc28b75887a89095815325ed Mon Sep 17 00:00:00 2001 +From: Andrew Lukoshko +Date: Sat, 17 May 2025 08:48:11 +0000 +Subject: [PATCH] =?UTF-8?q?Bring=20back=20KVM=20support=20for=20PPC=C2=A7?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -For PPC HV, get the number of pages directly from the new memslot instead -of computing the same from the userspace memory region, and explicitly -check for !DELETE instead of inferring the same when toggling mmio_update. -The motivation for these changes is to avoid referencing the @mem param -so that it can be dropped in a future commit. - -No functional change intended. - -Signed-off-by: Sean Christopherson -Signed-off-by: Maciej S. Szmigiero -Message-Id: <1e97fb5198be25f98ef82e63a8d770c682264cc9.1638817639.git.maciej.szmigiero@oracle.com> +Backport of the following upstream commits: +524ab50336b1190547ceb8074260a1fbebfee0be +93b71801a8274cd9511557faf04365a5de487197 +f771b55731fc82b1e8e9ef123f6f1b8d8c92bc63 --- - arch/powerpc/include/asm/kvm_ppc.h | 4 ---- - arch/powerpc/kvm/book3s.c | 6 ++---- - arch/powerpc/kvm/book3s_hv.c | 12 +++--------- - arch/powerpc/kvm/book3s_pr.c | 2 -- - arch/powerpc/kvm/booke.c | 2 -- - arch/powerpc/kvm/powerpc.c | 4 ++-- - 6 files changed, 7 insertions(+), 23 deletions(-) + Documentation/virt/kvm/api.rst | 14 ++++++++++++++ + arch/powerpc/include/asm/kvm_ppc.h | 4 ---- + arch/powerpc/include/asm/setup.h | 2 ++ + arch/powerpc/kvm/book3s.c | 6 ++---- + arch/powerpc/kvm/book3s_64_vio_hv.c | 2 +- + arch/powerpc/kvm/book3s_hv.c | 12 +++--------- + arch/powerpc/kvm/book3s_pr.c | 2 -- + arch/powerpc/kvm/booke.c | 2 -- + arch/powerpc/kvm/powerpc.c | 21 +++++++++++++++++++-- + arch/powerpc/platforms/pseries/setup.c | 13 ++++++++++++- + 10 files changed, 53 insertions(+), 25 deletions(-) +diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst +index 9f2f130c6..64aca1034 100644 +--- a/Documentation/virt/kvm/api.rst ++++ b/Documentation/virt/kvm/api.rst +@@ -7735,6 +7735,20 @@ indicated by the fd to the VM this is called on. + This is intended to support intra-host migration of VMs between userspace VMMs, + upgrading the VMM process without interrupting the guest. + ++7.30 KVM_CAP_PPC_AIL_MODE_3 ++------------------------------- ++ ++:Capability: KVM_CAP_PPC_AIL_MODE_3 ++:Architectures: ppc ++:Type: vm ++ ++This capability indicates that the kernel supports the mode 3 setting for the ++"Address Translation Mode on Interrupt" aka "Alternate Interrupt Location" ++resource that is controlled with the H_SET_MODE hypercall. ++ ++This capability allows a guest kernel to use a better-performance mode for ++handling interrupts and system calls. ++ + 7.31 KVM_CAP_DISABLE_QUIRKS2 + ---------------------------- + diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h -index 5c80c4955..6874cd89d 100644 +index 254a41648..e16491011 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -199,12 +199,10 @@ extern void kvmppc_core_destroy_vm(struct kvm *kvm); @@ -54,6 +78,24 @@ index 5c80c4955..6874cd89d 100644 struct kvm_memory_slot *old, const struct kvm_memory_slot *new, enum kvm_mr_change change); +diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h +index 31f315223..1868e4a07 100644 +--- a/arch/powerpc/include/asm/setup.h ++++ b/arch/powerpc/include/asm/setup.h +@@ -27,11 +27,13 @@ void setup_panic(void); + #define ARCH_PANIC_TIMEOUT 180 + + #ifdef CONFIG_PPC_PSERIES ++extern bool pseries_reloc_on_exception(void); + extern bool pseries_enable_reloc_on_exc(void); + extern void pseries_disable_reloc_on_exc(void); + extern void pseries_big_endian_exceptions(void); + extern void pseries_little_endian_exceptions(void); + #else ++static inline bool pseries_reloc_on_exception(void) { return false; } + static inline bool pseries_enable_reloc_on_exc(void) { return false; } + static inline void pseries_disable_reloc_on_exc(void) {} + static inline void pseries_big_endian_exceptions(void) {} diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 64fd4b3ea..cb7b5f365 100644 --- a/arch/powerpc/kvm/book3s.c @@ -82,8 +124,21 @@ index 64fd4b3ea..cb7b5f365 100644 } bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) +diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c +index f38dfe195..16e5872a1 100644 +--- a/arch/powerpc/kvm/book3s_64_vio_hv.c ++++ b/arch/powerpc/kvm/book3s_64_vio_hv.c +@@ -488,7 +488,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, + /* + * used to check for invalidations in progress + */ +- mmu_seq = kvm->mmu_notifier_seq; ++ mmu_seq = kvm->mmu_invalidate_seq; + smp_rmb(); + + stt = kvmppc_find_table(vcpu->kvm, liobn); diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c -index 9c3c9fd5e..7f4c188f3 100644 +index 5b2530818..f6ce07b4b 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4777,15 +4777,12 @@ static void kvmppc_core_free_memslot_hv(struct kvm_memory_slot *slot) @@ -127,7 +182,7 @@ index 9c3c9fd5e..7f4c188f3 100644 /* diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c -index 7891b9d0c..c0ae926af 100644 +index 48b48311a..6884c04f2 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -1892,7 +1892,6 @@ static void kvmppc_core_flush_memslot_pr(struct kvm *kvm, @@ -167,10 +222,34 @@ index b06ca6646..6cf2db284 100644 const struct kvm_memory_slot *new, enum kvm_mr_change change) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c -index 818815e15..f8f39a858 100644 +index 818815e15..b89271923 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c -@@ -686,7 +686,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, +@@ -662,6 +662,23 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) + r = 1; + break; + #endif ++ case KVM_CAP_PPC_AIL_MODE_3: ++ r = 0; ++ /* ++ * KVM PR, POWER7, and some POWER9s don't support AIL=3 mode. ++ * The POWER9s can support it if the guest runs in hash mode, ++ * but QEMU doesn't necessarily query the capability in time. ++ */ ++ if (hv_enabled) { ++ if (kvmhv_on_pseries()) { ++ if (pseries_reloc_on_exception()) ++ r = 1; ++ } else if (cpu_has_feature(CPU_FTR_ARCH_207S) && ++ !cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) { ++ r = 1; ++ } ++ } ++ break; + default: + r = 0; + break; +@@ -686,7 +703,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *new, enum kvm_mr_change change) { @@ -179,7 +258,7 @@ index 818815e15..f8f39a858 100644 } void kvm_arch_commit_memory_region(struct kvm *kvm, -@@ -694,7 +694,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, +@@ -694,7 +711,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, const struct kvm_memory_slot *new, enum kvm_mr_change change) { @@ -188,32 +267,44 @@ index 818815e15..f8f39a858 100644 } void kvm_arch_flush_shadow_memslot(struct kvm *kvm, --- -2.39.5 (Apple Git-154) - - -From 8c62d250a23bbbb1ecd84d4d475e7623810275aa Mon Sep 17 00:00:00 2001 -From: eabdullin -Date: Tue, 8 Apr 2025 10:13:43 +0300 -Subject: [PATCH 3/3] powerpc/kvm: use mmu_invalidate_seq instead of - mmu_notifier_seq - ---- - arch/powerpc/kvm/book3s_64_vio_hv.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c -index f38dfe195..16e5872a1 100644 ---- a/arch/powerpc/kvm/book3s_64_vio_hv.c -+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c -@@ -488,7 +488,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, - /* - * used to check for invalidations in progress - */ -- mmu_seq = kvm->mmu_notifier_seq; -+ mmu_seq = kvm->mmu_invalidate_seq; - smp_rmb(); +diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c +index f5c2718e2..1f7e535ab 100644 +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -367,6 +367,14 @@ static void pseries_lpar_idle(void) + pseries_idle_epilog(); + } - stt = kvmppc_find_table(vcpu->kvm, liobn); ++static bool pseries_reloc_on_exception_enabled; ++ ++bool pseries_reloc_on_exception(void) ++{ ++ return pseries_reloc_on_exception_enabled; ++} ++EXPORT_SYMBOL_GPL(pseries_reloc_on_exception); ++ + /* + * Enable relocation on during exceptions. This has partition wide scope and + * may take a while to complete, if it takes longer than one second we will +@@ -391,6 +399,7 @@ bool pseries_enable_reloc_on_exc(void) + " on exceptions: %ld\n", rc); + return false; + } ++ pseries_reloc_on_exception_enabled = true; + return true; + } + +@@ -418,7 +427,9 @@ void pseries_disable_reloc_on_exc(void) + break; + mdelay(get_longbusy_msecs(rc)); + } +- if (rc != H_SUCCESS) ++ if (rc == H_SUCCESS) ++ pseries_reloc_on_exception_enabled = false; ++ else + pr_warn("Warning: Failed to disable relocation on exceptions: %ld\n", + rc); + } -- -2.39.5 (Apple Git-154) +2.43.5 + From 526b4e4c1d66eeed1f94cd2c714c6e71dab3ac68 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Mon, 19 May 2025 14:06:39 +0300 Subject: [PATCH 02/17] Add kernel-kvm-debug --- config.yaml | 74 ++++++++++++++++++++++++++++++++++ scripts/copy_ppc64le_config.sh | 3 +- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index a6a4a5e..8371b70 100644 --- a/config.yaml +++ b/config.yaml @@ -229,6 +229,7 @@ actions: # PPC64le KVM support config Source10001: kernel-ppc64le-kvm-rhel.config + Source10002: kernel-ppc64le-kvm-debug-rhel.config count: 1 - target: "spec" find: | @@ -263,6 +264,21 @@ actions: The kernel package contains a variant of the PPC64le Linux kernel with KVM support. %endif + + %if %{with_ppc_kvm} && %{with_debug} + %define variant_summary The Linux kernel compiled with extra debugging enabled + %if !%{debugbuildsenabled} + %kernel_variant_package -m kvm-debug + %else + %kernel_variant_package kvm-debug + %endif + %description kvm-debug-core + The debug kernel package contains a variant of the PPC64le Linux kernel with + KVM support. + This variant of the kernel has numerous debugging options enabled. + It should only be installed when trying to gather additional information + on kernel bugs, as some of these options impact performance noticably. + %endif count: 1 - target: "spec" find: | @@ -276,6 +292,9 @@ actions: %if %{with_ppc_kvm} git apply $RPM_SOURCE_DIR/ppc64le-kvm-support.patch + %if %{with_debug} + BuildKernel %make_target %kernel_image %{_use_vdso} kvm-debug + %endif BuildKernel %make_target %kernel_image %{_use_vdso} kvm %endif count: 1 @@ -297,6 +316,9 @@ actions: if [ "%{with_ppc_kvm}" -ne "0" ]; then \ %{modsign_cmd} certs/signing_key.pem.sign+kvm certs/signing_key.x509.sign+kvm $RPM_BUILD_ROOT/lib/modules/%{KVERREL}+kvm/ \ fi \ + if [ "%{with_ppc_kvm}" -ne "0" ] && [ "%{with_debug}" -ne "0" ]; then \ + %{modsign_cmd} certs/signing_key.pem.sign+kvm-debug certs/signing_key.x509.sign+kvm-debug $RPM_BUILD_ROOT/lib/modules/%{KVERREL}+kvm-debug/ \ + fi \ count: 1 - target: "spec" find: | @@ -314,13 +336,65 @@ actions: %kernel_variant_preun -v kvm %kernel_variant_post -v kvm %endif + + %if %{with_ppc_kvm} && %{with_debug} + %kernel_variant_preun -v kvm-debug + %kernel_variant_post -v kvm-debug + %endif + count: 1 + - target: "spec" + find: | + %if %{with_debug_meta} + %files debug + %files debug-core + %files debug-devel + %files debug-devel-matched + %files debug-modules + %files debug-modules-core + %files debug-modules-extra + %if %{with_arm64_64k} + %files 64k-debug + %files 64k-debug-core + %files 64k-debug-devel + %files 64k-debug-devel-matched + %files 64k-debug-modules + %files 64k-debug-modules-extra + %endif + replace: | + %if %{with_debug_meta} + %files debug + %files debug-core + %files debug-devel + %files debug-devel-matched + %files debug-modules + %files debug-modules-core + %files debug-modules-extra + %if %{with_arm64_64k} + %files 64k-debug + %files 64k-debug-core + %files 64k-debug-devel + %files 64k-debug-devel-matched + %files 64k-debug-modules + %files 64k-debug-modules-extra + %endif + %if %{with_ppc_kvm} + %files kvm-debug + %files kvm-debug-core + %files kvm-debug-devel + %files kvm-debug-devel-matched + %files kvm-debug-modules + %files kvm-debug-modules-extra + %endif count: 1 - target: "spec" find: | %kernel_variant_files %{_use_vdso} %{with_arm64_64k} 64k replace: | %kernel_variant_files %{_use_vdso} %{with_arm64_64k} 64k + %if %{with_ppc_kvm} %kernel_variant_files %{_use_vdso} %{with_ppc_kvm} kvm + %kernel_variant_files %{_use_vdso} %{with_debug} kvm-debug + %endif count: 1 - delete_line: diff --git a/scripts/copy_ppc64le_config.sh b/scripts/copy_ppc64le_config.sh index 71d7ce6..ef0d600 100644 --- a/scripts/copy_ppc64le_config.sh +++ b/scripts/copy_ppc64le_config.sh @@ -1,2 +1,3 @@ cp SOURCES/kernel-ppc64le-rhel.config SOURCES/kernel-ppc64le-kvm-rhel.config -sed -i 's|# CONFIG_KVM_BOOK3S_64 is not set|CONFIG_KVM_BOOK3S_64=m\nCONFIG_KVM_BOOK3S_64_HV=m\n# CONFIG_KVM_BOOK3S_64_PR is not set\n# CONFIG_KVM_BOOK3S_HV_EXIT_TIMING is not set\nCONFIG_KVM_BOOK3S_PR_POSSIBLE=y\nCONFIG_KVM_XICS=y|g' SOURCES/kernel-ppc64le-kvm-rhel.config +cp SOURCES/kernel-ppc64le-debug-rhel.config SOURCES/kernel-ppc64le-kvm-debug-rhel.config +sed -i "" 's|# CONFIG_KVM_BOOK3S_64 is not set|CONFIG_KVM_BOOK3S_64=m\nCONFIG_KVM_BOOK3S_64_HV=m\n# CONFIG_KVM_BOOK3S_64_PR is not set\n# CONFIG_KVM_BOOK3S_HV_EXIT_TIMING is not set\nCONFIG_KVM_BOOK3S_PR_POSSIBLE=y\nCONFIG_KVM_XICS=y|g' SOURCES/kernel-ppc64le-kvm*-rhel.config From 7083d64254c415b1e600f6b3f33d562eb0f1ff9b Mon Sep 17 00:00:00 2001 From: eabdullin Date: Fri, 23 May 2025 14:05:14 +0300 Subject: [PATCH 03/17] Fix script --- scripts/copy_ppc64le_config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/copy_ppc64le_config.sh b/scripts/copy_ppc64le_config.sh index ef0d600..c7ef7fd 100644 --- a/scripts/copy_ppc64le_config.sh +++ b/scripts/copy_ppc64le_config.sh @@ -1,3 +1,3 @@ cp SOURCES/kernel-ppc64le-rhel.config SOURCES/kernel-ppc64le-kvm-rhel.config cp SOURCES/kernel-ppc64le-debug-rhel.config SOURCES/kernel-ppc64le-kvm-debug-rhel.config -sed -i "" 's|# CONFIG_KVM_BOOK3S_64 is not set|CONFIG_KVM_BOOK3S_64=m\nCONFIG_KVM_BOOK3S_64_HV=m\n# CONFIG_KVM_BOOK3S_64_PR is not set\n# CONFIG_KVM_BOOK3S_HV_EXIT_TIMING is not set\nCONFIG_KVM_BOOK3S_PR_POSSIBLE=y\nCONFIG_KVM_XICS=y|g' SOURCES/kernel-ppc64le-kvm*-rhel.config +sed -i 's|# CONFIG_KVM_BOOK3S_64 is not set|CONFIG_KVM_BOOK3S_64=m\nCONFIG_KVM_BOOK3S_64_HV=m\n# CONFIG_KVM_BOOK3S_64_PR is not set\n# CONFIG_KVM_BOOK3S_HV_EXIT_TIMING is not set\nCONFIG_KVM_BOOK3S_PR_POSSIBLE=y\nCONFIG_KVM_XICS=y|g' SOURCES/kernel-ppc64le-kvm*-rhel.config From 151f0dbd2d1e0b9dc0aca063940e38fc46a9ed94 Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Sat, 24 May 2025 17:27:51 +0200 Subject: [PATCH 04/17] Add almalinuxnvidia1.x509 cert --- config.yaml | 12 ++++++++++++ files/almalinuxnvidia1.x509 | Bin 0 -> 992 bytes 2 files changed, 12 insertions(+) create mode 100644 files/almalinuxnvidia1.x509 diff --git a/config.yaml b/config.yaml index 8371b70..919612b 100644 --- a/config.yaml +++ b/config.yaml @@ -33,6 +33,9 @@ actions: - type: "source" name: "almalinuxima.x509" number: 103 + - type: "source" + name: "almalinuxnvidia1.x509" + number: 106 - type: "patch" name: "ppc64le-kvm-support.patch" number: "Latest" @@ -98,6 +101,15 @@ actions: Source103: almalinuxima.x509 Source104: almalinuxima.x509 count: 1 + - target: "spec" + find: | + openssl x509 -inform der -in %{SOURCE105} -out nvidiagpuoot001.pem + cat rheldup3.pem rhelkpatch1.pem rhelimaca1.pem nvidiagpuoot001.pem > ../certs/rhel.pem + replace: | + openssl x509 -inform der -in %{SOURCE105} -out nvidiagpuoot001.pem + openssl x509 -inform der -in %{SOURCE106} -out almalinuxnvidia.pem + cat rheldup3.pem rhelkpatch1.pem rhelimaca1.pem nvidiagpuoot001.pem almalinuxnvidia.pem > ../certs/rhel.pem + count: 1 - target: "spec" find: "Summary: Various documentation bits found in the kernel source" replace: | diff --git a/files/almalinuxnvidia1.x509 b/files/almalinuxnvidia1.x509 new file mode 100644 index 0000000000000000000000000000000000000000..eb6248fc7b782d7ecae0f5fc46049c0d348874fa GIT binary patch literal 992 zcmXqLV!mV0#B^iS*(+s|eByS>zamyJ`a&724_sPGH(bn$dl@Xb#t%}G^ob~KO^=QT1lFf}qUG%+?X zFpL6n&5*bT#nf|;hJhNyJ@UBR6P%fzmzkGt(8Q>O94?Hk49rc8{0u;GE~X|%Muzzp zUO3JDuH=#1Qzl!+D6%VF<(Pw=T%P%3Nu5~5S%T}Hi?uRq2cGi2DLqlf;B8Bt^j`mG z^(N61Y-fIMU#+x%=0%&G7uHDL@QChxllp9_HZPydww#@No+$*p;o&LnSLzB$p z-7Kw7+;m|=YHZ1oUz|FA#o`5yZ`lJkUhg~Qp73c|lIV-|?Y;+E9~FMISfqEXYE?z% zU%_6Mx?7*+3Og0g|LNv_WB$=&Z5h)Idnd6AzjhV=d3pTdJ=E_;2I_~av+N)o3@ zc;sBoVqVL{%*epFxX>WqKpq&PvdSzH24W2&N7mT8SZy(9nr!DQk2i%io?lwuccw{3MXFm{$TKH~3qkp2J9 zcLIAWc9!=}Ua_)-p^xpui_m@ZPqIfUd^ozOE=KpryWbY;_q}MUp}mHL78uXY~Sz k<(|s@KQTuX9%)T$yRhna+wz3h3{v}K+&R+Hy?7@90G#r4nE(I) literal 0 HcmV?d00001 From 595f70809e6102d3cb4525a4a79bf5358d9573cb Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Wed, 6 Aug 2025 14:03:04 +0000 Subject: [PATCH 05/17] NFSD: fix hang in nfsd4_shutdown_callback --- config.yaml | 7 ++- ...bf455d75ce54314efc826364259b8a87a8d0.patch | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch diff --git a/config.yaml b/config.yaml index 919612b..6226e9e 100644 --- a/config.yaml +++ b/config.yaml @@ -40,6 +40,10 @@ actions: name: "ppc64le-kvm-support.patch" number: "Latest" modify_spec: false + - type: "patch" + name: "b86dbf455d75ce54314efc826364259b8a87a8d0.patch" + number: "Latest" + modify_spec: false - replace: - target: "kernel*rhel.config" @@ -440,7 +444,7 @@ actions: cwd: "rpms" - changelog_entry: - - name: "Andrei Lukoshko" + - name: "Andrew Lukoshko" email: "alukoshko@almalinux.org" line: - "hpsa: bring back deprecated PCI ids #CFHack #CFHack2024" @@ -451,6 +455,7 @@ actions: - "lpfc: bring back deprecated PCI ids" - "be2iscsi: bring back deprecated PCI ids" - "kernel/rh_messages.h: enable all disabled pci devices by moving to unmaintained" + - "NFSD: fix hang in nfsd4_shutdown_callback" - name: "Eduard Abdullin" email: "eabdullin@almalinux.org" line: diff --git a/files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch b/files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch new file mode 100644 index 0000000..f68a5e9 --- /dev/null +++ b/files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch @@ -0,0 +1,54 @@ +From b86dbf455d75ce54314efc826364259b8a87a8d0 Mon Sep 17 00:00:00 2001 +From: Olga Kornievskaia +Date: Mon, 3 Mar 2025 12:09:08 -0500 +Subject: [PATCH] NFSD: fix hang in nfsd4_shutdown_callback + +JIRA: https://issues.redhat.com/browse/RHEL-81291 +CVE: CVE-2025-21795 + +commit 036ac2778f7b28885814c6fbc07e156ad1624d03 +Author: Dai Ngo +Date: Thu Jan 30 11:01:27 2025 -0800 + + NFSD: fix hang in nfsd4_shutdown_callback + + If nfs4_client is in courtesy state then there is no point to send + the callback. This causes nfsd4_shutdown_callback to hang since + cl_cb_inflight is not 0. This hang lasts about 15 minutes until TCP + notifies NFSD that the connection was dropped. + + This patch modifies nfsd4_run_cb_work to skip the RPC call if + nfs4_client is in courtesy state. + + Signed-off-by: Dai Ngo + Fixes: 66af25799940 ("NFSD: add courteous server support for thread with only delegation") + Cc: stable@vger.kernel.org + Reviewed-by: Jeff Layton + Signed-off-by: Chuck Lever + +Signed-off-by: Olga Kornievskaia +--- + fs/nfsd/nfs4callback.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 0d7cc2f9a8e07..d8eed853d528d 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -1480,8 +1480,11 @@ nfsd4_run_cb_work(struct work_struct *work) + nfsd4_process_cb_update(cb); + + clnt = clp->cl_cb_client; +- if (!clnt) { +- /* Callback channel broken, or client killed; give up: */ ++ if (!clnt || clp->cl_state == NFSD4_COURTESY) { ++ /* ++ * Callback channel broken, client killed or ++ * nfs4_client in courtesy state; give up. ++ */ + nfsd41_destroy_cb(cb); + return; + } +-- +GitLab + From ba877d1f8aca2465e4416fc752d98d0c83e9b370 Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Wed, 6 Aug 2025 14:45:37 +0000 Subject: [PATCH 06/17] Apply b86dbf455d75ce54314efc826364259b8a87a8d0.patch --- config.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 6226e9e..7ae48c6 100644 --- a/config.yaml +++ b/config.yaml @@ -42,8 +42,7 @@ actions: modify_spec: false - type: "patch" name: "b86dbf455d75ce54314efc826364259b8a87a8d0.patch" - number: "Latest" - modify_spec: false + number: "3001" - replace: - target: "kernel*rhel.config" From 71d3aaa7cce9cb2de0bfdf82a940cc10dd13695e Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Wed, 6 Aug 2025 14:50:07 +0000 Subject: [PATCH 07/17] Fix patch number --- config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 7ae48c6..d926bf3 100644 --- a/config.yaml +++ b/config.yaml @@ -42,7 +42,7 @@ actions: modify_spec: false - type: "patch" name: "b86dbf455d75ce54314efc826364259b8a87a8d0.patch" - number: "3001" + number: 3001 - replace: - target: "kernel*rhel.config" From 1f436b52e4b8104ae13d49b8e034f5ec1ded2721 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Tue, 16 Sep 2025 08:53:47 +0300 Subject: [PATCH 08/17] Drop b86dbf455d75ce54314efc826364259b8a87a8d0.patch as it already in upstream Update 0004 patch --- config.yaml | 4 ---- ...0004-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/config.yaml b/config.yaml index d926bf3..5e2f0ab 100644 --- a/config.yaml +++ b/config.yaml @@ -40,9 +40,6 @@ actions: name: "ppc64le-kvm-support.patch" number: "Latest" modify_spec: false - - type: "patch" - name: "b86dbf455d75ce54314efc826364259b8a87a8d0.patch" - number: 3001 - replace: - target: "kernel*rhel.config" @@ -454,7 +451,6 @@ actions: - "lpfc: bring back deprecated PCI ids" - "be2iscsi: bring back deprecated PCI ids" - "kernel/rh_messages.h: enable all disabled pci devices by moving to unmaintained" - - "NFSD: fix hang in nfsd4_shutdown_callback" - name: "Eduard Abdullin" email: "eabdullin@almalinux.org" line: diff --git a/files/0004-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch b/files/0004-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch index ead1bb5..733d460 100644 --- a/files/0004-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch +++ b/files/0004-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch @@ -14,7 +14,7 @@ index 036f26c42..1d7b684dc 100644 @@ -8121,7 +8121,6 @@ static const struct pci_error_handlers qla2xxx_err_handler = { }; - static struct pci_device_id qla2xxx_pci_tbl[] = { + static const struct pci_device_id qla2xxx_pci_tbl[] = { -#ifndef CONFIG_RHEL_DIFFERENCES { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) }, @@ -40,4 +40,3 @@ index 036f26c42..1d7b684dc 100644 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2261) }, -- 2.27.0 - From 1ee03d7941b72178f82de9ec47efa9974d6c888d Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Tue, 11 Nov 2025 11:23:12 +0000 Subject: [PATCH 09/17] Update for 5.14.0-611.5.1.el9_7 --- config.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 5e2f0ab..1062fed 100644 --- a/config.yaml +++ b/config.yaml @@ -84,7 +84,7 @@ actions: %define pesign_name_0 centossecureboot201 %else %ifarch x86_64 aarch64 - %define pesign_name_0 redhatsecureboot501 + %define pesign_name_0 redhatsecureboot801 %endif %ifarch s390x %define pesign_name_0 redhatsecureboot302 @@ -181,6 +181,10 @@ actions: find: "UKI_secureboot_name=redhatsecureboot504" replace: "UKI_secureboot_name=alsecureboot001" count: 1 + - target: "spec" + find: "UKI_secureboot_cert=%{SOURCE153}" + replace: "UKI_secureboot_cert=%{_datadir}/pki/sb-certs/secureboot-uki-virt-%{_arch}.cer" + count: 1 - target: "spec" find: "# Red Hat UEFI Secure Boot CA cert, which can be used to authenticate the kernel" replace: "# AlmaLinux UEFI Secure Boot CA cert, which can be used to authenticate the kernel" @@ -434,6 +438,9 @@ actions: if [ "$KernelExtension" == "gz" ]; then gzip -f9 $SignImage fi + - | + # Temporary use redhatsecureboot504 for x86 UKI, see RHEL-122230 + Source153: redhatsecureboot504.cer - run_script: - script: "copy_ppc64le_config.sh" From 69d30fcbc48301b7a239a56b5561c6ade14010ef Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Sun, 8 Mar 2026 21:47:08 +0000 Subject: [PATCH 10/17] Replace pesign_name_0 with AlmaLinux secure boot cert name --- config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 1062fed..13d3da8 100644 --- a/config.yaml +++ b/config.yaml @@ -93,7 +93,7 @@ actions: %define pesign_name_0 redhatsecureboot701 %endif %endif - replace: "%define pesign_name_0 almalinuxsecurebootca0" + replace: "%define pesign_name_0 almalinuxsecureboot0" count: 1 - target: "spec" find: "Source103: almalinuxima.x509" From 9e98278db8d896ed2fd130a9251e72f80e9889ec Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Tue, 21 Apr 2026 19:40:20 +0000 Subject: [PATCH 11/17] Fix signing key name for UKI --- config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 13d3da8..1b9e687 100644 --- a/config.yaml +++ b/config.yaml @@ -175,11 +175,11 @@ actions: count: 1 - target: "spec" find: "UKI_secureboot_name=centossecureboot204" - replace: "UKI_secureboot_name=alsecureboot001" + replace: "UKI_secureboot_name=%{pesign_name_0}" count: 1 - target: "spec" find: "UKI_secureboot_name=redhatsecureboot504" - replace: "UKI_secureboot_name=alsecureboot001" + replace: "UKI_secureboot_name=%{pesign_name_0}" count: 1 - target: "spec" find: "UKI_secureboot_cert=%{SOURCE153}" From dd695406190fd83dccb7bf13b6277a09e4c78770 Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Wed, 29 Apr 2026 23:45:28 +0200 Subject: [PATCH 12/17] crypto: algif_aead - Revert to operating out-of-place --- config.yaml | 4 + ...ead-Revert-to-operating-out-of-place.patch | 308 ++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch diff --git a/config.yaml b/config.yaml index 1b9e687..7993cab 100644 --- a/config.yaml +++ b/config.yaml @@ -40,6 +40,9 @@ actions: name: "ppc64le-kvm-support.patch" number: "Latest" modify_spec: false + - type: "patch" + name: "1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch" + number: 1100 - replace: - target: "kernel*rhel.config" @@ -450,6 +453,7 @@ actions: - name: "Andrew Lukoshko" email: "alukoshko@almalinux.org" line: + - "crypto: algif_aead - Revert to operating out-of-place" - "hpsa: bring back deprecated PCI ids #CFHack #CFHack2024" - "mptsas: bring back deprecated PCI ids #CFHack #CFHack2024" - "megaraid_sas: bring back deprecated PCI ids #CFHack #CFHack2024" diff --git a/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch b/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch new file mode 100644 index 0000000..6652b2b --- /dev/null +++ b/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch @@ -0,0 +1,308 @@ +From a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 26 Mar 2026 15:30:20 +0900 +Subject: [PATCH] crypto: algif_aead - Revert to operating out-of-place + +This mostly reverts commit 72548b093ee3 except for the copying of +the associated data. + +There is no benefit in operating in-place in algif_aead since the +source and destination come from different mappings. Get rid of +all the complexity added for in-place operation and just copy the +AD directly. + +Backported to kernel-5.14.0-611.49.1.el9_7: this tree pre-dates upstream's +memcpy_sglist() helper, so the AAD copy keeps using +crypto_aead_copy_sgl(null_tfm, ...). The function signatures of +af_alg_count_tsgl() and af_alg_pull_tsgl() are reverted to drop the +offset parameters as in upstream. + +Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst") +Reported-by: Taeyang Lee <0wn@theori.io> +Signed-off-by: Herbert Xu +--- +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -525,15 +525,13 @@ + /** + * af_alg_count_tsgl - Count number of TX SG entries + * +- * The counting starts from the beginning of the SGL to @bytes. If +- * an @offset is provided, the counting of the SG entries starts at the @offset. ++ * The counting starts from the beginning of the SGL to @bytes. + * + * @sk: socket of connection to user space + * @bytes: Count the number of SG entries holding given number of bytes. +- * @offset: Start the counting of SG entries from the given offset. + * Return: Number of TX SG entries found given the constraints + */ +-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) ++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) + { + const struct alg_sock *ask = alg_sk(sk); + const struct af_alg_ctx *ctx = ask->private; +@@ -548,25 +546,11 @@ + const struct scatterlist *sg = sgl->sg; + + for (i = 0; i < sgl->cur; i++) { +- size_t bytes_count; +- +- /* Skip offset */ +- if (offset >= sg[i].length) { +- offset -= sg[i].length; +- bytes -= sg[i].length; +- continue; +- } +- +- bytes_count = sg[i].length - offset; +- +- offset = 0; + sgl_count++; +- +- /* If we have seen requested number of bytes, stop */ +- if (bytes_count >= bytes) ++ if (sg[i].length >= bytes) + return sgl_count; + +- bytes -= bytes_count; ++ bytes -= sg[i].length; + } + } + +@@ -578,19 +562,14 @@ + * af_alg_pull_tsgl - Release the specified buffers from TX SGL + * + * If @dst is non-null, reassign the pages to @dst. The caller must release +- * the pages. If @dst_offset is given only reassign the pages to @dst starting +- * at the @dst_offset (byte). The caller must ensure that @dst is large +- * enough (e.g. by using af_alg_count_tsgl with the same offset). ++ * the pages. + * + * @sk: socket of connection to user space + * @used: Number of bytes to pull from TX SGL + * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The + * caller must release the buffers in dst. +- * @dst_offset: Reassign the TX SGL from given offset. All buffers before +- * reaching the offset is released. + */ +-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, +- size_t dst_offset) ++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) + { + struct alg_sock *ask = alg_sk(sk); + struct af_alg_ctx *ctx = ask->private; +@@ -615,18 +594,10 @@ + * SG entries in dst. + */ + if (dst) { +- if (dst_offset >= plen) { +- /* discard page before offset */ +- dst_offset -= plen; +- } else { +- /* reassign page to dst after offset */ +- get_page(page); +- sg_set_page(dst + j, page, +- plen - dst_offset, +- sg[i].offset + dst_offset); +- dst_offset = 0; +- j++; +- } ++ /* reassign page to dst after offset */ ++ get_page(page); ++ sg_set_page(dst + j, page, plen, sg[i].offset); ++ j++; + } + + sg[i].length -= plen; +--- a/crypto/algif_aead.c ++++ b/crypto/algif_aead.c +@@ -96,9 +96,8 @@ + struct aead_tfm *aeadc = pask->private; + struct crypto_aead *tfm = aeadc->aead; + struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; +- unsigned int i, as = crypto_aead_authsize(tfm); ++ unsigned int as = crypto_aead_authsize(tfm); + struct af_alg_async_req *areq; +- struct af_alg_tsgl *tsgl, *tmp; + struct scatterlist *rsgl_src, *tsgl_src = NULL; + int err = 0; + size_t used = 0; /* [in] TX bufs to be en/decrypted */ +@@ -178,23 +177,24 @@ + outlen -= less; + } + ++ /* ++ * Create a per request TX SGL for this request which tracks the ++ * SG entries from the global TX SGL. ++ */ + processed = used + ctx->aead_assoclen; +- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { +- for (i = 0; i < tsgl->cur; i++) { +- struct scatterlist *process_sg = tsgl->sg + i; +- +- if (!(process_sg->length) || !sg_page(process_sg)) +- continue; +- tsgl_src = process_sg; +- break; +- } +- if (tsgl_src) +- break; +- } +- if (processed && !tsgl_src) { +- err = -EFAULT; ++ areq->tsgl_entries = af_alg_count_tsgl(sk, processed); ++ if (!areq->tsgl_entries) ++ areq->tsgl_entries = 1; ++ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), ++ areq->tsgl_entries), ++ GFP_KERNEL); ++ if (!areq->tsgl) { ++ err = -ENOMEM; + goto free; + } ++ sg_init_table(areq->tsgl, areq->tsgl_entries); ++ af_alg_pull_tsgl(sk, processed, areq->tsgl); ++ tsgl_src = areq->tsgl; + + /* + * Copy of AAD from source to destination +@@ -203,81 +203,18 @@ + * when user space uses an in-place cipher operation, the kernel + * will copy the data as it does not see whether such in-place operation + * is initiated. +- * +- * To ensure efficiency, the following implementation ensure that the +- * ciphers are invoked to perform a crypto operation in-place. This +- * is achieved by memory management specified as follows. + */ + +- /* Use the RX SGL as source (and destination) for crypto op. */ ++ /* Use the RX SGL as destination for crypto op. */ + rsgl_src = areq->first_rsgl.sgl.sg; + +- if (ctx->enc) { +- /* +- * Encryption operation - The in-place cipher operation is +- * achieved by the following operation: +- * +- * TX SGL: AAD || PT +- * | | +- * | copy | +- * v v +- * RX SGL: AAD || PT || Tag +- */ +- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, +- areq->first_rsgl.sgl.sg, processed); +- if (err) +- goto free; +- af_alg_pull_tsgl(sk, processed, NULL, 0); +- } else { +- /* +- * Decryption operation - To achieve an in-place cipher +- * operation, the following SGL structure is used: +- * +- * TX SGL: AAD || CT || Tag +- * | | ^ +- * | copy | | Create SGL link. +- * v v | +- * RX SGL: AAD || CT ----+ +- */ +- +- /* Copy AAD || CT to RX SGL buffer for in-place operation. */ +- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, +- areq->first_rsgl.sgl.sg, outlen); +- if (err) +- goto free; +- +- /* Create TX SGL for tag and chain it to RX SGL. */ +- areq->tsgl_entries = af_alg_count_tsgl(sk, processed, +- processed - as); +- if (!areq->tsgl_entries) +- areq->tsgl_entries = 1; +- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), +- areq->tsgl_entries), +- GFP_KERNEL); +- if (!areq->tsgl) { +- err = -ENOMEM; +- goto free; +- } +- sg_init_table(areq->tsgl, areq->tsgl_entries); +- +- /* Release TX SGL, except for tag data and reassign tag data. */ +- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); +- +- /* chain the areq TX SGL holding the tag with RX SGL */ +- if (usedpages) { +- /* RX SGL present */ +- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; +- +- sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); +- sg_chain(sgl_prev->sg, sgl_prev->npages + 1, +- areq->tsgl); +- } else +- /* no RX SGL present (e.g. authentication only) */ +- rsgl_src = areq->tsgl; +- } ++ err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src, ++ ctx->aead_assoclen); ++ if (err) ++ goto free; + + /* Initialize the crypto operation */ +- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, ++ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, + areq->first_rsgl.sgl.sg, used, ctx->iv); + aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); + aead_request_set_tfm(&areq->cra_u.aead_req, tfm); +@@ -526,7 +463,7 @@ + struct crypto_aead *tfm = aeadc->aead; + unsigned int ivlen = crypto_aead_ivsize(tfm); + +- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); ++ af_alg_pull_tsgl(sk, ctx->used, NULL); + sock_kzfree_s(sk, ctx->iv, ivlen); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -89,7 +89,7 @@ + * Create a per request TX SGL for this request which tracks the + * SG entries from the global TX SGL. + */ +- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); ++ areq->tsgl_entries = af_alg_count_tsgl(sk, len); + if (!areq->tsgl_entries) + areq->tsgl_entries = 1; + areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), +@@ -100,7 +100,7 @@ + goto free; + } + sg_init_table(areq->tsgl, areq->tsgl_entries); +- af_alg_pull_tsgl(sk, len, areq->tsgl, 0); ++ af_alg_pull_tsgl(sk, len, areq->tsgl); + + /* Initialize the crypto operation */ + skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); +@@ -313,7 +313,7 @@ + struct alg_sock *pask = alg_sk(psk); + struct crypto_skcipher *tfm = pask->private; + +- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); ++ af_alg_pull_tsgl(sk, ctx->used, NULL); + sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -226,9 +226,8 @@ + return PAGE_SIZE <= af_alg_rcvbuf(sk); + } + +-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); +-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, +- size_t dst_offset); ++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); ++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); + void af_alg_wmem_wakeup(struct sock *sk); + int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); + int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, From 32ede4fb1e3fae5756404edaf69a6540fc3a6ebc Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Thu, 30 Apr 2026 14:02:37 +0200 Subject: [PATCH 13/17] CVE-2026-31431 (Copy Fail): backport crypto AEAD/algif fixes --- config.yaml | 4 +- ...VE-2026-31431-crypto-Copy-Fail-fixes.patch | 962 ++++++++++++++++++ ...ead-Revert-to-operating-out-of-place.patch | 308 ------ 3 files changed, 964 insertions(+), 310 deletions(-) create mode 100644 files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch delete mode 100644 files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch diff --git a/config.yaml b/config.yaml index 7993cab..952ef64 100644 --- a/config.yaml +++ b/config.yaml @@ -41,7 +41,7 @@ actions: number: "Latest" modify_spec: false - type: "patch" - name: "1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch" + name: "1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch" number: 1100 - replace: @@ -453,7 +453,7 @@ actions: - name: "Andrew Lukoshko" email: "alukoshko@almalinux.org" line: - - "crypto: algif_aead - Revert to operating out-of-place" + - "CVE-2026-31431 (Copy Fail): backport crypto AEAD/algif fixes from stable-5.15.y" - "hpsa: bring back deprecated PCI ids #CFHack #CFHack2024" - "mptsas: bring back deprecated PCI ids #CFHack #CFHack2024" - "megaraid_sas: bring back deprecated PCI ids #CFHack #CFHack2024" diff --git a/files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch b/files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch new file mode 100644 index 0000000..193db49 --- /dev/null +++ b/files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch @@ -0,0 +1,962 @@ +From: AlmaLinux Backport +Subject: [PATCH] CVE-2026-31431 ("Copy Fail"): crypto AEAD/algif fixes from linux-5.15.y + +Combined backport addressing CVE-2026-31431 ("Copy Fail"), reported by +Taeyang Lee <0wn@theori.io>. EL9 kernel is based on 5.14.0; the closest +stable branch is linux-5.15.y. Pulls one prerequisite (committed +2026-02-06 to 5.15.y) plus nine 2026-04-30 stable fixes: + + fee86edf5803 crypto: authencesn - reject too-short AAD (assoclen<8) to match ESP/ESN spec + 36435a56cd6b crypto: scatterwalk - Backport memcpy_sglist() + 17774d99bb43 crypto: algif_aead - use memcpy_sglist() instead of null skcipher + 19d43105a97b crypto: algif_aead - Revert to operating out-of-place + a920cabdb0b7 crypto: algif_aead - snapshot IV for async AEAD requests + e416c41a96c8 crypto: authenc - use memcpy_sglist() instead of null skcipher + d589abd8b019 crypto: authencesn - Do not place hiseq at end of dst for out-of-place decryption + 723bb1b4a6dd crypto: authencesn - Fix src offset when decrypting in-place + 2b781d1d4f93 crypto: af_alg - Fix page reassignment overflow in af_alg_pull_tsgl + fd427dd84f22 crypto: algif_aead - Fix minimum RX size check for decryption + +fee86edf5803 is the prerequisite for d589abd8b019 to apply. + +Signed-off-by: Andrew Lukoshko +--- +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -525,15 +525,13 @@ + /** + * af_alg_count_tsgl - Count number of TX SG entries + * +- * The counting starts from the beginning of the SGL to @bytes. If +- * an @offset is provided, the counting of the SG entries starts at the @offset. ++ * The counting starts from the beginning of the SGL to @bytes. + * + * @sk: socket of connection to user space + * @bytes: Count the number of SG entries holding given number of bytes. +- * @offset: Start the counting of SG entries from the given offset. + * Return: Number of TX SG entries found given the constraints + */ +-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) ++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) + { + const struct alg_sock *ask = alg_sk(sk); + const struct af_alg_ctx *ctx = ask->private; +@@ -548,25 +546,11 @@ + const struct scatterlist *sg = sgl->sg; + + for (i = 0; i < sgl->cur; i++) { +- size_t bytes_count; +- +- /* Skip offset */ +- if (offset >= sg[i].length) { +- offset -= sg[i].length; +- bytes -= sg[i].length; +- continue; +- } +- +- bytes_count = sg[i].length - offset; +- +- offset = 0; + sgl_count++; +- +- /* If we have seen requested number of bytes, stop */ +- if (bytes_count >= bytes) ++ if (sg[i].length >= bytes) + return sgl_count; + +- bytes -= bytes_count; ++ bytes -= sg[i].length; + } + } + +@@ -578,19 +562,14 @@ + * af_alg_pull_tsgl - Release the specified buffers from TX SGL + * + * If @dst is non-null, reassign the pages to @dst. The caller must release +- * the pages. If @dst_offset is given only reassign the pages to @dst starting +- * at the @dst_offset (byte). The caller must ensure that @dst is large +- * enough (e.g. by using af_alg_count_tsgl with the same offset). ++ * the pages. + * + * @sk: socket of connection to user space + * @used: Number of bytes to pull from TX SGL + * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The + * caller must release the buffers in dst. +- * @dst_offset: Reassign the TX SGL from given offset. All buffers before +- * reaching the offset is released. + */ +-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, +- size_t dst_offset) ++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) + { + struct alg_sock *ask = alg_sk(sk); + struct af_alg_ctx *ctx = ask->private; +@@ -614,19 +593,11 @@ + * Assumption: caller created af_alg_count_tsgl(len) + * SG entries in dst. + */ +- if (dst) { +- if (dst_offset >= plen) { +- /* discard page before offset */ +- dst_offset -= plen; +- } else { +- /* reassign page to dst after offset */ +- get_page(page); +- sg_set_page(dst + j, page, +- plen - dst_offset, +- sg[i].offset + dst_offset); +- dst_offset = 0; +- j++; +- } ++ if (dst && plen) { ++ /* reassign page to dst */ ++ get_page(page); ++ sg_set_page(dst + j, page, plen, sg[i].offset); ++ j++; + } + + sg[i].length -= plen; +--- a/crypto/algif_aead.c ++++ b/crypto/algif_aead.c +@@ -26,8 +26,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -36,19 +34,13 @@ + #include + #include + +-struct aead_tfm { +- struct crypto_aead *aead; +- struct crypto_sync_skcipher *null_tfm; +-}; +- + static inline bool aead_sufficient_data(struct sock *sk) + { + struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); + struct af_alg_ctx *ctx = ask->private; +- struct aead_tfm *aeadc = pask->private; +- struct crypto_aead *tfm = aeadc->aead; ++ struct crypto_aead *tfm = pask->private; + unsigned int as = crypto_aead_authsize(tfm); + + /* +@@ -64,27 +56,12 @@ + struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); +- struct aead_tfm *aeadc = pask->private; +- struct crypto_aead *tfm = aeadc->aead; ++ struct crypto_aead *tfm = pask->private; + unsigned int ivsize = crypto_aead_ivsize(tfm); + + return af_alg_sendmsg(sock, msg, size, ivsize); + } + +-static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, +- struct scatterlist *src, +- struct scatterlist *dst, unsigned int len) +-{ +- SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); +- +- skcipher_request_set_sync_tfm(skreq, null_tfm); +- skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP, +- NULL, NULL); +- skcipher_request_set_crypt(skreq, src, dst, len, NULL); +- +- return crypto_skcipher_encrypt(skreq); +-} +- + static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) + { +@@ -93,13 +70,12 @@ + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); + struct af_alg_ctx *ctx = ask->private; +- struct aead_tfm *aeadc = pask->private; +- struct crypto_aead *tfm = aeadc->aead; +- struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; +- unsigned int i, as = crypto_aead_authsize(tfm); ++ struct crypto_aead *tfm = pask->private; ++ unsigned int as = crypto_aead_authsize(tfm); ++ unsigned int ivsize = crypto_aead_ivsize(tfm); + struct af_alg_async_req *areq; +- struct af_alg_tsgl *tsgl, *tmp; + struct scatterlist *rsgl_src, *tsgl_src = NULL; ++ void *iv; + int err = 0; + size_t used = 0; /* [in] TX bufs to be en/decrypted */ + size_t outlen = 0; /* [out] RX bufs produced by kernel */ +@@ -151,10 +127,14 @@ + + /* Allocate cipher request for current operation. */ + areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + +- crypto_aead_reqsize(tfm)); ++ crypto_aead_reqsize(tfm) + ivsize); + if (IS_ERR(areq)) + return PTR_ERR(areq); + ++ iv = (u8 *)aead_request_ctx(&areq->cra_u.aead_req) + ++ crypto_aead_reqsize(tfm); ++ memcpy(iv, ctx->iv, ivsize); ++ + /* convert iovecs of output buffers into RX SGL */ + err = af_alg_get_rsgl(sk, msg, flags, areq, outlen, &usedpages); + if (err) +@@ -170,7 +150,7 @@ + if (usedpages < outlen) { + size_t less = outlen - usedpages; + +- if (used < less) { ++ if (used < less + (ctx->enc ? 0 : as)) { + err = -EINVAL; + goto free; + } +@@ -178,23 +158,24 @@ + outlen -= less; + } + ++ /* ++ * Create a per request TX SGL for this request which tracks the ++ * SG entries from the global TX SGL. ++ */ + processed = used + ctx->aead_assoclen; +- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { +- for (i = 0; i < tsgl->cur; i++) { +- struct scatterlist *process_sg = tsgl->sg + i; +- +- if (!(process_sg->length) || !sg_page(process_sg)) +- continue; +- tsgl_src = process_sg; +- break; +- } +- if (tsgl_src) +- break; +- } +- if (processed && !tsgl_src) { +- err = -EFAULT; ++ areq->tsgl_entries = af_alg_count_tsgl(sk, processed); ++ if (!areq->tsgl_entries) ++ areq->tsgl_entries = 1; ++ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), ++ areq->tsgl_entries), ++ GFP_KERNEL); ++ if (!areq->tsgl) { ++ err = -ENOMEM; + goto free; + } ++ sg_init_table(areq->tsgl, areq->tsgl_entries); ++ af_alg_pull_tsgl(sk, processed, areq->tsgl); ++ tsgl_src = areq->tsgl; + + /* + * Copy of AAD from source to destination +@@ -203,82 +184,16 @@ + * when user space uses an in-place cipher operation, the kernel + * will copy the data as it does not see whether such in-place operation + * is initiated. +- * +- * To ensure efficiency, the following implementation ensure that the +- * ciphers are invoked to perform a crypto operation in-place. This +- * is achieved by memory management specified as follows. + */ + + /* Use the RX SGL as source (and destination) for crypto op. */ + rsgl_src = areq->first_rsgl.sgl.sg; + +- if (ctx->enc) { +- /* +- * Encryption operation - The in-place cipher operation is +- * achieved by the following operation: +- * +- * TX SGL: AAD || PT +- * | | +- * | copy | +- * v v +- * RX SGL: AAD || PT || Tag +- */ +- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, +- areq->first_rsgl.sgl.sg, processed); +- if (err) +- goto free; +- af_alg_pull_tsgl(sk, processed, NULL, 0); +- } else { +- /* +- * Decryption operation - To achieve an in-place cipher +- * operation, the following SGL structure is used: +- * +- * TX SGL: AAD || CT || Tag +- * | | ^ +- * | copy | | Create SGL link. +- * v v | +- * RX SGL: AAD || CT ----+ +- */ +- +- /* Copy AAD || CT to RX SGL buffer for in-place operation. */ +- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, +- areq->first_rsgl.sgl.sg, outlen); +- if (err) +- goto free; +- +- /* Create TX SGL for tag and chain it to RX SGL. */ +- areq->tsgl_entries = af_alg_count_tsgl(sk, processed, +- processed - as); +- if (!areq->tsgl_entries) +- areq->tsgl_entries = 1; +- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), +- areq->tsgl_entries), +- GFP_KERNEL); +- if (!areq->tsgl) { +- err = -ENOMEM; +- goto free; +- } +- sg_init_table(areq->tsgl, areq->tsgl_entries); +- +- /* Release TX SGL, except for tag data and reassign tag data. */ +- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); +- +- /* chain the areq TX SGL holding the tag with RX SGL */ +- if (usedpages) { +- /* RX SGL present */ +- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; +- +- sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); +- sg_chain(sgl_prev->sg, sgl_prev->npages + 1, +- areq->tsgl); +- } else +- /* no RX SGL present (e.g. authentication only) */ +- rsgl_src = areq->tsgl; +- } ++ memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen); + + /* Initialize the crypto operation */ +- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, +- areq->first_rsgl.sgl.sg, used, ctx->iv); ++ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, ++ areq->first_rsgl.sgl.sg, used, iv); + aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); + aead_request_set_tfm(&areq->cra_u.aead_req, tfm); + +@@ -378,7 +293,7 @@ + int err = 0; + struct sock *psk; + struct alg_sock *pask; +- struct aead_tfm *tfm; ++ struct crypto_aead *tfm; + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + +@@ -392,7 +307,7 @@ + + err = -ENOKEY; + lock_sock_nested(psk, SINGLE_DEPTH_NESTING); +- if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) ++ if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) + goto unlock; + + atomic_dec(&pask->nokey_refcnt); +@@ -466,54 +381,22 @@ + + static void *aead_bind(const char *name, u32 type, u32 mask) + { +- struct aead_tfm *tfm; +- struct crypto_aead *aead; +- struct crypto_sync_skcipher *null_tfm; +- +- tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); +- if (!tfm) +- return ERR_PTR(-ENOMEM); +- +- aead = crypto_alloc_aead(name, type, mask); +- if (IS_ERR(aead)) { +- kfree(tfm); +- return ERR_CAST(aead); +- } +- +- null_tfm = crypto_get_default_null_skcipher(); +- if (IS_ERR(null_tfm)) { +- crypto_free_aead(aead); +- kfree(tfm); +- return ERR_CAST(null_tfm); +- } +- +- tfm->aead = aead; +- tfm->null_tfm = null_tfm; +- +- return tfm; ++ return crypto_alloc_aead(name, type, mask); + } + + static void aead_release(void *private) + { +- struct aead_tfm *tfm = private; +- +- crypto_free_aead(tfm->aead); +- crypto_put_default_null_skcipher(); +- kfree(tfm); ++ crypto_free_aead(private); + } + + static int aead_setauthsize(void *private, unsigned int authsize) + { +- struct aead_tfm *tfm = private; +- +- return crypto_aead_setauthsize(tfm->aead, authsize); ++ return crypto_aead_setauthsize(private, authsize); + } + + static int aead_setkey(void *private, const u8 *key, unsigned int keylen) + { +- struct aead_tfm *tfm = private; +- +- return crypto_aead_setkey(tfm->aead, key, keylen); ++ return crypto_aead_setkey(private, key, keylen); + } + + static void aead_sock_destruct(struct sock *sk) +@@ -522,11 +405,10 @@ + struct af_alg_ctx *ctx = ask->private; + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); +- struct aead_tfm *aeadc = pask->private; +- struct crypto_aead *tfm = aeadc->aead; ++ struct crypto_aead *tfm = pask->private; + unsigned int ivlen = crypto_aead_ivsize(tfm); + +- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); ++ af_alg_pull_tsgl(sk, ctx->used, NULL); + sock_kzfree_s(sk, ctx->iv, ivlen); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +@@ -536,10 +418,9 @@ + { + struct af_alg_ctx *ctx; + struct alg_sock *ask = alg_sk(sk); +- struct aead_tfm *tfm = private; +- struct crypto_aead *aead = tfm->aead; ++ struct crypto_aead *tfm = private; + unsigned int len = sizeof(*ctx); +- unsigned int ivlen = crypto_aead_ivsize(aead); ++ unsigned int ivlen = crypto_aead_ivsize(tfm); + + ctx = sock_kmalloc(sk, len, GFP_KERNEL); + if (!ctx) +@@ -566,9 +447,9 @@ + + static int aead_accept_parent(void *private, struct sock *sk) + { +- struct aead_tfm *tfm = private; ++ struct crypto_aead *tfm = private; + +- if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) ++ if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) + return -ENOKEY; + + return aead_accept_parent_nokey(private, sk); +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -89,7 +89,7 @@ + * Create a per request TX SGL for this request which tracks the + * SG entries from the global TX SGL. + */ +- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); ++ areq->tsgl_entries = af_alg_count_tsgl(sk, len); + if (!areq->tsgl_entries) + areq->tsgl_entries = 1; + areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), +@@ -100,7 +100,7 @@ + goto free; + } + sg_init_table(areq->tsgl, areq->tsgl_entries); +- af_alg_pull_tsgl(sk, len, areq->tsgl, 0); ++ af_alg_pull_tsgl(sk, len, areq->tsgl); + + /* Initialize the crypto operation */ + skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); +@@ -313,7 +313,7 @@ + struct alg_sock *pask = alg_sk(psk); + struct crypto_skcipher *tfm = pask->private; + +- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); ++ af_alg_pull_tsgl(sk, ctx->used, NULL); + sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +--- a/crypto/authenc.c ++++ b/crypto/authenc.c +@@ -9,7 +9,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -28,7 +27,6 @@ + struct crypto_authenc_ctx { + struct crypto_ahash *auth; + struct crypto_skcipher *enc; +- struct crypto_sync_skcipher *null; + }; + + struct authenc_request_ctx { +@@ -174,21 +172,6 @@ + authenc_request_complete(areq, err); + } + +-static int crypto_authenc_copy_assoc(struct aead_request *req) +-{ +- struct crypto_aead *authenc = crypto_aead_reqtfm(req); +- struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); +- SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); +- +- skcipher_request_set_sync_tfm(skreq, ctx->null); +- skcipher_request_set_callback(skreq, aead_request_flags(req), +- NULL, NULL); +- skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, +- NULL); +- +- return crypto_skcipher_encrypt(skreq); +-} +- + static int crypto_authenc_encrypt(struct aead_request *req) + { + struct crypto_aead *authenc = crypto_aead_reqtfm(req); +@@ -207,10 +190,7 @@ + dst = src; + + if (req->src != req->dst) { +- err = crypto_authenc_copy_assoc(req); +- if (err) +- return err; +- ++ memcpy_sglist(req->dst, req->src, req->assoclen); + dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); + } + +@@ -311,7 +291,6 @@ + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); + struct crypto_ahash *auth; + struct crypto_skcipher *enc; +- struct crypto_sync_skcipher *null; + int err; + + auth = crypto_spawn_ahash(&ictx->auth); +@@ -323,14 +302,8 @@ + if (IS_ERR(enc)) + goto err_free_ahash; + +- null = crypto_get_default_null_skcipher(); +- err = PTR_ERR(null); +- if (IS_ERR(null)) +- goto err_free_skcipher; +- + ctx->auth = auth; + ctx->enc = enc; +- ctx->null = null; + + crypto_aead_set_reqsize( + tfm, +@@ -344,8 +317,6 @@ + + return 0; + +-err_free_skcipher: +- crypto_free_skcipher(enc); + err_free_ahash: + crypto_free_ahash(auth); + return err; +@@ -357,7 +328,6 @@ + + crypto_free_ahash(ctx->auth); + crypto_free_skcipher(ctx->enc); +- crypto_put_default_null_skcipher(); + } + + static void crypto_authenc_free(struct aead_instance *inst) +--- a/crypto/authencesn.c ++++ b/crypto/authencesn.c +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -31,7 +30,6 @@ + unsigned int reqoff; + struct crypto_ahash *auth; + struct crypto_skcipher *enc; +- struct crypto_sync_skcipher *null; + }; + + struct authenc_esn_request_ctx { +@@ -164,20 +162,6 @@ + authenc_esn_request_complete(areq, err); + } + +-static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len) +-{ +- struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); +- struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); +- SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); +- +- skcipher_request_set_sync_tfm(skreq, ctx->null); +- skcipher_request_set_callback(skreq, aead_request_flags(req), +- NULL, NULL); +- skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL); +- +- return crypto_skcipher_encrypt(skreq); +-} +- + static int crypto_authenc_esn_encrypt(struct aead_request *req) + { + struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); +@@ -191,15 +175,15 @@ + struct scatterlist *src, *dst; + int err; + ++ if (assoclen < 8) ++ return -EINVAL; ++ + sg_init_table(areq_ctx->src, 2); + src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen); + dst = src; + + if (req->src != req->dst) { +- err = crypto_authenc_esn_copy(req, assoclen); +- if (err) +- return err; +- ++ memcpy_sglist(req->dst, req->src, assoclen); + sg_init_table(areq_ctx->dst, 2); + dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen); + } +@@ -230,6 +214,7 @@ + crypto_ahash_alignmask(auth) + 1); + unsigned int cryptlen = req->cryptlen - authsize; + unsigned int assoclen = req->assoclen; ++ struct scatterlist *src = req->src; + struct scatterlist *dst = req->dst; + u8 *ihash = ohash + crypto_ahash_digestsize(auth); + u32 tmp[2]; +@@ -237,23 +222,29 @@ + if (!authsize) + goto decrypt; + +- /* Move high-order bits of sequence number back. */ +- scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); +- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); +- scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); ++ if (src == dst) { ++ /* Move high-order bits of sequence number back. */ ++ scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); ++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); ++ scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); ++ } else ++ memcpy_sglist(dst, src, assoclen); + + if (crypto_memneq(ihash, ohash, authsize)) + return -EBADMSG; + + decrypt: + +- sg_init_table(areq_ctx->dst, 2); + dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); ++ if (req->src == req->dst) ++ src = dst; ++ else ++ src = scatterwalk_ffwd(areq_ctx->src, src, assoclen); + + skcipher_request_set_tfm(skreq, ctx->enc); + skcipher_request_set_callback(skreq, flags, + req->base.complete, req->base.data); +- skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv); ++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); + + return crypto_skcipher_decrypt(skreq); + } +@@ -280,31 +271,36 @@ + unsigned int assoclen = req->assoclen; + unsigned int cryptlen = req->cryptlen; + u8 *ihash = ohash + crypto_ahash_digestsize(auth); ++ struct scatterlist *src = req->src; + struct scatterlist *dst = req->dst; + u32 tmp[2]; + int err; + +- cryptlen -= authsize; ++ if (assoclen < 8) ++ return -EINVAL; + +- if (req->src != dst) { +- err = crypto_authenc_esn_copy(req, assoclen + cryptlen); +- if (err) +- return err; +- } ++ if (!authsize) ++ goto tail; + ++ cryptlen -= authsize; + scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, + authsize, 0); + +- if (!authsize) +- goto tail; +- + /* Move high-order bits of sequence number to the end. */ +- scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); +- scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); +- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); +- +- sg_init_table(areq_ctx->dst, 2); +- dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); ++ scatterwalk_map_and_copy(tmp, src, 0, 8, 0); ++ if (src == dst) { ++ scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); ++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); ++ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); ++ } else { ++ scatterwalk_map_and_copy(tmp, dst, 0, 4, 1); ++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1); ++ ++ src = scatterwalk_ffwd(areq_ctx->src, src, 8); ++ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); ++ memcpy_sglist(dst, src, assoclen + cryptlen - 8); ++ dst = req->dst; ++ } + + ahash_request_set_tfm(ahreq, auth); + ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen); +@@ -326,7 +322,6 @@ + struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); + struct crypto_ahash *auth; + struct crypto_skcipher *enc; +- struct crypto_sync_skcipher *null; + int err; + + auth = crypto_spawn_ahash(&ictx->auth); +@@ -338,14 +333,8 @@ + if (IS_ERR(enc)) + goto err_free_ahash; + +- null = crypto_get_default_null_skcipher(); +- err = PTR_ERR(null); +- if (IS_ERR(null)) +- goto err_free_skcipher; +- + ctx->auth = auth; + ctx->enc = enc; +- ctx->null = null; + + ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth), + crypto_ahash_alignmask(auth) + 1); +@@ -362,8 +351,6 @@ + + return 0; + +-err_free_skcipher: +- crypto_free_skcipher(enc); + err_free_ahash: + crypto_free_ahash(auth); + return err; +@@ -375,7 +362,6 @@ + + crypto_free_ahash(ctx->auth); + crypto_free_skcipher(ctx->enc); +- crypto_put_default_null_skcipher(); + } + + static void crypto_authenc_esn_free(struct aead_instance *inst) +--- a/crypto/scatterwalk.c ++++ b/crypto/scatterwalk.c +@@ -69,6 +69,100 @@ + } + EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); + ++/** ++ * memcpy_sglist() - Copy data from one scatterlist to another ++ * @dst: The destination scatterlist. Can be NULL if @nbytes == 0. ++ * @src: The source scatterlist. Can be NULL if @nbytes == 0. ++ * @nbytes: Number of bytes to copy ++ * ++ * The scatterlists can describe exactly the same memory, in which case this ++ * function is a no-op. No other overlaps are supported. ++ * ++ * Context: Any context ++ */ ++void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ unsigned int src_offset, dst_offset; ++ ++ if (unlikely(nbytes == 0)) /* in case src and/or dst is NULL */ ++ return; ++ ++ src_offset = src->offset; ++ dst_offset = dst->offset; ++ for (;;) { ++ /* Compute the length to copy this step. */ ++ unsigned int len = min3(src->offset + src->length - src_offset, ++ dst->offset + dst->length - dst_offset, ++ nbytes); ++ struct page *src_page = sg_page(src); ++ struct page *dst_page = sg_page(dst); ++ const void *src_virt; ++ void *dst_virt; ++ ++ if (IS_ENABLED(CONFIG_HIGHMEM)) { ++ /* HIGHMEM: we may have to actually map the pages. */ ++ const unsigned int src_oip = offset_in_page(src_offset); ++ const unsigned int dst_oip = offset_in_page(dst_offset); ++ const unsigned int limit = PAGE_SIZE; ++ ++ /* Further limit len to not cross a page boundary. */ ++ len = min3(len, limit - src_oip, limit - dst_oip); ++ ++ /* Compute the source and destination pages. */ ++ src_page += src_offset / PAGE_SIZE; ++ dst_page += dst_offset / PAGE_SIZE; ++ ++ if (src_page != dst_page) { ++ /* Copy between different pages. */ ++ memcpy_page(dst_page, dst_oip, ++ src_page, src_oip, len); ++ flush_dcache_page(dst_page); ++ } else if (src_oip != dst_oip) { ++ /* Copy between different parts of same page. */ ++ dst_virt = kmap_local_page(dst_page); ++ memcpy(dst_virt + dst_oip, dst_virt + src_oip, ++ len); ++ kunmap_local(dst_virt); ++ flush_dcache_page(dst_page); ++ } /* Else, it's the same memory. No action needed. */ ++ } else { ++ /* ++ * !HIGHMEM: no mapping needed. Just work in the linear ++ * buffer of each sg entry. Note that we can cross page ++ * boundaries, as they are not significant in this case. ++ */ ++ src_virt = page_address(src_page) + src_offset; ++ dst_virt = page_address(dst_page) + dst_offset; ++ if (src_virt != dst_virt) { ++ memcpy(dst_virt, src_virt, len); ++ if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) ++ __scatterwalk_flush_dcache_pages( ++ dst_page, dst_offset, len); ++ } /* Else, it's the same memory. No action needed. */ ++ } ++ nbytes -= len; ++ if (nbytes == 0) /* No more to copy? */ ++ break; ++ ++ /* ++ * There's more to copy. Advance the offsets by the length ++ * copied this step, and advance the sg entries as needed. ++ */ ++ src_offset += len; ++ if (src_offset >= src->offset + src->length) { ++ src = sg_next(src); ++ src_offset = src->offset; ++ } ++ dst_offset += len; ++ if (dst_offset >= dst->offset + dst->length) { ++ dst = sg_next(dst); ++ dst_offset = dst->offset; ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(memcpy_sglist); ++ + struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], + struct scatterlist *src, + unsigned int len) +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -221,7 +221,6 @@ + select CRYPTO_SKCIPHER + select CRYPTO_MANAGER + select CRYPTO_HASH +- select CRYPTO_NULL + help + Authenc: Combined mode wrapper for IPsec. + This is required for IPSec. +@@ -2120,7 +2119,6 @@ + depends on NET + select CRYPTO_AEAD + select CRYPTO_SKCIPHER +- select CRYPTO_NULL + select CRYPTO_USER_API + help + This option enables the user-spaces interface for AEAD +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -226,9 +226,8 @@ + return PAGE_SIZE <= af_alg_rcvbuf(sk); + } + +-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); +-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, +- size_t dst_offset); ++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); ++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); + void af_alg_wmem_wakeup(struct sock *sk); + int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); + int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, +--- a/include/crypto/scatterwalk.h ++++ b/include/crypto/scatterwalk.h +@@ -89,6 +89,35 @@ + scatterwalk_start(walk, sg_next(walk->sg)); + } + ++/* ++ * Flush the dcache of any pages that overlap the region ++ * [offset, offset + nbytes) relative to base_page. ++ * ++ * This should be called only when ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, to ensure ++ * that all relevant code (including the call to sg_page() in the caller, if ++ * applicable) gets fully optimized out when !ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE. ++ */ ++static inline void __scatterwalk_flush_dcache_pages(struct page *base_page, ++ unsigned int offset, ++ unsigned int nbytes) ++{ ++ unsigned int num_pages; ++ unsigned int i; ++ ++ base_page += offset / PAGE_SIZE; ++ offset %= PAGE_SIZE; ++ ++ /* ++ * This is an overflow-safe version of ++ * num_pages = DIV_ROUND_UP(offset + nbytes, PAGE_SIZE). ++ */ ++ num_pages = nbytes / PAGE_SIZE; ++ num_pages += DIV_ROUND_UP(offset + (nbytes % PAGE_SIZE), PAGE_SIZE); ++ ++ for (i = 0; i < num_pages; i++) ++ flush_dcache_page(base_page + i); ++} ++ + static inline void scatterwalk_done(struct scatter_walk *walk, int out, + int more) + { +@@ -101,6 +130,9 @@ + size_t nbytes, int out); + void *scatterwalk_map(struct scatter_walk *walk); + ++void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, ++ unsigned int nbytes); ++ + void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, + unsigned int start, unsigned int nbytes, int out); + diff --git a/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch b/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch deleted file mode 100644 index 6652b2b..0000000 --- a/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch +++ /dev/null @@ -1,308 +0,0 @@ -From a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 Mon Sep 17 00:00:00 2001 -From: Herbert Xu -Date: Thu, 26 Mar 2026 15:30:20 +0900 -Subject: [PATCH] crypto: algif_aead - Revert to operating out-of-place - -This mostly reverts commit 72548b093ee3 except for the copying of -the associated data. - -There is no benefit in operating in-place in algif_aead since the -source and destination come from different mappings. Get rid of -all the complexity added for in-place operation and just copy the -AD directly. - -Backported to kernel-5.14.0-611.49.1.el9_7: this tree pre-dates upstream's -memcpy_sglist() helper, so the AAD copy keeps using -crypto_aead_copy_sgl(null_tfm, ...). The function signatures of -af_alg_count_tsgl() and af_alg_pull_tsgl() are reverted to drop the -offset parameters as in upstream. - -Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst") -Reported-by: Taeyang Lee <0wn@theori.io> -Signed-off-by: Herbert Xu ---- ---- a/crypto/af_alg.c -+++ b/crypto/af_alg.c -@@ -525,15 +525,13 @@ - /** - * af_alg_count_tsgl - Count number of TX SG entries - * -- * The counting starts from the beginning of the SGL to @bytes. If -- * an @offset is provided, the counting of the SG entries starts at the @offset. -+ * The counting starts from the beginning of the SGL to @bytes. - * - * @sk: socket of connection to user space - * @bytes: Count the number of SG entries holding given number of bytes. -- * @offset: Start the counting of SG entries from the given offset. - * Return: Number of TX SG entries found given the constraints - */ --unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) -+unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) - { - const struct alg_sock *ask = alg_sk(sk); - const struct af_alg_ctx *ctx = ask->private; -@@ -548,25 +546,11 @@ - const struct scatterlist *sg = sgl->sg; - - for (i = 0; i < sgl->cur; i++) { -- size_t bytes_count; -- -- /* Skip offset */ -- if (offset >= sg[i].length) { -- offset -= sg[i].length; -- bytes -= sg[i].length; -- continue; -- } -- -- bytes_count = sg[i].length - offset; -- -- offset = 0; - sgl_count++; -- -- /* If we have seen requested number of bytes, stop */ -- if (bytes_count >= bytes) -+ if (sg[i].length >= bytes) - return sgl_count; - -- bytes -= bytes_count; -+ bytes -= sg[i].length; - } - } - -@@ -578,19 +562,14 @@ - * af_alg_pull_tsgl - Release the specified buffers from TX SGL - * - * If @dst is non-null, reassign the pages to @dst. The caller must release -- * the pages. If @dst_offset is given only reassign the pages to @dst starting -- * at the @dst_offset (byte). The caller must ensure that @dst is large -- * enough (e.g. by using af_alg_count_tsgl with the same offset). -+ * the pages. - * - * @sk: socket of connection to user space - * @used: Number of bytes to pull from TX SGL - * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The - * caller must release the buffers in dst. -- * @dst_offset: Reassign the TX SGL from given offset. All buffers before -- * reaching the offset is released. - */ --void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, -- size_t dst_offset) -+void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) - { - struct alg_sock *ask = alg_sk(sk); - struct af_alg_ctx *ctx = ask->private; -@@ -615,18 +594,10 @@ - * SG entries in dst. - */ - if (dst) { -- if (dst_offset >= plen) { -- /* discard page before offset */ -- dst_offset -= plen; -- } else { -- /* reassign page to dst after offset */ -- get_page(page); -- sg_set_page(dst + j, page, -- plen - dst_offset, -- sg[i].offset + dst_offset); -- dst_offset = 0; -- j++; -- } -+ /* reassign page to dst after offset */ -+ get_page(page); -+ sg_set_page(dst + j, page, plen, sg[i].offset); -+ j++; - } - - sg[i].length -= plen; ---- a/crypto/algif_aead.c -+++ b/crypto/algif_aead.c -@@ -96,9 +96,8 @@ - struct aead_tfm *aeadc = pask->private; - struct crypto_aead *tfm = aeadc->aead; - struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; -- unsigned int i, as = crypto_aead_authsize(tfm); -+ unsigned int as = crypto_aead_authsize(tfm); - struct af_alg_async_req *areq; -- struct af_alg_tsgl *tsgl, *tmp; - struct scatterlist *rsgl_src, *tsgl_src = NULL; - int err = 0; - size_t used = 0; /* [in] TX bufs to be en/decrypted */ -@@ -178,23 +177,24 @@ - outlen -= less; - } - -+ /* -+ * Create a per request TX SGL for this request which tracks the -+ * SG entries from the global TX SGL. -+ */ - processed = used + ctx->aead_assoclen; -- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { -- for (i = 0; i < tsgl->cur; i++) { -- struct scatterlist *process_sg = tsgl->sg + i; -- -- if (!(process_sg->length) || !sg_page(process_sg)) -- continue; -- tsgl_src = process_sg; -- break; -- } -- if (tsgl_src) -- break; -- } -- if (processed && !tsgl_src) { -- err = -EFAULT; -+ areq->tsgl_entries = af_alg_count_tsgl(sk, processed); -+ if (!areq->tsgl_entries) -+ areq->tsgl_entries = 1; -+ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -+ areq->tsgl_entries), -+ GFP_KERNEL); -+ if (!areq->tsgl) { -+ err = -ENOMEM; - goto free; - } -+ sg_init_table(areq->tsgl, areq->tsgl_entries); -+ af_alg_pull_tsgl(sk, processed, areq->tsgl); -+ tsgl_src = areq->tsgl; - - /* - * Copy of AAD from source to destination -@@ -203,81 +203,18 @@ - * when user space uses an in-place cipher operation, the kernel - * will copy the data as it does not see whether such in-place operation - * is initiated. -- * -- * To ensure efficiency, the following implementation ensure that the -- * ciphers are invoked to perform a crypto operation in-place. This -- * is achieved by memory management specified as follows. - */ - -- /* Use the RX SGL as source (and destination) for crypto op. */ -+ /* Use the RX SGL as destination for crypto op. */ - rsgl_src = areq->first_rsgl.sgl.sg; - -- if (ctx->enc) { -- /* -- * Encryption operation - The in-place cipher operation is -- * achieved by the following operation: -- * -- * TX SGL: AAD || PT -- * | | -- * | copy | -- * v v -- * RX SGL: AAD || PT || Tag -- */ -- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, -- areq->first_rsgl.sgl.sg, processed); -- if (err) -- goto free; -- af_alg_pull_tsgl(sk, processed, NULL, 0); -- } else { -- /* -- * Decryption operation - To achieve an in-place cipher -- * operation, the following SGL structure is used: -- * -- * TX SGL: AAD || CT || Tag -- * | | ^ -- * | copy | | Create SGL link. -- * v v | -- * RX SGL: AAD || CT ----+ -- */ -- -- /* Copy AAD || CT to RX SGL buffer for in-place operation. */ -- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, -- areq->first_rsgl.sgl.sg, outlen); -- if (err) -- goto free; -- -- /* Create TX SGL for tag and chain it to RX SGL. */ -- areq->tsgl_entries = af_alg_count_tsgl(sk, processed, -- processed - as); -- if (!areq->tsgl_entries) -- areq->tsgl_entries = 1; -- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -- areq->tsgl_entries), -- GFP_KERNEL); -- if (!areq->tsgl) { -- err = -ENOMEM; -- goto free; -- } -- sg_init_table(areq->tsgl, areq->tsgl_entries); -- -- /* Release TX SGL, except for tag data and reassign tag data. */ -- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); -- -- /* chain the areq TX SGL holding the tag with RX SGL */ -- if (usedpages) { -- /* RX SGL present */ -- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; -- -- sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); -- sg_chain(sgl_prev->sg, sgl_prev->npages + 1, -- areq->tsgl); -- } else -- /* no RX SGL present (e.g. authentication only) */ -- rsgl_src = areq->tsgl; -- } -+ err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src, -+ ctx->aead_assoclen); -+ if (err) -+ goto free; - - /* Initialize the crypto operation */ -- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, -+ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, - areq->first_rsgl.sgl.sg, used, ctx->iv); - aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); - aead_request_set_tfm(&areq->cra_u.aead_req, tfm); -@@ -526,7 +463,7 @@ - struct crypto_aead *tfm = aeadc->aead; - unsigned int ivlen = crypto_aead_ivsize(tfm); - -- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); -+ af_alg_pull_tsgl(sk, ctx->used, NULL); - sock_kzfree_s(sk, ctx->iv, ivlen); - sock_kfree_s(sk, ctx, ctx->len); - af_alg_release_parent(sk); ---- a/crypto/algif_skcipher.c -+++ b/crypto/algif_skcipher.c -@@ -89,7 +89,7 @@ - * Create a per request TX SGL for this request which tracks the - * SG entries from the global TX SGL. - */ -- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); -+ areq->tsgl_entries = af_alg_count_tsgl(sk, len); - if (!areq->tsgl_entries) - areq->tsgl_entries = 1; - areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -@@ -100,7 +100,7 @@ - goto free; - } - sg_init_table(areq->tsgl, areq->tsgl_entries); -- af_alg_pull_tsgl(sk, len, areq->tsgl, 0); -+ af_alg_pull_tsgl(sk, len, areq->tsgl); - - /* Initialize the crypto operation */ - skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); -@@ -313,7 +313,7 @@ - struct alg_sock *pask = alg_sk(psk); - struct crypto_skcipher *tfm = pask->private; - -- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); -+ af_alg_pull_tsgl(sk, ctx->used, NULL); - sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); - sock_kfree_s(sk, ctx, ctx->len); - af_alg_release_parent(sk); ---- a/include/crypto/if_alg.h -+++ b/include/crypto/if_alg.h -@@ -226,9 +226,8 @@ - return PAGE_SIZE <= af_alg_rcvbuf(sk); - } - --unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); --void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, -- size_t dst_offset); -+unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); -+void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); - void af_alg_wmem_wakeup(struct sock *sk); - int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); - int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, From 3498408ca16c23d000df38c0b60e2bf6c4a17900 Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Tue, 5 May 2026 07:30:53 +0000 Subject: [PATCH 14/17] Revert "CVE-2026-31431 (Copy Fail): backport crypto AEAD/algif fixes" This reverts commit 32ede4fb1e3fae5756404edaf69a6540fc3a6ebc. --- config.yaml | 4 +- ...VE-2026-31431-crypto-Copy-Fail-fixes.patch | 962 ------------------ ...ead-Revert-to-operating-out-of-place.patch | 308 ++++++ 3 files changed, 310 insertions(+), 964 deletions(-) delete mode 100644 files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch create mode 100644 files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch diff --git a/config.yaml b/config.yaml index 952ef64..7993cab 100644 --- a/config.yaml +++ b/config.yaml @@ -41,7 +41,7 @@ actions: number: "Latest" modify_spec: false - type: "patch" - name: "1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch" + name: "1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch" number: 1100 - replace: @@ -453,7 +453,7 @@ actions: - name: "Andrew Lukoshko" email: "alukoshko@almalinux.org" line: - - "CVE-2026-31431 (Copy Fail): backport crypto AEAD/algif fixes from stable-5.15.y" + - "crypto: algif_aead - Revert to operating out-of-place" - "hpsa: bring back deprecated PCI ids #CFHack #CFHack2024" - "mptsas: bring back deprecated PCI ids #CFHack #CFHack2024" - "megaraid_sas: bring back deprecated PCI ids #CFHack #CFHack2024" diff --git a/files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch b/files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch deleted file mode 100644 index 193db49..0000000 --- a/files/1100-CVE-2026-31431-crypto-Copy-Fail-fixes.patch +++ /dev/null @@ -1,962 +0,0 @@ -From: AlmaLinux Backport -Subject: [PATCH] CVE-2026-31431 ("Copy Fail"): crypto AEAD/algif fixes from linux-5.15.y - -Combined backport addressing CVE-2026-31431 ("Copy Fail"), reported by -Taeyang Lee <0wn@theori.io>. EL9 kernel is based on 5.14.0; the closest -stable branch is linux-5.15.y. Pulls one prerequisite (committed -2026-02-06 to 5.15.y) plus nine 2026-04-30 stable fixes: - - fee86edf5803 crypto: authencesn - reject too-short AAD (assoclen<8) to match ESP/ESN spec - 36435a56cd6b crypto: scatterwalk - Backport memcpy_sglist() - 17774d99bb43 crypto: algif_aead - use memcpy_sglist() instead of null skcipher - 19d43105a97b crypto: algif_aead - Revert to operating out-of-place - a920cabdb0b7 crypto: algif_aead - snapshot IV for async AEAD requests - e416c41a96c8 crypto: authenc - use memcpy_sglist() instead of null skcipher - d589abd8b019 crypto: authencesn - Do not place hiseq at end of dst for out-of-place decryption - 723bb1b4a6dd crypto: authencesn - Fix src offset when decrypting in-place - 2b781d1d4f93 crypto: af_alg - Fix page reassignment overflow in af_alg_pull_tsgl - fd427dd84f22 crypto: algif_aead - Fix minimum RX size check for decryption - -fee86edf5803 is the prerequisite for d589abd8b019 to apply. - -Signed-off-by: Andrew Lukoshko ---- ---- a/crypto/af_alg.c -+++ b/crypto/af_alg.c -@@ -525,15 +525,13 @@ - /** - * af_alg_count_tsgl - Count number of TX SG entries - * -- * The counting starts from the beginning of the SGL to @bytes. If -- * an @offset is provided, the counting of the SG entries starts at the @offset. -+ * The counting starts from the beginning of the SGL to @bytes. - * - * @sk: socket of connection to user space - * @bytes: Count the number of SG entries holding given number of bytes. -- * @offset: Start the counting of SG entries from the given offset. - * Return: Number of TX SG entries found given the constraints - */ --unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) -+unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) - { - const struct alg_sock *ask = alg_sk(sk); - const struct af_alg_ctx *ctx = ask->private; -@@ -548,25 +546,11 @@ - const struct scatterlist *sg = sgl->sg; - - for (i = 0; i < sgl->cur; i++) { -- size_t bytes_count; -- -- /* Skip offset */ -- if (offset >= sg[i].length) { -- offset -= sg[i].length; -- bytes -= sg[i].length; -- continue; -- } -- -- bytes_count = sg[i].length - offset; -- -- offset = 0; - sgl_count++; -- -- /* If we have seen requested number of bytes, stop */ -- if (bytes_count >= bytes) -+ if (sg[i].length >= bytes) - return sgl_count; - -- bytes -= bytes_count; -+ bytes -= sg[i].length; - } - } - -@@ -578,19 +562,14 @@ - * af_alg_pull_tsgl - Release the specified buffers from TX SGL - * - * If @dst is non-null, reassign the pages to @dst. The caller must release -- * the pages. If @dst_offset is given only reassign the pages to @dst starting -- * at the @dst_offset (byte). The caller must ensure that @dst is large -- * enough (e.g. by using af_alg_count_tsgl with the same offset). -+ * the pages. - * - * @sk: socket of connection to user space - * @used: Number of bytes to pull from TX SGL - * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The - * caller must release the buffers in dst. -- * @dst_offset: Reassign the TX SGL from given offset. All buffers before -- * reaching the offset is released. - */ --void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, -- size_t dst_offset) -+void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) - { - struct alg_sock *ask = alg_sk(sk); - struct af_alg_ctx *ctx = ask->private; -@@ -614,19 +593,11 @@ - * Assumption: caller created af_alg_count_tsgl(len) - * SG entries in dst. - */ -- if (dst) { -- if (dst_offset >= plen) { -- /* discard page before offset */ -- dst_offset -= plen; -- } else { -- /* reassign page to dst after offset */ -- get_page(page); -- sg_set_page(dst + j, page, -- plen - dst_offset, -- sg[i].offset + dst_offset); -- dst_offset = 0; -- j++; -- } -+ if (dst && plen) { -+ /* reassign page to dst */ -+ get_page(page); -+ sg_set_page(dst + j, page, plen, sg[i].offset); -+ j++; - } - - sg[i].length -= plen; ---- a/crypto/algif_aead.c -+++ b/crypto/algif_aead.c -@@ -26,8 +26,6 @@ - #include - #include - #include --#include --#include - #include - #include - #include -@@ -36,19 +34,13 @@ - #include - #include - --struct aead_tfm { -- struct crypto_aead *aead; -- struct crypto_sync_skcipher *null_tfm; --}; -- - static inline bool aead_sufficient_data(struct sock *sk) - { - struct alg_sock *ask = alg_sk(sk); - struct sock *psk = ask->parent; - struct alg_sock *pask = alg_sk(psk); - struct af_alg_ctx *ctx = ask->private; -- struct aead_tfm *aeadc = pask->private; -- struct crypto_aead *tfm = aeadc->aead; -+ struct crypto_aead *tfm = pask->private; - unsigned int as = crypto_aead_authsize(tfm); - - /* -@@ -64,27 +56,12 @@ - struct alg_sock *ask = alg_sk(sk); - struct sock *psk = ask->parent; - struct alg_sock *pask = alg_sk(psk); -- struct aead_tfm *aeadc = pask->private; -- struct crypto_aead *tfm = aeadc->aead; -+ struct crypto_aead *tfm = pask->private; - unsigned int ivsize = crypto_aead_ivsize(tfm); - - return af_alg_sendmsg(sock, msg, size, ivsize); - } - --static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, -- struct scatterlist *src, -- struct scatterlist *dst, unsigned int len) --{ -- SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); -- -- skcipher_request_set_sync_tfm(skreq, null_tfm); -- skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP, -- NULL, NULL); -- skcipher_request_set_crypt(skreq, src, dst, len, NULL); -- -- return crypto_skcipher_encrypt(skreq); --} -- - static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, - size_t ignored, int flags) - { -@@ -93,13 +70,12 @@ - struct sock *psk = ask->parent; - struct alg_sock *pask = alg_sk(psk); - struct af_alg_ctx *ctx = ask->private; -- struct aead_tfm *aeadc = pask->private; -- struct crypto_aead *tfm = aeadc->aead; -- struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; -- unsigned int i, as = crypto_aead_authsize(tfm); -+ struct crypto_aead *tfm = pask->private; -+ unsigned int as = crypto_aead_authsize(tfm); -+ unsigned int ivsize = crypto_aead_ivsize(tfm); - struct af_alg_async_req *areq; -- struct af_alg_tsgl *tsgl, *tmp; - struct scatterlist *rsgl_src, *tsgl_src = NULL; -+ void *iv; - int err = 0; - size_t used = 0; /* [in] TX bufs to be en/decrypted */ - size_t outlen = 0; /* [out] RX bufs produced by kernel */ -@@ -151,10 +127,14 @@ - - /* Allocate cipher request for current operation. */ - areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + -- crypto_aead_reqsize(tfm)); -+ crypto_aead_reqsize(tfm) + ivsize); - if (IS_ERR(areq)) - return PTR_ERR(areq); - -+ iv = (u8 *)aead_request_ctx(&areq->cra_u.aead_req) + -+ crypto_aead_reqsize(tfm); -+ memcpy(iv, ctx->iv, ivsize); -+ - /* convert iovecs of output buffers into RX SGL */ - err = af_alg_get_rsgl(sk, msg, flags, areq, outlen, &usedpages); - if (err) -@@ -170,7 +150,7 @@ - if (usedpages < outlen) { - size_t less = outlen - usedpages; - -- if (used < less) { -+ if (used < less + (ctx->enc ? 0 : as)) { - err = -EINVAL; - goto free; - } -@@ -178,23 +158,24 @@ - outlen -= less; - } - -+ /* -+ * Create a per request TX SGL for this request which tracks the -+ * SG entries from the global TX SGL. -+ */ - processed = used + ctx->aead_assoclen; -- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { -- for (i = 0; i < tsgl->cur; i++) { -- struct scatterlist *process_sg = tsgl->sg + i; -- -- if (!(process_sg->length) || !sg_page(process_sg)) -- continue; -- tsgl_src = process_sg; -- break; -- } -- if (tsgl_src) -- break; -- } -- if (processed && !tsgl_src) { -- err = -EFAULT; -+ areq->tsgl_entries = af_alg_count_tsgl(sk, processed); -+ if (!areq->tsgl_entries) -+ areq->tsgl_entries = 1; -+ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -+ areq->tsgl_entries), -+ GFP_KERNEL); -+ if (!areq->tsgl) { -+ err = -ENOMEM; - goto free; - } -+ sg_init_table(areq->tsgl, areq->tsgl_entries); -+ af_alg_pull_tsgl(sk, processed, areq->tsgl); -+ tsgl_src = areq->tsgl; - - /* - * Copy of AAD from source to destination -@@ -203,82 +184,16 @@ - * when user space uses an in-place cipher operation, the kernel - * will copy the data as it does not see whether such in-place operation - * is initiated. -- * -- * To ensure efficiency, the following implementation ensure that the -- * ciphers are invoked to perform a crypto operation in-place. This -- * is achieved by memory management specified as follows. - */ - - /* Use the RX SGL as source (and destination) for crypto op. */ - rsgl_src = areq->first_rsgl.sgl.sg; - -- if (ctx->enc) { -- /* -- * Encryption operation - The in-place cipher operation is -- * achieved by the following operation: -- * -- * TX SGL: AAD || PT -- * | | -- * | copy | -- * v v -- * RX SGL: AAD || PT || Tag -- */ -- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, -- areq->first_rsgl.sgl.sg, processed); -- if (err) -- goto free; -- af_alg_pull_tsgl(sk, processed, NULL, 0); -- } else { -- /* -- * Decryption operation - To achieve an in-place cipher -- * operation, the following SGL structure is used: -- * -- * TX SGL: AAD || CT || Tag -- * | | ^ -- * | copy | | Create SGL link. -- * v v | -- * RX SGL: AAD || CT ----+ -- */ -- -- /* Copy AAD || CT to RX SGL buffer for in-place operation. */ -- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, -- areq->first_rsgl.sgl.sg, outlen); -- if (err) -- goto free; -- -- /* Create TX SGL for tag and chain it to RX SGL. */ -- areq->tsgl_entries = af_alg_count_tsgl(sk, processed, -- processed - as); -- if (!areq->tsgl_entries) -- areq->tsgl_entries = 1; -- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -- areq->tsgl_entries), -- GFP_KERNEL); -- if (!areq->tsgl) { -- err = -ENOMEM; -- goto free; -- } -- sg_init_table(areq->tsgl, areq->tsgl_entries); -- -- /* Release TX SGL, except for tag data and reassign tag data. */ -- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); -- -- /* chain the areq TX SGL holding the tag with RX SGL */ -- if (usedpages) { -- /* RX SGL present */ -- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; -- -- sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); -- sg_chain(sgl_prev->sg, sgl_prev->npages + 1, -- areq->tsgl); -- } else -- /* no RX SGL present (e.g. authentication only) */ -- rsgl_src = areq->tsgl; -- } -+ memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen); - - /* Initialize the crypto operation */ -- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, -- areq->first_rsgl.sgl.sg, used, ctx->iv); -+ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, -+ areq->first_rsgl.sgl.sg, used, iv); - aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); - aead_request_set_tfm(&areq->cra_u.aead_req, tfm); - -@@ -378,7 +293,7 @@ - int err = 0; - struct sock *psk; - struct alg_sock *pask; -- struct aead_tfm *tfm; -+ struct crypto_aead *tfm; - struct sock *sk = sock->sk; - struct alg_sock *ask = alg_sk(sk); - -@@ -392,7 +307,7 @@ - - err = -ENOKEY; - lock_sock_nested(psk, SINGLE_DEPTH_NESTING); -- if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) -+ if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - goto unlock; - - atomic_dec(&pask->nokey_refcnt); -@@ -466,54 +381,22 @@ - - static void *aead_bind(const char *name, u32 type, u32 mask) - { -- struct aead_tfm *tfm; -- struct crypto_aead *aead; -- struct crypto_sync_skcipher *null_tfm; -- -- tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); -- if (!tfm) -- return ERR_PTR(-ENOMEM); -- -- aead = crypto_alloc_aead(name, type, mask); -- if (IS_ERR(aead)) { -- kfree(tfm); -- return ERR_CAST(aead); -- } -- -- null_tfm = crypto_get_default_null_skcipher(); -- if (IS_ERR(null_tfm)) { -- crypto_free_aead(aead); -- kfree(tfm); -- return ERR_CAST(null_tfm); -- } -- -- tfm->aead = aead; -- tfm->null_tfm = null_tfm; -- -- return tfm; -+ return crypto_alloc_aead(name, type, mask); - } - - static void aead_release(void *private) - { -- struct aead_tfm *tfm = private; -- -- crypto_free_aead(tfm->aead); -- crypto_put_default_null_skcipher(); -- kfree(tfm); -+ crypto_free_aead(private); - } - - static int aead_setauthsize(void *private, unsigned int authsize) - { -- struct aead_tfm *tfm = private; -- -- return crypto_aead_setauthsize(tfm->aead, authsize); -+ return crypto_aead_setauthsize(private, authsize); - } - - static int aead_setkey(void *private, const u8 *key, unsigned int keylen) - { -- struct aead_tfm *tfm = private; -- -- return crypto_aead_setkey(tfm->aead, key, keylen); -+ return crypto_aead_setkey(private, key, keylen); - } - - static void aead_sock_destruct(struct sock *sk) -@@ -522,11 +405,10 @@ - struct af_alg_ctx *ctx = ask->private; - struct sock *psk = ask->parent; - struct alg_sock *pask = alg_sk(psk); -- struct aead_tfm *aeadc = pask->private; -- struct crypto_aead *tfm = aeadc->aead; -+ struct crypto_aead *tfm = pask->private; - unsigned int ivlen = crypto_aead_ivsize(tfm); - -- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); -+ af_alg_pull_tsgl(sk, ctx->used, NULL); - sock_kzfree_s(sk, ctx->iv, ivlen); - sock_kfree_s(sk, ctx, ctx->len); - af_alg_release_parent(sk); -@@ -536,10 +418,9 @@ - { - struct af_alg_ctx *ctx; - struct alg_sock *ask = alg_sk(sk); -- struct aead_tfm *tfm = private; -- struct crypto_aead *aead = tfm->aead; -+ struct crypto_aead *tfm = private; - unsigned int len = sizeof(*ctx); -- unsigned int ivlen = crypto_aead_ivsize(aead); -+ unsigned int ivlen = crypto_aead_ivsize(tfm); - - ctx = sock_kmalloc(sk, len, GFP_KERNEL); - if (!ctx) -@@ -566,9 +447,9 @@ - - static int aead_accept_parent(void *private, struct sock *sk) - { -- struct aead_tfm *tfm = private; -+ struct crypto_aead *tfm = private; - -- if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) -+ if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - - return aead_accept_parent_nokey(private, sk); ---- a/crypto/algif_skcipher.c -+++ b/crypto/algif_skcipher.c -@@ -89,7 +89,7 @@ - * Create a per request TX SGL for this request which tracks the - * SG entries from the global TX SGL. - */ -- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); -+ areq->tsgl_entries = af_alg_count_tsgl(sk, len); - if (!areq->tsgl_entries) - areq->tsgl_entries = 1; - areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -@@ -100,7 +100,7 @@ - goto free; - } - sg_init_table(areq->tsgl, areq->tsgl_entries); -- af_alg_pull_tsgl(sk, len, areq->tsgl, 0); -+ af_alg_pull_tsgl(sk, len, areq->tsgl); - - /* Initialize the crypto operation */ - skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); -@@ -313,7 +313,7 @@ - struct alg_sock *pask = alg_sk(psk); - struct crypto_skcipher *tfm = pask->private; - -- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); -+ af_alg_pull_tsgl(sk, ctx->used, NULL); - sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); - sock_kfree_s(sk, ctx, ctx->len); - af_alg_release_parent(sk); ---- a/crypto/authenc.c -+++ b/crypto/authenc.c -@@ -9,7 +9,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -28,7 +27,6 @@ - struct crypto_authenc_ctx { - struct crypto_ahash *auth; - struct crypto_skcipher *enc; -- struct crypto_sync_skcipher *null; - }; - - struct authenc_request_ctx { -@@ -174,21 +172,6 @@ - authenc_request_complete(areq, err); - } - --static int crypto_authenc_copy_assoc(struct aead_request *req) --{ -- struct crypto_aead *authenc = crypto_aead_reqtfm(req); -- struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); -- SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); -- -- skcipher_request_set_sync_tfm(skreq, ctx->null); -- skcipher_request_set_callback(skreq, aead_request_flags(req), -- NULL, NULL); -- skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, -- NULL); -- -- return crypto_skcipher_encrypt(skreq); --} -- - static int crypto_authenc_encrypt(struct aead_request *req) - { - struct crypto_aead *authenc = crypto_aead_reqtfm(req); -@@ -207,10 +190,7 @@ - dst = src; - - if (req->src != req->dst) { -- err = crypto_authenc_copy_assoc(req); -- if (err) -- return err; -- -+ memcpy_sglist(req->dst, req->src, req->assoclen); - dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); - } - -@@ -311,7 +291,6 @@ - struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); - struct crypto_ahash *auth; - struct crypto_skcipher *enc; -- struct crypto_sync_skcipher *null; - int err; - - auth = crypto_spawn_ahash(&ictx->auth); -@@ -323,14 +302,8 @@ - if (IS_ERR(enc)) - goto err_free_ahash; - -- null = crypto_get_default_null_skcipher(); -- err = PTR_ERR(null); -- if (IS_ERR(null)) -- goto err_free_skcipher; -- - ctx->auth = auth; - ctx->enc = enc; -- ctx->null = null; - - crypto_aead_set_reqsize( - tfm, -@@ -344,8 +317,6 @@ - - return 0; - --err_free_skcipher: -- crypto_free_skcipher(enc); - err_free_ahash: - crypto_free_ahash(auth); - return err; -@@ -357,7 +328,6 @@ - - crypto_free_ahash(ctx->auth); - crypto_free_skcipher(ctx->enc); -- crypto_put_default_null_skcipher(); - } - - static void crypto_authenc_free(struct aead_instance *inst) ---- a/crypto/authencesn.c -+++ b/crypto/authencesn.c -@@ -12,7 +12,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -31,7 +30,6 @@ - unsigned int reqoff; - struct crypto_ahash *auth; - struct crypto_skcipher *enc; -- struct crypto_sync_skcipher *null; - }; - - struct authenc_esn_request_ctx { -@@ -164,20 +162,6 @@ - authenc_esn_request_complete(areq, err); - } - --static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len) --{ -- struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); -- struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); -- SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); -- -- skcipher_request_set_sync_tfm(skreq, ctx->null); -- skcipher_request_set_callback(skreq, aead_request_flags(req), -- NULL, NULL); -- skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL); -- -- return crypto_skcipher_encrypt(skreq); --} -- - static int crypto_authenc_esn_encrypt(struct aead_request *req) - { - struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); -@@ -191,15 +175,15 @@ - struct scatterlist *src, *dst; - int err; - -+ if (assoclen < 8) -+ return -EINVAL; -+ - sg_init_table(areq_ctx->src, 2); - src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen); - dst = src; - - if (req->src != req->dst) { -- err = crypto_authenc_esn_copy(req, assoclen); -- if (err) -- return err; -- -+ memcpy_sglist(req->dst, req->src, assoclen); - sg_init_table(areq_ctx->dst, 2); - dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen); - } -@@ -230,6 +214,7 @@ - crypto_ahash_alignmask(auth) + 1); - unsigned int cryptlen = req->cryptlen - authsize; - unsigned int assoclen = req->assoclen; -+ struct scatterlist *src = req->src; - struct scatterlist *dst = req->dst; - u8 *ihash = ohash + crypto_ahash_digestsize(auth); - u32 tmp[2]; -@@ -237,23 +222,29 @@ - if (!authsize) - goto decrypt; - -- /* Move high-order bits of sequence number back. */ -- scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); -- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); -- scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); -+ if (src == dst) { -+ /* Move high-order bits of sequence number back. */ -+ scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); -+ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); -+ scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); -+ } else -+ memcpy_sglist(dst, src, assoclen); - - if (crypto_memneq(ihash, ohash, authsize)) - return -EBADMSG; - - decrypt: - -- sg_init_table(areq_ctx->dst, 2); - dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); -+ if (req->src == req->dst) -+ src = dst; -+ else -+ src = scatterwalk_ffwd(areq_ctx->src, src, assoclen); - - skcipher_request_set_tfm(skreq, ctx->enc); - skcipher_request_set_callback(skreq, flags, - req->base.complete, req->base.data); -- skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv); -+ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); - - return crypto_skcipher_decrypt(skreq); - } -@@ -280,31 +271,36 @@ - unsigned int assoclen = req->assoclen; - unsigned int cryptlen = req->cryptlen; - u8 *ihash = ohash + crypto_ahash_digestsize(auth); -+ struct scatterlist *src = req->src; - struct scatterlist *dst = req->dst; - u32 tmp[2]; - int err; - -- cryptlen -= authsize; -+ if (assoclen < 8) -+ return -EINVAL; - -- if (req->src != dst) { -- err = crypto_authenc_esn_copy(req, assoclen + cryptlen); -- if (err) -- return err; -- } -+ if (!authsize) -+ goto tail; - -+ cryptlen -= authsize; - scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, - authsize, 0); - -- if (!authsize) -- goto tail; -- - /* Move high-order bits of sequence number to the end. */ -- scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); -- scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); -- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); -- -- sg_init_table(areq_ctx->dst, 2); -- dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); -+ scatterwalk_map_and_copy(tmp, src, 0, 8, 0); -+ if (src == dst) { -+ scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); -+ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); -+ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); -+ } else { -+ scatterwalk_map_and_copy(tmp, dst, 0, 4, 1); -+ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1); -+ -+ src = scatterwalk_ffwd(areq_ctx->src, src, 8); -+ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); -+ memcpy_sglist(dst, src, assoclen + cryptlen - 8); -+ dst = req->dst; -+ } - - ahash_request_set_tfm(ahreq, auth); - ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen); -@@ -326,7 +322,6 @@ - struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); - struct crypto_ahash *auth; - struct crypto_skcipher *enc; -- struct crypto_sync_skcipher *null; - int err; - - auth = crypto_spawn_ahash(&ictx->auth); -@@ -338,14 +333,8 @@ - if (IS_ERR(enc)) - goto err_free_ahash; - -- null = crypto_get_default_null_skcipher(); -- err = PTR_ERR(null); -- if (IS_ERR(null)) -- goto err_free_skcipher; -- - ctx->auth = auth; - ctx->enc = enc; -- ctx->null = null; - - ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth), - crypto_ahash_alignmask(auth) + 1); -@@ -362,8 +351,6 @@ - - return 0; - --err_free_skcipher: -- crypto_free_skcipher(enc); - err_free_ahash: - crypto_free_ahash(auth); - return err; -@@ -375,7 +362,6 @@ - - crypto_free_ahash(ctx->auth); - crypto_free_skcipher(ctx->enc); -- crypto_put_default_null_skcipher(); - } - - static void crypto_authenc_esn_free(struct aead_instance *inst) ---- a/crypto/scatterwalk.c -+++ b/crypto/scatterwalk.c -@@ -69,6 +69,100 @@ - } - EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); - -+/** -+ * memcpy_sglist() - Copy data from one scatterlist to another -+ * @dst: The destination scatterlist. Can be NULL if @nbytes == 0. -+ * @src: The source scatterlist. Can be NULL if @nbytes == 0. -+ * @nbytes: Number of bytes to copy -+ * -+ * The scatterlists can describe exactly the same memory, in which case this -+ * function is a no-op. No other overlaps are supported. -+ * -+ * Context: Any context -+ */ -+void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ unsigned int src_offset, dst_offset; -+ -+ if (unlikely(nbytes == 0)) /* in case src and/or dst is NULL */ -+ return; -+ -+ src_offset = src->offset; -+ dst_offset = dst->offset; -+ for (;;) { -+ /* Compute the length to copy this step. */ -+ unsigned int len = min3(src->offset + src->length - src_offset, -+ dst->offset + dst->length - dst_offset, -+ nbytes); -+ struct page *src_page = sg_page(src); -+ struct page *dst_page = sg_page(dst); -+ const void *src_virt; -+ void *dst_virt; -+ -+ if (IS_ENABLED(CONFIG_HIGHMEM)) { -+ /* HIGHMEM: we may have to actually map the pages. */ -+ const unsigned int src_oip = offset_in_page(src_offset); -+ const unsigned int dst_oip = offset_in_page(dst_offset); -+ const unsigned int limit = PAGE_SIZE; -+ -+ /* Further limit len to not cross a page boundary. */ -+ len = min3(len, limit - src_oip, limit - dst_oip); -+ -+ /* Compute the source and destination pages. */ -+ src_page += src_offset / PAGE_SIZE; -+ dst_page += dst_offset / PAGE_SIZE; -+ -+ if (src_page != dst_page) { -+ /* Copy between different pages. */ -+ memcpy_page(dst_page, dst_oip, -+ src_page, src_oip, len); -+ flush_dcache_page(dst_page); -+ } else if (src_oip != dst_oip) { -+ /* Copy between different parts of same page. */ -+ dst_virt = kmap_local_page(dst_page); -+ memcpy(dst_virt + dst_oip, dst_virt + src_oip, -+ len); -+ kunmap_local(dst_virt); -+ flush_dcache_page(dst_page); -+ } /* Else, it's the same memory. No action needed. */ -+ } else { -+ /* -+ * !HIGHMEM: no mapping needed. Just work in the linear -+ * buffer of each sg entry. Note that we can cross page -+ * boundaries, as they are not significant in this case. -+ */ -+ src_virt = page_address(src_page) + src_offset; -+ dst_virt = page_address(dst_page) + dst_offset; -+ if (src_virt != dst_virt) { -+ memcpy(dst_virt, src_virt, len); -+ if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) -+ __scatterwalk_flush_dcache_pages( -+ dst_page, dst_offset, len); -+ } /* Else, it's the same memory. No action needed. */ -+ } -+ nbytes -= len; -+ if (nbytes == 0) /* No more to copy? */ -+ break; -+ -+ /* -+ * There's more to copy. Advance the offsets by the length -+ * copied this step, and advance the sg entries as needed. -+ */ -+ src_offset += len; -+ if (src_offset >= src->offset + src->length) { -+ src = sg_next(src); -+ src_offset = src->offset; -+ } -+ dst_offset += len; -+ if (dst_offset >= dst->offset + dst->length) { -+ dst = sg_next(dst); -+ dst_offset = dst->offset; -+ } -+ } -+} -+EXPORT_SYMBOL_GPL(memcpy_sglist); -+ - struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], - struct scatterlist *src, - unsigned int len) ---- a/crypto/Kconfig -+++ b/crypto/Kconfig -@@ -221,7 +221,6 @@ - select CRYPTO_SKCIPHER - select CRYPTO_MANAGER - select CRYPTO_HASH -- select CRYPTO_NULL - help - Authenc: Combined mode wrapper for IPsec. - This is required for IPSec. -@@ -2120,7 +2119,6 @@ - depends on NET - select CRYPTO_AEAD - select CRYPTO_SKCIPHER -- select CRYPTO_NULL - select CRYPTO_USER_API - help - This option enables the user-spaces interface for AEAD ---- a/include/crypto/if_alg.h -+++ b/include/crypto/if_alg.h -@@ -226,9 +226,8 @@ - return PAGE_SIZE <= af_alg_rcvbuf(sk); - } - --unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); --void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, -- size_t dst_offset); -+unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); -+void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); - void af_alg_wmem_wakeup(struct sock *sk); - int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); - int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, ---- a/include/crypto/scatterwalk.h -+++ b/include/crypto/scatterwalk.h -@@ -89,6 +89,35 @@ - scatterwalk_start(walk, sg_next(walk->sg)); - } - -+/* -+ * Flush the dcache of any pages that overlap the region -+ * [offset, offset + nbytes) relative to base_page. -+ * -+ * This should be called only when ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, to ensure -+ * that all relevant code (including the call to sg_page() in the caller, if -+ * applicable) gets fully optimized out when !ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE. -+ */ -+static inline void __scatterwalk_flush_dcache_pages(struct page *base_page, -+ unsigned int offset, -+ unsigned int nbytes) -+{ -+ unsigned int num_pages; -+ unsigned int i; -+ -+ base_page += offset / PAGE_SIZE; -+ offset %= PAGE_SIZE; -+ -+ /* -+ * This is an overflow-safe version of -+ * num_pages = DIV_ROUND_UP(offset + nbytes, PAGE_SIZE). -+ */ -+ num_pages = nbytes / PAGE_SIZE; -+ num_pages += DIV_ROUND_UP(offset + (nbytes % PAGE_SIZE), PAGE_SIZE); -+ -+ for (i = 0; i < num_pages; i++) -+ flush_dcache_page(base_page + i); -+} -+ - static inline void scatterwalk_done(struct scatter_walk *walk, int out, - int more) - { -@@ -101,6 +130,9 @@ - size_t nbytes, int out); - void *scatterwalk_map(struct scatter_walk *walk); - -+void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes); -+ - void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, - unsigned int start, unsigned int nbytes, int out); - diff --git a/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch b/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch new file mode 100644 index 0000000..6652b2b --- /dev/null +++ b/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch @@ -0,0 +1,308 @@ +From a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 26 Mar 2026 15:30:20 +0900 +Subject: [PATCH] crypto: algif_aead - Revert to operating out-of-place + +This mostly reverts commit 72548b093ee3 except for the copying of +the associated data. + +There is no benefit in operating in-place in algif_aead since the +source and destination come from different mappings. Get rid of +all the complexity added for in-place operation and just copy the +AD directly. + +Backported to kernel-5.14.0-611.49.1.el9_7: this tree pre-dates upstream's +memcpy_sglist() helper, so the AAD copy keeps using +crypto_aead_copy_sgl(null_tfm, ...). The function signatures of +af_alg_count_tsgl() and af_alg_pull_tsgl() are reverted to drop the +offset parameters as in upstream. + +Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst") +Reported-by: Taeyang Lee <0wn@theori.io> +Signed-off-by: Herbert Xu +--- +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -525,15 +525,13 @@ + /** + * af_alg_count_tsgl - Count number of TX SG entries + * +- * The counting starts from the beginning of the SGL to @bytes. If +- * an @offset is provided, the counting of the SG entries starts at the @offset. ++ * The counting starts from the beginning of the SGL to @bytes. + * + * @sk: socket of connection to user space + * @bytes: Count the number of SG entries holding given number of bytes. +- * @offset: Start the counting of SG entries from the given offset. + * Return: Number of TX SG entries found given the constraints + */ +-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) ++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) + { + const struct alg_sock *ask = alg_sk(sk); + const struct af_alg_ctx *ctx = ask->private; +@@ -548,25 +546,11 @@ + const struct scatterlist *sg = sgl->sg; + + for (i = 0; i < sgl->cur; i++) { +- size_t bytes_count; +- +- /* Skip offset */ +- if (offset >= sg[i].length) { +- offset -= sg[i].length; +- bytes -= sg[i].length; +- continue; +- } +- +- bytes_count = sg[i].length - offset; +- +- offset = 0; + sgl_count++; +- +- /* If we have seen requested number of bytes, stop */ +- if (bytes_count >= bytes) ++ if (sg[i].length >= bytes) + return sgl_count; + +- bytes -= bytes_count; ++ bytes -= sg[i].length; + } + } + +@@ -578,19 +562,14 @@ + * af_alg_pull_tsgl - Release the specified buffers from TX SGL + * + * If @dst is non-null, reassign the pages to @dst. The caller must release +- * the pages. If @dst_offset is given only reassign the pages to @dst starting +- * at the @dst_offset (byte). The caller must ensure that @dst is large +- * enough (e.g. by using af_alg_count_tsgl with the same offset). ++ * the pages. + * + * @sk: socket of connection to user space + * @used: Number of bytes to pull from TX SGL + * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The + * caller must release the buffers in dst. +- * @dst_offset: Reassign the TX SGL from given offset. All buffers before +- * reaching the offset is released. + */ +-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, +- size_t dst_offset) ++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) + { + struct alg_sock *ask = alg_sk(sk); + struct af_alg_ctx *ctx = ask->private; +@@ -615,18 +594,10 @@ + * SG entries in dst. + */ + if (dst) { +- if (dst_offset >= plen) { +- /* discard page before offset */ +- dst_offset -= plen; +- } else { +- /* reassign page to dst after offset */ +- get_page(page); +- sg_set_page(dst + j, page, +- plen - dst_offset, +- sg[i].offset + dst_offset); +- dst_offset = 0; +- j++; +- } ++ /* reassign page to dst after offset */ ++ get_page(page); ++ sg_set_page(dst + j, page, plen, sg[i].offset); ++ j++; + } + + sg[i].length -= plen; +--- a/crypto/algif_aead.c ++++ b/crypto/algif_aead.c +@@ -96,9 +96,8 @@ + struct aead_tfm *aeadc = pask->private; + struct crypto_aead *tfm = aeadc->aead; + struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; +- unsigned int i, as = crypto_aead_authsize(tfm); ++ unsigned int as = crypto_aead_authsize(tfm); + struct af_alg_async_req *areq; +- struct af_alg_tsgl *tsgl, *tmp; + struct scatterlist *rsgl_src, *tsgl_src = NULL; + int err = 0; + size_t used = 0; /* [in] TX bufs to be en/decrypted */ +@@ -178,23 +177,24 @@ + outlen -= less; + } + ++ /* ++ * Create a per request TX SGL for this request which tracks the ++ * SG entries from the global TX SGL. ++ */ + processed = used + ctx->aead_assoclen; +- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { +- for (i = 0; i < tsgl->cur; i++) { +- struct scatterlist *process_sg = tsgl->sg + i; +- +- if (!(process_sg->length) || !sg_page(process_sg)) +- continue; +- tsgl_src = process_sg; +- break; +- } +- if (tsgl_src) +- break; +- } +- if (processed && !tsgl_src) { +- err = -EFAULT; ++ areq->tsgl_entries = af_alg_count_tsgl(sk, processed); ++ if (!areq->tsgl_entries) ++ areq->tsgl_entries = 1; ++ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), ++ areq->tsgl_entries), ++ GFP_KERNEL); ++ if (!areq->tsgl) { ++ err = -ENOMEM; + goto free; + } ++ sg_init_table(areq->tsgl, areq->tsgl_entries); ++ af_alg_pull_tsgl(sk, processed, areq->tsgl); ++ tsgl_src = areq->tsgl; + + /* + * Copy of AAD from source to destination +@@ -203,81 +203,18 @@ + * when user space uses an in-place cipher operation, the kernel + * will copy the data as it does not see whether such in-place operation + * is initiated. +- * +- * To ensure efficiency, the following implementation ensure that the +- * ciphers are invoked to perform a crypto operation in-place. This +- * is achieved by memory management specified as follows. + */ + +- /* Use the RX SGL as source (and destination) for crypto op. */ ++ /* Use the RX SGL as destination for crypto op. */ + rsgl_src = areq->first_rsgl.sgl.sg; + +- if (ctx->enc) { +- /* +- * Encryption operation - The in-place cipher operation is +- * achieved by the following operation: +- * +- * TX SGL: AAD || PT +- * | | +- * | copy | +- * v v +- * RX SGL: AAD || PT || Tag +- */ +- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, +- areq->first_rsgl.sgl.sg, processed); +- if (err) +- goto free; +- af_alg_pull_tsgl(sk, processed, NULL, 0); +- } else { +- /* +- * Decryption operation - To achieve an in-place cipher +- * operation, the following SGL structure is used: +- * +- * TX SGL: AAD || CT || Tag +- * | | ^ +- * | copy | | Create SGL link. +- * v v | +- * RX SGL: AAD || CT ----+ +- */ +- +- /* Copy AAD || CT to RX SGL buffer for in-place operation. */ +- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, +- areq->first_rsgl.sgl.sg, outlen); +- if (err) +- goto free; +- +- /* Create TX SGL for tag and chain it to RX SGL. */ +- areq->tsgl_entries = af_alg_count_tsgl(sk, processed, +- processed - as); +- if (!areq->tsgl_entries) +- areq->tsgl_entries = 1; +- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), +- areq->tsgl_entries), +- GFP_KERNEL); +- if (!areq->tsgl) { +- err = -ENOMEM; +- goto free; +- } +- sg_init_table(areq->tsgl, areq->tsgl_entries); +- +- /* Release TX SGL, except for tag data and reassign tag data. */ +- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); +- +- /* chain the areq TX SGL holding the tag with RX SGL */ +- if (usedpages) { +- /* RX SGL present */ +- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; +- +- sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); +- sg_chain(sgl_prev->sg, sgl_prev->npages + 1, +- areq->tsgl); +- } else +- /* no RX SGL present (e.g. authentication only) */ +- rsgl_src = areq->tsgl; +- } ++ err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src, ++ ctx->aead_assoclen); ++ if (err) ++ goto free; + + /* Initialize the crypto operation */ +- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, ++ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, + areq->first_rsgl.sgl.sg, used, ctx->iv); + aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); + aead_request_set_tfm(&areq->cra_u.aead_req, tfm); +@@ -526,7 +463,7 @@ + struct crypto_aead *tfm = aeadc->aead; + unsigned int ivlen = crypto_aead_ivsize(tfm); + +- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); ++ af_alg_pull_tsgl(sk, ctx->used, NULL); + sock_kzfree_s(sk, ctx->iv, ivlen); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -89,7 +89,7 @@ + * Create a per request TX SGL for this request which tracks the + * SG entries from the global TX SGL. + */ +- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); ++ areq->tsgl_entries = af_alg_count_tsgl(sk, len); + if (!areq->tsgl_entries) + areq->tsgl_entries = 1; + areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), +@@ -100,7 +100,7 @@ + goto free; + } + sg_init_table(areq->tsgl, areq->tsgl_entries); +- af_alg_pull_tsgl(sk, len, areq->tsgl, 0); ++ af_alg_pull_tsgl(sk, len, areq->tsgl); + + /* Initialize the crypto operation */ + skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); +@@ -313,7 +313,7 @@ + struct alg_sock *pask = alg_sk(psk); + struct crypto_skcipher *tfm = pask->private; + +- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); ++ af_alg_pull_tsgl(sk, ctx->used, NULL); + sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -226,9 +226,8 @@ + return PAGE_SIZE <= af_alg_rcvbuf(sk); + } + +-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); +-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, +- size_t dst_offset); ++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); ++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); + void af_alg_wmem_wakeup(struct sock *sk); + int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); + int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, From 0e0aafe917d187fa4769111c9fc42bfa80709c0e Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Tue, 5 May 2026 07:30:56 +0000 Subject: [PATCH 15/17] Revert "crypto: algif_aead - Revert to operating out-of-place" This reverts commit dd695406190fd83dccb7bf13b6277a09e4c78770. --- config.yaml | 4 - ...ead-Revert-to-operating-out-of-place.patch | 308 ------------------ 2 files changed, 312 deletions(-) delete mode 100644 files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch diff --git a/config.yaml b/config.yaml index 7993cab..1b9e687 100644 --- a/config.yaml +++ b/config.yaml @@ -40,9 +40,6 @@ actions: name: "ppc64le-kvm-support.patch" number: "Latest" modify_spec: false - - type: "patch" - name: "1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch" - number: 1100 - replace: - target: "kernel*rhel.config" @@ -453,7 +450,6 @@ actions: - name: "Andrew Lukoshko" email: "alukoshko@almalinux.org" line: - - "crypto: algif_aead - Revert to operating out-of-place" - "hpsa: bring back deprecated PCI ids #CFHack #CFHack2024" - "mptsas: bring back deprecated PCI ids #CFHack #CFHack2024" - "megaraid_sas: bring back deprecated PCI ids #CFHack #CFHack2024" diff --git a/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch b/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch deleted file mode 100644 index 6652b2b..0000000 --- a/files/1100-crypto-algif_aead-Revert-to-operating-out-of-place.patch +++ /dev/null @@ -1,308 +0,0 @@ -From a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 Mon Sep 17 00:00:00 2001 -From: Herbert Xu -Date: Thu, 26 Mar 2026 15:30:20 +0900 -Subject: [PATCH] crypto: algif_aead - Revert to operating out-of-place - -This mostly reverts commit 72548b093ee3 except for the copying of -the associated data. - -There is no benefit in operating in-place in algif_aead since the -source and destination come from different mappings. Get rid of -all the complexity added for in-place operation and just copy the -AD directly. - -Backported to kernel-5.14.0-611.49.1.el9_7: this tree pre-dates upstream's -memcpy_sglist() helper, so the AAD copy keeps using -crypto_aead_copy_sgl(null_tfm, ...). The function signatures of -af_alg_count_tsgl() and af_alg_pull_tsgl() are reverted to drop the -offset parameters as in upstream. - -Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst") -Reported-by: Taeyang Lee <0wn@theori.io> -Signed-off-by: Herbert Xu ---- ---- a/crypto/af_alg.c -+++ b/crypto/af_alg.c -@@ -525,15 +525,13 @@ - /** - * af_alg_count_tsgl - Count number of TX SG entries - * -- * The counting starts from the beginning of the SGL to @bytes. If -- * an @offset is provided, the counting of the SG entries starts at the @offset. -+ * The counting starts from the beginning of the SGL to @bytes. - * - * @sk: socket of connection to user space - * @bytes: Count the number of SG entries holding given number of bytes. -- * @offset: Start the counting of SG entries from the given offset. - * Return: Number of TX SG entries found given the constraints - */ --unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) -+unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) - { - const struct alg_sock *ask = alg_sk(sk); - const struct af_alg_ctx *ctx = ask->private; -@@ -548,25 +546,11 @@ - const struct scatterlist *sg = sgl->sg; - - for (i = 0; i < sgl->cur; i++) { -- size_t bytes_count; -- -- /* Skip offset */ -- if (offset >= sg[i].length) { -- offset -= sg[i].length; -- bytes -= sg[i].length; -- continue; -- } -- -- bytes_count = sg[i].length - offset; -- -- offset = 0; - sgl_count++; -- -- /* If we have seen requested number of bytes, stop */ -- if (bytes_count >= bytes) -+ if (sg[i].length >= bytes) - return sgl_count; - -- bytes -= bytes_count; -+ bytes -= sg[i].length; - } - } - -@@ -578,19 +562,14 @@ - * af_alg_pull_tsgl - Release the specified buffers from TX SGL - * - * If @dst is non-null, reassign the pages to @dst. The caller must release -- * the pages. If @dst_offset is given only reassign the pages to @dst starting -- * at the @dst_offset (byte). The caller must ensure that @dst is large -- * enough (e.g. by using af_alg_count_tsgl with the same offset). -+ * the pages. - * - * @sk: socket of connection to user space - * @used: Number of bytes to pull from TX SGL - * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The - * caller must release the buffers in dst. -- * @dst_offset: Reassign the TX SGL from given offset. All buffers before -- * reaching the offset is released. - */ --void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, -- size_t dst_offset) -+void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) - { - struct alg_sock *ask = alg_sk(sk); - struct af_alg_ctx *ctx = ask->private; -@@ -615,18 +594,10 @@ - * SG entries in dst. - */ - if (dst) { -- if (dst_offset >= plen) { -- /* discard page before offset */ -- dst_offset -= plen; -- } else { -- /* reassign page to dst after offset */ -- get_page(page); -- sg_set_page(dst + j, page, -- plen - dst_offset, -- sg[i].offset + dst_offset); -- dst_offset = 0; -- j++; -- } -+ /* reassign page to dst after offset */ -+ get_page(page); -+ sg_set_page(dst + j, page, plen, sg[i].offset); -+ j++; - } - - sg[i].length -= plen; ---- a/crypto/algif_aead.c -+++ b/crypto/algif_aead.c -@@ -96,9 +96,8 @@ - struct aead_tfm *aeadc = pask->private; - struct crypto_aead *tfm = aeadc->aead; - struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; -- unsigned int i, as = crypto_aead_authsize(tfm); -+ unsigned int as = crypto_aead_authsize(tfm); - struct af_alg_async_req *areq; -- struct af_alg_tsgl *tsgl, *tmp; - struct scatterlist *rsgl_src, *tsgl_src = NULL; - int err = 0; - size_t used = 0; /* [in] TX bufs to be en/decrypted */ -@@ -178,23 +177,24 @@ - outlen -= less; - } - -+ /* -+ * Create a per request TX SGL for this request which tracks the -+ * SG entries from the global TX SGL. -+ */ - processed = used + ctx->aead_assoclen; -- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { -- for (i = 0; i < tsgl->cur; i++) { -- struct scatterlist *process_sg = tsgl->sg + i; -- -- if (!(process_sg->length) || !sg_page(process_sg)) -- continue; -- tsgl_src = process_sg; -- break; -- } -- if (tsgl_src) -- break; -- } -- if (processed && !tsgl_src) { -- err = -EFAULT; -+ areq->tsgl_entries = af_alg_count_tsgl(sk, processed); -+ if (!areq->tsgl_entries) -+ areq->tsgl_entries = 1; -+ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -+ areq->tsgl_entries), -+ GFP_KERNEL); -+ if (!areq->tsgl) { -+ err = -ENOMEM; - goto free; - } -+ sg_init_table(areq->tsgl, areq->tsgl_entries); -+ af_alg_pull_tsgl(sk, processed, areq->tsgl); -+ tsgl_src = areq->tsgl; - - /* - * Copy of AAD from source to destination -@@ -203,81 +203,18 @@ - * when user space uses an in-place cipher operation, the kernel - * will copy the data as it does not see whether such in-place operation - * is initiated. -- * -- * To ensure efficiency, the following implementation ensure that the -- * ciphers are invoked to perform a crypto operation in-place. This -- * is achieved by memory management specified as follows. - */ - -- /* Use the RX SGL as source (and destination) for crypto op. */ -+ /* Use the RX SGL as destination for crypto op. */ - rsgl_src = areq->first_rsgl.sgl.sg; - -- if (ctx->enc) { -- /* -- * Encryption operation - The in-place cipher operation is -- * achieved by the following operation: -- * -- * TX SGL: AAD || PT -- * | | -- * | copy | -- * v v -- * RX SGL: AAD || PT || Tag -- */ -- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, -- areq->first_rsgl.sgl.sg, processed); -- if (err) -- goto free; -- af_alg_pull_tsgl(sk, processed, NULL, 0); -- } else { -- /* -- * Decryption operation - To achieve an in-place cipher -- * operation, the following SGL structure is used: -- * -- * TX SGL: AAD || CT || Tag -- * | | ^ -- * | copy | | Create SGL link. -- * v v | -- * RX SGL: AAD || CT ----+ -- */ -- -- /* Copy AAD || CT to RX SGL buffer for in-place operation. */ -- err = crypto_aead_copy_sgl(null_tfm, tsgl_src, -- areq->first_rsgl.sgl.sg, outlen); -- if (err) -- goto free; -- -- /* Create TX SGL for tag and chain it to RX SGL. */ -- areq->tsgl_entries = af_alg_count_tsgl(sk, processed, -- processed - as); -- if (!areq->tsgl_entries) -- areq->tsgl_entries = 1; -- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -- areq->tsgl_entries), -- GFP_KERNEL); -- if (!areq->tsgl) { -- err = -ENOMEM; -- goto free; -- } -- sg_init_table(areq->tsgl, areq->tsgl_entries); -- -- /* Release TX SGL, except for tag data and reassign tag data. */ -- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); -- -- /* chain the areq TX SGL holding the tag with RX SGL */ -- if (usedpages) { -- /* RX SGL present */ -- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; -- -- sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); -- sg_chain(sgl_prev->sg, sgl_prev->npages + 1, -- areq->tsgl); -- } else -- /* no RX SGL present (e.g. authentication only) */ -- rsgl_src = areq->tsgl; -- } -+ err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src, -+ ctx->aead_assoclen); -+ if (err) -+ goto free; - - /* Initialize the crypto operation */ -- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, -+ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, - areq->first_rsgl.sgl.sg, used, ctx->iv); - aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); - aead_request_set_tfm(&areq->cra_u.aead_req, tfm); -@@ -526,7 +463,7 @@ - struct crypto_aead *tfm = aeadc->aead; - unsigned int ivlen = crypto_aead_ivsize(tfm); - -- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); -+ af_alg_pull_tsgl(sk, ctx->used, NULL); - sock_kzfree_s(sk, ctx->iv, ivlen); - sock_kfree_s(sk, ctx, ctx->len); - af_alg_release_parent(sk); ---- a/crypto/algif_skcipher.c -+++ b/crypto/algif_skcipher.c -@@ -89,7 +89,7 @@ - * Create a per request TX SGL for this request which tracks the - * SG entries from the global TX SGL. - */ -- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); -+ areq->tsgl_entries = af_alg_count_tsgl(sk, len); - if (!areq->tsgl_entries) - areq->tsgl_entries = 1; - areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), -@@ -100,7 +100,7 @@ - goto free; - } - sg_init_table(areq->tsgl, areq->tsgl_entries); -- af_alg_pull_tsgl(sk, len, areq->tsgl, 0); -+ af_alg_pull_tsgl(sk, len, areq->tsgl); - - /* Initialize the crypto operation */ - skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); -@@ -313,7 +313,7 @@ - struct alg_sock *pask = alg_sk(psk); - struct crypto_skcipher *tfm = pask->private; - -- af_alg_pull_tsgl(sk, ctx->used, NULL, 0); -+ af_alg_pull_tsgl(sk, ctx->used, NULL); - sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); - sock_kfree_s(sk, ctx, ctx->len); - af_alg_release_parent(sk); ---- a/include/crypto/if_alg.h -+++ b/include/crypto/if_alg.h -@@ -226,9 +226,8 @@ - return PAGE_SIZE <= af_alg_rcvbuf(sk); - } - --unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); --void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, -- size_t dst_offset); -+unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); -+void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); - void af_alg_wmem_wakeup(struct sock *sk); - int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); - int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, From 3b87ad6a089418e0b81477ed12c96fcd1e199afd Mon Sep 17 00:00:00 2001 From: AlmaLinux Date: Fri, 17 Jul 2026 16:59:43 +0000 Subject: [PATCH 16/17] Sync with a9-beta --- config.yaml | 46 +++-- ...bols-global-for-ppc64le-module-build.patch | 53 ++++++ ...race-between-release_task-and-lookup.patch | 172 ++++++++++++++++++ 3 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 files/0001-Make-KVM-PMU-symbols-global-for-ppc64le-module-build.patch create mode 100644 files/0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch diff --git a/config.yaml b/config.yaml index 1b9e687..e173998 100644 --- a/config.yaml +++ b/config.yaml @@ -21,6 +21,12 @@ actions: - type: "patch" name: "0007-Bring-back-deprecated-pci-ids-to-be2iscsi-driver.patch" number: 2007 + - type: "patch" + name: "0001-Make-KVM-PMU-symbols-global-for-ppc64le-module-build.patch" + number: 2008 + - type: "patch" + name: "0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch" + number: 2009 - type: "source" name: "almalinuxdup1.x509" number: 100 @@ -35,7 +41,7 @@ actions: number: 103 - type: "source" name: "almalinuxnvidia1.x509" - number: 106 + number: 108 - type: "patch" name: "ppc64le-kvm-support.patch" number: "Latest" @@ -103,12 +109,12 @@ actions: count: 1 - target: "spec" find: | - openssl x509 -inform der -in %{SOURCE105} -out nvidiagpuoot001.pem - cat rheldup3.pem rhelkpatch1.pem rhelimaca1.pem nvidiagpuoot001.pem > ../certs/rhel.pem + openssl x509 -inform der -in %{SOURCE107} -out nvidiabfdpu.pem + cat rheldup3.pem rhelkpatch1.pem rhelimaca1.pem nvidiagpuoot001.pem nvidiajetsonsoc.pem nvidiabfdpu.pem > ../certs/rhel.pem replace: | - openssl x509 -inform der -in %{SOURCE105} -out nvidiagpuoot001.pem - openssl x509 -inform der -in %{SOURCE106} -out almalinuxnvidia.pem - cat rheldup3.pem rhelkpatch1.pem rhelimaca1.pem nvidiagpuoot001.pem almalinuxnvidia.pem > ../certs/rhel.pem + openssl x509 -inform der -in %{SOURCE107} -out nvidiabfdpu.pem + openssl x509 -inform der -in %{SOURCE108} -out almalinuxnvidia.pem + cat rheldup3.pem rhelkpatch1.pem rhelimaca1.pem nvidiagpuoot001.pem nvidiajetsonsoc.pem nvidiabfdpu.pem almalinuxnvidia.pem > ../certs/rhel.pem count: 1 - target: "spec" find: "Summary: Various documentation bits found in the kernel source" @@ -157,29 +163,35 @@ actions: replace: " sed -i 's/CONFIG_CRYPTO_FIPS_NAME=.*/CONFIG_CRYPTO_FIPS_NAME=\"AlmaLinux %{rhel} - Kernel Cryptographic API\"/' $i" count: 1 - target: "spec" - find: "SBATsuffix=\"centos\"" - replace: "SBATsuffix=\"rhel\"" + find: "%global sbat_suffix centos" + replace: "%global sbat_suffix rhel" count: 1 - target: "spec" find: | linux,1,Red Hat,linux,$KernelVer,mailto:secalert@redhat.com - linux.$SBATsuffix,1,Red Hat,linux,$KernelVer,mailto:secalert@redhat.com - kernel-uki-virt.$SBATsuffix,1,Red Hat,kernel-uki-virt,$KernelVer,mailto:secalert@redhat.com + linux.%{sbat_suffix},1,Red Hat,linux,$KernelVer,mailto:secalert@redhat.com + kernel-uki-virt.%{sbat_suffix},1,Red Hat,kernel-uki-virt,$KernelVer,mailto:secalert@redhat.com replace: | linux,1,Red Hat,linux,$KernelVer,mailto:secalert@redhat.com linux,1,AlmaLinux,linux,$KernelVer,mailto:security@almalinux.org - linux.$SBATsuffix,1,Red Hat,linux,$KernelVer,mailto:secalert@redhat.com + linux.%{sbat_suffix},1,Red Hat,linux,$KernelVer,mailto:secalert@redhat.com linux.almalinux,1,AlmaLinux,linux,$KernelVer,mailto:security@almalinux.org - kernel-uki-virt.$SBATsuffix,1,Red Hat,kernel-uki-virt,$KernelVer,mailto:secalert@redhat.com + kernel-uki-virt.%{sbat_suffix},1,Red Hat,kernel-uki-virt,$KernelVer,mailto:secalert@redhat.com kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,$KernelVer,mailto:security@almalinux.org count: 1 + - target: "kernel.sbat.template" + find: "kernel.@SBAT_SUFFIX,1,Red Hat,kernel-core,@KVER,mailto:secalert@redhat.com" + replace: | + kernel.@SBAT_SUFFIX,1,Red Hat,kernel-core,@KVER,mailto:secalert@redhat.com + kernel.almalinux,1,AlmaLinux,kernel-core,@KVER,mailto:security@almalinux.org + count: 1 - target: "spec" find: "UKI_secureboot_name=centossecureboot204" - replace: "UKI_secureboot_name=%{pesign_name_0}" + replace: "UKI_secureboot_name=almalinuxsecureboot0" count: 1 - target: "spec" find: "UKI_secureboot_name=redhatsecureboot504" - replace: "UKI_secureboot_name=%{pesign_name_0}" + replace: "UKI_secureboot_name=almalinuxsecureboot0" count: 1 - target: "spec" find: "UKI_secureboot_cert=%{SOURCE153}" @@ -316,9 +328,9 @@ actions: count: 1 - target: "spec" find: | - %if !%{with_debug} && !%{with_zfcpdump} && !%{with_pae} && !%{with_up} && !%{with_arm64_64k} && !%{with_realtime} + %if !%{with_debug} && !%{with_zfcpdump} && !%{with_pae} && !%{with_up} && !%{with_arm64_64k} && !%{with_realtime} && !%{with_realtime_arm64_64k} replace: | - %if !%{with_debug} && !%{with_zfcpdump} && !%{with_pae} && !%{with_up} && !%{with_arm64_64k} && !%{with_realtime} && !%{with_ppc_kvm} + %if !%{with_debug} && !%{with_zfcpdump} && !%{with_pae} && !%{with_up} && !%{with_arm64_64k} && !%{with_realtime} && !%{with_realtime_arm64_64k} && !%{with_ppc_kvm} count: 1 - target: "spec" find: | @@ -450,6 +462,7 @@ actions: - name: "Andrew Lukoshko" email: "alukoshko@almalinux.org" line: + - "proc: fix a dentry lock race between release_task and lookup" - "hpsa: bring back deprecated PCI ids #CFHack #CFHack2024" - "mptsas: bring back deprecated PCI ids #CFHack #CFHack2024" - "megaraid_sas: bring back deprecated PCI ids #CFHack #CFHack2024" @@ -464,3 +477,4 @@ actions: - "Use AlmaLinux OS secure boot cert" - "Debrand for AlmaLinux OS" - "Add KVM support for ppc64le" + - "KVM: PPC: Book3S HV: Make PMU save/restore symbols global for module builds" diff --git a/files/0001-Make-KVM-PMU-symbols-global-for-ppc64le-module-build.patch b/files/0001-Make-KVM-PMU-symbols-global-for-ppc64le-module-build.patch new file mode 100644 index 0000000..9896d82 --- /dev/null +++ b/files/0001-Make-KVM-PMU-symbols-global-for-ppc64le-module-build.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eduard Abdullin +Date: Sun, 6 Apr 2026 00:00:00 +0000 +Subject: [PATCH] KVM: PPC: Book3S HV: Make PMU save/restore symbols global for + module builds + +--- + arch/powerpc/kvm/book3s_hv_interrupts.S | 2 +- + arch/powerpc/kvm/book3s_hv_rmhandlers.S | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S +--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S ++++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S +@@ -2788,7 +2788,7 @@ + /* + * Load up guest PMU state. R3 points to the vcpu struct. + */ +-SYM_FUNC_START_LOCAL(kvmhv_load_guest_pmu) ++SYM_FUNC_START(kvmhv_load_guest_pmu) + EXPORT_SYMBOL_GPL(kvmhv_load_guest_pmu) + mr r4, r3 + mflr r0 +@@ -2854,7 +2854,7 @@ + /* + * Reload host PMU state saved in the PACA by kvmhv_save_host_pmu. + */ +-SYM_FUNC_START_LOCAL(kvmhv_load_host_pmu) ++SYM_FUNC_START(kvmhv_load_host_pmu) + EXPORT_SYMBOL_GPL(kvmhv_load_host_pmu) + mflr r0 + lbz r4, PACA_PMCINUSE(r13) /* is the host using the PMU? */ +@@ -2911,7 +2911,7 @@ + * Save guest PMU state into the vcpu struct. + * r3 = vcpu, r4 = full save flag (PMU in use flag set in VPA) + */ +-SYM_FUNC_START_LOCAL(kvmhv_save_guest_pmu) ++SYM_FUNC_START(kvmhv_save_guest_pmu) + EXPORT_SYMBOL_GPL(kvmhv_save_guest_pmu) + mr r9, r3 + mr r8, r4 +diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S +--- a/arch/powerpc/kvm/book3s_hv_interrupts.S ++++ b/arch/powerpc/kvm/book3s_hv_interrupts.S +@@ -105,7 +105,7 @@ + mtlr r0 + blr + +-SYM_FUNC_START_LOCAL(kvmhv_save_host_pmu) ++SYM_FUNC_START(kvmhv_save_host_pmu) + BEGIN_FTR_SECTION + /* Work around P8 PMAE bug */ + li r3, -1 diff --git a/files/0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch b/files/0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch new file mode 100644 index 0000000..231334b --- /dev/null +++ b/files/0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch @@ -0,0 +1,172 @@ +From 9f855caf390cf2b760c65a60649c88a7d7d60b01 Mon Sep 17 00:00:00 2001 +From: Andrew Lukoshko +Date: Fri, 9 Jan 2026 10:09:48 +0000 +Subject: [PATCH] proc: fix a dentry lock race between release_task and lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +JIRA: https://issues.redhat.com/browse/RHEL-124568 + +commit d919a1e79bac890421537cf02ae773007bf55e6b +Author: Zhihao Cheng +Date: Wed Jul 13 21:00:29 2022 +0800 + + proc: fix a dentry lock race between release_task and lookup + + Commit 7bc3e6e55acf06 ("proc: Use a list of inodes to flush from proc") + moved proc_flush_task() behind __exit_signal(). Then, process systemd can + take long period high cpu usage during releasing task in following + concurrent processes: + + systemd ps + kernel_waitid stat(/proc/tgid) + do_wait filename_lookup + wait_consider_task lookup_fast + release_task + __exit_signal + __unhash_process + detach_pid + __change_pid // remove task->pid_links + d_revalidate -> pid_revalidate // 0 + d_invalidate(/proc/tgid) + shrink_dcache_parent(/proc/tgid) + d_walk(/proc/tgid) + spin_lock_nested(/proc/tgid/fd) + // iterating opened fd + proc_flush_pid | + d_invalidate (/proc/tgid/fd) | + shrink_dcache_parent(/proc/tgid/fd) | + shrink_dentry_list(subdirs) ↓ + shrink_lock_dentry(/proc/tgid/fd) --> race on dentry lock + + Function d_invalidate() will remove dentry from hash firstly, but why does + proc_flush_pid() process dentry '/proc/tgid/fd' before dentry + '/proc/tgid'? That's because proc_pid_make_inode() adds proc inode in + reverse order by invoking hlist_add_head_rcu(). But proc should not add + any inodes under '/proc/tgid' except '/proc/tgid/task/pid', fix it by + adding inode into 'pid->inodes' only if the inode is /proc/tgid or + /proc/tgid/task/pid. + + Performance regression: + Create 200 tasks, each task open one file for 50,000 times. Kill all + tasks when opened files exceed 10,000,000 (cat /proc/sys/fs/file-nr). + + Before fix: + $ time killall -wq aa + real 4m40.946s # During this period, we can see 'ps' and 'systemd' + taking high cpu usage. + + After fix: + $ time killall -wq aa + real 1m20.732s # During this period, we can see 'systemd' taking + high cpu usage. + + Link: https://lkml.kernel.org/r/20220713130029.4133533-1-chengzhihao1@huawei.com + Fixes: 7bc3e6e55acf06 ("proc: Use a list of inodes to flush from proc") + Link: https://bugzilla.kernel.org/show_bug.cgi?id=216054 + Signed-off-by: Zhihao Cheng + Signed-off-by: Zhang Yi + Suggested-by: Brian Foster + Reviewed-by: Brian Foster + Cc: Al Viro + Cc: Alexey Dobriyan + Cc: Eric Biederman + Cc: Matthew Wilcox + Cc: Baoquan He + Cc: Kalesh Singh + Cc: Yu Kuai + Signed-off-by: Andrew Morton + +Signed-off-by: Andrew Lukoshko +--- + fs/proc/base.c | 46 ++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 38 insertions(+), 8 deletions(-) + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index dbb251465954..67d1afedaa47 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -1887,7 +1887,7 @@ void proc_pid_evict_inode(struct proc_inode *ei) + put_pid(pid); + } + +-struct inode *proc_pid_make_inode(struct super_block * sb, ++struct inode *proc_pid_make_inode(struct super_block *sb, + struct task_struct *task, umode_t mode) + { + struct inode * inode; +@@ -1916,11 +1916,6 @@ struct inode *proc_pid_make_inode(struct super_block * sb, + + /* Let the pid remember us for quick removal */ + ei->pid = pid; +- if (S_ISDIR(mode)) { +- spin_lock(&pid->lock); +- hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); +- spin_unlock(&pid->lock); +- } + + task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); + security_task_to_inode(task, inode); +@@ -1933,6 +1928,39 @@ struct inode *proc_pid_make_inode(struct super_block * sb, + return NULL; + } + ++/* ++ * Generating an inode and adding it into @pid->inodes, so that task will ++ * invalidate inode's dentry before being released. ++ * ++ * This helper is used for creating dir-type entries under '/proc' and ++ * '/proc//task'. Other entries(eg. fd, stat) under '/proc/' ++ * can be released by invalidating '/proc/' dentry. ++ * In theory, dentries under '/proc//task' can also be released by ++ * invalidating '/proc/' dentry, we reserve it to handle single ++ * thread exiting situation: Any one of threads should invalidate its ++ * '/proc//task/' dentry before released. ++ */ ++static struct inode *proc_pid_make_base_inode(struct super_block *sb, ++ struct task_struct *task, umode_t mode) ++{ ++ struct inode *inode; ++ struct proc_inode *ei; ++ struct pid *pid; ++ ++ inode = proc_pid_make_inode(sb, task, mode); ++ if (!inode) ++ return NULL; ++ ++ /* Let proc_flush_pid find this directory inode */ ++ ei = PROC_I(inode); ++ pid = ei->pid; ++ spin_lock(&pid->lock); ++ hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); ++ spin_unlock(&pid->lock); ++ ++ return inode; ++} ++ + int pid_getattr(struct mnt_idmap *idmap, const struct path *path, + struct kstat *stat, u32 request_mask, unsigned int query_flags) + { +@@ -3401,7 +3429,8 @@ static struct dentry *proc_pid_instantiate(struct dentry * dentry, + { + struct inode *inode; + +- inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); ++ inode = proc_pid_make_base_inode(dentry->d_sb, task, ++ S_IFDIR | S_IRUGO | S_IXUGO); + if (!inode) + return ERR_PTR(-ENOENT); + +@@ -3705,7 +3734,8 @@ static struct dentry *proc_task_instantiate(struct dentry *dentry, + struct task_struct *task, const void *ptr) + { + struct inode *inode; +- inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); ++ inode = proc_pid_make_base_inode(dentry->d_sb, task, ++ S_IFDIR | S_IRUGO | S_IXUGO); + if (!inode) + return ERR_PTR(-ENOENT); + +-- +2.43.5 From d5335bead2b87ffbf9e768dd475f68e0e8ad65a2 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Fri, 21 Aug 2026 12:35:59 +0300 Subject: [PATCH 17/17] Add gve patches --- config.yaml | 15 + ...e-Update-QPL-page-registration-logic.patch | 160 ++++++++++ ...inq-support-for-modifiable-ring-size.patch | 274 ++++++++++++++++++ ...htool-support-for-changing-ring-size.patch | 166 +++++++++++ ...-harden-modifiable-ring-size-support.patch | 120 ++++++++ ...bf455d75ce54314efc826364259b8a87a8d0.patch | 54 ---- 6 files changed, 735 insertions(+), 54 deletions(-) create mode 100644 files/2100-gve-Update-QPL-page-registration-logic.patch create mode 100644 files/2101-gve-Add-adminq-support-for-modifiable-ring-size.patch create mode 100644 files/2102-gve-Add-ethtool-support-for-changing-ring-size.patch create mode 100644 files/2103-gve-harden-modifiable-ring-size-support.patch delete mode 100644 files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch diff --git a/config.yaml b/config.yaml index e173998..2cd34da 100644 --- a/config.yaml +++ b/config.yaml @@ -27,6 +27,21 @@ actions: - type: "patch" name: "0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch" number: 2009 + +# GVE patches + - type: "patch" + name: "2100-gve-Update-QPL-page-registration-logic.patch" + number: 2100 + - type: "patch" + name: "2101-gve-Add-adminq-support-for-modifiable-ring-size.patch" + number: 2101 + - type: "patch" + name: "2102-gve-Add-ethtool-support-for-changing-ring-size.patch" + number: 2102 + - type: "patch" + name: "2103-gve-harden-modifiable-ring-size-support.patch" + number: 2103 + - type: "source" name: "almalinuxdup1.x509" number: 100 diff --git a/files/2100-gve-Update-QPL-page-registration-logic.patch b/files/2100-gve-Update-QPL-page-registration-logic.patch new file mode 100644 index 0000000..5cff277 --- /dev/null +++ b/files/2100-gve-Update-QPL-page-registration-logic.patch @@ -0,0 +1,160 @@ +From 07993df560917357610e0625a9a2e7531c3211fc Mon Sep 17 00:00:00 2001 +From: Matt Olson +Date: Wed, 25 Feb 2026 10:23:41 -0800 +Subject: gve: Update QPL page registration logic + +For DQO, change QPL page registration logic to be more flexible to honor +the "max_registered_pages" parameter from the gVNIC device. + +Previously the number of RX pages per QPL was hardcoded to twice the +ring size, and the number of TX pages per QPL was dictated by the device +in the DQO-QPL device option. Now [in DQO-QPL mode], the driver will +ignore the "tx_pages_per_qpl" parameter indicated in the DQO-QPL device +option and instead allocate up to (tx_queue_length / 2) pages per TX QPL +and up to (rx_queue_length * 2) pages per RX QPL while keeping the total +number of pages under the "max_registered_pages". + +Merge DQO and GQI QPL page calculation logic into a unified +gve_update_num_qpl_pages function. Add rx_pages_per_qpl to the priv +struct for consumption by both DQO and GQI. + +Signed-off-by: Matt Olson +Signed-off-by: Max Yuan +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Reviewed-by: Willem de Bruijn +Reviewed-by: Praveen Kaligineedi +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260225182342.1049816-2-joshwash@google.com +Signed-off-by: Jakub Kicinski +[Jonathan Wright: adapted to the centralized QPL-allocation model in this kernel, + which predates the upstream gve_{tx,rx}_alloc_rings_cfg / queues_mem_alloc + per-ring QPL refactor and the gve_buffer_mgmt_dqo split. There are no + alloc_rings_cfg structs here, so gve_update_num_qpl_pages operates on + priv directly (priv->{tx,rx}_pages_per_qpl already exist) and is called + from gve_alloc_qpls() before the QPLs are allocated. rx_pages_per_qpl is + already consumed by gve_rx_alloc_ring_dqo() and gve_alloc_qpl_page_dqo(). + The GQI path is left unchanged: it already sizes RX QPLs from + rx_data_slot_cnt and TX QPLs from the device-provided tx_pages_per_qpl.] +Signed-off-by: Jonathan Wright +--- + drivers/net/ethernet/google/gve/gve.h | 7 ++---- + drivers/net/ethernet/google/gve/gve_adminq.c | 12 ---------- + drivers/net/ethernet/google/gve/gve_main.c | 40 +++++++++++++++++++++++++++++ + 3 files changed, 43 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h +index cbdf3a842cfe0..1d66d3834f7e6 100644 +--- a/drivers/net/ethernet/google/gve/gve.h ++++ b/drivers/net/ethernet/google/gve/gve.h +@@ -56,9 +56,6 @@ + + #define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182 + +-#define DQO_QPL_DEFAULT_TX_PAGES 512 +-#define DQO_QPL_DEFAULT_RX_PAGES 2048 +- + /* Maximum TSO size supported on DQO */ + #define GVE_DQO_TX_MAX 0x3FFFF + +@@ -650,8 +647,8 @@ struct gve_priv { + u16 num_event_counters; + u16 tx_desc_cnt; /* num desc per ring */ + u16 rx_desc_cnt; /* num desc per ring */ +- u16 tx_pages_per_qpl; /* Suggested number of pages per qpl for TX queues by NIC */ +- u16 rx_pages_per_qpl; /* Suggested number of pages per qpl for RX queues by NIC */ ++ u16 tx_pages_per_qpl; /* Number of pages per qpl for TX queues */ ++ u16 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */ + u16 rx_data_slot_cnt; /* rx buffer length */ + u64 max_registered_pages; + u64 num_registered_pages; /* num pages registered with NIC */ +diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c +index b72cc0fa2ba2b..2c233009621bc 100644 +--- a/drivers/net/ethernet/google/gve/gve_adminq.c ++++ b/drivers/net/ethernet/google/gve/gve_adminq.c +@@ -767,18 +767,6 @@ static void gve_enable_supported_features(struct gve_priv *priv, + "JUMBO FRAMES device option enabled.\n"); + priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu); + } +- +- /* Override pages for qpl for DQO-QPL */ +- if (dev_op_dqo_qpl) { +- priv->tx_pages_per_qpl = +- be16_to_cpu(dev_op_dqo_qpl->tx_pages_per_qpl); +- priv->rx_pages_per_qpl = +- be16_to_cpu(dev_op_dqo_qpl->rx_pages_per_qpl); +- if (priv->tx_pages_per_qpl == 0) +- priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES; +- if (priv->rx_pages_per_qpl == 0) +- priv->rx_pages_per_qpl = DQO_QPL_DEFAULT_RX_PAGES; +- } + } + + int gve_adminq_describe_device(struct gve_priv *priv) +diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c +index 9eb4b3614c4f5..c654cf503c1a2 100644 +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1106,6 +1107,43 @@ static int gve_alloc_xdp_qpls(struct gve_priv *priv) + return err; + } + ++/* For DQO, update the suggested number of pages per qpl to be more flexible ++ * and honor the "max_registered_pages" parameter from the gVNIC device. ++ * ++ * Ignore the "tx_pages_per_qpl"/"rx_pages_per_qpl" parameters indicated in the ++ * DQO-QPL device option and instead allocate up to (tx_queue_length / 2) pages ++ * per TX QPL and up to (rx_queue_length * 2) pages per RX QPL while keeping the ++ * total number of pages under "max_registered_pages". ++ */ ++static void gve_update_num_qpl_pages(struct gve_priv *priv) ++{ ++ u64 ideal_tx_pages, ideal_rx_pages; ++ u16 tx_num_queues, rx_num_queues; ++ u64 max_pages, tx_pages; ++ ++ if (priv->queue_format != GVE_DQO_QPL_FORMAT) ++ return; ++ ++ /* We want 2 pages per RX descriptor and half a page per TX descriptor, ++ * which means the fraction ideal_tx_pages / (ideal_tx_pages + ++ * ideal_rx_pages) of the pages we allocate should be for TX. Shrink ++ * proportionally as necessary to avoid allocating more than ++ * max_registered_pages total pages. ++ */ ++ tx_num_queues = priv->tx_cfg.num_queues; ++ rx_num_queues = priv->rx_cfg.num_queues; ++ ++ ideal_tx_pages = (u64)priv->tx_desc_cnt * tx_num_queues / 2; ++ ideal_rx_pages = (u64)priv->rx_desc_cnt * rx_num_queues * 2; ++ max_pages = min(priv->max_registered_pages, ++ ideal_tx_pages + ideal_rx_pages); ++ ++ tx_pages = div64_u64(max_pages * ideal_tx_pages, ++ ideal_tx_pages + ideal_rx_pages); ++ priv->tx_pages_per_qpl = div_u64(tx_pages, tx_num_queues); ++ priv->rx_pages_per_qpl = div_u64(max_pages - tx_pages, rx_num_queues); ++} ++ + static int gve_alloc_qpls(struct gve_priv *priv) + { + int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues; +@@ -1117,6 +1155,8 @@ static int gve_alloc_qpls(struct gve_priv *priv) + if (!gve_is_qpl(priv)) + return 0; + ++ gve_update_num_qpl_pages(priv); ++ + priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL); + if (!priv->qpls) + return -ENOMEM; +-- +2.43.0 diff --git a/files/2101-gve-Add-adminq-support-for-modifiable-ring-size.patch b/files/2101-gve-Add-adminq-support-for-modifiable-ring-size.patch new file mode 100644 index 0000000..8f0d77c --- /dev/null +++ b/files/2101-gve-Add-adminq-support-for-modifiable-ring-size.patch @@ -0,0 +1,274 @@ +From: Joshua Washington +Date: Fri, 5 Jun 2026 00:00:00 +0000 +Subject: gve: Add adminq support for modifiable ring size + +Add support for the gVNIC "modify ring" device option, which allows the +device to report the maximum and minimum TX/RX ring sizes it supports. +Store those bounds in the priv struct and report the device-provided +maximums through ethtool -g "Pre-set maximums" instead of hardcoding the +current (default) ring size as the maximum. + +If the device does not provide minimums, fall back to the default +minimums of 256 descriptors for TX and 512 for RX. + +This is the first half of the upstream gve modifiable-ring-size feature. +It only changes the advertised ring size range; actually resizing the +rings is added in the following patch. + +[Jonathan Wright: backported the upstream modifiable-ring-size support to + this kernel's gve, using the implementation carried by the RHEL 10 / + AlmaLinux 10 gve driver (kernel 6.12.0-211.7.1.el10_2) as the reference, + since this 5.14-based gve predates the feature entirely. Adaptations: + threaded dev_op_modify_ring through this tree's smaller + gve_parse_device_option()/gve_process_device_options() signatures; seeded + the default ring-size ranges in both gve_set_desc_cnt() and + gve_set_desc_cnt_dqo(). Dropped the upstream + "if (priv->queue_format != GVE_DQO_QPL_FORMAT)" guard around the max ring + size assignment: that guard exists because DQO-QPL used a fixed QPL page + budget, which no longer applies now that QPL pages scale with ring size + (see 1106-gve-Update-QPL-page-registration-logic.patch), and keeping it + would deny DQO-QPL VMs the larger ring sizes this feature is for.] +Signed-off-by: Jonathan Wright +--- +diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h +index f916e81..a3c1caa 100644 +--- a/drivers/net/ethernet/google/gve/gve.h ++++ b/drivers/net/ethernet/google/gve/gve.h +@@ -52,6 +52,9 @@ + + #define GVE_DEFAULT_RX_BUFFER_OFFSET 2048 + ++#define GVE_DEFAULT_MIN_TX_RING_SIZE 256 ++#define GVE_DEFAULT_MIN_RX_RING_SIZE 512 ++ + #define GVE_XDP_ACTIONS 5 + + #define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182 +@@ -647,6 +650,12 @@ struct gve_priv { + u16 num_event_counters; + u16 tx_desc_cnt; /* num desc per ring */ + u16 rx_desc_cnt; /* num desc per ring */ ++ u16 max_tx_desc_cnt; ++ u16 max_rx_desc_cnt; ++ u16 min_tx_desc_cnt; ++ u16 min_rx_desc_cnt; ++ bool modify_ring_size_enabled; ++ bool default_min_ring_size; + u16 tx_pages_per_qpl; /* Number of pages per qpl for TX queues */ + u16 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */ + u16 rx_data_slot_cnt; /* rx buffer length */ +diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c +index 62817f8..b7f86bc 100644 +--- a/drivers/net/ethernet/google/gve/gve_adminq.c ++++ b/drivers/net/ethernet/google/gve/gve_adminq.c +@@ -20,6 +20,8 @@ + + #define GVE_DEVICE_OPTION_TOO_BIG_FMT "Length of %s option larger than expected. Possible older version of guest driver.\n" + ++#define GVE_DEVICE_OPTION_NO_MIN_RING_SIZE 8 ++ + static + struct gve_device_option *gve_get_next_option(struct gve_device_descriptor *descriptor, + struct gve_device_option *option) +@@ -40,7 +42,8 @@ void gve_parse_device_option(struct gve_priv *priv, + struct gve_device_option_gqi_qpl **dev_op_gqi_qpl, + struct gve_device_option_dqo_rda **dev_op_dqo_rda, + struct gve_device_option_jumbo_frames **dev_op_jumbo_frames, +- struct gve_device_option_dqo_qpl **dev_op_dqo_qpl) ++ struct gve_device_option_dqo_qpl **dev_op_dqo_qpl, ++ struct gve_device_option_modify_ring **dev_op_modify_ring) + { + u32 req_feat_mask = be32_to_cpu(option->required_features_mask); + u16 option_length = be16_to_cpu(option->option_length); +@@ -129,6 +132,27 @@ void gve_parse_device_option(struct gve_priv *priv, + } + *dev_op_dqo_qpl = (void *)(option + 1); + break; ++ case GVE_DEV_OPT_ID_MODIFY_RING: ++ if (option_length < GVE_DEVICE_OPTION_NO_MIN_RING_SIZE || ++ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING) { ++ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT, ++ "Modify Ring", (int)sizeof(**dev_op_modify_ring), ++ GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING, ++ option_length, req_feat_mask); ++ break; ++ } ++ ++ if (option_length > sizeof(**dev_op_modify_ring)) { ++ dev_warn(&priv->pdev->dev, ++ GVE_DEVICE_OPTION_TOO_BIG_FMT, "Modify Ring"); ++ } ++ ++ *dev_op_modify_ring = (void *)(option + 1); ++ ++ /* device has not provided min ring size */ ++ if (option_length == GVE_DEVICE_OPTION_NO_MIN_RING_SIZE) ++ priv->default_min_ring_size = true; ++ break; + case GVE_DEV_OPT_ID_JUMBO_FRAMES: + if (option_length < sizeof(**dev_op_jumbo_frames) || + req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES) { +@@ -164,7 +188,8 @@ gve_process_device_options(struct gve_priv *priv, + struct gve_device_option_gqi_qpl **dev_op_gqi_qpl, + struct gve_device_option_dqo_rda **dev_op_dqo_rda, + struct gve_device_option_jumbo_frames **dev_op_jumbo_frames, +- struct gve_device_option_dqo_qpl **dev_op_dqo_qpl) ++ struct gve_device_option_dqo_qpl **dev_op_dqo_qpl, ++ struct gve_device_option_modify_ring **dev_op_modify_ring) + { + const int num_options = be16_to_cpu(descriptor->num_device_options); + struct gve_device_option *dev_opt; +@@ -185,7 +210,7 @@ gve_process_device_options(struct gve_priv *priv, + gve_parse_device_option(priv, descriptor, dev_opt, + dev_op_gqi_rda, dev_op_gqi_qpl, + dev_op_dqo_rda, dev_op_jumbo_frames, +- dev_op_dqo_qpl); ++ dev_op_dqo_qpl, dev_op_modify_ring); + dev_opt = next_opt; + } + +@@ -728,6 +753,12 @@ static int gve_set_desc_cnt(struct gve_priv *priv, + { + priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries); + priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries); ++ ++ /* set default ranges */ ++ priv->max_tx_desc_cnt = priv->tx_desc_cnt; ++ priv->max_rx_desc_cnt = priv->rx_desc_cnt; ++ priv->min_tx_desc_cnt = priv->tx_desc_cnt; ++ priv->min_rx_desc_cnt = priv->rx_desc_cnt; + return 0; + } + +@@ -739,6 +770,12 @@ gve_set_desc_cnt_dqo(struct gve_priv *priv, + priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries); + priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries); + ++ /* set default ranges */ ++ priv->max_tx_desc_cnt = priv->tx_desc_cnt; ++ priv->max_rx_desc_cnt = priv->rx_desc_cnt; ++ priv->min_tx_desc_cnt = priv->tx_desc_cnt; ++ priv->min_rx_desc_cnt = priv->rx_desc_cnt; ++ + if (priv->queue_format == GVE_DQO_QPL_FORMAT) + return 0; + +@@ -755,7 +792,9 @@ static void gve_enable_supported_features(struct gve_priv *priv, + const struct gve_device_option_jumbo_frames + *dev_op_jumbo_frames, + const struct gve_device_option_dqo_qpl +- *dev_op_dqo_qpl) ++ *dev_op_dqo_qpl, ++ const struct gve_device_option_modify_ring ++ *dev_op_modify_ring) + { + /* Before control reaches this point, the page-size-capped max MTU from + * the gve_device_descriptor field has already been stored in +@@ -767,10 +806,29 @@ static void gve_enable_supported_features(struct gve_priv *priv, + "JUMBO FRAMES device option enabled.\n"); + priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu); + } ++ ++ /* Read and store ring size ranges given by device */ ++ if (dev_op_modify_ring && ++ (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) { ++ priv->modify_ring_size_enabled = true; ++ ++ priv->max_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_rx_ring_size); ++ priv->max_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_tx_ring_size); ++ ++ if (priv->default_min_ring_size) { ++ /* If device hasn't provided minimums, use default minimums */ ++ priv->min_tx_desc_cnt = GVE_DEFAULT_MIN_TX_RING_SIZE; ++ priv->min_rx_desc_cnt = GVE_DEFAULT_MIN_RX_RING_SIZE; ++ } else { ++ priv->min_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_rx_ring_size); ++ priv->min_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_tx_ring_size); ++ } ++ } + } + + int gve_adminq_describe_device(struct gve_priv *priv) + { ++ struct gve_device_option_modify_ring *dev_op_modify_ring = NULL; + struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL; + struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL; + struct gve_device_option_gqi_qpl *dev_op_gqi_qpl = NULL; +@@ -804,7 +862,7 @@ int gve_adminq_describe_device(struct gve_priv *priv) + err = gve_process_device_options(priv, descriptor, &dev_op_gqi_rda, + &dev_op_gqi_qpl, &dev_op_dqo_rda, + &dev_op_jumbo_frames, +- &dev_op_dqo_qpl); ++ &dev_op_dqo_qpl, &dev_op_modify_ring); + if (err) + goto free_device_descriptor; + +@@ -873,7 +931,8 @@ int gve_adminq_describe_device(struct gve_priv *priv) + priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues); + + gve_enable_supported_features(priv, supported_features_mask, +- dev_op_jumbo_frames, dev_op_dqo_qpl); ++ dev_op_jumbo_frames, dev_op_dqo_qpl, ++ dev_op_modify_ring); + + free_device_descriptor: + dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus); +diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h +index 5865ccd..0d1dd38 100644 +--- a/drivers/net/ethernet/google/gve/gve_adminq.h ++++ b/drivers/net/ethernet/google/gve/gve_adminq.h +@@ -125,6 +125,16 @@ struct gve_device_option_jumbo_frames { + + static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8); + ++struct gve_device_option_modify_ring { ++ __be32 supported_featured_mask; ++ __be16 max_rx_ring_size; ++ __be16 max_tx_ring_size; ++ __be16 min_rx_ring_size; ++ __be16 min_tx_ring_size; ++}; ++ ++static_assert(sizeof(struct gve_device_option_modify_ring) == 12); ++ + /* Terminology: + * + * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA +@@ -138,6 +148,7 @@ enum gve_dev_opt_id { + GVE_DEV_OPT_ID_GQI_RDA = 0x2, + GVE_DEV_OPT_ID_GQI_QPL = 0x3, + GVE_DEV_OPT_ID_DQO_RDA = 0x4, ++ GVE_DEV_OPT_ID_MODIFY_RING = 0x6, + GVE_DEV_OPT_ID_DQO_QPL = 0x7, + GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8, + }; +@@ -149,9 +160,11 @@ enum gve_dev_opt_req_feat_mask { + GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0, + GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES = 0x0, + GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL = 0x0, ++ GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING = 0x0, + }; + + enum gve_sup_feature_mask { ++ GVE_SUP_MODIFY_RING_MASK = 1 << 0, + GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2, + }; + +diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c +index e5397aa..fb7b477 100644 +--- a/drivers/net/ethernet/google/gve/gve_ethtool.c ++++ b/drivers/net/ethernet/google/gve/gve_ethtool.c +@@ -476,8 +476,8 @@ static void gve_get_ringparam(struct net_device *netdev, + { + struct gve_priv *priv = netdev_priv(netdev); + +- cmd->rx_max_pending = priv->rx_desc_cnt; +- cmd->tx_max_pending = priv->tx_desc_cnt; ++ cmd->rx_max_pending = priv->max_rx_desc_cnt; ++ cmd->tx_max_pending = priv->max_tx_desc_cnt; + cmd->rx_pending = priv->rx_desc_cnt; + cmd->tx_pending = priv->tx_desc_cnt; + } +-- +2.43.0 + diff --git a/files/2102-gve-Add-ethtool-support-for-changing-ring-size.patch b/files/2102-gve-Add-ethtool-support-for-changing-ring-size.patch new file mode 100644 index 0000000..3521848 --- /dev/null +++ b/files/2102-gve-Add-ethtool-support-for-changing-ring-size.patch @@ -0,0 +1,166 @@ +From: Joshua Washington +Date: Fri, 5 Jun 2026 00:00:01 +0000 +Subject: gve: Add ethtool support for changing ring size + +Add ethtool -G (set_ringparam) support so the TX/RX ring sizes can +actually be changed within the bounds reported by the device in the +"modify ring" device option. + +Requested ring sizes are validated against the device-provided minimums +and maximums and must be a power of two. Changing the ring size tears the +device down, applies the new descriptor counts, and brings it back up. + +[Jonathan Wright: backported the upstream modifiable-ring-size support to + this kernel's gve, using the RHEL 10 / AlmaLinux 10 gve driver + (kernel 6.12.0-211.7.1.el10_2) as the reference. Adaptations: upstream's + gve_adjust_ring_sizes() reconfigures via gve_get_curr_alloc_cfgs() / + gve_adjust_config(), which do not exist in this tree (it predates the + gve_{tx,rx}_alloc_rings_cfg / queues_mem_alloc refactor). Instead + gve_adjust_ring_sizes() lives in gve_main.c and follows the existing + gve_adjust_queues() pattern used by this tree for ethtool -L: teardown + with gve_close(), set the new descriptor counts, then gve_open(), which + rebuilds the rings and re-sizes the QPLs from the new ring size via + gve_update_num_qpl_pages() (1106). It is declared in gve.h because + gve_close()/gve_open() are static to gve_main.c. Upstream's + gve_set_ringparam() also handles header-split/tcp_data_split; that + feature does not exist in this tree, so only the ring-size logic is + carried over.] +Signed-off-by: Jonathan Wright +--- +diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h +index a3c1caa..acac856 100644 +--- a/drivers/net/ethernet/google/gve/gve.h ++++ b/drivers/net/ethernet/google/gve/gve.h +@@ -1074,6 +1074,9 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown); + int gve_adjust_queues(struct gve_priv *priv, + struct gve_queue_config new_rx_config, + struct gve_queue_config new_tx_config); ++int gve_adjust_ring_sizes(struct gve_priv *priv, ++ u16 new_tx_desc_cnt, ++ u16 new_rx_desc_cnt); + /* report stats handling */ + void gve_handle_report_stats(struct gve_priv *priv); + /* exported by ethtool.c */ +diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c +index fb7b477..a8822c9 100644 +--- a/drivers/net/ethernet/google/gve/gve_ethtool.c ++++ b/drivers/net/ethernet/google/gve/gve_ethtool.c +@@ -6,6 +6,7 @@ + + #include + #include ++#include + #include "gve.h" + #include "gve_adminq.h" + #include "gve_dqo.h" +@@ -482,6 +483,50 @@ static void gve_get_ringparam(struct net_device *netdev, + cmd->tx_pending = priv->tx_desc_cnt; + } + ++static int gve_validate_req_ring_size(struct gve_priv *priv, u16 new_tx_desc_cnt, ++ u16 new_rx_desc_cnt) ++{ ++ /* check for valid range */ ++ if (new_tx_desc_cnt < priv->min_tx_desc_cnt || ++ new_tx_desc_cnt > priv->max_tx_desc_cnt || ++ new_rx_desc_cnt < priv->min_rx_desc_cnt || ++ new_rx_desc_cnt > priv->max_rx_desc_cnt) { ++ dev_err(&priv->pdev->dev, "Requested descriptor count out of range\n"); ++ return -EINVAL; ++ } ++ ++ if (!is_power_of_2(new_tx_desc_cnt) || !is_power_of_2(new_rx_desc_cnt)) { ++ dev_err(&priv->pdev->dev, "Requested descriptor count has to be a power of 2\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int gve_set_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *cmd, ++ struct kernel_ethtool_ringparam *kernel_cmd, ++ struct netlink_ext_ack *extack) ++{ ++ struct gve_priv *priv = netdev_priv(netdev); ++ u16 new_tx_cnt, new_rx_cnt; ++ ++ if (cmd->tx_pending == priv->tx_desc_cnt && cmd->rx_pending == priv->rx_desc_cnt) ++ return 0; ++ ++ if (!priv->modify_ring_size_enabled) { ++ dev_err(&priv->pdev->dev, "Modify ring size is not supported.\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ new_tx_cnt = cmd->tx_pending; ++ new_rx_cnt = cmd->rx_pending; ++ ++ if (gve_validate_req_ring_size(priv, new_tx_cnt, new_rx_cnt)) ++ return -EINVAL; ++ ++ return gve_adjust_ring_sizes(priv, new_tx_cnt, new_rx_cnt); ++} ++ + static int gve_user_reset(struct net_device *netdev, u32 *flags) + { + struct gve_priv *priv = netdev_priv(netdev); +@@ -667,6 +712,7 @@ const struct ethtool_ops gve_ethtool_ops = { + .get_coalesce = gve_get_coalesce, + .set_coalesce = gve_set_coalesce, + .get_ringparam = gve_get_ringparam, ++ .set_ringparam = gve_set_ringparam, + .reset = gve_user_reset, + .get_tunable = gve_get_tunable, + .set_tunable = gve_set_tunable, +diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c +index a21df52..e939750 100644 +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -1780,6 +1780,44 @@ err: + return err; + } + ++int gve_adjust_ring_sizes(struct gve_priv *priv, ++ u16 new_tx_desc_cnt, ++ u16 new_rx_desc_cnt) ++{ ++ int err; ++ ++ if (netif_carrier_ok(priv->dev)) { ++ /* To make this process as simple as possible we teardown the ++ * device, set the new ring sizes, and then bring the device ++ * up again. ++ */ ++ err = gve_close(priv->dev); ++ /* we have already tried to reset in close, ++ * just fail at this point ++ */ ++ if (err) ++ return err; ++ priv->tx_desc_cnt = new_tx_desc_cnt; ++ priv->rx_desc_cnt = new_rx_desc_cnt; ++ ++ err = gve_open(priv->dev); ++ if (err) ++ goto err; ++ ++ return 0; ++ } ++ /* Set the ring sizes for the next up. */ ++ priv->tx_desc_cnt = new_tx_desc_cnt; ++ priv->rx_desc_cnt = new_rx_desc_cnt; ++ ++ return 0; ++err: ++ netif_err(priv, drv, priv->dev, ++ "Adjust ring sizes failed! !!! DISABLING ALL QUEUES !!!\n"); ++ gve_turndown(priv); ++ return err; ++} ++ + static void gve_turndown(struct gve_priv *priv) + { + int idx; +-- +2.43.0 + diff --git a/files/2103-gve-harden-modifiable-ring-size-support.patch b/files/2103-gve-harden-modifiable-ring-size-support.patch new file mode 100644 index 0000000..74ad158 --- /dev/null +++ b/files/2103-gve-harden-modifiable-ring-size-support.patch @@ -0,0 +1,120 @@ +From: Jonathan Wright +Date: Wed, 5 Aug 2026 00:00:00 +0000 +Subject: gve: harden modifiable ring size support for the EL9 gve architecture + +Follow-up hardening for the modifiable-ring-size backport (patches 1107 +and 1108), addressing three ways the older EL9 gve architecture differs +from the EL10/upstream driver the feature was designed against. Found in +review; none affect the DQO resize paths already validated on GCP. + +1) Do not enable modifiable ring sizes for GQI queue formats. + In this kernel's gve, the GQI branches of + gve_adminq_create_{tx,rx}_queue carry no ring size (only the DQO + branches send one), so after a resize the device would keep using its + probe-time default ring size against rings the driver re-sized: + device and driver would index the same DMA memory modulo different + sizes. Shrinking the RX ring would additionally let the device DMA + past the smaller allocation, and the GQI datapath sizes its data ring + and mask from the fixed rx_data_slot_cnt (with a NAPI livelock + possible on GQI-RDA once rx_desc_cnt >= 2 * data slots). Gate the + feature on !gve_is_gqi(): GQI keeps the pre-feature fixed-ring + behavior and ethtool -G returns -EOPNOTSUPP. + +2) Key gve_adjust_ring_sizes() on netif_running(), not + netif_carrier_ok(), matching the EL10 implementation. The rings are + allocated whenever the interface is administratively up, even while + the link is down; taking the "set for next up" shortcut in that state + would change priv->{tx,rx}_desc_cnt under allocated rings, and the + GQI RX free path sizes dma_free_coherent() from priv->rx_desc_cnt. + +3) Clamp the advertised ring size range for DQO-RDA. In this kernel the + DQO-RDA TX completion ring and RX buffer ring keep the fixed sizes + from the DQO-RDA device option and do not scale with the descriptor + rings (upstream removed that coupling before modifiable ring sizes + were introduced). Growing the TX ring beyond tx_comp_ring_entries + could overrun the TX completion queue with report-event completions + (num_pending_packets reserves complq_size/32 slots for REs, but REs + scale with posted descriptors on the grown ring) or have queue + creation rejected; shrinking the RX descriptor/completion ring below + rx_buff_ring_entries could overflow the RX completion queue. Clamp + max_tx_desc_cnt and min_rx_desc_cnt so such sizes cannot be + requested. DQO-QPL is unaffected (its completion/buffer rings track + the descriptor ring size). +Signed-off-by: Jonathan Wright +--- +diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c +index b7f86bc..eef7cca 100644 +--- a/drivers/net/ethernet/google/gve/gve_adminq.c ++++ b/drivers/net/ethernet/google/gve/gve_adminq.c +@@ -807,8 +807,18 @@ static void gve_enable_supported_features(struct gve_priv *priv, + priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu); + } + +- /* Read and store ring size ranges given by device */ +- if (dev_op_modify_ring && ++ /* Read and store ring size ranges given by device. ++ * ++ * Modifiable ring sizes are supported for DQO queue formats only. ++ * In this kernel's gve, the GQI branches of ++ * gve_adminq_create_{tx,rx}_queue do not carry a ring size, so after ++ * a resize the device would keep using its default ring size against ++ * rings the driver re-sized, desynchronizing device and driver views ++ * of the rings. The GQI datapath (rx_data_slot_cnt data ring, TX ++ * FIFO) also assumes the probe-time fixed ring sizes. Keep GQI at ++ * fixed ring sizes. ++ */ ++ if (dev_op_modify_ring && !gve_is_gqi(priv) && + (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) { + priv->modify_ring_size_enabled = true; + +@@ -823,6 +833,27 @@ static void gve_enable_supported_features(struct gve_priv *priv, + priv->min_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_rx_ring_size); + priv->min_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_tx_ring_size); + } ++ ++ /* In this kernel's gve, the DQO-RDA TX completion ring and RX ++ * buffer ring keep the fixed sizes provided in the DQO-RDA ++ * device option; they do not scale with the descriptor rings ++ * (upstream removed that coupling before modifiable ring ++ * sizes were introduced). Clamp the advertised range so a ++ * resize cannot create a descriptor ring the fixed rings ++ * cannot absorb: ++ * - growing the TX ring beyond tx_comp_ring_entries could ++ * overrun the TX completion queue with report-event ++ * completions (or be rejected at queue creation); ++ * - shrinking the RX ring (the RX completion queue) below ++ * rx_buff_ring_entries could overflow the RX completion ++ * queue. ++ */ ++ if (priv->queue_format == GVE_DQO_RDA_FORMAT) { ++ priv->max_tx_desc_cnt = min(priv->max_tx_desc_cnt, ++ priv->options_dqo_rda.tx_comp_ring_entries); ++ priv->min_rx_desc_cnt = max(priv->min_rx_desc_cnt, ++ priv->options_dqo_rda.rx_buff_ring_entries); ++ } + } + } + +diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c +index e939750..516f222 100644 +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -1786,7 +1786,14 @@ int gve_adjust_ring_sizes(struct gve_priv *priv, + { + int err; + +- if (netif_carrier_ok(priv->dev)) { ++ /* Key on the administrative state (netif_running), not the link ++ * state: the rings are allocated whenever the interface is up, even ++ * while the carrier is down. Changing the descriptor counts without ++ * reallocating the rings would desynchronize them from ++ * priv->{tx,rx}_desc_cnt, which the GQI free path uses to size ++ * dma_free_coherent(). ++ */ ++ if (netif_running(priv->dev)) { + /* To make this process as simple as possible we teardown the + * device, set the new ring sizes, and then bring the device + * up again. +-- +2.43.0 + diff --git a/files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch b/files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch deleted file mode 100644 index f68a5e9..0000000 --- a/files/b86dbf455d75ce54314efc826364259b8a87a8d0.patch +++ /dev/null @@ -1,54 +0,0 @@ -From b86dbf455d75ce54314efc826364259b8a87a8d0 Mon Sep 17 00:00:00 2001 -From: Olga Kornievskaia -Date: Mon, 3 Mar 2025 12:09:08 -0500 -Subject: [PATCH] NFSD: fix hang in nfsd4_shutdown_callback - -JIRA: https://issues.redhat.com/browse/RHEL-81291 -CVE: CVE-2025-21795 - -commit 036ac2778f7b28885814c6fbc07e156ad1624d03 -Author: Dai Ngo -Date: Thu Jan 30 11:01:27 2025 -0800 - - NFSD: fix hang in nfsd4_shutdown_callback - - If nfs4_client is in courtesy state then there is no point to send - the callback. This causes nfsd4_shutdown_callback to hang since - cl_cb_inflight is not 0. This hang lasts about 15 minutes until TCP - notifies NFSD that the connection was dropped. - - This patch modifies nfsd4_run_cb_work to skip the RPC call if - nfs4_client is in courtesy state. - - Signed-off-by: Dai Ngo - Fixes: 66af25799940 ("NFSD: add courteous server support for thread with only delegation") - Cc: stable@vger.kernel.org - Reviewed-by: Jeff Layton - Signed-off-by: Chuck Lever - -Signed-off-by: Olga Kornievskaia ---- - fs/nfsd/nfs4callback.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c -index 0d7cc2f9a8e07..d8eed853d528d 100644 ---- a/fs/nfsd/nfs4callback.c -+++ b/fs/nfsd/nfs4callback.c -@@ -1480,8 +1480,11 @@ nfsd4_run_cb_work(struct work_struct *work) - nfsd4_process_cb_update(cb); - - clnt = clp->cl_cb_client; -- if (!clnt) { -- /* Callback channel broken, or client killed; give up: */ -+ if (!clnt || clp->cl_state == NFSD4_COURTESY) { -+ /* -+ * Callback channel broken, client killed or -+ * nfs4_client in courtesy state; give up. -+ */ - nfsd41_destroy_cb(cb); - return; - } --- -GitLab -