]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 20 Mar 2026 09:00:05 +0000 (10:00 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 20 Mar 2026 09:00:05 +0000 (10:00 +0100)
added patches:
bluetooth-l2cap-fix-type-confusion-in-l2cap_ecred_reconf_rsp.patch
bluetooth-l2cap-validate-l2cap_info_rsp-payload-length-before-access.patch
net-macb-fix-use-after-free-access-to-ptp-clock.patch
nfc-nxp-nci-allow-gpios-to-sleep.patch
nvdimm-bus-fix-potential-use-after-free-in-asynchronous-initialization.patch
sunrpc-fix-cache_request-leak-in-cache_release.patch

queue-5.15/bluetooth-l2cap-fix-type-confusion-in-l2cap_ecred_reconf_rsp.patch [new file with mode: 0644]
queue-5.15/bluetooth-l2cap-validate-l2cap_info_rsp-payload-length-before-access.patch [new file with mode: 0644]
queue-5.15/net-macb-fix-use-after-free-access-to-ptp-clock.patch [new file with mode: 0644]
queue-5.15/nfc-nxp-nci-allow-gpios-to-sleep.patch [new file with mode: 0644]
queue-5.15/nvdimm-bus-fix-potential-use-after-free-in-asynchronous-initialization.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/sunrpc-fix-cache_request-leak-in-cache_release.patch [new file with mode: 0644]

diff --git a/queue-5.15/bluetooth-l2cap-fix-type-confusion-in-l2cap_ecred_reconf_rsp.patch b/queue-5.15/bluetooth-l2cap-fix-type-confusion-in-l2cap_ecred_reconf_rsp.patch
new file mode 100644 (file)
index 0000000..0943ac7
--- /dev/null
@@ -0,0 +1,59 @@
+From 15145675690cab2de1056e7ed68e59cbd0452529 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Lukas=20Johannes=20M=C3=B6ller?=
+ <research@johannes-moeller.dev>
+Date: Tue, 10 Mar 2026 21:59:46 +0000
+Subject: Bluetooth: L2CAP: Fix type confusion in l2cap_ecred_reconf_rsp()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lukas Johannes Möller <research@johannes-moeller.dev>
+
+commit 15145675690cab2de1056e7ed68e59cbd0452529 upstream.
+
+l2cap_ecred_reconf_rsp() casts the incoming data to struct
+l2cap_ecred_conn_rsp (the ECRED *connection* response, 8 bytes with
+result at offset 6) instead of struct l2cap_ecred_reconf_rsp (2 bytes
+with result at offset 0).
+
+This causes two problems:
+
+ - The sizeof(*rsp) length check requires 8 bytes instead of the
+   correct 2, so valid L2CAP_ECRED_RECONF_RSP packets are rejected
+   with -EPROTO.
+
+ - rsp->result reads from offset 6 instead of offset 0, returning
+   wrong data when the packet is large enough to pass the check.
+
+Fix by using the correct type.  Also pass the already byte-swapped
+result variable to BT_DBG instead of the raw __le16 field.
+
+Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
+Cc: stable@vger.kernel.org
+Signed-off-by: Lukas Johannes Möller <research@johannes-moeller.dev>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/l2cap_core.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/bluetooth/l2cap_core.c
++++ b/net/bluetooth/l2cap_core.c
+@@ -6397,7 +6397,7 @@ static inline int l2cap_ecred_reconf_rsp
+                                        u8 *data)
+ {
+       struct l2cap_chan *chan, *tmp;
+-      struct l2cap_ecred_conn_rsp *rsp = (void *) data;
++      struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
+       u16 result;
+       if (cmd_len < sizeof(*rsp))
+@@ -6405,7 +6405,7 @@ static inline int l2cap_ecred_reconf_rsp
+       result = __le16_to_cpu(rsp->result);
+-      BT_DBG("result 0x%4.4x", rsp->result);
++      BT_DBG("result 0x%4.4x", result);
+       if (!result)
+               return 0;
diff --git a/queue-5.15/bluetooth-l2cap-validate-l2cap_info_rsp-payload-length-before-access.patch b/queue-5.15/bluetooth-l2cap-validate-l2cap_info_rsp-payload-length-before-access.patch
new file mode 100644 (file)
index 0000000..233e1e3
--- /dev/null
@@ -0,0 +1,63 @@
+From dd815e6e3918dc75a49aaabac36e4f024d675101 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Lukas=20Johannes=20M=C3=B6ller?=
+ <research@johannes-moeller.dev>
+Date: Tue, 10 Mar 2026 21:59:47 +0000
+Subject: Bluetooth: L2CAP: Validate L2CAP_INFO_RSP payload length before access
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lukas Johannes Möller <research@johannes-moeller.dev>
+
+commit dd815e6e3918dc75a49aaabac36e4f024d675101 upstream.
+
+l2cap_information_rsp() checks that cmd_len covers the fixed
+l2cap_info_rsp header (type + result, 4 bytes) but then reads
+rsp->data without verifying that the payload is present:
+
+ - L2CAP_IT_FEAT_MASK calls get_unaligned_le32(rsp->data), which reads
+   4 bytes past the header (needs cmd_len >= 8).
+
+ - L2CAP_IT_FIXED_CHAN reads rsp->data[0], 1 byte past the header
+   (needs cmd_len >= 5).
+
+A truncated L2CAP_INFO_RSP with result == L2CAP_IR_SUCCESS triggers an
+out-of-bounds read of adjacent skb data.
+
+Guard each data access with the required payload length check.  If the
+payload is too short, skip the read and let the state machine complete
+with safe defaults (feat_mask and remote_fixed_chan remain zero from
+kzalloc), so the info timer cleanup and l2cap_conn_start() still run
+and the connection is not stalled.
+
+Fixes: 4e8402a3f884 ("[Bluetooth] Retrieve L2CAP features mask on connection setup")
+Cc: stable@vger.kernel.org
+Signed-off-by: Lukas Johannes Möller <research@johannes-moeller.dev>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/l2cap_core.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/net/bluetooth/l2cap_core.c
++++ b/net/bluetooth/l2cap_core.c
+@@ -4837,7 +4837,8 @@ static inline int l2cap_information_rsp(
+       switch (type) {
+       case L2CAP_IT_FEAT_MASK:
+-              conn->feat_mask = get_unaligned_le32(rsp->data);
++              if (cmd_len >= sizeof(*rsp) + sizeof(u32))
++                      conn->feat_mask = get_unaligned_le32(rsp->data);
+               if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
+                       struct l2cap_info_req req;
+@@ -4856,7 +4857,8 @@ static inline int l2cap_information_rsp(
+               break;
+       case L2CAP_IT_FIXED_CHAN:
+-              conn->remote_fixed_chan = rsp->data[0];
++              if (cmd_len >= sizeof(*rsp) + sizeof(rsp->data[0]))
++                      conn->remote_fixed_chan = rsp->data[0];
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+               conn->info_ident = 0;
diff --git a/queue-5.15/net-macb-fix-use-after-free-access-to-ptp-clock.patch b/queue-5.15/net-macb-fix-use-after-free-access-to-ptp-clock.patch
new file mode 100644 (file)
index 0000000..ecda43f
--- /dev/null
@@ -0,0 +1,128 @@
+From 8da13e6d63c1a97f7302d342c89c4a56a55c7015 Mon Sep 17 00:00:00 2001
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+Date: Mon, 16 Mar 2026 13:38:24 +0300
+Subject: net: macb: fix use-after-free access to PTP clock
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+commit 8da13e6d63c1a97f7302d342c89c4a56a55c7015 upstream.
+
+PTP clock is registered on every opening of the interface and destroyed on
+every closing.  However it may be accessed via get_ts_info ethtool call
+which is possible while the interface is just present in the kernel.
+
+BUG: KASAN: use-after-free in ptp_clock_index+0x47/0x50 drivers/ptp/ptp_clock.c:426
+Read of size 4 at addr ffff8880194345cc by task syz.0.6/948
+
+CPU: 1 PID: 948 Comm: syz.0.6 Not tainted 6.1.164+ #109
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:88 [inline]
+ dump_stack_lvl+0x8d/0xba lib/dump_stack.c:106
+ print_address_description mm/kasan/report.c:316 [inline]
+ print_report+0x17f/0x496 mm/kasan/report.c:420
+ kasan_report+0xd9/0x180 mm/kasan/report.c:524
+ ptp_clock_index+0x47/0x50 drivers/ptp/ptp_clock.c:426
+ gem_get_ts_info+0x138/0x1e0 drivers/net/ethernet/cadence/macb_main.c:3349
+ macb_get_ts_info+0x68/0xb0 drivers/net/ethernet/cadence/macb_main.c:3371
+ __ethtool_get_ts_info+0x17c/0x260 net/ethtool/common.c:558
+ ethtool_get_ts_info net/ethtool/ioctl.c:2367 [inline]
+ __dev_ethtool net/ethtool/ioctl.c:3017 [inline]
+ dev_ethtool+0x2b05/0x6290 net/ethtool/ioctl.c:3095
+ dev_ioctl+0x637/0x1070 net/core/dev_ioctl.c:510
+ sock_do_ioctl+0x20d/0x2c0 net/socket.c:1215
+ sock_ioctl+0x577/0x6d0 net/socket.c:1320
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:870 [inline]
+ __se_sys_ioctl fs/ioctl.c:856 [inline]
+ __x64_sys_ioctl+0x18c/0x210 fs/ioctl.c:856
+ do_syscall_x64 arch/x86/entry/common.c:46 [inline]
+ do_syscall_64+0x35/0x80 arch/x86/entry/common.c:76
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 457:
+ kmalloc include/linux/slab.h:563 [inline]
+ kzalloc include/linux/slab.h:699 [inline]
+ ptp_clock_register+0x144/0x10e0 drivers/ptp/ptp_clock.c:235
+ gem_ptp_init+0x46f/0x930 drivers/net/ethernet/cadence/macb_ptp.c:375
+ macb_open+0x901/0xd10 drivers/net/ethernet/cadence/macb_main.c:2920
+ __dev_open+0x2ce/0x500 net/core/dev.c:1501
+ __dev_change_flags+0x56a/0x740 net/core/dev.c:8651
+ dev_change_flags+0x92/0x170 net/core/dev.c:8722
+ do_setlink+0xaf8/0x3a80 net/core/rtnetlink.c:2833
+ __rtnl_newlink+0xbf4/0x1940 net/core/rtnetlink.c:3608
+ rtnl_newlink+0x63/0xa0 net/core/rtnetlink.c:3655
+ rtnetlink_rcv_msg+0x3c6/0xed0 net/core/rtnetlink.c:6150
+ netlink_rcv_skb+0x15d/0x430 net/netlink/af_netlink.c:2511
+ netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
+ netlink_unicast+0x6d7/0xa30 net/netlink/af_netlink.c:1344
+ netlink_sendmsg+0x97e/0xeb0 net/netlink/af_netlink.c:1872
+ sock_sendmsg_nosec net/socket.c:718 [inline]
+ __sock_sendmsg+0x14b/0x180 net/socket.c:730
+ __sys_sendto+0x320/0x3b0 net/socket.c:2152
+ __do_sys_sendto net/socket.c:2164 [inline]
+ __se_sys_sendto net/socket.c:2160 [inline]
+ __x64_sys_sendto+0xdc/0x1b0 net/socket.c:2160
+ do_syscall_x64 arch/x86/entry/common.c:46 [inline]
+ do_syscall_64+0x35/0x80 arch/x86/entry/common.c:76
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 938:
+ kasan_slab_free include/linux/kasan.h:177 [inline]
+ slab_free_hook mm/slub.c:1729 [inline]
+ slab_free_freelist_hook mm/slub.c:1755 [inline]
+ slab_free mm/slub.c:3687 [inline]
+ __kmem_cache_free+0xbc/0x320 mm/slub.c:3700
+ device_release+0xa0/0x240 drivers/base/core.c:2507
+ kobject_cleanup lib/kobject.c:681 [inline]
+ kobject_release lib/kobject.c:712 [inline]
+ kref_put include/linux/kref.h:65 [inline]
+ kobject_put+0x1cd/0x350 lib/kobject.c:729
+ put_device+0x1b/0x30 drivers/base/core.c:3805
+ ptp_clock_unregister+0x171/0x270 drivers/ptp/ptp_clock.c:391
+ gem_ptp_remove+0x4e/0x1f0 drivers/net/ethernet/cadence/macb_ptp.c:404
+ macb_close+0x1c8/0x270 drivers/net/ethernet/cadence/macb_main.c:2966
+ __dev_close_many+0x1b9/0x310 net/core/dev.c:1585
+ __dev_close net/core/dev.c:1597 [inline]
+ __dev_change_flags+0x2bb/0x740 net/core/dev.c:8649
+ dev_change_flags+0x92/0x170 net/core/dev.c:8722
+ dev_ifsioc+0x151/0xe00 net/core/dev_ioctl.c:326
+ dev_ioctl+0x33e/0x1070 net/core/dev_ioctl.c:572
+ sock_do_ioctl+0x20d/0x2c0 net/socket.c:1215
+ sock_ioctl+0x577/0x6d0 net/socket.c:1320
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:870 [inline]
+ __se_sys_ioctl fs/ioctl.c:856 [inline]
+ __x64_sys_ioctl+0x18c/0x210 fs/ioctl.c:856
+ do_syscall_x64 arch/x86/entry/common.c:46 [inline]
+ do_syscall_64+0x35/0x80 arch/x86/entry/common.c:76
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Set the PTP clock pointer to NULL after unregistering.
+
+Fixes: c2594d804d5c ("macb: Common code to enable ptp support for MACB/GEM")
+Cc: stable@vger.kernel.org
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260316103826.74506-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/cadence/macb_ptp.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/cadence/macb_ptp.c
++++ b/drivers/net/ethernet/cadence/macb_ptp.c
+@@ -395,8 +395,10 @@ void gem_ptp_remove(struct net_device *n
+ {
+       struct macb *bp = netdev_priv(ndev);
+-      if (bp->ptp_clock)
++      if (bp->ptp_clock) {
+               ptp_clock_unregister(bp->ptp_clock);
++              bp->ptp_clock = NULL;
++      }
+       gem_ptp_clear_timer(bp);
diff --git a/queue-5.15/nfc-nxp-nci-allow-gpios-to-sleep.patch b/queue-5.15/nfc-nxp-nci-allow-gpios-to-sleep.patch
new file mode 100644 (file)
index 0000000..a129ecc
--- /dev/null
@@ -0,0 +1,41 @@
+From 55dc632ab2ac2889b15995a9eef56c753d48ebc7 Mon Sep 17 00:00:00 2001
+From: Ian Ray <ian.ray@gehealthcare.com>
+Date: Tue, 17 Mar 2026 10:53:36 +0200
+Subject: NFC: nxp-nci: allow GPIOs to sleep
+
+From: Ian Ray <ian.ray@gehealthcare.com>
+
+commit 55dc632ab2ac2889b15995a9eef56c753d48ebc7 upstream.
+
+Allow the firmware and enable GPIOs to sleep.
+
+This fixes a `WARN_ON' and allows the driver to operate GPIOs which are
+connected to I2C GPIO expanders.
+
+-- >8 --
+kernel: WARNING: CPU: 3 PID: 2636 at drivers/gpio/gpiolib.c:3880 gpiod_set_value+0x88/0x98
+-- >8 --
+
+Fixes: 43201767b44c ("NFC: nxp-nci: Convert to use GPIO descriptor")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ian Ray <ian.ray@gehealthcare.com>
+Link: https://patch.msgid.link/20260317085337.146545-1-ian.ray@gehealthcare.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nfc/nxp-nci/i2c.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/nfc/nxp-nci/i2c.c
++++ b/drivers/nfc/nxp-nci/i2c.c
+@@ -47,8 +47,8 @@ static int nxp_nci_i2c_set_mode(void *ph
+ {
+       struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
+-      gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
+-      gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
++      gpiod_set_value_cansleep(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
++      gpiod_set_value_cansleep(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
+       usleep_range(10000, 15000);
+       if (mode == NXP_NCI_MODE_COLD)
diff --git a/queue-5.15/nvdimm-bus-fix-potential-use-after-free-in-asynchronous-initialization.patch b/queue-5.15/nvdimm-bus-fix-potential-use-after-free-in-asynchronous-initialization.patch
new file mode 100644 (file)
index 0000000..dccd074
--- /dev/null
@@ -0,0 +1,55 @@
+From a8aec14230322ed8f1e8042b6d656c1631d41163 Mon Sep 17 00:00:00 2001
+From: Ira Weiny <ira.weiny@intel.com>
+Date: Fri, 6 Mar 2026 12:33:05 -0600
+Subject: nvdimm/bus: Fix potential use after free in asynchronous initialization
+
+From: Ira Weiny <ira.weiny@intel.com>
+
+commit a8aec14230322ed8f1e8042b6d656c1631d41163 upstream.
+
+Dingisoul with KASAN reports a use after free if device_add() fails in
+nd_async_device_register().
+
+Commit b6eae0f61db2 ("libnvdimm: Hold reference on parent while
+scheduling async init") correctly added a reference on the parent device
+to be held until asynchronous initialization was complete.  However, if
+device_add() results in an allocation failure the ref count of the
+device drops to 0 prior to the parent pointer being accessed.  Thus
+resulting in use after free.
+
+The bug bot AI correctly identified the fix.  Save a reference to the
+parent pointer to be used to drop the parent reference regardless of the
+outcome of device_add().
+
+Reported-by: Dingisoul <dingiso.kernel@gmail.com>
+Closes: http://lore.kernel.org/8855544b-be9e-4153-aa55-0bc328b13733@gmail.com
+Fixes: b6eae0f61db2 ("libnvdimm: Hold reference on parent while scheduling async init")
+Cc: stable@vger.kernel.org
+Reviewed-by: Dave Jiang <dave.jiang@intel.com>
+Link: https://patch.msgid.link/20260306-fix-uaf-async-init-v1-1-a28fd7526723@intel.com
+Signed-off-by: Ira Weiny <ira.weiny@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvdimm/bus.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvdimm/bus.c
++++ b/drivers/nvdimm/bus.c
+@@ -492,14 +492,15 @@ EXPORT_SYMBOL_GPL(nd_synchronize);
+ static void nd_async_device_register(void *d, async_cookie_t cookie)
+ {
+       struct device *dev = d;
++      struct device *parent = dev->parent;
+       if (device_add(dev) != 0) {
+               dev_err(dev, "%s: failed\n", __func__);
+               put_device(dev);
+       }
+       put_device(dev);
+-      if (dev->parent)
+-              put_device(dev->parent);
++      if (parent)
++              put_device(parent);
+ }
+ static void nd_async_device_unregister(void *d, async_cookie_t cookie)
index dadc340770f97a7b9b6f65cb167d2eb805fb6753..5ad824cfe398ea93cad12c3ea4fc2abde11ff11d 100644 (file)
@@ -194,3 +194,9 @@ bpf-forget-ranges-when-refining-tnum-after-jset.patch
 l2tp-do-not-use-sock_hold-in-pppol2tp_session_get_sock.patch
 io_uring-io-wq-check-io_wq_bit_exit-inside-work-run-loop.patch
 driver-iio-add-missing-checks-on-iio_info-s-callback-access.patch
+sunrpc-fix-cache_request-leak-in-cache_release.patch
+nvdimm-bus-fix-potential-use-after-free-in-asynchronous-initialization.patch
+nfc-nxp-nci-allow-gpios-to-sleep.patch
+net-macb-fix-use-after-free-access-to-ptp-clock.patch
+bluetooth-l2cap-fix-type-confusion-in-l2cap_ecred_reconf_rsp.patch
+bluetooth-l2cap-validate-l2cap_info_rsp-payload-length-before-access.patch
diff --git a/queue-5.15/sunrpc-fix-cache_request-leak-in-cache_release.patch b/queue-5.15/sunrpc-fix-cache_request-leak-in-cache_release.patch
new file mode 100644 (file)
index 0000000..c5006d4
--- /dev/null
@@ -0,0 +1,86 @@
+From 17ad31b3a43b72aec3a3d83605891e1397d0d065 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Mon, 23 Feb 2026 12:09:58 -0500
+Subject: sunrpc: fix cache_request leak in cache_release
+
+From: Jeff Layton <jlayton@kernel.org>
+
+commit 17ad31b3a43b72aec3a3d83605891e1397d0d065 upstream.
+
+When a reader's file descriptor is closed while in the middle of reading
+a cache_request (rp->offset != 0), cache_release() decrements the
+request's readers count but never checks whether it should free the
+request.
+
+In cache_read(), when readers drops to 0 and CACHE_PENDING is clear, the
+cache_request is removed from the queue and freed along with its buffer
+and cache_head reference. cache_release() lacks this cleanup.
+
+The only other path that frees requests with readers == 0 is
+cache_dequeue(), but it runs only when CACHE_PENDING transitions from
+set to clear. If that transition already happened while readers was
+still non-zero, cache_dequeue() will have skipped the request, and no
+subsequent call will clean it up.
+
+Add the same cleanup logic from cache_read() to cache_release(): after
+decrementing readers, check if it reached 0 with CACHE_PENDING clear,
+and if so, dequeue and free the cache_request.
+
+Reported-by: NeilBrown <neilb@ownmail.net>
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@kernel.org
+Signed-off-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/cache.c |   26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+--- a/net/sunrpc/cache.c
++++ b/net/sunrpc/cache.c
+@@ -1037,14 +1037,25 @@ static int cache_release(struct inode *i
+       struct cache_reader *rp = filp->private_data;
+       if (rp) {
++              struct cache_request *rq = NULL;
++
+               spin_lock(&queue_lock);
+               if (rp->offset) {
+                       struct cache_queue *cq;
+-                      for (cq= &rp->q; &cq->list != &cd->queue;
+-                           cq = list_entry(cq->list.next, struct cache_queue, list))
++                      for (cq = &rp->q; &cq->list != &cd->queue;
++                           cq = list_entry(cq->list.next,
++                                           struct cache_queue, list))
+                               if (!cq->reader) {
+-                                      container_of(cq, struct cache_request, q)
+-                                              ->readers--;
++                                      struct cache_request *cr =
++                                              container_of(cq,
++                                              struct cache_request, q);
++                                      cr->readers--;
++                                      if (cr->readers == 0 &&
++                                          !test_bit(CACHE_PENDING,
++                                                    &cr->item->flags)) {
++                                              list_del(&cr->q.list);
++                                              rq = cr;
++                                      }
+                                       break;
+                               }
+                       rp->offset = 0;
+@@ -1052,9 +1063,14 @@ static int cache_release(struct inode *i
+               list_del(&rp->q.list);
+               spin_unlock(&queue_lock);
++              if (rq) {
++                      cache_put(rq->item, cd);
++                      kfree(rq->buf);
++                      kfree(rq);
++              }
++
+               filp->private_data = NULL;
+               kfree(rp);
+-
+       }
+       if (filp->f_mode & FMODE_WRITE) {
+               atomic_dec(&cd->writers);