--- /dev/null
+From stable+bounces-265000-greg=kroah.com@vger.kernel.org Tue Jun 16 18:01:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Jun 2026 12:56:09 -0400
+Subject: Drivers: hv: vmbus: Improve the logic of reserving fb_mmio on Gen2 VMs
+To: stable@vger.kernel.org
+Cc: Dexuan Cui <decui@microsoft.com>, Michael Kelley <mhklinux@outlook.com>, Krister Johansen <kjlx@templeofstupid.com>, Matthew Ruffell <matthew.ruffell@canonical.com>, Wei Liu <wei.liu@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616165609.3366925-1-sashal@kernel.org>
+
+From: Dexuan Cui <decui@microsoft.com>
+
+[ Upstream commit 016a25e4b0df4d77e7c258edee4aaf982e4ee809 ]
+
+If vmbus_reserve_fb() in the kdump/kexec kernel fails to properly reserve
+the framebuffer MMIO range (which is below 4GB) due to a Gen2 VM's
+screen.lfb_base being zero [1], there is an MMIO conflict between the
+drivers hyperv-drm and pci-hyperv: when the driver pci-hyperv's
+hv_allocate_config_window() calls vmbus_allocate_mmio() to get an
+MMIO range, typically it gets a 32-bit MMIO range that overlaps with the
+framebuffer MMIO range, and later hv_pci_enter_d0() fails with an
+error message "PCI Pass-through VSP failed D0 Entry with status" since
+the host thinks that PCI devices must not use MMIO space that the
+host has assigned to the framebuffer.
+
+This is especially an issue if pci-hyperv is built-in and hyperv-drm is
+built as a module. Consequently, the kdump/kexec kernel fails to detect
+PCI devices via pci-hyperv, and may fail to mount the root file system,
+which may reside in a NVMe disk. The issue described here has existed
+for SR-IOV VF NICs since day one of the pci-hyperv driver, and has been
+worked around on x64 when possible. With the recent introduction of
+ARM64 VMs that boot from NVMe, there is no workaround, so we need a
+formal fix.
+
+On Gen2 VMs, if the screen.lfb_base is 0 in the kdump/kexec kernel [1],
+fall back to the low MMIO base, which should be equal to the framebuffer
+MMIO base [2] (the statement is true according to my testing on x64
+Windows Server 2016, and on x64 and ARM64 Windows Server 2025 and on
+Azure. I checked with the Hyper-V team and they said the statement should
+continue to be true for Gen2 VMs). In the first kernel, screen.lfb_base
+is not 0; if the user specifies a very high resolution, it's not enough
+to only reserve 8MB: let's always reserve half of the space below 4GB,
+but cap the reservation to 128MB, which is the required framebuffer size
+of the highest resolution 7680*4320 supported by Hyper-V.
+
+While at it, fix the comparison "end > VTPM_BASE_ADDRESS" by changing
+the > to >=. Here the 'end' is an inclusive end (typically, it's
+0xFFFF_FFFF for the low MMIO range).
+
+Note: vmbus_reserve_fb() now also reserves an MMIO range at the beginning
+of the low MMIO range on CVMs, which have no framebuffers (the
+'screen.lfb_base' in vmbus_reserve_fb() is 0 for CVMs), just in case the
+host might treat the beginning of the low MMIO range specially [3]. BTW,
+the OpenHCL kernel is not affected by the change, because that kernel
+boots with DeviceTree rather than ACPI (so vmbus_reserve_fb() won't run
+there), and there is no framebuffer device for that kernel.
+
+Note: normally Gen1 VMs don't have the MMIO conflict issue because the
+framebuffer MMIO range (which is hardcoded to base=4GB-128MB and
+size=64MB for Gen1 VMs by the host) is always reported via the legacy PCI
+graphics device's BAR, so the kdump/kexec kernel can reserve the 64MB
+MMIO range; however, if the VM is configured to use a very high resolution
+and the required framebuffer size exceeds 64MB (AFAIK, in practice, this
+isn't a typical configuration by users), the hyperv-drm driver may need to
+allocate an MMIO range above 4GB and change the framebuffer MMIO location
+to the allocated MMIO range -- in this case, there can still be issues [4]
+which can't be easily fixed: any possible affected Gen1 users would have
+to use a resolution whose framebuffer size is <= 64MB, or switch to Gen2
+VMs.
+
+[1] https://lore.kernel.org/all/SA1PR21MB692176C1BC53BFC9EAE5CF8EBF51A@SA1PR21MB6921.namprd21.prod.outlook.com/
+[2] https://lore.kernel.org/all/SA1PR21MB69218F955B62DFF62E3E88D2BF222@SA1PR21MB6921.namprd21.prod.outlook.com/
+[3] https://lore.kernel.org/all/SN6PR02MB415726B17D5A6027CD1717E8D4342@SN6PR02MB4157.namprd02.prod.outlook.com/
+[4] https://lore.kernel.org/all/SA1PR21MB69213486F821CA5A2C793C81BF342@SA1PR21MB6921.namprd21.prod.outlook.com/
+
+Fixes: 4daace0d8ce8 ("PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs")
+CC: stable@vger.kernel.org
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Tested-by: Krister Johansen <kjlx@templeofstupid.com>
+Tested-by: Matthew Ruffell <matthew.ruffell@canonical.com>
+Signed-off-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hv/vmbus_drv.c | 29 ++++++++++++++++++++++++++---
+ 1 file changed, 26 insertions(+), 3 deletions(-)
+
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -2291,8 +2291,8 @@ static acpi_status vmbus_walk_resources(
+ return AE_NO_MEMORY;
+
+ /* If this range overlaps the virtual TPM, truncate it. */
+- if (end > VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS)
+- end = VTPM_BASE_ADDRESS;
++ if (end >= VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS)
++ end = VTPM_BASE_ADDRESS - 1;
+
+ new_res->name = "hyperv mmio";
+ new_res->flags = IORESOURCE_MEM;
+@@ -2359,6 +2359,7 @@ static void vmbus_mmio_remove(void)
+ static void __maybe_unused vmbus_reserve_fb(void)
+ {
+ resource_size_t start = 0, size;
++ resource_size_t low_mmio_base;
+ struct pci_dev *pdev;
+
+ if (efi_enabled(EFI_BOOT)) {
+@@ -2366,6 +2367,24 @@ static void __maybe_unused vmbus_reserve
+ if (IS_ENABLED(CONFIG_SYSFB)) {
+ start = screen_info.lfb_base;
+ size = max_t(__u32, screen_info.lfb_size, 0x800000);
++
++ low_mmio_base = hyperv_mmio->start;
++ if (!low_mmio_base || upper_32_bits(low_mmio_base) ||
++ (start && start < low_mmio_base)) {
++ pr_warn("Unexpected low mmio base %pa\n", &low_mmio_base);
++ } else {
++ /*
++ * If the kdump/kexec or CVM kernel's lfb_base
++ * is 0, fall back to the low mmio base.
++ */
++ if (!start)
++ start = low_mmio_base;
++ /*
++ * Reserve half of the space below 4GB for high
++ * resolutions, but cap the reservation to 128MB.
++ */
++ size = min((SZ_4G - start) / 2, SZ_128M);
++ }
+ }
+ } else {
+ /* Gen1 VM: get FB base from PCI */
+@@ -2386,8 +2405,10 @@ static void __maybe_unused vmbus_reserve
+ pci_dev_put(pdev);
+ }
+
+- if (!start)
++ if (!start) {
++ pr_warn("Unexpected framebuffer mmio base of zero\n");
+ return;
++ }
+
+ /*
+ * Make a claim for the frame buffer in the resource tree under the
+@@ -2397,6 +2418,8 @@ static void __maybe_unused vmbus_reserve
+ */
+ for (; !fb_mmio && (size >= 0x100000); size >>= 1)
+ fb_mmio = __request_region(hyperv_mmio, start, size, fb_mmio_name, 0);
++
++ pr_info("hv_mmio=%pR,%pR fb=%pR\n", hyperv_mmio, hyperv_mmio->sibling, fb_mmio);
+ }
+
+ /**
--- /dev/null
+From stable+bounces-266607-greg=kroah.com@vger.kernel.org Wed Jun 17 02:47:28 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Jun 2026 21:47:19 -0400
+Subject: firmware: samsung: acpm: Fix cross-thread RX length corruption
+To: stable@vger.kernel.org
+Cc: Tudor Ambarus <tudor.ambarus@linaro.org>, Titouan Ameline de Cadeville <titouan.ameline@gmail.com>, Krzysztof Kozlowski <krzk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260617014719.3671631-1-sashal@kernel.org>
+
+From: Tudor Ambarus <tudor.ambarus@linaro.org>
+
+[ Upstream commit f133bd4b5daf71bccdde0ad1a4f47fac76a6bfb1 ]
+
+Sashiko identified a cross-thread RX length corruption bug when
+reviewing the thermal addition to ACPM [1].
+
+When multiple threads concurrently send IPC requests, the ACPM polling
+mechanism can encounter responses belonging to other threads. To drain
+the queue, the driver saves these concurrent responses into an internal
+cache (`rx_data->cmd`) to be retrieved later by the owning thread.
+
+Previously, the driver incorrectly used `xfer->rxcnt` (the expected
+receive length of the *current* polling thread) when copying data for
+*other* threads into this cache. If the threads expected responses of
+different lengths, this resulted in buffer underflows (leading to reads
+of uninitialized memory) or potential buffer overflows.
+
+Fix this by replacing the boolean `response` flag in
+`struct acpm_rx_data` with `rxcnt`, caching the exact expected receive
+length for each specific transaction during transfer preparation. Use
+this cached length when saving concurrent responses.
+
+Consequently, ensure that `xfer->rxcnt` is explicitly zeroed in driver
+helpers (e.g., `acpm_dvfs_set_xfer`) for fire-and-forget messages to
+prevent uninitialized stack garbage from being interpreted as a massive
+expected receive length.
+
+Cc: stable@vger.kernel.org
+Fixes: a88927b534ba ("firmware: add Exynos ACPM protocol driver")
+Closes: https://sashiko.dev/#/patchset/20260420-acpm-tmu-v3-0-3dc8e93f0b26%40linaro.org [1]
+Reported-by: Titouan Ameline de Cadeville <titouan.ameline@gmail.com>
+Closes: https://lore.kernel.org/r/20260426210255.73674-1-titouan.ameline@gmail.com/
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-1-43b5ee7f1674@linaro.org
+Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/firmware/samsung/exynos-acpm.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/drivers/firmware/samsung/exynos-acpm.c
++++ b/drivers/firmware/samsung/exynos-acpm.c
+@@ -103,12 +103,12 @@ struct acpm_queue {
+ *
+ * @cmd: pointer to where the data shall be saved.
+ * @n_cmd: number of 32-bit commands.
+- * @response: true if the client expects the RX data.
++ * @rxcnt: expected length of the response in 32-bit words.
+ */
+ struct acpm_rx_data {
+ u32 *cmd;
+ size_t n_cmd;
+- bool response;
++ size_t rxcnt;
+ };
+
+ #define ACPM_SEQNUM_MAX 64
+@@ -196,7 +196,7 @@ static void acpm_get_saved_rx(struct acp
+ const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];
+ u32 rx_seqnum;
+
+- if (!rx_data->response)
++ if (!rx_data->rxcnt)
+ return;
+
+ rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
+@@ -253,7 +253,7 @@ static int acpm_get_rx(struct acpm_chan
+ seqnum = rx_seqnum - 1;
+ rx_data = &achan->rx_data[seqnum];
+
+- if (rx_data->response) {
++ if (rx_data->rxcnt) {
+ if (rx_seqnum == tx_seqnum) {
+ __ioread32_copy(xfer->rxd, addr,
+ xfer->rxlen / 4);
+@@ -267,7 +267,7 @@ static int acpm_get_rx(struct acpm_chan
+ * after the response is copied to the request.
+ */
+ __ioread32_copy(rx_data->cmd, addr,
+- xfer->rxlen / 4);
++ rx_data->rxcnt);
+ }
+ } else {
+ clear_bit(seqnum, achan->bitmap_seqnum);
+@@ -379,8 +379,8 @@ static void acpm_prepare_xfer(struct acp
+ /* Clear data for upcoming responses */
+ rx_data = &achan->rx_data[achan->seqnum - 1];
+ memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);
+- if (xfer->rxd)
+- rx_data->response = true;
++ /* zero means no response expected */
++ rx_data->rxcnt = xfer->rxlen / 4;
+
+ /* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
+ set_bit(achan->seqnum - 1, achan->bitmap_seqnum);
--- /dev/null
+From stable+bounces-264996-greg=kroah.com@vger.kernel.org Tue Jun 16 18:01:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Jun 2026 12:55:57 -0400
+Subject: hv: utils: handle and propagate errors in kvp_register
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Long Li <longli@microsoft.com>, Wei Liu <wei.liu@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616165557.3366587-1-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ Upstream commit 3fcf923302a8f5c0dc3af3d2ca2657cb5fae4297 ]
+
+Make kvp_register() return an error code instead of silently ignoring
+failures, and propagate the error from kvp_handle_handshake() instead of
+returning success.
+
+This propagates both kzalloc_obj() and hvutil_transport_send() failures
+to kvp_handle_handshake() and thus to kvp_on_msg().
+
+Fixes: 245ba56a52a3 ("Staging: hv: Implement key/value pair (KVP)")
+Cc: stable@vger.kernel.org
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Reviewed-by: Long Li <longli@microsoft.com>
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hv/hv_kvp.c | 27 ++++++++++++++-------------
+ 1 file changed, 14 insertions(+), 13 deletions(-)
+
+--- a/drivers/hv/hv_kvp.c
++++ b/drivers/hv/hv_kvp.c
+@@ -93,7 +93,7 @@ static void kvp_send_key(struct work_str
+ static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
+ static void kvp_timeout_func(struct work_struct *dummy);
+ static void kvp_host_handshake_func(struct work_struct *dummy);
+-static void kvp_register(int);
++static int kvp_register(int);
+
+ static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
+ static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
+@@ -127,24 +127,26 @@ static void kvp_register_done(void)
+ hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
+ }
+
+-static void
++static int
+ kvp_register(int reg_value)
+ {
+
+ struct hv_kvp_msg *kvp_msg;
+ char *version;
++ int ret;
+
+ kvp_msg = kzalloc(sizeof(*kvp_msg), GFP_KERNEL);
++ if (!kvp_msg)
++ return -ENOMEM;
+
+- if (kvp_msg) {
+- version = kvp_msg->body.kvp_register.version;
+- kvp_msg->kvp_hdr.operation = reg_value;
+- strcpy(version, HV_DRV_VERSION);
+-
+- hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
+- kvp_register_done);
+- kfree(kvp_msg);
+- }
++ version = kvp_msg->body.kvp_register.version;
++ kvp_msg->kvp_hdr.operation = reg_value;
++ strcpy(version, HV_DRV_VERSION);
++
++ ret = hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
++ kvp_register_done);
++ kfree(kvp_msg);
++ return ret;
+ }
+
+ static void kvp_timeout_func(struct work_struct *dummy)
+@@ -186,9 +188,8 @@ static int kvp_handle_handshake(struct h
+ */
+ pr_debug("KVP: userspace daemon ver. %d connected\n",
+ msg->kvp_hdr.operation);
+- kvp_register(dm_reg_value);
+
+- return 0;
++ return kvp_register(dm_reg_value);
+ }
+
+
--- /dev/null
+From 497330b203d2c59c5ff3fa4c34d14494d7203bc3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andr=C3=A9=20Draszik?= <andre.draszik@linaro.org>
+Date: Fri, 9 Jan 2026 08:38:38 +0000
+Subject: regulator: core: fix locking in regulator_resolve_supply() error path
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: André Draszik <andre.draszik@linaro.org>
+
+commit 497330b203d2c59c5ff3fa4c34d14494d7203bc3 upstream.
+
+If late enabling of a supply regulator fails in
+regulator_resolve_supply(), the code currently triggers a lockdep
+warning:
+
+ WARNING: drivers/regulator/core.c:2649 at _regulator_put+0x80/0xa0, CPU#6: kworker/u32:4/596
+ ...
+ Call trace:
+ _regulator_put+0x80/0xa0 (P)
+ regulator_resolve_supply+0x7cc/0xbe0
+ regulator_register_resolve_supply+0x28/0xb8
+
+as the regulator_list_mutex must be held when calling _regulator_put().
+
+To solve this, simply switch to using regulator_put().
+
+While at it, we should also make sure that no concurrent access happens
+to our rdev while we clear out the supply pointer. Add appropriate
+locking to ensure that.
+
+While the code in question will be removed altogether in a follow-up
+commit, I believe it is still beneficial to have this corrected before
+removal for future reference.
+
+Fixes: 36a1f1b6ddc6 ("regulator: core: Fix memory leak in regulator_resolve_supply()")
+Fixes: 8e5356a73604 ("regulator: core: Clear the supply pointer if enabling fails")
+Signed-off-by: André Draszik <andre.draszik@linaro.org>
+Link: https://patch.msgid.link/20260109-regulators-defer-v2-2-1a25dc968e60@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Nazar Kalashnikov <nazarkalashnikov0@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/regulator/core.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/regulator/core.c
++++ b/drivers/regulator/core.c
+@@ -2159,8 +2159,16 @@ static int regulator_resolve_supply(stru
+ if (rdev->use_count) {
+ ret = regulator_enable(rdev->supply);
+ if (ret < 0) {
+- _regulator_put(rdev->supply);
++ struct regulator *supply;
++
++ regulator_lock_two(rdev, rdev->supply->rdev, &ww_ctx);
++
++ supply = rdev->supply;
+ rdev->supply = NULL;
++
++ regulator_unlock_two(rdev, supply->rdev, &ww_ctx);
++
++ regulator_put(supply);
+ goto out;
+ }
+ }
--- /dev/null
+From 9b222cb1d23ff210975e9df5ebab7b011acb6fad Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sun, 31 May 2026 15:41:45 +0200
+Subject: rose: cancel neighbour timers in rose_neigh_put() before freeing
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit 9b222cb1d23ff210975e9df5ebab7b011acb6fad upstream.
+
+rose_neigh_put() kfree()s the neighbour but never cancels its ftimer and
+t0timer. Until now every caller that dropped the final reference first
+called rose_remove_neigh(), which deletes those timers. The socket
+heartbeat reaping path drops the last reference directly, so a neighbour
+could be freed with t0timer still armed -- it re-arms itself in
+rose_t0timer_expiry() -- leading to a use-after-free write in
+enqueue_timer().
+
+Cancel both timers with timer_delete_sync() (the synchronous variant, to
+wait out a concurrently running, self-rearming handler) in the
+refcount-zero branch of rose_neigh_put().
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/rose.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/include/net/rose.h
++++ b/include/net/rose.h
+@@ -160,6 +160,18 @@ static inline void rose_neigh_hold(struc
+ static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
+ {
+ if (refcount_dec_and_test(&rose_neigh->use)) {
++ /* We are dropping the last reference, so we are about to free the
++ * neighbour. Its timers may still be armed -- t0timer in particular
++ * re-arms itself in rose_t0timer_expiry(). rose_remove_neigh()
++ * cancels them before its own put, but callers that drop the final
++ * reference without first calling rose_remove_neigh() (the socket
++ * heartbeat reaping path) would otherwise kfree() a neighbour with a
++ * live timer -> use-after-free. timer_delete_sync() (not the async
++ * variant) is required: it waits out a concurrently running handler
++ * and loops until the self-rearming timer stays stopped.
++ */
++ timer_delete_sync(&rose_neigh->ftimer);
++ timer_delete_sync(&rose_neigh->t0timer);
+ if (rose_neigh->ax25)
+ ax25_cb_put(rose_neigh->ax25);
+ kfree(rose_neigh->digipeat);
--- /dev/null
+From e8eb0c6faa8849ba7769516c1a8c84d9f612acf6 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sat, 16 May 2026 12:10:38 +0200
+Subject: rose: clear neighbour pointer after rose_neigh_put() in state machines
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit e8eb0c6faa8849ba7769516c1a8c84d9f612acf6 upstream.
+
+After calling rose_neigh_put() in rose_state1_machine() through
+rose_state5_machine(), rose->neighbour was left pointing at the
+potentially freed neighbour structure. A subsequent timer expiry or
+concurrent teardown path could dereference the stale pointer, causing
+a use-after-free.
+
+Set rose->neighbour to NULL immediately after each rose_neigh_put()
+call in the state machine functions.
+
+Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t")
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_in.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/net/rose/rose_in.c
++++ b/net/rose/rose_in.c
+@@ -57,6 +57,7 @@ static int rose_state1_machine(struct so
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
+ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
+ break;
+
+ default:
+@@ -80,11 +81,13 @@ static int rose_state2_machine(struct so
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
+ break;
+
+ case ROSE_CLEAR_CONFIRMATION:
+ rose_disconnect(sk, 0, -1, -1);
+ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
+ break;
+
+ default:
+@@ -122,6 +125,7 @@ static int rose_state3_machine(struct so
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
+ break;
+
+ case ROSE_RR:
+@@ -235,6 +239,7 @@ static int rose_state4_machine(struct so
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
+ break;
+
+ default:
+@@ -255,6 +260,7 @@ static int rose_state5_machine(struct so
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose_neigh_put(rose_sk(sk)->neighbour);
++ rose_sk(sk)->neighbour = NULL;
+ }
+
+ return 0;
--- /dev/null
+From 606e42d195b467480d4d405f8814c48d1651a76a Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sun, 31 May 2026 15:41:45 +0200
+Subject: rose: clear neighbour pointer in rose_kill_by_device()
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit 606e42d195b467480d4d405f8814c48d1651a76a upstream.
+
+rose_kill_by_device() drops the neighbour reference but leaves
+rose->neighbour pointing at it, unlike every other rose_neigh_put() site
+(see "rose: clear neighbour pointer after rose_neigh_put() in state
+machines"). The heartbeat STATE_0 reaping path then puts the same
+neighbour a second time, causing a rose_neigh refcount underflow and a
+use-after-free.
+
+Set rose->neighbour = NULL after the put, restoring the invariant.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/af_rose.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -216,8 +216,16 @@ start:
+ * looping forever in ROSE_STATE_0 with no owner.
+ */
+ sock_set_flag(sk, SOCK_DESTROY);
+- if (rose->neighbour)
++ if (rose->neighbour) {
+ rose_neigh_put(rose->neighbour);
++ /* Clear the pointer after dropping the reference, as
++ * every other rose_neigh_put() site does. Otherwise
++ * rose_heartbeat_expiry() (STATE_0 reaping) sees a stale
++ * rose->neighbour and puts it a second time -> rose_neigh
++ * refcount underflow / use-after-free.
++ */
++ rose->neighbour = NULL;
++ }
+ netdev_put(rose->device, &rose->dev_tracker);
+ rose->device = NULL;
+ }
--- /dev/null
+From d4f4cf9f09a3f5fafa8f09110a7c1b5d10f2f261 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Thu, 28 May 2026 17:38:18 +0200
+Subject: rose: disconnect orphaned STATE_2 sockets when device is gone
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit d4f4cf9f09a3f5fafa8f09110a7c1b5d10f2f261 upstream.
+
+When ax25stop brings down ROSE interfaces, sockets in ROSE_STATE_2
+(awaiting CLEAR CONFIRM) whose device pointer is already NULL are not
+reached by rose_kill_by_device() and wait for T3 (up to 180s) before
+self-cleaning via rose_timer_expiry(). This keeps the rose module
+usecount at 1, blocking rmmod for the full T3 duration.
+
+In rose_heartbeat_expiry(), detect ROSE_STATE_2 sockets with no device,
+cancel T3, release the neighbour reference, and call rose_disconnect()
++ sock_set_flag(SOCK_DESTROY). The next heartbeat tick (<=5s) then
+destroys the socket via the existing ROSE_STATE_0/SOCK_DESTROY path,
+allowing clean module unload within 10s instead of up to 180s.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_timer.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/net/rose/rose_timer.c
++++ b/net/rose/rose_timer.c
+@@ -139,6 +139,20 @@ static void rose_heartbeat_expiry(struct
+ }
+ break;
+
++ case ROSE_STATE_2:
++ /* Device gone before CLEAR CONFIRM arrived: stop waiting for T3
++ * and disconnect now instead of blocking rmmod for up to 180s. */
++ if (!rose->device) {
++ rose_stop_timer(sk);
++ if (rose->neighbour) {
++ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
++ }
++ rose_disconnect(sk, ENETDOWN, -1, -1);
++ sock_set_flag(sk, SOCK_DESTROY);
++ }
++ break;
++
+ case ROSE_STATE_3:
+ /*
+ * Check for the state of the receive buffer.
--- /dev/null
+From 56576518920edd7b6c3479477d8d490fe2ebdaaa Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sun, 31 May 2026 15:41:45 +0200
+Subject: rose: don't free fd-owned sockets when reaping in the heartbeat
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit 56576518920edd7b6c3479477d8d490fe2ebdaaa upstream.
+
+The heartbeat reaps orphaned ROSE sockets after their bound device goes
+down. A socket still attached to a struct socket (sk->sk_socket != NULL --
+e.g. an incoming connection an fpad client has accepted and kept open) is
+owned by that userspace fd: rose_release() frees it on close(). Freeing it
+from the heartbeat left the fd dangling, so the eventual close() touched
+freed memory -- slab-use-after-free in rose_release().
+
+Reap only sockets with sk->sk_socket == NULL (unaccepted incoming
+connections and post-close orphans). For an fd-owned socket whose device
+went down, disconnect it and fall through to the switch so close() does
+the teardown. Also release the neighbour reference held by orphaned
+incoming sockets before tearing them down.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_timer.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 56 insertions(+), 1 deletion(-)
+
+--- a/net/rose/rose_timer.c
++++ b/net/rose/rose_timer.c
+@@ -126,13 +126,68 @@ static void rose_heartbeat_expiry(struct
+ sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ/20);
+ goto out;
+ }
++
++ /* The bound device went down while we still hold a reference on it.
++ * This catches the narrow race where rose_loopback_timer() created a
++ * socket in the window after rose_kill_by_device()'s NETDEV_DOWN sweep
++ * but before rose_insert_socket() -- leaving a STATE_3 socket that no
++ * other branch reaps. A down device means the link is dead, so tear
++ * the socket down regardless of state. rose_destroy_socket() releases
++ * the held netdev reference (rose->device still set).
++ */
++ if (rose->device && !netif_running(rose->device)) {
++ if (rose->neighbour) {
++ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
++ }
++ rose_disconnect(sk, ENETDOWN, -1, -1);
++
++ /* Only reap the socket if userspace no longer holds it. A socket
++ * still attached to a struct socket (sk->sk_socket != NULL -- e.g.
++ * a connection an fpad client has accepted and kept open) is owned
++ * by that fd: rose_release() will destroy it on close(). Dropping
++ * the last reference here leaves the open fd dangling, so the
++ * eventual close() touches freed memory -> slab-use-after-free in
++ * rose_release(). Unaccepted incoming sockets and post-close
++ * orphans have sk->sk_socket == NULL and stay safe to reap here.
++ */
++ if (!sk->sk_socket) {
++ sock_set_flag(sk, SOCK_DESTROY);
++ bh_unlock_sock(sk);
++ rose_destroy_socket(sk);
++ sock_put(sk);
++ return;
++ }
++
++ /* Owned by userspace: the link is down and the socket is now
++ * disconnected (rose_disconnect() moved it to STATE_0). Fall
++ * through to the switch, which re-arms the heartbeat; the close()
++ * will tear the socket down. */
++ }
++
+ switch (rose->state) {
+ case ROSE_STATE_0:
+ /* Destroy any orphaned STATE_0 socket: either explicitly
+ * flagged SOCK_DESTROY, or SOCK_DEAD (covers both unaccepted
+ * incoming connections and listening sockets whose link died).
+ */
+- if (sock_flag(sk, SOCK_DESTROY) || sock_flag(sk, SOCK_DEAD)) {
++ if ((sock_flag(sk, SOCK_DESTROY) || sock_flag(sk, SOCK_DEAD)) &&
++ !sk->sk_socket) {
++ /* Reap only orphaned sockets (sk->sk_socket == NULL). A
++ * socket still owned by a userspace fd reaches here via the
++ * STATE_2 device-gone branch, which sets SOCK_DESTROY without
++ * knowing about the fd; freeing it would race rose_release()
++ * at close() -> use-after-free. Leave it for close().
++ *
++ * Orphaned incoming sockets (rose_rx_call_request) hold a
++ * neighbour reference; release it before teardown, as the
++ * STATE_2 and device-down branches do. rose_destroy_socket()
++ * does not drop it.
++ */
++ if (rose->neighbour) {
++ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
++ }
+ bh_unlock_sock(sk);
+ rose_destroy_socket(sk);
+ sock_put(sk);
--- /dev/null
+From cf5567a2652e44866eae8987dff4c1ea507680df Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Thu, 28 May 2026 20:20:55 +0200
+Subject: rose: drop CALL_REQUEST in loopback timer when device is not running
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit cf5567a2652e44866eae8987dff4c1ea507680df upstream.
+
+When ax25stop brings down rose0 while the loopback timer has pending
+CALL_REQUEST frames, rose_loopback_timer() calls rose_dev_get() and
+finds the device still registered (unregister_netdevice waits for
+refs to drop), then calls rose_rx_call_request() which takes a
+netdev_hold() for the new socket.
+
+But NETDEV_DOWN fires only once: rose_kill_by_device() already ran
+before this timer tick, so the new socket is never cleaned up. The
+stuck reference prevents unregister_netdevice from completing, and the
+orphan socket's timers eventually fire on freed memory (KASAN
+slab-use-after-free in __run_timers).
+
+The kernel clears IFF_UP via dev_close() before sending NETDEV_DOWN,
+so checking netif_running() after rose_dev_get() is sufficient: if the
+device is no longer running, the CALL_REQUEST is silently dropped and
+no socket is created. This closes the race without touching the
+module-exit path (which already stops the timer via loopback_stopping).
+
+Tested: unregister_netdevice completes immediately after ax25stop with
+active loopback connections; no ref_tracker warnings, no KASAN.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_loopback.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/net/rose/rose_loopback.c
++++ b/net/rose/rose_loopback.c
+@@ -118,6 +118,16 @@ static void rose_loopback_timer(struct t
+ kfree_skb(skb);
+ continue;
+ }
++ /* rose_kill_by_device() runs on NETDEV_DOWN (IFF_UP cleared)
++ * before the device is unregistered. If we create a new
++ * socket here after that cleanup, the ref never gets released
++ * because NETDEV_DOWN fires only once. Drop the call instead.
++ */
++ if (!netif_running(dev)) {
++ dev_put(dev);
++ kfree_skb(skb);
++ continue;
++ }
+
+ if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0)
+ kfree_skb(skb);
--- /dev/null
+From ff91adc54db2b62c7cdf063ff761eceb5adf2215 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sat, 16 May 2026 12:09:33 +0200
+Subject: rose: fix dev_put() leak in rose_loopback_timer()
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit ff91adc54db2b62c7cdf063ff761eceb5adf2215 upstream.
+
+rose_rx_call_request() always consumes or returns the skb but never
+releases the device reference obtained from rose_dev_get(). When
+rose_rx_call_request() succeeds (returns non-zero) dev_put() was never
+called, leaking one reference per loopback CALL_REQUEST.
+
+Move dev_put() outside the conditional so it is called unconditionally
+after rose_rx_call_request() in all cases.
+
+Also remove the dead check (!rose_loopback_neigh->dev &&
+!rose_loopback_neigh->loopback) that immediately precedes it: the
+loopback neighbour always has loopback=1 so this condition can never
+be true.
+
+Fixes: 0453c6824595 ("net/rose: fix unbound loop in rose_loopback_timer()")
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_loopback.c | 11 ++---------
+ 1 file changed, 2 insertions(+), 9 deletions(-)
+
+--- a/net/rose/rose_loopback.c
++++ b/net/rose/rose_loopback.c
+@@ -96,22 +96,15 @@ static void rose_loopback_timer(struct t
+ }
+
+ if (frametype == ROSE_CALL_REQUEST) {
+- if (!rose_loopback_neigh->dev &&
+- !rose_loopback_neigh->loopback) {
+- kfree_skb(skb);
+- continue;
+- }
+-
+ dev = rose_dev_get(dest);
+ if (!dev) {
+ kfree_skb(skb);
+ continue;
+ }
+
+- if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) {
+- dev_put(dev);
++ if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0)
+ kfree_skb(skb);
+- }
++ dev_put(dev);
+ } else {
+ kfree_skb(skb);
+ }
--- /dev/null
+From b9fb21ceb4f0d043767a1eba60786ec84809033b Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Thu, 28 May 2026 19:11:55 +0200
+Subject: rose: fix netdev double-hold in rose_make_new()
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit b9fb21ceb4f0d043767a1eba60786ec84809033b upstream.
+
+rose_make_new() copies orose->device from the listener socket and calls
+netdev_hold(), storing the tracker in rose->dev_tracker. The only
+caller, rose_rx_call_request(), then overwrites both make_rose->device
+and make_rose->dev_tracker with a fresh netdev_hold() for the actual
+incoming-call device.
+
+This orphans the tracker allocated by rose_make_new(): it remains in
+the device's refcount_tracker list but no pointer exists to free it
+via netdev_put(). The result is one spurious outstanding reference per
+accepted CALL_REQUEST, visible at rmmod time as:
+
+ ref_tracker: netdev@X has 2/2 users at
+ rose_rx_call_request+0xba3/0x1d50 [rose]
+ rose_loopback_timer+0x3eb/0x670 [rose]
+
+The second entry is the orphaned tracker from rose_make_new(); the
+first is the correctly-managed socket reference from rose_rx_call_request().
+
+Fix: initialise rose->device to NULL in rose_make_new() and let
+rose_rx_call_request() -- the sole caller -- assign the correct device
+and take the sole netdev_hold() as it already does.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/af_rose.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -631,9 +631,7 @@ static struct sock *rose_make_new(struct
+ rose->hb = orose->hb;
+ rose->idle = orose->idle;
+ rose->defer = orose->defer;
+- rose->device = orose->device;
+- if (rose->device)
+- netdev_hold(rose->device, &rose->dev_tracker, GFP_ATOMIC);
++ rose->device = NULL; /* rose_rx_call_request() sets this */
+ rose->qbitincl = orose->qbitincl;
+
+ return sk;
--- /dev/null
+From c675277c3ba0d2310e0825577d58308c39931e14 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Tue, 26 May 2026 15:57:04 +0200
+Subject: rose: fix netdev double-hold in rose_rx_call_request()
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit c675277c3ba0d2310e0825577d58308c39931e14 upstream.
+
+rose_rx_call_request() used netdev_tracker_alloc() after assigning
+make_rose->device, intending to take ownership of the reference passed
+by the caller. But every caller -- rose_route_frame() and
+rose_loopback_timer() -- already calls dev_put() for its own hold after
+the function returns, so the socket ended up with a tracker entry
+pointing at a reference that had already been released.
+
+The result was spurious refcount_t warnings ("saturated", "decrement
+hit 0") on every incoming CALL_REQUEST, leading to refcount corruption
+and eventual silent freeze.
+
+Replace netdev_tracker_alloc() with netdev_hold() so that
+rose_rx_call_request() acquires its own independent reference. Each
+caller retains its own hold from rose_dev_get() and releases it via
+dev_put() as before; socket cleanup releases the socket's separate hold
+via netdev_put().
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/af_rose.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -1078,9 +1078,11 @@ int rose_rx_call_request(struct sk_buff
+ make_rose->source_digis[n] = facilities.source_digis[n];
+ make_rose->neighbour = neigh;
+ make_rose->device = dev;
+- /* Caller got a reference for us. */
+- netdev_tracker_alloc(make_rose->device, &make_rose->dev_tracker,
+- GFP_ATOMIC);
++ /* Take an independent reference for this socket; callers keep their
++ * own reference (from rose_dev_get / dev_hold) and will release it
++ * themselves via dev_put().
++ */
++ netdev_hold(make_rose->device, &make_rose->dev_tracker, GFP_ATOMIC);
+ make_rose->facilities = facilities;
+
+ rose_neigh_hold(make_rose->neighbour);
--- /dev/null
+From f71a8a1edc14dba746edde38adddd654ba202b4d Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Tue, 26 May 2026 15:57:47 +0200
+Subject: rose: fix notifier unregistered too early in rose_exit()
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit f71a8a1edc14dba746edde38adddd654ba202b4d upstream.
+
+rose_exit() called unregister_netdevice_notifier() before the loop that
+calls unregister_netdev() on each ROSE virtual device. As a result,
+the NETDEV_DOWN event fired by unregister_netdev() was never delivered
+to rose_device_event(), so rose_kill_by_device() never ran.
+
+Every socket whose rose->device pointed at a ROSE device therefore kept
+its netdev_tracker entry live until free_netdev() destroyed the
+ref_tracker_dir, at which point the kernel reported all of them as
+leaked references (165 entries in a typical FPAC setup). Worse, those
+sockets retained stale device pointers and live timers that could fire
+into freed module text after module unload, causing a silent system
+freeze with no kernel panic logged.
+
+Fix by moving unregister_netdevice_notifier() to after the device-
+unregistration loop. unregister_netdev() then delivers NETDEV_DOWN
+while the notifier is still registered, rose_kill_by_device() runs for
+each device, releases all netdev references held by open sockets, and
+calls rose_disconnect() which stops the per-socket timers.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/af_rose.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -1669,19 +1669,28 @@ static void __exit rose_exit(void)
+ #ifdef CONFIG_SYSCTL
+ rose_unregister_sysctl();
+ #endif
+- unregister_netdevice_notifier(&rose_dev_notifier);
+-
+ sock_unregister(PF_ROSE);
+
+ for (i = 0; i < rose_ndevs; i++) {
+ struct net_device *dev = dev_rose[i];
+
+ if (dev) {
++ /* unregister_netdev() fires NETDEV_DOWN, which -- while the
++ * notifier is still registered below -- invokes
++ * rose_kill_by_device(dev). That releases every socket's
++ * netdev reference and disconnects all active circuits.
++ * Unregistering the notifier before this loop was the
++ * original bug: NETDEV_DOWN was never delivered, leaving
++ * 165 netdev_tracker entries leaked and stale timers live.
++ */
+ unregister_netdev(dev);
+ free_netdev(dev);
+ }
+ }
+
++ /* Now safe to remove the notifier -- all ROSE devices are gone. */
++ unregister_netdevice_notifier(&rose_dev_notifier);
++
+ kfree(dev_rose);
+ proto_unregister(&rose_proto);
+ }
--- /dev/null
+From 47dd6ec1a77d77895afb00aa2e68373a48289108 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sat, 16 May 2026 12:10:20 +0200
+Subject: rose: fix race between loopback timer and module removal
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit 47dd6ec1a77d77895afb00aa2e68373a48289108 upstream.
+
+rose_loopback_clear() called timer_delete() which returns immediately
+without waiting for any running callback to complete. If the timer
+fired concurrently with module removal, rose_loopback_timer() could
+re-arm the timer after timer_delete() returned and then access
+rose_loopback_neigh after it was freed.
+
+Two complementary changes close the race:
+
+1. Add a loopback_stopping atomic flag. rose_loopback_timer() checks
+ it at entry (before acquiring a reference) and again inside the
+ loop; when set it drains the queue and exits without re-arming the
+ timer.
+
+2. Switch rose_loopback_clear() to timer_delete_sync() so it blocks
+ until any in-flight callback has returned before freeing resources.
+
+The smp_mb() between setting the flag and calling timer_delete_sync()
+ensures the flag is visible to any callback that is about to run.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_loopback.c | 31 ++++++++++++++++++++++++-------
+ 1 file changed, 24 insertions(+), 7 deletions(-)
+
+--- a/net/rose/rose_loopback.c
++++ b/net/rose/rose_loopback.c
+@@ -12,13 +12,15 @@
+ #include <net/rose.h>
+ #include <linux/init.h>
+
+-static struct sk_buff_head loopback_queue;
+ #define ROSE_LOOPBACK_LIMIT 1000
+-static struct timer_list loopback_timer;
+
++static struct timer_list loopback_timer;
++static struct sk_buff_head loopback_queue;
+ static void rose_set_loopback_timer(void);
+ static void rose_loopback_timer(struct timer_list *unused);
+
++static atomic_t loopback_stopping = ATOMIC_INIT(0);
++
+ void rose_loopback_init(void)
+ {
+ skb_queue_head_init(&loopback_queue);
+@@ -66,6 +68,9 @@ static void rose_loopback_timer(struct t
+ unsigned int lci_i, lci_o;
+ int count;
+
++ if (atomic_read(&loopback_stopping))
++ return;
++
+ if (rose_loopback_neigh)
+ rose_neigh_hold(rose_loopback_neigh);
+ else
+@@ -75,6 +80,13 @@ static void rose_loopback_timer(struct t
+ skb = skb_dequeue(&loopback_queue);
+ if (!skb)
+ goto out;
++
++ if (atomic_read(&loopback_stopping)) {
++ kfree_skb(skb);
++ skb_queue_purge(&loopback_queue);
++ goto out;
++ }
++
+ if (skb->len < ROSE_MIN_LEN) {
+ kfree_skb(skb);
+ continue;
+@@ -118,7 +130,7 @@ static void rose_loopback_timer(struct t
+ out:
+ rose_neigh_put(rose_loopback_neigh);
+
+- if (!skb_queue_empty(&loopback_queue))
++ if (!atomic_read(&loopback_stopping) && !skb_queue_empty(&loopback_queue))
+ mod_timer(&loopback_timer, jiffies + 1);
+ }
+
+@@ -126,10 +138,15 @@ void __exit rose_loopback_clear(void)
+ {
+ struct sk_buff *skb;
+
+- timer_delete(&loopback_timer);
++ atomic_set(&loopback_stopping, 1);
++ /* Pairs with atomic_read() in rose_loopback_timer(): ensure the
++ * stopping flag is visible before we cancel, so a concurrent
++ * callback aborts its loop early rather than re-arming the timer.
++ */
++ smp_mb();
++
++ timer_delete_sync(&loopback_timer);
+
+- while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+- skb->sk = NULL;
++ while ((skb = skb_dequeue(&loopback_queue)) != NULL)
+ kfree_skb(skb);
+- }
+ }
--- /dev/null
+From 2b67342c6ff899a0b83359517146a5b7b243af97 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sat, 16 May 2026 12:10:55 +0200
+Subject: rose: guard rose_neigh_put() against NULL in timer expiry
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit 2b67342c6ff899a0b83359517146a5b7b243af97 upstream.
+
+In rose_timer_expiry(), the ROSE_STATE_2 branch calls
+rose_neigh_put(rose->neighbour) without first checking whether the
+pointer is NULL. After commit 5de7665e0a07 ("net: rose: fix timer
+races against user threads") the timer is re-armed when the socket is
+owned by a user thread; between the re-arm and the next firing, a
+device-down event or concurrent teardown via rose_kill_by_device() can
+set rose->neighbour to NULL, leading to a NULL-pointer dereference
+inside rose_neigh_put().
+
+Add a NULL check before the put and clear the pointer afterwards.
+
+Fixes: 5de7665e0a07 ("net: rose: fix timer races against user threads")
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_timer.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/net/rose/rose_timer.c
++++ b/net/rose/rose_timer.c
+@@ -180,7 +180,10 @@ static void rose_timer_expiry(struct tim
+ break;
+
+ case ROSE_STATE_2: /* T3 */
+- rose_neigh_put(rose->neighbour);
++ if (rose->neighbour) {
++ rose_neigh_put(rose->neighbour);
++ rose->neighbour = NULL;
++ }
+ rose_disconnect(sk, ETIMEDOUT, -1, -1);
+ break;
+
--- /dev/null
+From d270a7a5793af84555c40dd1eb80f1d497fdf53c Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Sat, 16 May 2026 12:10:03 +0200
+Subject: rose: hold loopback neighbour reference across timer callback
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit d270a7a5793af84555c40dd1eb80f1d497fdf53c upstream.
+
+rose_loopback_timer() dereferences rose_loopback_neigh throughout its
+body but holds no reference on it. A concurrent rose_loopback_clear()
+followed by rose_add_loopback_neigh() could free and reallocate the
+neighbour while the timer body is running, causing a use-after-free.
+
+Take a reference with rose_neigh_hold() at the start of the callback
+(bailing out if the pointer is already NULL) and release it with
+rose_neigh_put() at the single exit point. The neigh cannot be freed
+while the callback holds a reference.
+
+Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t")
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/rose_loopback.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/net/rose/rose_loopback.c
++++ b/net/rose/rose_loopback.c
+@@ -66,10 +66,15 @@ static void rose_loopback_timer(struct t
+ unsigned int lci_i, lci_o;
+ int count;
+
++ if (rose_loopback_neigh)
++ rose_neigh_hold(rose_loopback_neigh);
++ else
++ return;
++
+ for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) {
+ skb = skb_dequeue(&loopback_queue);
+ if (!skb)
+- return;
++ goto out;
+ if (skb->len < ROSE_MIN_LEN) {
+ kfree_skb(skb);
+ continue;
+@@ -109,6 +114,10 @@ static void rose_loopback_timer(struct t
+ kfree_skb(skb);
+ }
+ }
++
++out:
++ rose_neigh_put(rose_loopback_neigh);
++
+ if (!skb_queue_empty(&loopback_queue))
+ mod_timer(&loopback_timer, jiffies + 1);
+ }
--- /dev/null
+From df12be096302d2c947388acc25764456c7f18cc1 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Thu, 28 May 2026 19:38:31 +0200
+Subject: rose: release netdev ref and destroy orphaned incoming sockets
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit df12be096302d2c947388acc25764456c7f18cc1 upstream.
+
+Two related cleanup gaps left the module unremovable after a loopback
+session:
+
+1. rose_destroy_socket() did not release the device reference. When
+ an unaccepted incoming socket (created by rose_rx_call_request()) is
+ destroyed via rose_heartbeat_expiry(), it is removed from rose_list
+ before rose_kill_by_device() can find it, so the netdev_hold() taken
+ in rose_rx_call_request() was never matched by netdev_put(). Add the
+ release at the top of rose_destroy_socket() guarded by a NULL check
+ so that rose_release() and rose_kill_by_device(), which already call
+ netdev_put() and set device = NULL, are not affected.
+
+2. rose_heartbeat_expiry() STATE_0 cleanup required TCP_LISTEN in
+ addition to SOCK_DEAD. Unaccepted incoming sockets are
+ TCP_ESTABLISHED, so the condition was never true and those sockets
+ lingered forever, holding the module use count above zero and
+ blocking rmmod. Drop the TCP_LISTEN restriction: any STATE_0 +
+ SOCK_DEAD socket is orphaned and should be destroyed.
+
+Together with the earlier rose_make_new() double-hold fix these three
+patches allow clean rmmod after loopback sessions.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/af_rose.c | 9 +++++++++
+ net/rose/rose_timer.c | 9 +++++----
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -363,6 +363,7 @@ static void rose_destroy_timer(struct ti
+ */
+ void rose_destroy_socket(struct sock *sk)
+ {
++ struct rose_sock *rose = rose_sk(sk);
+ struct sk_buff *skb;
+
+ rose_remove_socket(sk);
+@@ -370,6 +371,14 @@ void rose_destroy_socket(struct sock *sk
+ rose_stop_idletimer(sk);
+ rose_stop_timer(sk);
+
++ /* Drop any device reference not already released by rose_kill_by_device()
++ * or rose_release() -- e.g. incoming sockets that were never accepted.
++ */
++ if (rose->device) {
++ netdev_put(rose->device, &rose->dev_tracker);
++ rose->device = NULL;
++ }
++
+ rose_clear_queues(sk); /* Flush the queues */
+
+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+--- a/net/rose/rose_timer.c
++++ b/net/rose/rose_timer.c
+@@ -128,10 +128,11 @@ static void rose_heartbeat_expiry(struct
+ }
+ switch (rose->state) {
+ case ROSE_STATE_0:
+- /* Magic here: If we listen() and a new link dies before it
+- is accepted() it isn't 'dead' so doesn't get removed. */
+- if (sock_flag(sk, SOCK_DESTROY) ||
+- (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
++ /* Destroy any orphaned STATE_0 socket: either explicitly
++ * flagged SOCK_DESTROY, or SOCK_DEAD (covers both unaccepted
++ * incoming connections and listening sockets whose link died).
++ */
++ if (sock_flag(sk, SOCK_DESTROY) || sock_flag(sk, SOCK_DEAD)) {
+ bh_unlock_sock(sk);
+ rose_destroy_socket(sk);
+ sock_put(sk);
--- /dev/null
+From 741a4863ad570889c75f7a8e404567d8f3e46335 Mon Sep 17 00:00:00 2001
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Date: Wed, 27 May 2026 14:11:21 +0200
+Subject: rose: set SOCK_DESTROY in rose_kill_by_device() for prompt cleanup
+
+From: Bernard Pidoux <bernard.f6bvp@gmail.com>
+
+commit 741a4863ad570889c75f7a8e404567d8f3e46335 upstream.
+
+When rose_kill_by_device() is called (via NETDEV_DOWN on module exit
+or interface removal), it calls rose_disconnect() which transitions
+sockets to ROSE_STATE_0 and sets SOCK_DEAD. However,
+rose_heartbeat_expiry() only calls rose_destroy_socket() at
+ROSE_STATE_0 if SOCK_DESTROY is set -- the SOCK_DEAD path is reserved
+for TCP_LISTEN sockets. Without SOCK_DESTROY, orphaned sockets in
+ROSE_STATE_2 (clearing) loop indefinitely in the heartbeat without
+ever being freed, keeping the module use-count elevated and blocking
+modprobe -r rose until the T1 timer (up to 200 s) expires.
+
+Set SOCK_DESTROY immediately after rose_disconnect() so the heartbeat
+destroys the socket at its next tick (within 5 s), allowing clean
+module unload.
+
+Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rose/af_rose.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -211,6 +211,11 @@ start:
+ spin_lock_bh(&rose_list_lock);
+ if (rose->device == dev) {
+ rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
++ /* Mark for destruction so rose_heartbeat_expiry()
++ * cleans up the socket at its next tick rather than
++ * looping forever in ROSE_STATE_0 with no owner.
++ */
++ sock_set_flag(sk, SOCK_DESTROY);
+ if (rose->neighbour)
+ rose_neigh_put(rose->neighbour);
+ netdev_put(rose->device, &rose->dev_tracker);
--- /dev/null
+From stable+bounces-268290-greg=kroah.com@vger.kernel.org Thu Jun 25 08:45:49 2026
+From: Alexander Martyniuk <alexevgmart@gmail.com>
+Date: Thu, 25 Jun 2026 10:43:46 +0300
+Subject: sctp: disable BH before calling udp_tunnel_xmit_skb()
+To: stable@vger.kernel.org, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: marcelo.leitner@gmail.com, lucien.xin@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, bestswngs@gmail.com, linux-sctp@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Alexander Martyniuk <alexevgmart@gmail.com>
+Message-ID: <20260625074348.90149-1-alexevgmart@gmail.com>
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit 2cd7e6971fc2787408ceef17906ea152791448cf upstream.
+
+udp_tunnel_xmit_skb() / udp_tunnel6_xmit_skb() are expected to run with
+BH disabled. After commit 6f1a9140ecda ("add xmit recursion limit to
+tunnel xmit functions"), on the path:
+
+ udp(6)_tunnel_xmit_skb() -> ip(6)tunnel_xmit()
+
+dev_xmit_recursion_inc()/dec() must stay balanced on the same CPU.
+
+Without local_bh_disable(), the context may move between CPUs, which can
+break the inc/dec pairing. This may lead to incorrect recursion level
+detection and cause packets to be dropped in ip(6)_tunnel_xmit() or
+__dev_queue_xmit().
+
+Fix it by disabling BH around both IPv4 and IPv6 SCTP UDP xmit paths.
+
+In my testing, after enabling the SCTP over UDP:
+
+ # ip net exec ha sysctl -w net.sctp.udp_port=9899
+ # ip net exec ha sysctl -w net.sctp.encap_port=9899
+ # ip net exec hb sysctl -w net.sctp.udp_port=9899
+ # ip net exec hb sysctl -w net.sctp.encap_port=9899
+
+ # ip net exec ha iperf3 -s
+
+- without this patch:
+
+ # ip net exec hb iperf3 -c 192.168.0.1 --sctp
+ [ 5] 0.00-10.00 sec 37.2 MBytes 31.2 Mbits/sec sender
+ [ 5] 0.00-10.00 sec 37.1 MBytes 31.1 Mbits/sec receiver
+
+- with this patch:
+
+ # ip net exec hb iperf3 -c 192.168.0.1 --sctp
+ [ 5] 0.00-10.00 sec 3.14 GBytes 2.69 Gbits/sec sender
+ [ 5] 0.00-10.00 sec 3.14 GBytes 2.69 Gbits/sec receiver
+
+Fixes: 6f1a9140ecda ("net: add xmit recursion limit to tunnel xmit functions")
+Fixes: 046c052b475e ("sctp: enable udp tunneling socks")
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Link: https://patch.msgid.link/c874a8548221dcd56ff03c65ba75a74e6cf99119.1776017727.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sctp/ipv6.c | 2 ++
+ net/sctp/protocol.c | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -261,9 +261,11 @@ static int sctp_v6_xmit(struct sk_buff *
+ skb_set_inner_ipproto(skb, IPPROTO_SCTP);
+ label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6);
+
++ local_bh_disable();
+ udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, &fl6->daddr,
+ tclass, ip6_dst_hoplimit(dst), label,
+ sctp_sk(sk)->udp_port, t->encap_port, false, 0);
++ local_bh_enable();
+ return 0;
+ }
+
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -1102,10 +1102,12 @@ static inline int sctp_v4_xmit(struct sk
+ skb_reset_inner_mac_header(skb);
+ skb_reset_inner_transport_header(skb);
+ skb_set_inner_ipproto(skb, IPPROTO_SCTP);
++ local_bh_disable();
+ udp_tunnel_xmit_skb(dst_rtable(dst), sk, skb, fl4->saddr,
+ fl4->daddr, dscp, ip4_dst_hoplimit(dst), df,
+ sctp_sk(sk)->udp_port, t->encap_port, false, false,
+ 0);
++ local_bh_enable();
+ return 0;
+ }
+
net-qualcomm-rmnet-fix-endpoint-use-after-free-in-rmnet_dellink.patch
agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch
acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch
+rose-fix-dev_put-leak-in-rose_loopback_timer.patch
+rose-hold-loopback-neighbour-reference-across-timer-callback.patch
+rose-fix-race-between-loopback-timer-and-module-removal.patch
+rose-clear-neighbour-pointer-after-rose_neigh_put-in-state-machines.patch
+rose-guard-rose_neigh_put-against-null-in-timer-expiry.patch
+rose-fix-netdev-double-hold-in-rose_rx_call_request.patch
+rose-fix-notifier-unregistered-too-early-in-rose_exit.patch
+rose-set-sock_destroy-in-rose_kill_by_device-for-prompt-cleanup.patch
+rose-disconnect-orphaned-state_2-sockets-when-device-is-gone.patch
+rose-fix-netdev-double-hold-in-rose_make_new.patch
+rose-release-netdev-ref-and-destroy-orphaned-incoming-sockets.patch
+rose-drop-call_request-in-loopback-timer-when-device-is-not-running.patch
+rose-cancel-neighbour-timers-in-rose_neigh_put-before-freeing.patch
+rose-clear-neighbour-pointer-in-rose_kill_by_device.patch
+rose-don-t-free-fd-owned-sockets-when-reaping-in-the-heartbeat.patch
+regulator-core-fix-locking-in-regulator_resolve_supply-error-path.patch
+hv-utils-handle-and-propagate-errors-in-kvp_register.patch
+drivers-hv-vmbus-improve-the-logic-of-reserving-fb_mmio-on-gen2-vms.patch
+firmware-samsung-acpm-fix-cross-thread-rx-length-corruption.patch
+sctp-disable-bh-before-calling-udp_tunnel_xmit_skb.patch