]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Feb 2026 21:52:18 +0000 (13:52 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Feb 2026 21:52:18 +0000 (13:52 -0800)
added patches:
ata-pata_ftide010-fix-some-dma-timings.patch
ext4-don-t-cache-extent-during-splitting-extent.patch
ext4-fix-memory-leak-in-ext4_ext_shift_extents.patch
mips-work-around-llvm-bug-when-gp-is-used-as-global-register-variable.patch
sunrpc-auth_gss-fix-memory-leaks-in-xdr-decoding-error-paths.patch
sunrpc-fix-gss_auth-kref-leak-in-gss_alloc_msg-error-path.patch

queue-5.10/ata-pata_ftide010-fix-some-dma-timings.patch [new file with mode: 0644]
queue-5.10/ext4-don-t-cache-extent-during-splitting-extent.patch [new file with mode: 0644]
queue-5.10/ext4-fix-memory-leak-in-ext4_ext_shift_extents.patch [new file with mode: 0644]
queue-5.10/mips-work-around-llvm-bug-when-gp-is-used-as-global-register-variable.patch [new file with mode: 0644]
queue-5.10/series
queue-5.10/sunrpc-auth_gss-fix-memory-leaks-in-xdr-decoding-error-paths.patch [new file with mode: 0644]
queue-5.10/sunrpc-fix-gss_auth-kref-leak-in-gss_alloc_msg-error-path.patch [new file with mode: 0644]

diff --git a/queue-5.10/ata-pata_ftide010-fix-some-dma-timings.patch b/queue-5.10/ata-pata_ftide010-fix-some-dma-timings.patch
new file mode 100644 (file)
index 0000000..0d282bb
--- /dev/null
@@ -0,0 +1,39 @@
+From ff4a46c278ac6a4b3f39be1492a4568b6dcc6105 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linusw@kernel.org>
+Date: Tue, 3 Feb 2026 11:23:01 +0100
+Subject: ata: pata_ftide010: Fix some DMA timings
+
+From: Linus Walleij <linusw@kernel.org>
+
+commit ff4a46c278ac6a4b3f39be1492a4568b6dcc6105 upstream.
+
+The FTIDE010 has been missing some timing settings since its
+inception, since the upstream OpenWrt patch was missing these.
+
+The community has since come up with the appropriate timings.
+
+Fixes: be4e456ed3a5 ("ata: Add driver for Faraday Technology FTIDE010")
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Walleij <linusw@kernel.org>
+Signed-off-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/pata_ftide010.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/ata/pata_ftide010.c
++++ b/drivers/ata/pata_ftide010.c
+@@ -123,10 +123,10 @@ static const u8 mwdma_50_active_time[3]
+ static const u8 mwdma_50_recovery_time[3] = {6, 2, 1};
+ static const u8 mwdma_66_active_time[3] = {8, 3, 3};
+ static const u8 mwdma_66_recovery_time[3] = {8, 2, 1};
+-static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 1};
++static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 9};
+ static const u8 udma_50_hold_time[6] = {3, 1, 1, 1, 1, 1};
+-static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, };
+-static const u8 udma_66_hold_time[7] = {};
++static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, 1, 9, 9};
++static const u8 udma_66_hold_time[7] = {4, 2, 1, 1, 1, 1, 1};
+ /*
+  * We set 66 MHz for all MWDMA modes
diff --git a/queue-5.10/ext4-don-t-cache-extent-during-splitting-extent.patch b/queue-5.10/ext4-don-t-cache-extent-during-splitting-extent.patch
new file mode 100644 (file)
index 0000000..ebd042b
--- /dev/null
@@ -0,0 +1,74 @@
+From 8b4b19a2f96348d70bfa306ef7d4a13b0bcbea79 Mon Sep 17 00:00:00 2001
+From: Zhang Yi <yi.zhang@huawei.com>
+Date: Sat, 29 Nov 2025 18:32:37 +0800
+Subject: ext4: don't cache extent during splitting extent
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+commit 8b4b19a2f96348d70bfa306ef7d4a13b0bcbea79 upstream.
+
+Caching extents during the splitting process is risky, as it may result
+in stale extents remaining in the status tree. Moreover, in most cases,
+the corresponding extent block entries are likely already cached before
+the split happens, making caching here not particularly useful.
+
+Assume we have an unwritten extent, and then DIO writes the first half.
+
+  [UUUUUUUUUUUUUUUU] on-disk extent        U: unwritten extent
+  [UUUUUUUUUUUUUUUU] extent status tree
+  |<-   ->| ----> dio write this range
+
+First, when ext4_split_extent_at() splits this extent, it truncates the
+existing extent and then inserts a new one. During this process, this
+extent status entry may be shrunk, and calls to ext4_find_extent() and
+ext4_cache_extents() may occur, which could potentially insert the
+truncated range as a hole into the extent status tree. After the split
+is completed, this hole is not replaced with the correct status.
+
+  [UUUUUUU|UUUUUUUU] on-disk extent        U: unwritten extent
+  [UUUUUUU|HHHHHHHH] extent status tree    H: hole
+
+Then, the outer calling functions will not correct this remaining hole
+extent either. Finally, if we perform a delayed buffer write on this
+latter part, it will re-insert the delayed extent and cause an error in
+space accounting.
+
+In adition, if the unwritten extent cache is not shrunk during the
+splitting, ext4_cache_extents() also conflicts with existing extents
+when caching extents. In the future, we will add checks when caching
+extents, which will trigger a warning. Therefore, Do not cache extents
+that are being split.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Reviewed-by: Baokun Li <libaokun1@huawei.com>
+Cc: stable@kernel.org
+Message-ID: <20251129103247.686136-6-yi.zhang@huaweicloud.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/extents.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -3168,6 +3168,9 @@ static int ext4_split_extent_at(handle_t
+       BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) ==
+              (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2));
++      /* Do not cache extents that are in the process of being modified. */
++      flags |= EXT4_EX_NOCACHE;
++
+       ext_debug(inode, "logical block %llu\n", (unsigned long long)split);
+       ext4_ext_show_leaf(inode, path);
+@@ -3338,6 +3341,9 @@ static int ext4_split_extent(handle_t *h
+       ee_len = ext4_ext_get_actual_len(ex);
+       unwritten = ext4_ext_is_unwritten(ex);
++      /* Do not cache extents that are in the process of being modified. */
++      flags |= EXT4_EX_NOCACHE;
++
+       if (map->m_lblk + map->m_len < ee_block + ee_len) {
+               split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
+               flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;
diff --git a/queue-5.10/ext4-fix-memory-leak-in-ext4_ext_shift_extents.patch b/queue-5.10/ext4-fix-memory-leak-in-ext4_ext_shift_extents.patch
new file mode 100644 (file)
index 0000000..b8b9239
--- /dev/null
@@ -0,0 +1,40 @@
+From ca81109d4a8f192dc1cbad4a1ee25246363c2833 Mon Sep 17 00:00:00 2001
+From: Zilin Guan <zilin@seu.edu.cn>
+Date: Thu, 25 Dec 2025 08:48:00 +0000
+Subject: ext4: fix memory leak in ext4_ext_shift_extents()
+
+From: Zilin Guan <zilin@seu.edu.cn>
+
+commit ca81109d4a8f192dc1cbad4a1ee25246363c2833 upstream.
+
+In ext4_ext_shift_extents(), if the extent is NULL in the while loop, the
+function returns immediately without releasing the path obtained via
+ext4_find_extent(), leading to a memory leak.
+
+Fix this by jumping to the out label to ensure the path is properly
+released.
+
+Fixes: a18ed359bdddc ("ext4: always check ext4_ext_find_extent result")
+Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
+Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Baokun Li <libaokun1@huawei.com>
+Link: https://patch.msgid.link/20251225084800.905701-1-zilin@seu.edu.cn
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/extents.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -5261,7 +5261,8 @@ again:
+               if (!extent) {
+                       EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
+                                        (unsigned long) *iterator);
+-                      return -EFSCORRUPTED;
++                      ret = -EFSCORRUPTED;
++                      goto out;
+               }
+               if (SHIFT == SHIFT_LEFT && *iterator >
+                   le32_to_cpu(extent->ee_block)) {
diff --git a/queue-5.10/mips-work-around-llvm-bug-when-gp-is-used-as-global-register-variable.patch b/queue-5.10/mips-work-around-llvm-bug-when-gp-is-used-as-global-register-variable.patch
new file mode 100644 (file)
index 0000000..ea2d130
--- /dev/null
@@ -0,0 +1,98 @@
+From 30bfc2d6a1132a89a5f1c3b96c59cf3e4d076ea3 Mon Sep 17 00:00:00 2001
+From: Yao Zi <me@ziyao.cc>
+Date: Thu, 5 Feb 2026 15:56:44 +0000
+Subject: MIPS: Work around LLVM bug when gp is used as global register variable
+
+From: Yao Zi <me@ziyao.cc>
+
+commit 30bfc2d6a1132a89a5f1c3b96c59cf3e4d076ea3 upstream.
+
+On MIPS, __current_thread_info is defined as global register variable
+locating in $gp, and is simply assigned with new address during kernel
+relocation.
+
+This however is broken with LLVM, which always restores $gp if it finds
+$gp is clobbered in any form, including when intentionally through a
+global register variable. This is against GCC's documentation[1], which
+requires a callee-saved register used as global register variable not to
+be restored if it's clobbered.
+
+As a result, $gp will continue to point to the unrelocated kernel after
+the epilog of relocate_kernel(), leading to an early crash in init_idle,
+
+[    0.000000] CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff81afada8, ra == ffffffff81afad90
+[    0.000000] Oops[#1]:
+[    0.000000] CPU: 0 UID: 0 PID: 0 Comm: swapper Tainted: G        W           6.19.0-rc5-00262-gd3eeb99bbc99-dirty #188 VOLUNTARY
+[    0.000000] Tainted: [W]=WARN
+[    0.000000] Hardware name: loongson,loongson64v-4core-virtio
+[    0.000000] $ 0   : 0000000000000000 0000000000000000 0000000000000001 0000000000000000
+[    0.000000] $ 4   : ffffffff80b80ec0 ffffffff80b53d48 0000000000000000 00000000000f4240
+[    0.000000] $ 8   : 0000000000000100 ffffffff81d82f80 ffffffff81d82f80 0000000000000001
+[    0.000000] $12   : 0000000000000000 ffffffff81776f58 00000000000005da 0000000000000002
+[    0.000000] $16   : ffffffff80b80e40 0000000000000000 ffffffff80b81614 9800000005dfbe80
+[    0.000000] $20   : 00000000540000e0 ffffffff81980000 0000000000000000 ffffffff80f81c80
+[    0.000000] $24   : 0000000000000a26 ffffffff8114fb90
+[    0.000000] $28   : ffffffff80b50000 ffffffff80b53d40 0000000000000000 ffffffff81afad90
+[    0.000000] Hi    : 0000000000000000
+[    0.000000] Lo    : 0000000000000000
+[    0.000000] epc   : ffffffff81afada8 init_idle+0x130/0x270
+[    0.000000] ra    : ffffffff81afad90 init_idle+0x118/0x270
+[    0.000000] Status: 540000e2        KX SX UX KERNEL EXL
+[    0.000000] Cause : 00000008 (ExcCode 02)
+[    0.000000] BadVA : 0000000000000000
+[    0.000000] PrId  : 00006305 (ICT Loongson-3)
+[    0.000000] Process swapper (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
+[    0.000000] Stack : 9800000005dfbf00 ffffffff8178e950 0000000000000000 0000000000000000
+[    0.000000]         0000000000000000 ffffffff81970000 000000000000003f ffffffff810a6528
+[    0.000000]         0000000000000001 9800000005dfbe80 9800000005dfbf00 ffffffff81980000
+[    0.000000]         ffffffff810a6450 ffffffff81afb6c0 0000000000000000 ffffffff810a2258
+[    0.000000]         ffffffff81d82ec8 ffffffff8198d010 ffffffff81b67e80 ffffffff8197dd98
+[    0.000000]         ffffffff81d81c80 ffffffff81930000 0000000000000040 0000000000000000
+[    0.000000]         0000000000000000 0000000000000000 0000000000000000 0000000000000000
+[    0.000000]         0000000000000000 000000000000009e ffffffff9fc01000 0000000000000000
+[    0.000000]         0000000000000000 0000000000000000 0000000000000000 0000000000000000
+[    0.000000]         0000000000000000 ffffffff81ae86dc ffffffff81b3c741 0000000000000002
+[    0.000000]         ...
+[    0.000000] Call Trace:
+[    0.000000] [<ffffffff81afada8>] init_idle+0x130/0x270
+[    0.000000] [<ffffffff81afb6c0>] sched_init+0x5c8/0x6c0
+[    0.000000] [<ffffffff81ae86dc>] start_kernel+0x27c/0x7a8
+
+This bug has been reported to LLVM[2] and affects version from (at
+least) 18 to 21. Let's work around this by using inline assembly to
+assign $gp before a fix is widely available.
+
+Cc: stable@vger.kernel.org
+Link: https://gcc.gnu.org/onlinedocs/gcc-15.2.0/gcc/Global-Register-Variables.html # [1]
+Link: https://github.com/llvm/llvm-project/issues/176546 # [2]
+Signed-off-by: Yao Zi <me@ziyao.cc>
+Acked-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/mips/kernel/relocate.c |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/arch/mips/kernel/relocate.c
++++ b/arch/mips/kernel/relocate.c
+@@ -399,7 +399,20 @@ void *__init relocate_kernel(void)
+                       goto out;
+               /* The current thread is now within the relocated image */
++#ifndef CONFIG_CC_IS_CLANG
+               __current_thread_info = RELOCATED(&init_thread_union);
++#else
++              /*
++               * LLVM may wrongly restore $gp ($28) in epilog even if it's
++               * intentionally modified. Work around this by using inline
++               * assembly to assign $gp. $gp couldn't be listed as output or
++               * clobber, or LLVM will still restore its original value.
++               * See also LLVM upstream issue
++               * https://github.com/llvm/llvm-project/issues/176546
++               */
++              asm volatile("move $28, %0" : :
++                           "r" (RELOCATED(&init_thread_union)));
++#endif
+               /* Return the new kernel's entry point */
+               kernel_entry = RELOCATED(start_kernel);
index f7424854d0352ab12346f42f9ba435cb470a7adf..1d9c73b69d5fd7301569920cc088db2aa628525c 100644 (file)
@@ -153,3 +153,9 @@ apparmor-fix-rlimit-for-posix-cpu-timers.patch
 apparmor-fix-invalid-deref-of-rawdata-when-export_bi.patch
 drm-i915-acpi-free-_dsm-package-when-no-connectors.patch
 btrfs-fix-invalid-leaf-access-in-btrfs_quota_enable-.patch
+mips-work-around-llvm-bug-when-gp-is-used-as-global-register-variable.patch
+ext4-don-t-cache-extent-during-splitting-extent.patch
+ext4-fix-memory-leak-in-ext4_ext_shift_extents.patch
+ata-pata_ftide010-fix-some-dma-timings.patch
+sunrpc-auth_gss-fix-memory-leaks-in-xdr-decoding-error-paths.patch
+sunrpc-fix-gss_auth-kref-leak-in-gss_alloc_msg-error-path.patch
diff --git a/queue-5.10/sunrpc-auth_gss-fix-memory-leaks-in-xdr-decoding-error-paths.patch b/queue-5.10/sunrpc-auth_gss-fix-memory-leaks-in-xdr-decoding-error-paths.patch
new file mode 100644 (file)
index 0000000..1758317
--- /dev/null
@@ -0,0 +1,222 @@
+From 3e6397b056335cc56ef0e9da36c95946a19f5118 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 26 Dec 2025 10:15:32 -0500
+Subject: SUNRPC: auth_gss: fix memory leaks in XDR decoding error paths
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+commit 3e6397b056335cc56ef0e9da36c95946a19f5118 upstream.
+
+The gssx_dec_ctx(), gssx_dec_status(), and gssx_dec_name()
+functions allocate memory via gssx_dec_buffer(), which calls
+kmemdup(). When a subsequent decode operation fails, these
+functions return immediately without freeing previously
+allocated buffers, causing memory leaks.
+
+The leak in gssx_dec_ctx() is particularly relevant because
+the caller (gssp_accept_sec_context_upcall) initializes several
+buffer length fields to non-zero values, resulting in memory
+allocation:
+
+    struct gssx_ctx rctxh = {
+        .exported_context_token.len = GSSX_max_output_handle_sz,
+        .mech.len = GSS_OID_MAX_LEN,
+        .src_name.display_name.len = GSSX_max_princ_sz,
+        .targ_name.display_name.len = GSSX_max_princ_sz
+    };
+
+If, for example, gssx_dec_name() succeeds for src_name but
+fails for targ_name, the memory allocated for
+exported_context_token, mech, and src_name.display_name
+remains unreferenced and cannot be reclaimed.
+
+Add error handling with goto-based cleanup to free any
+previously allocated buffers before returning an error.
+
+Reported-by: Xingjing Deng <micro6947@gmail.com>
+Closes: https://lore.kernel.org/linux-nfs/CAK+ZN9qttsFDu6h1FoqGadXjMx1QXqPMoYQ=6O9RY4SxVTvKng@mail.gmail.com/
+Fixes: 1d658336b05f ("SUNRPC: Add RPC based upcall mechanism for RPCGSS auth")
+Cc: stable@vger.kernel.org
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sunrpc/auth_gss/gss_rpc_xdr.c |   82 +++++++++++++++++++++++++++++---------
+ 1 file changed, 64 insertions(+), 18 deletions(-)
+
+--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
+@@ -320,29 +320,47 @@ static int gssx_dec_status(struct xdr_st
+       /* status->minor_status */
+       p = xdr_inline_decode(xdr, 8);
+-      if (unlikely(p == NULL))
+-              return -ENOSPC;
++      if (unlikely(p == NULL)) {
++              err = -ENOSPC;
++              goto out_free_mech;
++      }
+       p = xdr_decode_hyper(p, &status->minor_status);
+       /* status->major_status_string */
+       err = gssx_dec_buffer(xdr, &status->major_status_string);
+       if (err)
+-              return err;
++              goto out_free_mech;
+       /* status->minor_status_string */
+       err = gssx_dec_buffer(xdr, &status->minor_status_string);
+       if (err)
+-              return err;
++              goto out_free_major_status_string;
+       /* status->server_ctx */
+       err = gssx_dec_buffer(xdr, &status->server_ctx);
+       if (err)
+-              return err;
++              goto out_free_minor_status_string;
+       /* we assume we have no options for now, so simply consume them */
+       /* status->options */
+       err = dummy_dec_opt_array(xdr, &status->options);
++      if (err)
++              goto out_free_server_ctx;
++      return 0;
++
++out_free_server_ctx:
++      kfree(status->server_ctx.data);
++      status->server_ctx.data = NULL;
++out_free_minor_status_string:
++      kfree(status->minor_status_string.data);
++      status->minor_status_string.data = NULL;
++out_free_major_status_string:
++      kfree(status->major_status_string.data);
++      status->major_status_string.data = NULL;
++out_free_mech:
++      kfree(status->mech.data);
++      status->mech.data = NULL;
+       return err;
+ }
+@@ -505,28 +523,35 @@ static int gssx_dec_name(struct xdr_stre
+       /* name->name_type */
+       err = gssx_dec_buffer(xdr, &dummy_netobj);
+       if (err)
+-              return err;
++              goto out_free_display_name;
+       /* name->exported_name */
+       err = gssx_dec_buffer(xdr, &dummy_netobj);
+       if (err)
+-              return err;
++              goto out_free_display_name;
+       /* name->exported_composite_name */
+       err = gssx_dec_buffer(xdr, &dummy_netobj);
+       if (err)
+-              return err;
++              goto out_free_display_name;
+       /* we assume we have no attributes for now, so simply consume them */
+       /* name->name_attributes */
+       err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
+       if (err)
+-              return err;
++              goto out_free_display_name;
+       /* we assume we have no options for now, so simply consume them */
+       /* name->extensions */
+       err = dummy_dec_opt_array(xdr, &dummy_option_array);
++      if (err)
++              goto out_free_display_name;
++      return 0;
++
++out_free_display_name:
++      kfree(name->display_name.data);
++      name->display_name.data = NULL;
+       return err;
+ }
+@@ -649,32 +674,34 @@ static int gssx_dec_ctx(struct xdr_strea
+       /* ctx->state */
+       err = gssx_dec_buffer(xdr, &ctx->state);
+       if (err)
+-              return err;
++              goto out_free_exported_context_token;
+       /* ctx->need_release */
+       err = gssx_dec_bool(xdr, &ctx->need_release);
+       if (err)
+-              return err;
++              goto out_free_state;
+       /* ctx->mech */
+       err = gssx_dec_buffer(xdr, &ctx->mech);
+       if (err)
+-              return err;
++              goto out_free_state;
+       /* ctx->src_name */
+       err = gssx_dec_name(xdr, &ctx->src_name);
+       if (err)
+-              return err;
++              goto out_free_mech;
+       /* ctx->targ_name */
+       err = gssx_dec_name(xdr, &ctx->targ_name);
+       if (err)
+-              return err;
++              goto out_free_src_name;
+       /* ctx->lifetime */
+       p = xdr_inline_decode(xdr, 8+8);
+-      if (unlikely(p == NULL))
+-              return -ENOSPC;
++      if (unlikely(p == NULL)) {
++              err = -ENOSPC;
++              goto out_free_targ_name;
++      }
+       p = xdr_decode_hyper(p, &ctx->lifetime);
+       /* ctx->ctx_flags */
+@@ -683,17 +710,36 @@ static int gssx_dec_ctx(struct xdr_strea
+       /* ctx->locally_initiated */
+       err = gssx_dec_bool(xdr, &ctx->locally_initiated);
+       if (err)
+-              return err;
++              goto out_free_targ_name;
+       /* ctx->open */
+       err = gssx_dec_bool(xdr, &ctx->open);
+       if (err)
+-              return err;
++              goto out_free_targ_name;
+       /* we assume we have no options for now, so simply consume them */
+       /* ctx->options */
+       err = dummy_dec_opt_array(xdr, &ctx->options);
++      if (err)
++              goto out_free_targ_name;
++
++      return 0;
++out_free_targ_name:
++      kfree(ctx->targ_name.display_name.data);
++      ctx->targ_name.display_name.data = NULL;
++out_free_src_name:
++      kfree(ctx->src_name.display_name.data);
++      ctx->src_name.display_name.data = NULL;
++out_free_mech:
++      kfree(ctx->mech.data);
++      ctx->mech.data = NULL;
++out_free_state:
++      kfree(ctx->state.data);
++      ctx->state.data = NULL;
++out_free_exported_context_token:
++      kfree(ctx->exported_context_token.data);
++      ctx->exported_context_token.data = NULL;
+       return err;
+ }
diff --git a/queue-5.10/sunrpc-fix-gss_auth-kref-leak-in-gss_alloc_msg-error-path.patch b/queue-5.10/sunrpc-fix-gss_auth-kref-leak-in-gss_alloc_msg-error-path.patch
new file mode 100644 (file)
index 0000000..1d1a911
--- /dev/null
@@ -0,0 +1,51 @@
+From dd2fdc3504592d85e549c523b054898a036a6afe Mon Sep 17 00:00:00 2001
+From: Daniel Hodges <git@danielhodges.dev>
+Date: Fri, 6 Feb 2026 15:41:46 -0500
+Subject: SUNRPC: fix gss_auth kref leak in gss_alloc_msg error path
+
+From: Daniel Hodges <git@danielhodges.dev>
+
+commit dd2fdc3504592d85e549c523b054898a036a6afe upstream.
+
+Commit 5940d1cf9f42 ("SUNRPC: Rebalance a kref in auth_gss.c") added
+a kref_get(&gss_auth->kref) call to balance the gss_put_auth() done
+in gss_release_msg(), but forgot to add a corresponding kref_put()
+on the error path when kstrdup_const() fails.
+
+If service_name is non-NULL and kstrdup_const() fails, the function
+jumps to err_put_pipe_version which calls put_pipe_version() and
+kfree(gss_msg), but never releases the gss_auth reference. This leads
+to a kref leak where the gss_auth structure is never freed.
+
+Add a forward declaration for gss_free_callback() and call kref_put()
+in the err_put_pipe_version error path to properly release the
+reference taken earlier.
+
+Fixes: 5940d1cf9f42 ("SUNRPC: Rebalance a kref in auth_gss.c")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Hodges <git@danielhodges.dev>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sunrpc/auth_gss/auth_gss.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/sunrpc/auth_gss/auth_gss.c
++++ b/net/sunrpc/auth_gss/auth_gss.c
+@@ -39,6 +39,8 @@ static const struct rpc_authops authgss_
+ static const struct rpc_credops gss_credops;
+ static const struct rpc_credops gss_nullops;
++static void gss_free_callback(struct kref *kref);
++
+ #define GSS_RETRY_EXPIRED 5
+ static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
+@@ -534,6 +536,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
+       }
+       return gss_msg;
+ err_put_pipe_version:
++      kref_put(&gss_auth->kref, gss_free_callback);
+       put_pipe_version(gss_auth->net);
+ err_free_msg:
+       kfree(gss_msg);