From: Greg Kroah-Hartman Date: Tue, 30 Sep 2025 11:09:16 +0000 (+0200) Subject: 6.16-stable patches X-Git-Tag: v5.4.300~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=04f737ce55b5d86f0bf040640b500ea9bc980fb6;p=thirdparty%2Fkernel%2Fstable-queue.git 6.16-stable patches added patches: iommufd-fix-race-during-abort-for-file-descriptors.patch spi-cadence-qspi-defer-runtime-support-on-socfpga-if-reset-bit-is-enabled.patch spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch --- diff --git a/queue-6.16/iommufd-fix-race-during-abort-for-file-descriptors.patch b/queue-6.16/iommufd-fix-race-during-abort-for-file-descriptors.patch new file mode 100644 index 0000000000..aafeb881b8 --- /dev/null +++ b/queue-6.16/iommufd-fix-race-during-abort-for-file-descriptors.patch @@ -0,0 +1,203 @@ +From stable+bounces-181947-greg=kroah.com@vger.kernel.org Mon Sep 29 17:47:52 2025 +From: Sasha Levin +Date: Mon, 29 Sep 2025 11:47:41 -0400 +Subject: iommufd: Fix race during abort for file descriptors +To: stable@vger.kernel.org +Cc: Jason Gunthorpe , Nicolin Chen , Nirmoy Das , Kevin Tian , syzbot+80620e2d0d0a33b09f93@syzkaller.appspotmail.com, Sasha Levin +Message-ID: <20250929154741.136377-1-sashal@kernel.org> + +From: Jason Gunthorpe + +[ Upstream commit 4e034bf045b12852a24d5d33f2451850818ba0c1 ] + +fput() doesn't actually call file_operations release() synchronously, it +puts the file on a work queue and it will be released eventually. + +This is normally fine, except for iommufd the file and the iommufd_object +are tied to gether. The file has the object as it's private_data and holds +a users refcount, while the object is expected to remain alive as long as +the file is. + +When the allocation of a new object aborts before installing the file it +will fput() the file and then go on to immediately kfree() the obj. This +causes a UAF once the workqueue completes the fput() and tries to +decrement the users refcount. + +Fix this by putting the core code in charge of the file lifetime, and call +__fput_sync() during abort to ensure that release() is called before +kfree. __fput_sync() is a bit too tricky to open code in all the object +implementations. Instead the objects tell the core code where the file +pointer is and the core will take care of the life cycle. + +If the object is successfully allocated then the file will hold a users +refcount and the iommufd_object cannot be destroyed. + +It is worth noting that close(); ioctl(IOMMU_DESTROY); doesn't have an +issue because close() is already using a synchronous version of fput(). + +The UAF looks like this: + + BUG: KASAN: slab-use-after-free in iommufd_eventq_fops_release+0x45/0xc0 drivers/iommu/iommufd/eventq.c:376 + Write of size 4 at addr ffff888059c97804 by task syz.0.46/6164 + + CPU: 0 UID: 0 PID: 6164 Comm: syz.0.46 Not tainted syzkaller #0 PREEMPT(full) + Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/18/2025 + Call Trace: + + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xcd/0x630 mm/kasan/report.c:482 + kasan_report+0xe0/0x110 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:183 [inline] + kasan_check_range+0x100/0x1b0 mm/kasan/generic.c:189 + instrument_atomic_read_write include/linux/instrumented.h:96 [inline] + atomic_fetch_sub_release include/linux/atomic/atomic-instrumented.h:400 [inline] + __refcount_dec include/linux/refcount.h:455 [inline] + refcount_dec include/linux/refcount.h:476 [inline] + iommufd_eventq_fops_release+0x45/0xc0 drivers/iommu/iommufd/eventq.c:376 + __fput+0x402/0xb70 fs/file_table.c:468 + task_work_run+0x14d/0x240 kernel/task_work.c:227 + resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] + exit_to_user_mode_loop+0xeb/0x110 kernel/entry/common.c:43 + exit_to_user_mode_prepare include/linux/irq-entry-common.h:225 [inline] + syscall_exit_to_user_mode_work include/linux/entry-common.h:175 [inline] + syscall_exit_to_user_mode include/linux/entry-common.h:210 [inline] + do_syscall_64+0x41c/0x4c0 arch/x86/entry/syscall_64.c:100 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Link: https://patch.msgid.link/r/1-v1-02cd136829df+31-iommufd_syz_fput_jgg@nvidia.com +Cc: stable@vger.kernel.org +Fixes: 07838f7fd529 ("iommufd: Add iommufd fault object") +Reviewed-by: Nicolin Chen +Reviewed-by: Nirmoy Das +Reviewed-by: Kevin Tian +Tested-by: Nicolin Chen +Reported-by: syzbot+80620e2d0d0a33b09f93@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/r/68c8583d.050a0220.2ff435.03a2.GAE@google.com +Signed-off-by: Jason Gunthorpe +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommufd/eventq.c | 9 ++------- + drivers/iommu/iommufd/main.c | 35 ++++++++++++++++++++++++++++++++--- + 2 files changed, 34 insertions(+), 10 deletions(-) + +--- a/drivers/iommu/iommufd/eventq.c ++++ b/drivers/iommu/iommufd/eventq.c +@@ -393,12 +393,12 @@ static int iommufd_eventq_init(struct io + const struct file_operations *fops) + { + struct file *filep; +- int fdno; + + spin_lock_init(&eventq->lock); + INIT_LIST_HEAD(&eventq->deliver); + init_waitqueue_head(&eventq->wait_queue); + ++ /* The filep is fput() by the core code during failure */ + filep = anon_inode_getfile(name, fops, eventq, O_RDWR); + if (IS_ERR(filep)) + return PTR_ERR(filep); +@@ -408,10 +408,7 @@ static int iommufd_eventq_init(struct io + eventq->filep = filep; + refcount_inc(&eventq->obj.users); + +- fdno = get_unused_fd_flags(O_CLOEXEC); +- if (fdno < 0) +- fput(filep); +- return fdno; ++ return get_unused_fd_flags(O_CLOEXEC); + } + + static const struct file_operations iommufd_fault_fops = +@@ -455,7 +452,6 @@ int iommufd_fault_alloc(struct iommufd_u + return 0; + out_put_fdno: + put_unused_fd(fdno); +- fput(fault->common.filep); + out_abort: + iommufd_object_abort_and_destroy(ucmd->ictx, &fault->common.obj); + +@@ -542,7 +538,6 @@ int iommufd_veventq_alloc(struct iommufd + + out_put_fdno: + put_unused_fd(fdno); +- fput(veventq->common.filep); + out_abort: + iommufd_object_abort_and_destroy(ucmd->ictx, &veventq->common.obj); + out_unlock_veventqs: +--- a/drivers/iommu/iommufd/main.c ++++ b/drivers/iommu/iommufd/main.c +@@ -23,6 +23,7 @@ + #include "iommufd_test.h" + + struct iommufd_object_ops { ++ size_t file_offset; + void (*destroy)(struct iommufd_object *obj); + void (*abort)(struct iommufd_object *obj); + }; +@@ -71,10 +72,30 @@ void iommufd_object_abort(struct iommufd + void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx, + struct iommufd_object *obj) + { +- if (iommufd_object_ops[obj->type].abort) +- iommufd_object_ops[obj->type].abort(obj); ++ const struct iommufd_object_ops *ops = &iommufd_object_ops[obj->type]; ++ ++ if (ops->file_offset) { ++ struct file **filep = ((void *)obj) + ops->file_offset; ++ ++ /* ++ * A file should hold a users refcount while the file is open ++ * and put it back in its release. The file should hold a ++ * pointer to obj in their private data. Normal fput() is ++ * deferred to a workqueue and can get out of order with the ++ * following kfree(obj). Using the sync version ensures the ++ * release happens immediately. During abort we require the file ++ * refcount is one at this point - meaning the object alloc ++ * function cannot do anything to allow another thread to take a ++ * refcount prior to a guaranteed success. ++ */ ++ if (*filep) ++ __fput_sync(*filep); ++ } ++ ++ if (ops->abort) ++ ops->abort(obj); + else +- iommufd_object_ops[obj->type].destroy(obj); ++ ops->destroy(obj); + iommufd_object_abort(ictx, obj); + } + +@@ -493,6 +514,12 @@ void iommufd_ctx_put(struct iommufd_ctx + } + EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, "IOMMUFD"); + ++#define IOMMUFD_FILE_OFFSET(_struct, _filep, _obj) \ ++ .file_offset = (offsetof(_struct, _filep) + \ ++ BUILD_BUG_ON_ZERO(!__same_type( \ ++ struct file *, ((_struct *)NULL)->_filep)) + \ ++ BUILD_BUG_ON_ZERO(offsetof(_struct, _obj))) ++ + static const struct iommufd_object_ops iommufd_object_ops[] = { + [IOMMUFD_OBJ_ACCESS] = { + .destroy = iommufd_access_destroy_object, +@@ -502,6 +529,7 @@ static const struct iommufd_object_ops i + }, + [IOMMUFD_OBJ_FAULT] = { + .destroy = iommufd_fault_destroy, ++ IOMMUFD_FILE_OFFSET(struct iommufd_fault, common.filep, common.obj), + }, + [IOMMUFD_OBJ_HWPT_PAGING] = { + .destroy = iommufd_hwpt_paging_destroy, +@@ -520,6 +548,7 @@ static const struct iommufd_object_ops i + [IOMMUFD_OBJ_VEVENTQ] = { + .destroy = iommufd_veventq_destroy, + .abort = iommufd_veventq_abort, ++ IOMMUFD_FILE_OFFSET(struct iommufd_veventq, common.filep, common.obj), + }, + [IOMMUFD_OBJ_VIOMMU] = { + .destroy = iommufd_viommu_destroy, diff --git a/queue-6.16/series b/queue-6.16/series index 97839511c0..f62c7a6445 100644 --- a/queue-6.16/series +++ b/queue-6.16/series @@ -138,3 +138,6 @@ wifi-iwlwifi-fix-byte-count-table-for-old-devices.patch wifi-iwlwifi-pcie-fix-byte-count-table-for-some-devices.patch sched_ext-idle-make-local-functions-static-in-ext_idle.c.patch sched_ext-idle-handle-migration-disabled-tasks-in-bpf-code.patch +spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch +spi-cadence-qspi-defer-runtime-support-on-socfpga-if-reset-bit-is-enabled.patch +iommufd-fix-race-during-abort-for-file-descriptors.patch diff --git a/queue-6.16/spi-cadence-qspi-defer-runtime-support-on-socfpga-if-reset-bit-is-enabled.patch b/queue-6.16/spi-cadence-qspi-defer-runtime-support-on-socfpga-if-reset-bit-is-enabled.patch new file mode 100644 index 0000000000..e3735b9482 --- /dev/null +++ b/queue-6.16/spi-cadence-qspi-defer-runtime-support-on-socfpga-if-reset-bit-is-enabled.patch @@ -0,0 +1,160 @@ +From stable+bounces-181994-greg=kroah.com@vger.kernel.org Mon Sep 29 21:43:08 2025 +From: Sasha Levin +Date: Mon, 29 Sep 2025 15:42:55 -0400 +Subject: spi: cadence-qspi: defer runtime support on socfpga if reset bit is enabled +To: stable@vger.kernel.org +Cc: Khairul Anuar Romli , Adrian Ng Ho Yin , Niravkumar L Rabara , Matthew Gerlach , Mark Brown , Sasha Levin +Message-ID: <20250929194255.332788-2-sashal@kernel.org> + +From: Khairul Anuar Romli + +[ Upstream commit 30dbc1c8d50f13c1581b49abe46fe89f393eacbf ] + +Enabling runtime PM allows the kernel to gate clocks and power to idle +devices. On SoCFPGA, a warm reset does not fully reinitialize these +domains.This leaves devices suspended and powered down, preventing U-Boot +or the kernel from reusing them after a warm reset, which breaks the boot +process. + +Fixes: 4892b374c9b7 ("mtd: spi-nor: cadence-quadspi: Add runtime PM support") +CC: stable@vger.kernel.org # 6.12+ +Signed-off-by: Khairul Anuar Romli +Signed-off-by: Adrian Ng Ho Yin +Reviewed-by: Niravkumar L Rabara +Reviewed-by: Matthew Gerlach +Link: https://patch.msgid.link/910aad68ba5d948919a7b90fa85a2fadb687229b.1757491372.git.khairul.anuar.romli@altera.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-cadence-quadspi.c | 57 +++++++++++++++++++++++++------------- + 1 file changed, 38 insertions(+), 19 deletions(-) + +--- a/drivers/spi/spi-cadence-quadspi.c ++++ b/drivers/spi/spi-cadence-quadspi.c +@@ -46,6 +46,7 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SP + #define CQSPI_DMA_SET_MASK BIT(7) + #define CQSPI_SUPPORT_DEVICE_RESET BIT(8) + #define CQSPI_DISABLE_STIG_MODE BIT(9) ++#define CQSPI_DISABLE_RUNTIME_PM BIT(10) + + /* Capabilities */ + #define CQSPI_SUPPORTS_OCTAL BIT(0) +@@ -1468,14 +1469,17 @@ static int cqspi_exec_mem_op(struct spi_ + int ret; + struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller); + struct device *dev = &cqspi->pdev->dev; ++ const struct cqspi_driver_platdata *ddata = of_device_get_match_data(dev); + + if (refcount_read(&cqspi->inflight_ops) == 0) + return -ENODEV; + +- ret = pm_runtime_resume_and_get(dev); +- if (ret) { +- dev_err(&mem->spi->dev, "resume failed with %d\n", ret); +- return ret; ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret) { ++ dev_err(&mem->spi->dev, "resume failed with %d\n", ret); ++ return ret; ++ } + } + + if (!refcount_read(&cqspi->refcount)) +@@ -1491,8 +1495,10 @@ static int cqspi_exec_mem_op(struct spi_ + + ret = cqspi_mem_process(mem, op); + +- pm_runtime_mark_last_busy(dev); +- pm_runtime_put_autosuspend(dev); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ } + + if (ret) + dev_err(&mem->spi->dev, "operation failed with %d\n", ret); +@@ -1986,11 +1992,12 @@ static int cqspi_probe(struct platform_d + goto probe_setup_failed; + } + +- pm_runtime_enable(dev); +- +- pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); +- pm_runtime_use_autosuspend(dev); +- pm_runtime_get_noresume(dev); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { ++ pm_runtime_enable(dev); ++ pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_get_noresume(dev); ++ } + + ret = spi_register_controller(host); + if (ret) { +@@ -1998,13 +2005,17 @@ static int cqspi_probe(struct platform_d + goto probe_setup_failed; + } + +- pm_runtime_mark_last_busy(dev); +- pm_runtime_put_autosuspend(dev); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { ++ pm_runtime_put_autosuspend(dev); ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ } + + return 0; + probe_setup_failed: + cqspi_controller_enable(cqspi, 0); +- pm_runtime_disable(dev); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) ++ pm_runtime_disable(dev); + probe_reset_failed: + if (cqspi->is_jh7110) + cqspi_jh7110_disable_clk(pdev, cqspi); +@@ -2015,7 +2026,11 @@ probe_clk_failed: + + static void cqspi_remove(struct platform_device *pdev) + { ++ const struct cqspi_driver_platdata *ddata; + struct cqspi_st *cqspi = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ ++ ddata = of_device_get_match_data(dev); + + refcount_set(&cqspi->refcount, 0); + +@@ -2028,14 +2043,17 @@ static void cqspi_remove(struct platform + if (cqspi->rx_chan) + dma_release_channel(cqspi->rx_chan); + +- if (pm_runtime_get_sync(&pdev->dev) >= 0) +- clk_disable(cqspi->clk); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) ++ if (pm_runtime_get_sync(&pdev->dev) >= 0) ++ clk_disable(cqspi->clk); + + if (cqspi->is_jh7110) + cqspi_jh7110_disable_clk(pdev, cqspi); + +- pm_runtime_put_sync(&pdev->dev); +- pm_runtime_disable(&pdev->dev); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ } + } + + static int cqspi_runtime_suspend(struct device *dev) +@@ -2114,7 +2132,8 @@ static const struct cqspi_driver_platdat + .quirks = CQSPI_DISABLE_DAC_MODE + | CQSPI_NO_SUPPORT_WR_COMPLETION + | CQSPI_SLOW_SRAM +- | CQSPI_DISABLE_STIG_MODE, ++ | CQSPI_DISABLE_STIG_MODE ++ | CQSPI_DISABLE_RUNTIME_PM, + }; + + static const struct cqspi_driver_platdata versal_ospi = { diff --git a/queue-6.16/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch b/queue-6.16/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch new file mode 100644 index 0000000000..dcae7f1a20 --- /dev/null +++ b/queue-6.16/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch @@ -0,0 +1,124 @@ +From stable+bounces-181993-greg=kroah.com@vger.kernel.org Mon Sep 29 21:43:06 2025 +From: Sasha Levin +Date: Mon, 29 Sep 2025 15:42:54 -0400 +Subject: spi: cadence-quadspi: Implement refcount to handle unbind during busy +To: stable@vger.kernel.org +Cc: Khairul Anuar Romli , Matthew Gerlach , Niravkumar L Rabara , Mark Brown , Sasha Levin +Message-ID: <20250929194255.332788-1-sashal@kernel.org> + +From: Khairul Anuar Romli + +[ Upstream commit 7446284023e8ef694fb392348185349c773eefb3 ] + +driver support indirect read and indirect write operation with +assumption no force device removal(unbind) operation. However +force device removal(removal) is still available to root superuser. + +Unbinding driver during operation causes kernel crash. This changes +ensure driver able to handle such operation for indirect read and +indirect write by implementing refcount to track attached devices +to the controller and gracefully wait and until attached devices +remove operation completed before proceed with removal operation. + +Signed-off-by: Khairul Anuar Romli +Reviewed-by: Matthew Gerlach +Reviewed-by: Niravkumar L Rabara +Link: https://patch.msgid.link/8704fd6bd2ff4d37bba4a0eacf5eba3ba001079e.1756168074.git.khairul.anuar.romli@altera.com +Signed-off-by: Mark Brown +Stable-dep-of: 30dbc1c8d50f ("spi: cadence-qspi: defer runtime support on socfpga if reset bit is enabled") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-cadence-quadspi.c | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +--- a/drivers/spi/spi-cadence-quadspi.c ++++ b/drivers/spi/spi-cadence-quadspi.c +@@ -108,6 +108,8 @@ struct cqspi_st { + + bool is_jh7110; /* Flag for StarFive JH7110 SoC */ + bool disable_stig_mode; ++ refcount_t refcount; ++ refcount_t inflight_ops; + + const struct cqspi_driver_platdata *ddata; + }; +@@ -735,6 +737,9 @@ static int cqspi_indirect_read_execute(s + u8 *rxbuf_end = rxbuf + n_rx; + int ret = 0; + ++ if (!refcount_read(&cqspi->refcount)) ++ return -ENODEV; ++ + writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); + writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); + +@@ -1071,6 +1076,9 @@ static int cqspi_indirect_write_execute( + unsigned int write_bytes; + int ret; + ++ if (!refcount_read(&cqspi->refcount)) ++ return -ENODEV; ++ + writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); + writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); + +@@ -1461,12 +1469,26 @@ static int cqspi_exec_mem_op(struct spi_ + struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller); + struct device *dev = &cqspi->pdev->dev; + ++ if (refcount_read(&cqspi->inflight_ops) == 0) ++ return -ENODEV; ++ + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(&mem->spi->dev, "resume failed with %d\n", ret); + return ret; + } + ++ if (!refcount_read(&cqspi->refcount)) ++ return -EBUSY; ++ ++ refcount_inc(&cqspi->inflight_ops); ++ ++ if (!refcount_read(&cqspi->refcount)) { ++ if (refcount_read(&cqspi->inflight_ops)) ++ refcount_dec(&cqspi->inflight_ops); ++ return -EBUSY; ++ } ++ + ret = cqspi_mem_process(mem, op); + + pm_runtime_mark_last_busy(dev); +@@ -1475,6 +1497,9 @@ static int cqspi_exec_mem_op(struct spi_ + if (ret) + dev_err(&mem->spi->dev, "operation failed with %d\n", ret); + ++ if (refcount_read(&cqspi->inflight_ops) > 1) ++ refcount_dec(&cqspi->inflight_ops); ++ + return ret; + } + +@@ -1926,6 +1951,9 @@ static int cqspi_probe(struct platform_d + } + } + ++ refcount_set(&cqspi->refcount, 1); ++ refcount_set(&cqspi->inflight_ops, 1); ++ + ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0, + pdev->name, cqspi); + if (ret) { +@@ -1989,6 +2017,11 @@ static void cqspi_remove(struct platform + { + struct cqspi_st *cqspi = platform_get_drvdata(pdev); + ++ refcount_set(&cqspi->refcount, 0); ++ ++ if (!refcount_dec_and_test(&cqspi->inflight_ops)) ++ cqspi_wait_idle(cqspi); ++ + spi_unregister_controller(cqspi->host); + cqspi_controller_enable(cqspi, 0); +