From: Greg Kroah-Hartman Date: Mon, 20 Jul 2026 15:30:59 +0000 (+0200) Subject: 6.18-stable patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=42173a867bb167b83af4bd93ede80e71415e726f;p=thirdparty%2Fkernel%2Fstable-queue.git 6.18-stable patches added patches: accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch block-fix-race-in-blk_time_get_ns-returning-0.patch block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch bpf-add-missing-access_ok-call-to-copy_user_syms.patch bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch bus-mhi-host-pci_generic-fix-the-physical-function-check.patch can-bcm-add-missing-rcu-list-annotations-and-operations.patch can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch dm-integrity-don-t-increment-hash_offset-twice.patch dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch dm-integrity-fix-leaking-uninitialized-kernel-memory.patch dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch dm-pcache-reject-option-groups-without-values.patch dm-stats-fix-dm_jiffies_to_msec64.patch dm-stats-fix-merge-accounting.patch dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch dm-verity-fix-a-possible-null-pointer-dereference.patch dm-verity-increase-sprintf-buffer-size.patch dm-verity-make-error-counter-atomic.patch dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch dmaengine-tegra-fix-burst-size-calculation.patch fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch ice-fix-ice_init_link-error-return-preventing-probe.patch irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch mtd-spi-nor-swp-improve-locking-user-experience.patch net-sparx5-unregister-blocking-notifier-on-init-failure.patch net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch nfs-charge-unstable-writes-by-request-size-not-folio-size.patch nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch nvmet-auth-reject-short-auth_receive-buffers.patch nvmet-fix-refcount-leak-in-nvmet_sq_create.patch nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch openrisc-fix-jump_label-smp-syncing.patch pkey-move-keytype-check-from-pkey-api-to-handler.patch platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch platform-x86-isst-restore-sst-pp-control-to-all-domains.patch s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch scsi-sg-report-request-table-problems-when-any-status-is-set.patch scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch selftests-bpf-cover-negative-buffer-pointer-offsets.patch smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch sunrpc-fix-uninitialized-xprt_create_args-structure.patch taskstats-retain-dead-thread-stats-in-tgid-queries.patch tcp-decrement-tcp_md5_needed-static-branch.patch tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch tpm-make-the-tpm-character-devices-non-seekable.patch tpm-restore-timeout-for-key-creation-commands.patch tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch xen-gntdev-fix-error-handling-in-ioctl.patch xfrm-nat_keepalive-avoid-double-free-on-send-error.patch xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch --- diff --git a/queue-6.18/accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch b/queue-6.18/accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch new file mode 100644 index 0000000000..803493dcab --- /dev/null +++ b/queue-6.18/accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch @@ -0,0 +1,46 @@ +From 63bbf9ac5dde2ba85e7b39d0a0b7d540e6252ba4 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Thu, 25 Jun 2026 19:32:39 +0800 +Subject: accel/amdxdna: Fix use-after-free in amdxdna_gem_dmabuf_mmap() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Wentao Liang + +commit 63bbf9ac5dde2ba85e7b39d0a0b7d540e6252ba4 upstream. + +When vm_insert_pages() fails, the error path calls vma->vm_ops->close(vma) +which internally calls drm_gem_vm_close() → drm_gem_object_put(), +releasing the GEM object reference acquired at the start of the function. +However, the close_vma label then falls through to put_obj, which calls +drm_gem_object_put() a second time on the same object. + +If the first put releases the last reference, the object is freed and the +second put accesses freed memory, causing a use-after-free. + +Fix by returning directly from close_vma instead of falling through to +put_obj, since the close handler already performs all necessary cleanup +including the object put. + +Cc: stable@vger.kernel.org +Fixes: e486147c912f ("accel/amdxdna: Add BO import and export") +Signed-off-by: Wentao Liang +Reviewed-by: Lizhi Hou +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260625113239.49764-1-vulab@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +--- + drivers/accel/amdxdna/amdxdna_gem.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/accel/amdxdna/amdxdna_gem.c ++++ b/drivers/accel/amdxdna/amdxdna_gem.c +@@ -374,6 +374,7 @@ static int amdxdna_gem_dmabuf_mmap(struc + + close_vma: + vma->vm_ops->close(vma); ++ return ret; + put_obj: + drm_gem_object_put(gobj); + return ret; diff --git a/queue-6.18/accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch b/queue-6.18/accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch new file mode 100644 index 0000000000..018f4f2daf --- /dev/null +++ b/queue-6.18/accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch @@ -0,0 +1,50 @@ +From ddb44baed257560f192b145ed36cf8c0a412de47 Mon Sep 17 00:00:00 2001 +From: Jhonraushan +Date: Wed, 15 Jul 2026 13:12:06 +0530 +Subject: accel/ivpu: Reject firmware log with size smaller than header + +From: Jhonraushan + +commit ddb44baed257560f192b145ed36cf8c0a412de47 upstream. + +fw_log_from_bo() validates the tracing buffer header_size and that the +log fits within the BO, but never checks that log->size is at least +log->header_size. fw_log_print_buffer() then computes: + + u32 data_size = log->size - log->header_size; + +which underflows to a near-U32_MAX value when firmware reports a log whose +size is smaller than its header. That huge data_size defeats the +log_start/log_end bounds clamps added by commit dd1311bcf0e6 ("accel/ivpu: +Add bounds checks for firmware log indices"), so fw_log_print_lines() reads +far past the small real data region of the BO. A size of 0 also makes +fw_log_from_bo() advance the offset by 0, causing the callers to loop +forever on the same header. + +Reject logs whose size is smaller than the header (which also rejects +size == 0). + +Fixes: d4e4257afa6e ("accel/ivpu: Add firmware tracing support") +Cc: stable@vger.kernel.org +Signed-off-by: Jhonraushan +Reviewed-by: Karol Wachowski +Signed-off-by: Karol Wachowski +Link: https://patch.msgid.link/20260715074206.867712-1-raushan.jhon@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/accel/ivpu/ivpu_fw_log.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/accel/ivpu/ivpu_fw_log.c ++++ b/drivers/accel/ivpu/ivpu_fw_log.c +@@ -43,6 +43,10 @@ static int fw_log_from_bo(struct ivpu_de + ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size); + return -EINVAL; + } ++ if (log->size < log->header_size) { ++ ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size); ++ return -EINVAL; ++ } + if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) { + ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size); + return -EINVAL; diff --git a/queue-6.18/block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch b/queue-6.18/block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch new file mode 100644 index 0000000000..fc24075142 --- /dev/null +++ b/queue-6.18/block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch @@ -0,0 +1,41 @@ +From 4f919141be38ea2b1314e3a531b7b998eb64e8bc Mon Sep 17 00:00:00 2001 +From: Yitang Yang +Date: Tue, 16 Jun 2026 23:51:29 +0800 +Subject: block: fix IORING_URING_CMD_REISSUE flags check in blkdev_uring_cmd + +From: Yitang Yang + +commit 4f919141be38ea2b1314e3a531b7b998eb64e8bc upstream. + +blkdev_uring_cmd() checks IORING_URING_CMD_REISSUE to determine whether +this is the first issue. However, this flag lives in cmd->flags instead +of issue_flags. + +Coincidentally, IO_URING_F_NONBLOCK shares bit 31 with +IORING_URING_CMD_REISSUE. As a result, the SQE read was never performed, +bic->len remained zero, and every BLOCK_URING_CMD_DISCARD failed with +-EINVAL. + +Fix it by checking cmd->flags as intended. + +Cc: stable@vger.kernel.org +Fixes: 212ec34e4e72 ("block: only read from sqe on initial invocation of blkdev_uring_cmd") +Signed-off-by: Yitang Yang +Link: https://patch.msgid.link/20260616155129.406057-1-yi1tang.yang@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/ioctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -857,7 +857,7 @@ int blkdev_uring_cmd(struct io_uring_cmd + u32 cmd_op = cmd->cmd_op; + + /* Read what we need from the SQE on the first issue */ +- if (!(issue_flags & IORING_URING_CMD_REISSUE)) { ++ if (!(cmd->flags & IORING_URING_CMD_REISSUE)) { + const struct io_uring_sqe *sqe = cmd->sqe; + + if (unlikely(sqe->ioprio || sqe->__pad1 || sqe->len || diff --git a/queue-6.18/block-fix-race-in-blk_time_get_ns-returning-0.patch b/queue-6.18/block-fix-race-in-blk_time_get_ns-returning-0.patch new file mode 100644 index 0000000000..6c2b7c04e6 --- /dev/null +++ b/queue-6.18/block-fix-race-in-blk_time_get_ns-returning-0.patch @@ -0,0 +1,90 @@ +From 691b052139c94ee6640ac39e0b764dd3867897c0 Mon Sep 17 00:00:00 2001 +From: Mike Waychison +Date: Wed, 15 Jul 2026 15:29:50 -0400 +Subject: block: fix race in blk_time_get_ns() returning 0 + +From: Mike Waychison + +commit 691b052139c94ee6640ac39e0b764dd3867897c0 upstream. + +blk_time_get_ns() populates the per-plug cached timestamp and then +returns it by re-reading the field: + + if (!plug->cur_ktime) { + plug->cur_ktime = ktime_get_ns(); + current->flags |= PF_BLOCK_TS; + } + return plug->cur_ktime; + +This is problematic when the compiler emits the final +"return plug->cur_ktime" as a reload from memory, after PF_BLOCK_TS has +already been set. + +Since the cached timestamp is now invalidated from finish_task_switch() +(fad156c2af22 "block: invalidate cached plug timestamp after task +switch"), a task preempted between setting PF_BLOCK_TS and that reload +has plug->cur_ktime zeroed by blk_plug_invalidate_ts() when it is +scheduled back in. The reload then returns 0. + +A 0 handed back here is stored as a start timestamp -- e.g. +blk_account_io_start() writes it to rq->start_time_ns -- and later +subtracted from "now". blk_account_io_done() then adds (now - 0), i.e. +roughly the system uptime, to the per-group nsecs[] counters. On an +otherwise idle, healthy device this appears as sudden ~uptime-sized jumps +in the diskstats time fields (write_ticks/discard_ticks/time_in_queue). + +The solution is to be explicit in our reads and writes to this field +that is preemption volatile. We also add a barrier() to ensure that any +setting of PF_BLOCK_TS is ordered to happen after the cur_ktime update. + +This issue was discovered using AI-assisted kprobes looking for paths +that were leaking zeroed timestamps in a live system, based on the +observation that we were sometimes seeing uptime-sized jumps in kernel +exported counters. This was flagged by NodeDiskIOSaturation +prometheus alerts that started firing on all hosts post 7.1.3 kernel +upgrade, due to node-exporter now exporting a nonsensical +node_disk_io_time_weighted_seconds_total. + +Fixes: fad156c2af22 ("block: invalidate cached plug timestamp after task switch") +Cc: stable@vger.kernel.org +Signed-off-by: Mike Waychison +Assisted-by: Claude:claude-opus-4.8 +Link: https://patch.msgid.link/20260715192950.2488921-1-mike@waychison.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/blk.h | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +--- a/block/blk.h ++++ b/block/blk.h +@@ -699,6 +699,7 @@ static inline int req_ref_read(struct re + static inline u64 blk_time_get_ns(void) + { + struct blk_plug *plug = current->plug; ++ u64 now; + + if (!plug || !in_task()) + return ktime_get_ns(); +@@ -707,12 +708,18 @@ static inline u64 blk_time_get_ns(void) + * 0 could very well be a valid time, but rather than flag "this is + * a valid timestamp" separately, just accept that we'll do an extra + * ktime_get_ns() if we just happen to get 0 as the current time. ++ * ++ * cur_ktime can be zeroed by pre-emption the moment PF_BLOCK_TS is set. + */ +- if (!plug->cur_ktime) { +- plug->cur_ktime = ktime_get_ns(); ++ now = READ_ONCE(plug->cur_ktime); ++ if (!now) { ++ now = ktime_get_ns(); ++ WRITE_ONCE(plug->cur_ktime, now); ++ /* Ensure PF_BLOCK_TS is set after cur_ktime. */ ++ barrier(); + current->flags |= PF_BLOCK_TS; + } +- return plug->cur_ktime; ++ return now; + } + + static inline ktime_t blk_time_get(void) diff --git a/queue-6.18/block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch b/queue-6.18/block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch new file mode 100644 index 0000000000..0020ee605e --- /dev/null +++ b/queue-6.18/block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch @@ -0,0 +1,61 @@ +From 181bb9c9eae4f69fe510a62a42c2932d0314a800 Mon Sep 17 00:00:00 2001 +From: Connor Williamson +Date: Mon, 15 Jun 2026 13:07:15 +0000 +Subject: block: remove redundant GD_NEED_PART_SCAN in add_disk_final() + +From: Connor Williamson + +commit 181bb9c9eae4f69fe510a62a42c2932d0314a800 upstream. + +add_disk_final() sets GD_NEED_PART_SCAN before calling bdev_add(), +then calls disk_scan_partitions() which sets the flag itself. The +early set is redundant and introduces a race. + +Between bdev_add() and disk_scan_partitions(), concurrent openers +(multipathd, blkid, LVM) see the flag in blkdev_get_whole() and +trigger bdev_disk_changed(). When disk_scan_partitions() then runs, +it calls bdev_disk_changed() again, dropping the partitions the +concurrent opener already created before re-adding them, which can +result in transient partition disappearances. + +The race is observable by inserting an msleep() between bdev_add() +and disk_scan_partitions() while running concurrent open() calls +during device bind. Without artificial delay, it manifests under +scheduling pressure during boot on systems with aggressive device +scanners (multipathd, systemd-udevd). + +Therefore, do not set GD_NEED_PART_SCAN in add_disk_final(). Other +GD_NEED_PART_SCAN consumers (blkdev_get_whole(), +sd_need_revalidate()) should not be affected as the flag +is set internally by disk_scan_partitions(). + +The retry-on-next-open intention from commit e5cfefa97bcc +("block: fix scan partition for exclusively open device again") +should also not be affected as the early return paths in +disk_scan_partitions() should be unreachable at device registration +time (bd_holder is NULL and open_partitions is zero). + +Fixes: e5cfefa97bcc ("block: fix scan partition for exclusively open device again") +Cc: stable@vger.kernel.org +Signed-off-by: Connor Williamson +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260615130715.53693-1-connordw@amazon.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/genhd.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -407,10 +407,6 @@ static void add_disk_final(struct gendis + struct device *ddev = disk_to_dev(disk); + + if (!(disk->flags & GENHD_FL_HIDDEN)) { +- /* Make sure the first partition scan will be proceed */ +- if (get_capacity(disk) && disk_has_partscan(disk)) +- set_bit(GD_NEED_PART_SCAN, &disk->state); +- + bdev_add(disk->part0, ddev->devt); + if (get_capacity(disk)) + disk_scan_partitions(disk, BLK_OPEN_READ); diff --git a/queue-6.18/bpf-add-missing-access_ok-call-to-copy_user_syms.patch b/queue-6.18/bpf-add-missing-access_ok-call-to-copy_user_syms.patch new file mode 100644 index 0000000000..ae157dd345 --- /dev/null +++ b/queue-6.18/bpf-add-missing-access_ok-call-to-copy_user_syms.patch @@ -0,0 +1,58 @@ +From d5dc200c3a3f217de072af269dd90adddf90e48d Mon Sep 17 00:00:00 2001 +From: Jiri Olsa +Date: Tue, 16 Jun 2026 10:30:56 +0200 +Subject: bpf: Add missing access_ok call to copy_user_syms + +From: Jiri Olsa + +commit d5dc200c3a3f217de072af269dd90adddf90e48d upstream. + +As reported by sashiko we use __get_user without prior access_ok call on the +user space pointer. Adding the missing call for the whole pointer array. + +Plus removing the err check in the error path, because it's not needed and +also we can return -ENOMEM directly from the first kvmalloc_array fail path. + +Cc: stable@vger.kernel.org +[1] https://lore.kernel.org/bpf/20260611115503.AC16D1F00893@smtp.kernel.org/ +Fixes: 0236fec57a15 ("bpf: Resolve symbols with ftrace_lookup_symbols for kprobe multi link") +Reported-by: Sashiko +Closes: https://lore.kernel.org/bpf/20260611115503.AC16D1F00893@smtp.kernel.org/ +Signed-off-by: Jiri Olsa +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260616083056.405652-1-jolsa@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/bpf_trace.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2318,9 +2318,12 @@ static int copy_user_syms(struct user_sy + int err = -ENOMEM; + unsigned int i; + ++ if (!access_ok(usyms, cnt * sizeof(*usyms))) ++ return -EFAULT; ++ + syms = kvmalloc_array(cnt, sizeof(*syms), GFP_KERNEL); + if (!syms) +- goto error; ++ return -ENOMEM; + + buf = kvmalloc_array(cnt, KSYM_NAME_LEN, GFP_KERNEL); + if (!buf) +@@ -2345,10 +2348,8 @@ static int copy_user_syms(struct user_sy + return 0; + + error: +- if (err) { +- kvfree(syms); +- kvfree(buf); +- } ++ kvfree(syms); ++ kvfree(buf); + return err; + } + diff --git a/queue-6.18/bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch b/queue-6.18/bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch new file mode 100644 index 0000000000..d359005144 --- /dev/null +++ b/queue-6.18/bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch @@ -0,0 +1,66 @@ +From 9b51a6155d14389876916726430da30eabb1d4ed Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Fri, 26 Jun 2026 17:52:52 +0200 +Subject: bpf,fork: wipe ->bpf_storage before bailouts that access it + +From: Jann Horn + +commit 9b51a6155d14389876916726430da30eabb1d4ed upstream. + +Currently, copy_process() can bail out to free_task() before p->bpf_storage +has been initialized, with this call graph (shown here for the +!CONFIG_MEMCG case): + +copy_process + dup_task_struct + arch_dup_task_struct + [copies the entire task_struct, including ->bpf_storage member] + [RLIMIT_NPROC check fails] + delayed_free_task + free_task + bpf_task_storage_free + rcu_dereference(task->bpf_storage) + bpf_local_storage_destroy + +In this case, the nascent task's ->bpf_storage member that +bpf_local_storage_destroy() operates on is a plain copy of the parent's +->bpf_storage pointer, not a real initialized pointer. +This leads to badness (kernel hangs, UAF). + +This is reachable as long as the process calling fork() has been inserted +into a task storage map. + +Cc: stable@kernel.org +Fixes: a10787e6d58c ("bpf: Enable task local storage for tracing programs") +Signed-off-by: Jann Horn +Signed-off-by: Andrii Nakryiko +Signed-off-by: Greg Kroah-Hartman +--- + kernel/fork.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -961,6 +961,11 @@ static struct task_struct *dup_task_stru + tsk->mm_cid_active = 0; + tsk->migrate_from_cpu = -1; + #endif ++ ++#ifdef CONFIG_BPF_SYSCALL ++ RCU_INIT_POINTER(tsk->bpf_storage, NULL); ++ tsk->bpf_ctx = NULL; ++#endif + return tsk; + + free_stack: +@@ -2143,10 +2148,6 @@ __latent_entropy struct task_struct *cop + p->sequential_io = 0; + p->sequential_io_avg = 0; + #endif +-#ifdef CONFIG_BPF_SYSCALL +- RCU_INIT_POINTER(p->bpf_storage, NULL); +- p->bpf_ctx = NULL; +-#endif + + unwind_task_init(p); + diff --git a/queue-6.18/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch b/queue-6.18/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch new file mode 100644 index 0000000000..974c11940d --- /dev/null +++ b/queue-6.18/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch @@ -0,0 +1,47 @@ +From 5e0b273e0a62cc04ec338c7b502797c66c2ed42a Mon Sep 17 00:00:00 2001 +From: Tristan Madani +Date: Mon, 22 Jun 2026 23:01:22 +0000 +Subject: bpf: Reset register bounds before narrowing retval range in check_mem_access() + +From: Tristan Madani + +commit 5e0b273e0a62cc04ec338c7b502797c66c2ed42a upstream. + +When the BPF verifier processes a context load of an LSM hook return +value, it calls __mark_reg_s32_range() to narrow the register to the +hook's valid range. However, __mark_reg_s32_range() intersects the new +range with the register's existing bounds using max_t()/min_t() rather +than replacing them. + +If the destination register carries stale bounds from a prior instruction +(e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than +reality. The verifier then believes it knows the register's exact value, +while at runtime the actual hook return value is loaded, creating a +verifier/runtime mismatch that can be used to bypass BPF memory safety +checks. + +The else branch already calls mark_reg_unknown() to reset register state +before any narrowing. Apply the same reset in the is_retval path so +stale bounds are cleared before __mark_reg_s32_range() intersects. + +Fixes: 5d99e198be27 ("bpf, lsm: Add check for BPF LSM return value") +Cc: stable@vger.kernel.org +Signed-off-by: Tristan Madani +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260622230123.3695446-2-tristmd@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/verifier.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -7672,6 +7672,7 @@ static int check_mem_access(struct bpf_v + */ + if (info.reg_type == SCALAR_VALUE) { + if (info.is_retval && get_func_retval_range(env->prog, &range)) { ++ mark_reg_unknown(env, regs, value_regno); + err = __mark_reg_s32_range(env, regs, value_regno, + range.minval, range.maxval); + if (err) diff --git a/queue-6.18/bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch b/queue-6.18/bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch new file mode 100644 index 0000000000..5a35dc7fac --- /dev/null +++ b/queue-6.18/bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch @@ -0,0 +1,39 @@ +From 519ddf194b158b91439319f6b977b8a465fda0fb Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Mon, 2 Mar 2026 14:26:12 +0530 +Subject: bus: mhi: ep: Protect mhi_ep_handle_syserr() in the error path + +From: Manivannan Sadhasivam + +commit 519ddf194b158b91439319f6b977b8a465fda0fb upstream. + +All the callers of mhi_ep_handle_syserr() except mhi_ep_process_cmd_ring() +are holding the 'state_lock' to avoid the race in setting the MHI state. So +do the same in mhi_ep_process_cmd_ring() for sanity. + +Fixes: e827569062a8 ("bus: mhi: ep: Add support for processing command rings") +Cc: stable@vger.kernel.org # 5.18 +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260302085612.18725-1-manivannan.sadhasivam@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/ep/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c +index 5330b03dc636..9db2a2a2c913 100644 +--- a/drivers/bus/mhi/ep/main.c ++++ b/drivers/bus/mhi/ep/main.c +@@ -232,7 +232,9 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele + ret = mhi_ep_create_device(mhi_cntrl, ch_id); + if (ret) { + dev_err(dev, "Error creating device for channel (%u)\n", ch_id); ++ mutex_lock(&mhi_cntrl->state_lock); + mhi_ep_handle_syserr(mhi_cntrl); ++ mutex_unlock(&mhi_cntrl->state_lock); + return ret; + } + } +-- +2.55.0 + diff --git a/queue-6.18/bus-mhi-host-pci_generic-fix-the-physical-function-check.patch b/queue-6.18/bus-mhi-host-pci_generic-fix-the-physical-function-check.patch new file mode 100644 index 0000000000..bd65696a19 --- /dev/null +++ b/queue-6.18/bus-mhi-host-pci_generic-fix-the-physical-function-check.patch @@ -0,0 +1,121 @@ +From 32845111e8ea6ef5e837b6d25080e69e99bd4561 Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Wed, 27 May 2026 10:46:13 +0200 +Subject: bus: mhi: host: pci_generic: Fix the physical function check + +From: Manivannan Sadhasivam + +commit 32845111e8ea6ef5e837b6d25080e69e99bd4561 upstream. + +Commit b4d01c5b9a9d ("bus: mhi: host: pci_generic: Read SUBSYSTEM_VENDOR_ID +for VF's to check status") added the check for physical function by +checking for 'pdev->is_physfn. But 'pdev->is_physfn' is only set for the +physical function of a SR-IOV capable device. But for the non-SR-IOV device +this variable will be 0. So this check ended up breaking the health check +functionality for all non-SR-IOV devices. + +Fix it by checking for '!pdev->is_virtfn' to make sure that the check is +only skipped for virtual functions. + +Cc: stable@vger.kernel.org # 6.18 +Reported-by: Slark Xiao +Tested-by: Slark Xiao +Fixes: b4d01c5b9a9d ("bus: mhi: host: pci_generic: Read SUBSYSTEM_VENDOR_ID for VF's to check status") +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/host/pci_generic.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -1197,7 +1197,7 @@ static void mhi_pci_recovery_work(struct + + dev_warn(&pdev->dev, "device recovery started\n"); + +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + timer_delete(&mhi_pdev->health_check_timer); + + pm_runtime_forbid(&pdev->dev); +@@ -1227,7 +1227,7 @@ static void mhi_pci_recovery_work(struct + + set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); + +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + + return; +@@ -1318,7 +1318,7 @@ static int mhi_pci_probe(struct pci_dev + mhi_cntrl_config = info->config; + + /* Initialize health check monitor only for Physical functions */ +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + timer_setup(&mhi_pdev->health_check_timer, health_check, 0); + + mhi_cntrl = &mhi_pdev->mhi_cntrl; +@@ -1340,7 +1340,7 @@ static int mhi_pci_probe(struct pci_dev + mhi_cntrl->mru = info->mru_default; + mhi_cntrl->name = info->name; + +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + mhi_pdev->reset_on_remove = info->reset_on_remove; + + if (info->edl_trigger) +@@ -1389,7 +1389,7 @@ static int mhi_pci_probe(struct pci_dev + set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); + + /* start health check */ +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + + /* Allow runtime suspend only if both PME from D3Hot and M3 are supported */ +@@ -1417,7 +1417,7 @@ static void mhi_pci_remove(struct pci_de + + pci_disable_sriov(pdev); + +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + timer_delete_sync(&mhi_pdev->health_check_timer); + cancel_work_sync(&mhi_pdev->recovery_work); + +@@ -1449,7 +1449,7 @@ static void mhi_pci_reset_prepare(struct + + dev_info(&pdev->dev, "reset\n"); + +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + timer_delete(&mhi_pdev->health_check_timer); + + /* Clean up MHI state */ +@@ -1495,7 +1495,7 @@ static void mhi_pci_reset_done(struct pc + } + + set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + } + +@@ -1561,7 +1561,7 @@ static int __maybe_unused mhi_pci_runti + if (test_and_set_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return 0; + +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + timer_delete(&mhi_pdev->health_check_timer); + + cancel_work_sync(&mhi_pdev->recovery_work); +@@ -1614,7 +1614,7 @@ static int __maybe_unused mhi_pci_runtim + } + + /* Resume health check */ +- if (pdev->is_physfn) ++ if (!pdev->is_virtfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + + /* It can be a remote wakeup (no mhi runtime_get), update access time */ diff --git a/queue-6.18/can-bcm-add-missing-rcu-list-annotations-and-operations.patch b/queue-6.18/can-bcm-add-missing-rcu-list-annotations-and-operations.patch new file mode 100644 index 0000000000..96c094a4e5 --- /dev/null +++ b/queue-6.18/can-bcm-add-missing-rcu-list-annotations-and-operations.patch @@ -0,0 +1,122 @@ +From 7b2c3eabc4dafc062a25e10711154f2107526a78 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Tue, 14 Jul 2026 18:55:27 +0200 +Subject: can: bcm: add missing rcu list annotations and operations + +From: Oliver Hartkopp + +commit 7b2c3eabc4dafc062a25e10711154f2107526a78 upstream. + +sashiko-bot remarked the missing use of list_add_rcu() in +bcm_[rx|tx]_setup() to have a proper initialized bcm_op structure +when bcm_proc_show() traverses the bcm_op's under rcu_read_lock(). + +To cover all initial settings of the bcm_op's the list_add_rcu() calls +are moved to the end of the setup code. + +While at it, also fix the mirroring removal side: bcm_release() called +bcm_remove_op() - which frees the op via call_rcu() - on ops that were +still linked in bo->tx_ops/bo->rx_ops, without list_del_rcu() first. +Unlink each op with list_del_rcu() before handing it to bcm_remove_op(), +matching the existing pattern in bcm_delete_tx_op()/bcm_delete_rx_op(). + +Reported-by: sashiko-reviews@lists.linux.dev +Closes: https://lore.kernel.org/linux-can/20260610094654.A1FFE1F00893@smtp.kernel.org/ +Fixes: dac5e6249159 ("can: bcm: add missing rcu read protection for procfs content") +Signed-off-by: Oliver Hartkopp +Link: https://patch.msgid.link/20260714-bcm_fixes-v15-5-562f7e3e42da@hartkopp.net +Cc: stable@kernel.org +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + net/can/bcm.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -260,7 +260,7 @@ static int bcm_proc_show(struct seq_file + (reduction == 100) ? "near " : "", reduction); + } + +- list_for_each_entry(op, &bo->tx_ops, list) { ++ list_for_each_entry_rcu(op, &bo->tx_ops, list) { + + seq_printf(m, "tx_op: %03X %s ", op->can_id, + bcm_proc_getifname(net, ifname, op->ifindex)); +@@ -946,6 +946,7 @@ static int bcm_tx_setup(struct bcm_msg_h + struct bcm_sock *bo = bcm_sk(sk); + struct bcm_op *op; + struct canfd_frame *cf; ++ bool add_op_to_list = false; + unsigned int i; + int err; + +@@ -1087,8 +1088,7 @@ static int bcm_tx_setup(struct bcm_msg_h + hrtimer_setup(&op->thrtimer, hrtimer_dummy_timeout, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_SOFT); + +- /* add this bcm_op to the list of the tx_ops */ +- list_add(&op->list, &bo->tx_ops); ++ add_op_to_list = true; + + } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */ + +@@ -1110,6 +1110,10 @@ static int bcm_tx_setup(struct bcm_msg_h + op->flags |= TX_ANNOUNCE; + } + ++ /* add this bcm_op to the list of the tx_ops? */ ++ if (add_op_to_list) ++ list_add_rcu(&op->list, &bo->tx_ops); ++ + if (op->flags & TX_ANNOUNCE) + bcm_can_tx(op); + +@@ -1250,9 +1254,6 @@ static int bcm_rx_setup(struct bcm_msg_h + hrtimer_setup(&op->thrtimer, bcm_rx_thr_handler, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_SOFT); + +- /* add this bcm_op to the list of the rx_ops */ +- list_add(&op->list, &bo->rx_ops); +- + /* call can_rx_register() */ + do_rx_register = 1; + +@@ -1331,10 +1332,12 @@ static int bcm_rx_setup(struct bcm_msg_h + bcm_rx_handler, op, "bcm", sk); + if (err) { + /* this bcm rx op is broken -> remove it */ +- list_del_rcu(&op->list); + bcm_remove_op(op); + return err; + } ++ ++ /* add this bcm_op to the list of the rx_ops */ ++ list_add_rcu(&op->list, &bo->rx_ops); + } + + return msg_head->nframes * op->cfsiz + MHSIZ; +@@ -1664,8 +1667,10 @@ static int bcm_release(struct socket *so + remove_proc_entry(bo->procname, net->can.bcmproc_dir); + #endif /* CONFIG_PROC_FS */ + +- list_for_each_entry_safe(op, next, &bo->tx_ops, list) ++ list_for_each_entry_safe(op, next, &bo->tx_ops, list) { ++ list_del_rcu(&op->list); + bcm_remove_op(op); ++ } + + list_for_each_entry_safe(op, next, &bo->rx_ops, list) { + /* +@@ -1696,8 +1701,10 @@ static int bcm_release(struct socket *so + + synchronize_rcu(); + +- list_for_each_entry_safe(op, next, &bo->rx_ops, list) ++ list_for_each_entry_safe(op, next, &bo->rx_ops, list) { ++ list_del_rcu(&op->list); + bcm_remove_op(op); ++ } + + /* remove device reference */ + if (bo->bound) { diff --git a/queue-6.18/can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch b/queue-6.18/can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch new file mode 100644 index 0000000000..dcfbdb780a --- /dev/null +++ b/queue-6.18/can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch @@ -0,0 +1,169 @@ +From 68973f9db76144825e4f35dfdc80fb8279eb2d57 Mon Sep 17 00:00:00 2001 +From: Lee Jones +Date: Tue, 14 Jul 2026 18:55:23 +0200 +Subject: can: bcm: defer rx_op deallocation to workqueue to fix thrtimer UAF + +From: Lee Jones + +commit 68973f9db76144825e4f35dfdc80fb8279eb2d57 upstream. + +Commit f1b4e32aca08 ("can: bcm: use call_rcu() instead of costly +synchronize_rcu()") replaced synchronize_rcu() in bcm_delete_rx_op() +with call_rcu() and introduced the RX_NO_AUTOTIMER flag. + +However, this flag check was omitted for thrtimer in the packet rx +fast-path. During BCM RX operation teardown, a concurrent RCU reader +(bcm_rx_handler) can race and re-arm thrtimer via +bcm_rx_update_and_send() after call_rcu() has been scheduled. Once +the RCU grace period elapses, bcm_op is freed. The subsequently +firing thrtimer then dereferences the deallocated op, causing a UAF. + +Adding flag checks to the rx fast-path (bcm_rx_update_and_send) does not +fully close the TOCTOU race and introduces latency for every CAN frame. +Conversely, calling hrtimer_cancel() directly inside the RCU callback +(softirq context) is fatal as hrtimer_cancel() can sleep, triggering +a "scheduling while atomic" panic. + +Resolve this by deferring the timer cancellation and memory free to a +dedicated unbound workqueue (bcm_wq). The RCU callback now queues a +work item to bcm_wq, which safely cancels both timers and deallocates +memory in sleepable process context. A dedicated workqueue is used to +prevent system-wide WQ saturation and is cleanly flushed/destroyed +on module unload to avoid rmmod page faults. + +Since the deferred work can now outlive the calling context by an +unbounded amount, also take a reference on op->sk when it is assigned +and drop it only once the deferred work has cancelled both timers, so a +socket can no longer be freed out from under a still-armed timer whose +callback (bcm_send_to_user()) dereferences op->sk. + +Fixes: f1b4e32aca08 ("can: bcm: use call_rcu() instead of costly synchronize_rcu()") +Tested-by: Feng Xue +Tested-by: Oliver Hartkopp +Signed-off-by: Lee Jones +Signed-off-by: Oliver Hartkopp +Link: https://patch.msgid.link/20260714-bcm_fixes-v15-1-562f7e3e42da@hartkopp.net +Cc: stable@kernel.org +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + net/can/bcm.c | 37 ++++++++++++++++++++++++++++++++++--- + 1 file changed, 34 insertions(+), 3 deletions(-) + +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -91,6 +92,8 @@ MODULE_ALIAS("can-proto-2"); + + #define BCM_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_ifindex) + ++static struct workqueue_struct *bcm_wq; ++ + /* + * easy access to the first 64 bit of can(fd)_frame payload. cp->data is + * 64 bit aligned so the offset has to be multiples of 8 which is ensured +@@ -104,6 +107,7 @@ static inline u64 get_u64(const struct c + struct bcm_op { + struct list_head list; + struct rcu_head rcu; ++ struct work_struct work; + int ifindex; + canid_t can_id; + u32 flags; +@@ -788,9 +792,12 @@ static struct bcm_op *bcm_find_op(struct + return NULL; + } + +-static void bcm_free_op_rcu(struct rcu_head *rcu_head) ++static void bcm_free_op_work(struct work_struct *work) + { +- struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu); ++ struct bcm_op *op = container_of(work, struct bcm_op, work); ++ ++ hrtimer_cancel(&op->timer); ++ hrtimer_cancel(&op->thrtimer); + + if ((op->frames) && (op->frames != &op->sframe)) + kfree(op->frames); +@@ -798,9 +805,23 @@ static void bcm_free_op_rcu(struct rcu_h + if ((op->last_frames) && (op->last_frames != &op->last_sframe)) + kfree(op->last_frames); + ++ /* the last possible access to op->timer/op->thrtimer has now ++ * happened above via hrtimer_cancel() - op->sk is no longer ++ * needed by any pending timer callback, so drop our reference ++ */ ++ sock_put(op->sk); ++ + kfree(op); + } + ++static void bcm_free_op_rcu(struct rcu_head *rcu_head) ++{ ++ struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu); ++ ++ INIT_WORK(&op->work, bcm_free_op_work); ++ queue_work(bcm_wq, &op->work); ++} ++ + static void bcm_remove_op(struct bcm_op *op) + { + hrtimer_cancel(&op->timer); +@@ -1055,6 +1076,7 @@ static int bcm_tx_setup(struct bcm_msg_h + + /* bcm_can_tx / bcm_tx_timeout_handler needs this */ + op->sk = sk; ++ sock_hold(sk); + op->ifindex = ifindex; + + /* initialize uninitialized (kzalloc) structure */ +@@ -1216,6 +1238,7 @@ static int bcm_rx_setup(struct bcm_msg_h + + /* bcm_can_tx / bcm_tx_timeout_handler needs this */ + op->sk = sk; ++ sock_hold(sk); + op->ifindex = ifindex; + + /* ifindex for timeout events w/o previous frame reception */ +@@ -1830,11 +1853,15 @@ static int __init bcm_module_init(void) + { + int err; + ++ bcm_wq = alloc_workqueue("can-bcm-wq", WQ_UNBOUND, 0); ++ if (!bcm_wq) ++ return -ENOMEM; ++ + pr_info("can: broadcast manager protocol\n"); + + err = register_pernet_subsys(&canbcm_pernet_ops); + if (err) +- return err; ++ goto register_pernet_failed; + + err = register_netdevice_notifier(&canbcm_notifier); + if (err) +@@ -1852,6 +1879,8 @@ register_proto_failed: + unregister_netdevice_notifier(&canbcm_notifier); + register_notifier_failed: + unregister_pernet_subsys(&canbcm_pernet_ops); ++register_pernet_failed: ++ destroy_workqueue(bcm_wq); + return err; + } + +@@ -1860,6 +1889,8 @@ static void __exit bcm_module_exit(void) + can_proto_unregister(&bcm_can_proto); + unregister_netdevice_notifier(&canbcm_notifier); + unregister_pernet_subsys(&canbcm_pernet_ops); ++ rcu_barrier(); ++ destroy_workqueue(bcm_wq); + } + + module_init(bcm_module_init); diff --git a/queue-6.18/can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch b/queue-6.18/can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch new file mode 100644 index 0000000000..40bcfa4a64 --- /dev/null +++ b/queue-6.18/can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch @@ -0,0 +1,186 @@ +From d9b091d9d22fee81ec53fb55d2032951993ceadb Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Tue, 14 Jul 2026 18:55:24 +0200 +Subject: can: bcm: fix lockless bound/ifindex race and silent RX_SETUP failure + +From: Oliver Hartkopp + +commit d9b091d9d22fee81ec53fb55d2032951993ceadb upstream. + +bcm_sendmsg() reads bo->ifindex and checks bo->bound before taking +lock_sock(), while bcm_notify(), bcm_connect() and bcm_release() all +mutate both fields under that same lock. Because the lockless reads +and the locked writes are unordered with respect to each other, a +racing bcm_notify() (device unregister) or bcm_connect() (concurrent +bind on another thread sharing the socket) can make bcm_sendmsg() +observe an inconsistent combination, e.g. a stale bound=1 together +with the now-cleared ifindex=0, silently turning a socket bound to a +specific CAN interface into one that also matches "any" interface. + +Keep the lockless bo->bound check purely as a fast-path reject, and +move the ifindex read (and a bo->bound re-check) into the locked +section, where every writer already serializes. This removes the +possibility of observing the two fields torn against each other, +rather than trying to fix it with more READ_ONCE()/WRITE_ONCE() pairs +on two independently updated fields. Annotate the now-purely-lockless +bo->bound accesses consistently across all its write sites. + +Also fix bcm_rx_setup() silently returning success when the target +device disappears concurrently instead of reporting -ENODEV, so a +broken RX op is no longer left registered as if it had succeeded. + +Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol") +Reported-by: Ginger +Closes: https://lore.kernel.org/linux-can/CAGp+u1aBK8QVjsvAxM2Ldzep4rEbsP9x_pV3At4g=h1kVEtyhA@mail.gmail.com/ +Signed-off-by: Oliver Hartkopp +Link: https://patch.msgid.link/20260714-bcm_fixes-v15-2-562f7e3e42da@hartkopp.net +Cc: stable@kernel.org +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + net/can/bcm.c | 65 +++++++++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 51 insertions(+), 14 deletions(-) + +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -1318,6 +1318,11 @@ static int bcm_rx_setup(struct bcm_msg_h + + op->rx_reg_dev = dev; + dev_put(dev); ++ } else { ++ /* the requested device is gone - do not ++ * silently succeed without registering ++ */ ++ err = -ENODEV; + } + + } else +@@ -1387,12 +1392,13 @@ static int bcm_sendmsg(struct socket *so + { + struct sock *sk = sock->sk; + struct bcm_sock *bo = bcm_sk(sk); +- int ifindex = bo->ifindex; /* default ifindex for this bcm_op */ ++ int ifindex; + struct bcm_msg_head msg_head; + int cfsiz; + int ret; /* read bytes or error codes as return value */ + +- if (!bo->bound) ++ /* Lockless fast-path check for bound socket */ ++ if (!READ_ONCE(bo->bound)) + return -ENOTCONN; + + /* check for valid message length from userspace */ +@@ -1408,17 +1414,38 @@ static int bcm_sendmsg(struct socket *so + if ((size - MHSIZ) % cfsiz) + return -EINVAL; + ++ lock_sock(sk); ++ ++ /* Re-validate under the socket lock: a concurrent bcm_notify() ++ * may have unbound this socket (device removal) after the ++ * lockless fast-path check above. bo->ifindex is only ever ++ * mutated under lock_sock(), so reading it here - instead of ++ * before taking the lock - guarantees it can't be observed ++ * torn against bo->bound. ++ */ ++ if (!bo->bound) { ++ ret = -ENOTCONN; ++ goto out_release; ++ } ++ ++ /* default ifindex for this bcm_op */ ++ ifindex = bo->ifindex; ++ + /* check for alternative ifindex for this bcm_op */ + + if (!ifindex && msg->msg_name) { + /* no bound device as default => check msg_name */ + DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); + +- if (msg->msg_namelen < BCM_MIN_NAMELEN) +- return -EINVAL; ++ if (msg->msg_namelen < BCM_MIN_NAMELEN) { ++ ret = -EINVAL; ++ goto out_release; ++ } + +- if (addr->can_family != AF_CAN) +- return -EINVAL; ++ if (addr->can_family != AF_CAN) { ++ ret = -EINVAL; ++ goto out_release; ++ } + + /* ifindex from sendto() */ + ifindex = addr->can_ifindex; +@@ -1427,20 +1454,21 @@ static int bcm_sendmsg(struct socket *so + struct net_device *dev; + + dev = dev_get_by_index(sock_net(sk), ifindex); +- if (!dev) +- return -ENODEV; ++ if (!dev) { ++ ret = -ENODEV; ++ goto out_release; ++ } + + if (dev->type != ARPHRD_CAN) { + dev_put(dev); +- return -ENODEV; ++ ret = -ENODEV; ++ goto out_release; + } + + dev_put(dev); + } + } + +- lock_sock(sk); +- + switch (msg_head.opcode) { + + case TX_SETUP: +@@ -1490,6 +1518,7 @@ static int bcm_sendmsg(struct socket *so + break; + } + ++out_release: + release_sock(sk); + + return ret; +@@ -1526,7 +1555,12 @@ static void bcm_notify(struct bcm_sock * + bo->bcm_proc_read = NULL; + } + #endif +- bo->bound = 0; ++ /* Paired with the lockless fast-path check in ++ * bcm_sendmsg(); bo->ifindex itself is only ever ++ * accessed under lock_sock() so it needs no ++ * annotation. ++ */ ++ WRITE_ONCE(bo->bound, 0); + bo->ifindex = 0; + notify_enodev = 1; + } +@@ -1667,7 +1701,7 @@ static int bcm_release(struct socket *so + + /* remove device reference */ + if (bo->bound) { +- bo->bound = 0; ++ WRITE_ONCE(bo->bound, 0); + bo->ifindex = 0; + } + +@@ -1737,7 +1771,10 @@ static int bcm_connect(struct socket *so + } + #endif /* CONFIG_PROC_FS */ + +- bo->bound = 1; ++ /* bo->ifindex above is fully assigned before this point; pairs ++ * with the lockless fast-path check in bcm_sendmsg() ++ */ ++ WRITE_ONCE(bo->bound, 1); + + fail: + release_sock(sk); diff --git a/queue-6.18/can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch b/queue-6.18/can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch new file mode 100644 index 0000000000..e64dc9c96e --- /dev/null +++ b/queue-6.18/can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch @@ -0,0 +1,54 @@ +From c43122fef328a70045fe7621c06de6b2b8e19264 Mon Sep 17 00:00:00 2001 +From: Fan Wu +Date: Thu, 9 Jul 2026 16:41:59 +0000 +Subject: can: esd_usb: kill anchored URBs before freeing netdevs + +From: Fan Wu + +commit c43122fef328a70045fe7621c06de6b2b8e19264 upstream. + +esd_usb_disconnect() frees each CAN netdev with free_candev() inside +its per-netdev loop and only calls unlink_all_urbs(dev) afterwards. +The per-netdev private data (struct esd_usb_net_priv) is embedded in +the net_device allocation returned by alloc_candev(), so once +free_candev() has run, dev->nets[i] points to freed memory. +unlink_all_urbs() then dereferences the freed dev->nets[i] to kill the +per-netdev TX anchor (usb_kill_anchored_urbs(&priv->tx_submitted)), +clear active_tx_jobs, and reset priv->tx_contexts[]. + +Reorder the teardown so the anchored URBs are killed before the netdevs +are freed, matching other CAN/USB drivers in the same directory such as +ems_usb, usb_8dev and mcba_usb, which unregister, then unlink, then +free: unregister the netdevs first (which stops their TX queues), call +unlink_all_urbs(dev) once, then free the netdevs. + +This issue was found by an in-house static analysis tool. + +Fixes: 96d8e90382dc ("can: Add driver for esd CAN-USB/2 device") +Cc: stable@vger.kernel.org +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Fan Wu +Link: https://patch.msgid.link/20260709164159.497640-1-fanwu01@zju.edu.cn +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/can/usb/esd_usb.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/net/can/usb/esd_usb.c ++++ b/drivers/net/can/usb/esd_usb.c +@@ -1387,10 +1387,13 @@ static void esd_usb_disconnect(struct us + netdev = dev->nets[i]->netdev; + netdev_info(netdev, "unregister\n"); + unregister_netdev(netdev); +- free_candev(netdev); + } + } + unlink_all_urbs(dev); ++ for (i = 0; i < dev->net_count; i++) { ++ if (dev->nets[i]) ++ free_candev(dev->nets[i]->netdev); ++ } + kfree(dev); + } + } diff --git a/queue-6.18/can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch b/queue-6.18/can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch new file mode 100644 index 0000000000..99830c4149 --- /dev/null +++ b/queue-6.18/can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch @@ -0,0 +1,232 @@ +From 20bab8b88baac140ca3701116e1d486c7f51e311 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Sun, 12 Jul 2026 19:59:42 +0200 +Subject: can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER + +From: Oliver Hartkopp + +commit 20bab8b88baac140ca3701116e1d486c7f51e311 upstream. + +isotp_release() looked up the bound network device via dev_get_by_index() +using the stored ifindex. During device unregistration the device is +unlisted from the ifindex hash before the NETDEV_UNREGISTER notifier +chain runs, so a concurrent isotp_release() could find no device, skip +can_rx_unregister() entirely, and still proceed to free the socket. +Since isotp_release() had already removed itself from the isotp +notifier list at that point, isotp_notify() would never get a chance to +clean up either, leaving a stale CAN filter that keeps pointing at the +freed socket. + +Fix this the same way raw.c already does: hold a tracked reference to +the bound net_device in the socket (so->dev/so->dev_tracker) from +bind() onward instead of re-resolving it from the ifindex, and +serialize bind()/release() with rtnl_lock() so that so->dev is always +consistent with what the NETDEV_UNREGISTER notifier sees. so->dev +stays valid regardless of ifindex-hash unlisting, and is only ever +cleared by whichever of isotp_release()/isotp_notify() gets there +first, so the filter is always removed exactly once. + +isotp_bind() now rejects a (re)bind with -EAGAIN while so->[tx|rx].state +isn't ISOTP_IDLE yet, so a timer left running by a prior +NETDEV_UNREGISTER can't act on a newly bound so->ifindex. Both checks +share the same lock_sock() section, so there is no window in which a +concurrent isotp_notify() clearing so->bound could be missed. + +Fixes: e057dd3fc20f ("can: add ISO 15765-2:2016 transport protocol") +Reported-by: sashiko-bot@kernel.org +Closes: https://lore.kernel.org/linux-can/20260707101420.47F261F000E9@smtp.kernel.org/ +Signed-off-by: Oliver Hartkopp +Link: https://patch.msgid.link/20260712-isotp-fixes-v10-2-793a1b1ce17f@hartkopp.net +Cc: stable@kernel.org +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + net/can/isotp.c | 87 +++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 59 insertions(+), 28 deletions(-) + +--- a/net/can/isotp.c ++++ b/net/can/isotp.c +@@ -151,6 +151,8 @@ struct isotp_sock { + struct sock sk; + int bound; + int ifindex; ++ struct net_device *dev; ++ netdevice_tracker dev_tracker; + canid_t txid; + canid_t rxid; + ktime_t tx_gap; +@@ -965,6 +967,14 @@ static int isotp_sendmsg(struct socket * + goto err_event_drop; + } + ++ /* so->bound is only checked once above - a wakeup may have ++ * unbound/rebound the socket meanwhile, so re-validate it ++ */ ++ if (!so->bound) { ++ err = -EADDRNOTAVAIL; ++ goto err_out_drop; ++ } ++ + /* PDU size > default => try max_pdu_size */ + if (size > so->tx.buflen && so->tx.buflen < max_pdu_size) { + u8 *newbuf = kmalloc(max_pdu_size, GFP_KERNEL); +@@ -1200,28 +1210,30 @@ static int isotp_release(struct socket * + list_del(&so->notifier); + spin_unlock(&isotp_notifier_lock); + ++ rtnl_lock(); + lock_sock(sk); + +- /* remove current filters & unregister */ +- if (so->bound) { +- if (so->ifindex) { +- struct net_device *dev; +- +- dev = dev_get_by_index(net, so->ifindex); +- if (dev) { +- if (isotp_register_rxid(so)) +- can_rx_unregister(net, dev, so->rxid, +- SINGLE_MASK(so->rxid), +- isotp_rcv, sk); +- +- can_rx_unregister(net, dev, so->txid, +- SINGLE_MASK(so->txid), +- isotp_rcv_echo, sk); +- dev_put(dev); +- } +- } ++ /* remove current filters & unregister ++ * tracked reference so->dev is taken at bind() time with rtnl_lock ++ */ ++ if (so->bound && so->dev) { ++ if (isotp_register_rxid(so)) ++ can_rx_unregister(net, so->dev, so->rxid, ++ SINGLE_MASK(so->rxid), ++ isotp_rcv, sk); ++ ++ can_rx_unregister(net, so->dev, so->txid, ++ SINGLE_MASK(so->txid), ++ isotp_rcv_echo, sk); ++ netdev_put(so->dev, &so->dev_tracker); + } + ++ so->ifindex = 0; ++ so->bound = 0; ++ so->dev = NULL; ++ ++ rtnl_unlock(); ++ + /* Always wait for a grace period before touching the timers below. + * A concurrent NETDEV_UNREGISTER may have already unregistered our + * filters and cleared so->bound in isotp_notify() without waiting +@@ -1234,9 +1246,6 @@ static int isotp_release(struct socket * + hrtimer_cancel(&so->txtimer); + hrtimer_cancel(&so->rxtimer); + +- so->ifindex = 0; +- so->bound = 0; +- + sock_orphan(sk); + sock->sk = NULL; + +@@ -1291,6 +1300,7 @@ static int isotp_bind(struct socket *soc + if (!addr->can_ifindex) + return -ENODEV; + ++ rtnl_lock(); + lock_sock(sk); + + if (so->bound) { +@@ -1298,6 +1308,17 @@ static int isotp_bind(struct socket *soc + goto out; + } + ++ /* A transmission or reception that outlived a previous binding ++ * (unbound by NETDEV_UNREGISTER) may still be draining; the FC/echo ++ * and RX watchdog timers bound how long this takes. Checked together ++ * with so->bound in the same lock_sock() section above, so there is ++ * no window in which a concurrent isotp_notify() could be missed. ++ */ ++ if (so->tx.state != ISOTP_IDLE || so->rx.state != ISOTP_IDLE) { ++ err = -EAGAIN; ++ goto out; ++ } ++ + /* ensure different CAN IDs when the rx_id is to be registered */ + if (isotp_register_rxid(so) && rx_id == tx_id) { + err = -EADDRNOTAVAIL; +@@ -1310,14 +1331,12 @@ static int isotp_bind(struct socket *soc + goto out; + } + if (dev->type != ARPHRD_CAN) { +- dev_put(dev); + err = -ENODEV; +- goto out; ++ goto out_put_dev; + } + if (READ_ONCE(dev->mtu) < so->ll.mtu) { +- dev_put(dev); + err = -EINVAL; +- goto out; ++ goto out_put_dev; + } + if (!(dev->flags & IFF_UP)) + notify_enetdown = 1; +@@ -1335,16 +1354,25 @@ static int isotp_bind(struct socket *soc + can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id), + isotp_rcv_echo, sk, "isotpe", sk); + +- dev_put(dev); +- + /* switch to new settings */ + so->ifindex = ifindex; + so->rxid = rx_id; + so->txid = tx_id; + so->bound = 1; + ++ /* bind() ok -> hold a reference for so->dev so that isotp_release() ++ * can safely reach the device later, even if a concurrent ++ * NETDEV_UNREGISTER has already unlisted it by ifindex. ++ */ ++ so->dev = dev; ++ netdev_hold(so->dev, &so->dev_tracker, GFP_KERNEL); ++ ++out_put_dev: ++ /* remove potential reference from dev_get_by_index() */ ++ dev_put(dev); + out: + release_sock(sk); ++ rtnl_unlock(); + + if (notify_enetdown) { + sk->sk_err = ENETDOWN; +@@ -1547,7 +1575,7 @@ static void isotp_notify(struct isotp_so + if (!net_eq(dev_net(dev), sock_net(sk))) + return; + +- if (so->ifindex != dev->ifindex) ++ if (so->dev != dev) + return; + + switch (msg) { +@@ -1563,10 +1591,12 @@ static void isotp_notify(struct isotp_so + can_rx_unregister(dev_net(dev), dev, so->txid, + SINGLE_MASK(so->txid), + isotp_rcv_echo, sk); ++ netdev_put(so->dev, &so->dev_tracker); + } + + so->ifindex = 0; + so->bound = 0; ++ so->dev = NULL; + release_sock(sk); + + sk->sk_err = ENODEV; +@@ -1626,6 +1656,7 @@ static int isotp_init(struct sock *sk) + + so->ifindex = 0; + so->bound = 0; ++ so->dev = NULL; + + so->opt.flags = CAN_ISOTP_DEFAULT_FLAGS; + so->opt.ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS; diff --git a/queue-6.18/can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch b/queue-6.18/can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch new file mode 100644 index 0000000000..4c73d32d0f --- /dev/null +++ b/queue-6.18/can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch @@ -0,0 +1,430 @@ +From cf070fe33bfbd1a4c21236078fadb35dd223a157 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Sun, 12 Jul 2026 19:59:43 +0200 +Subject: can: isotp: serialize TX state transitions under so->rx_lock + +From: Oliver Hartkopp + +commit cf070fe33bfbd1a4c21236078fadb35dd223a157 upstream. + +The TX state machine (so->tx.state) is driven from three contexts: +sendmsg() claiming and progressing a transfer, the RX path consuming +Flow Control/echo frames, and two hrtimers timing out a stalled +transfer. Mixing a lock-free cmpxchg() claim in sendmsg() with +hrtimer_cancel() calls made under so->rx_lock elsewhere left windows +where a frame or timer callback could act on a state that had already +moved on, corrupting an unrelated transfer. + +so->rx_lock now covers the full lifecycle of a TX claim: sendmsg() +takes it to check so->tx.state is ISOTP_IDLE, switch it to +ISOTP_SENDING, bump so->tx_gen and drain the previous transfer's +timers - all as one critical section. isotp_rcv_fc()/isotp_rcv_cf() +already run under this lock via isotp_rcv(), and isotp_rcv_echo() now +takes it itself, so none of them can ever observe a transfer mid-claim. +This also means a transfer can no longer be handed to sendmsg()'s +cleanup paths (signal or send error) while another thread is +concurrently claiming or finishing it, so those paths can cancel +timers and reset the state unconditionally. + +isotp_release() claims the socket the same way, so a racing sendmsg() +sees a consistent ISOTP_SHUTDOWN and skips arming its timer or sending. + +Only the hrtimer callbacks stay outside so->rx_lock, since they run +under so->rx_lock's cancellation elsewhere and taking it themselves +would deadlock. so->tx_gen lets them recognize whether the transfer +they timed out is still the one currently active, so they don't +report an error against a transfer that has since completed or been +superseded. + +Fixes: e057dd3fc20f ("can: add ISO 15765-2:2016 transport protocol") +Reported-by: sashiko-bot@kernel.org +Closes: https://lore.kernel.org/linux-can/20260710142146.BDAE61F000E9@smtp.kernel.org/ +Signed-off-by: Oliver Hartkopp +Link: https://patch.msgid.link/20260712-isotp-fixes-v10-3-793a1b1ce17f@hartkopp.net +Cc: stable@kernel.org +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + net/can/isotp.c | 202 ++++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 160 insertions(+), 42 deletions(-) + +--- a/net/can/isotp.c ++++ b/net/can/isotp.c +@@ -157,7 +157,7 @@ struct isotp_sock { + canid_t rxid; + ktime_t tx_gap; + ktime_t lastrxcf_tstamp; +- struct hrtimer rxtimer, txtimer, txfrtimer; ++ struct hrtimer rxtimer, txtimer, txfrtimer, echotimer; + struct can_isotp_options opt; + struct can_isotp_fc_options rxfc, txfc; + struct can_isotp_ll_options ll; +@@ -165,6 +165,7 @@ struct isotp_sock { + u32 force_tx_stmin; + u32 force_rx_stmin; + u32 cfecho; /* consecutive frame echo tag */ ++ u32 tx_gen; /* generation, bumped per new tx transfer */ + struct tpcon rx, tx; + struct list_head notifier; + wait_queue_head_t wait; +@@ -372,6 +373,15 @@ static int isotp_rcv_fc(struct isotp_soc + + hrtimer_cancel(&so->txtimer); + ++ /* isotp_tx_timeout() may have given up on this job while ++ * hrtimer_cancel() above waited for it to finish; so->rx_lock ++ * (held by our caller isotp_rcv()) rules out a concurrent claim, ++ * so a plain recheck is enough here. ++ */ ++ if (so->tx.state != ISOTP_WAIT_FC && ++ so->tx.state != ISOTP_WAIT_FIRST_FC) ++ return 1; ++ + if ((cf->len < ae + FC_CONTENT_SZ) || + ((so->opt.flags & ISOTP_CHECK_PADDING) && + check_pad(so, cf, ae + FC_CONTENT_SZ, so->opt.rxpad_content))) { +@@ -418,7 +428,7 @@ static int isotp_rcv_fc(struct isotp_soc + so->tx.bs = 0; + so->tx.state = ISOTP_SENDING; + /* send CF frame and enable echo timeout handling */ +- hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), ++ hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), + HRTIMER_MODE_REL_SOFT); + isotp_send_cframe(so); + break; +@@ -571,6 +581,14 @@ static int isotp_rcv_cf(struct sock *sk, + + hrtimer_cancel(&so->rxtimer); + ++ /* isotp_rx_timer_handler() may have raced us for so->rx.state ++ * while hrtimer_cancel() above waited for it to finish, already ++ * reporting ETIMEDOUT and resetting the reception; don't process ++ * this CF into a reassembly that has already been given up on. ++ */ ++ if (so->rx.state != ISOTP_WAIT_DATA) ++ return 1; ++ + /* CFs are never longer than the FF */ + if (cf->len > so->rx.ll_dl) + return 1; +@@ -860,20 +878,36 @@ static void isotp_rcv_echo(struct sk_buf + struct canfd_frame *cf = (struct canfd_frame *)skb->data; + + /* only handle my own local echo CF/SF skb's (no FF!) */ +- if (skb->sk != sk || so->cfecho != *(u32 *)cf->data) ++ if (skb->sk != sk) + return; + ++ /* unlike isotp_rcv_fc()/isotp_rcv_cf(), not already under so->rx_lock ++ * (no isotp_rcv() caller here), so take it ourselves ++ */ ++ spin_lock(&so->rx_lock); ++ ++ /* so->cfecho may since belong to a new transfer; recheck under lock */ ++ if (so->cfecho != *(u32 *)cf->data) ++ goto out_unlock; ++ + /* cancel local echo timeout */ +- hrtimer_cancel(&so->txtimer); ++ hrtimer_cancel(&so->echotimer); + + /* local echo skb with consecutive frame has been consumed */ + so->cfecho = 0; + ++ /* claiming a transfer also takes so->rx_lock, so a plain recheck ++ * is enough: so->tx.state can't have flipped to ISOTP_SENDING for ++ * a new claim while we're still in here ++ */ ++ if (so->tx.state != ISOTP_SENDING) ++ goto out_unlock; ++ + if (so->tx.idx >= so->tx.len) { + /* we are done */ + so->tx.state = ISOTP_IDLE; + wake_up_interruptible(&so->wait); +- return; ++ goto out_unlock; + } + + if (so->txfc.bs && so->tx.bs >= so->txfc.bs) { +@@ -881,53 +915,83 @@ static void isotp_rcv_echo(struct sk_buf + so->tx.state = ISOTP_WAIT_FC; + hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0), + HRTIMER_MODE_REL_SOFT); +- return; ++ goto out_unlock; + } + + /* no gap between data frames needed => use burst mode */ + if (!so->tx_gap) { + /* enable echo timeout handling */ +- hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), ++ hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), + HRTIMER_MODE_REL_SOFT); + isotp_send_cframe(so); +- return; ++ goto out_unlock; + } + + /* start timer to send next consecutive frame with correct delay */ + hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT); ++ ++out_unlock: ++ spin_unlock(&so->rx_lock); + } + +-static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer) ++/* shared by so->txtimer's and so->echotimer's callbacks. Both timers get ++ * cancelled under so->rx_lock elsewhere, so this must stay lock-free to ++ * avoid deadlocking with that; uses so->tx_gen instead to avoid tainting ++ * a new transfer with an error from the one that just timed out. ++ */ ++static enum hrtimer_restart isotp_tx_timeout(struct isotp_sock *so) + { +- struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, +- txtimer); + struct sock *sk = &so->sk; ++ u32 gen = READ_ONCE(so->tx_gen); ++ u32 old_state = READ_ONCE(so->tx.state); + + /* don't handle timeouts in IDLE or SHUTDOWN state */ +- if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN) ++ if (old_state == ISOTP_IDLE || old_state == ISOTP_SHUTDOWN) ++ return HRTIMER_NORESTART; ++ ++ /* only claim the timeout if the state is still unchanged */ ++ if (cmpxchg(&so->tx.state, old_state, ISOTP_IDLE) != old_state) + return HRTIMER_NORESTART; + + /* we did not get any flow control or echo frame in time */ + +- /* report 'communication error on send' */ +- sk->sk_err = ECOMM; +- if (!sock_flag(sk, SOCK_DEAD)) +- sk_error_report(sk); ++ if (READ_ONCE(so->tx_gen) == gen) { ++ /* report 'communication error on send' */ ++ sk->sk_err = ECOMM; ++ if (!sock_flag(sk, SOCK_DEAD)) ++ sk_error_report(sk); ++ } + +- /* reset tx state */ +- so->tx.state = ISOTP_IDLE; + wake_up_interruptible(&so->wait); + + return HRTIMER_NORESTART; + } + ++/* so->txtimer: fires when a Flow Control frame does not arrive in time */ ++static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer) ++{ ++ struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, ++ txtimer); ++ ++ return isotp_tx_timeout(so); ++} ++ ++/* so->echotimer: fires when a sent CF/SF's local echo does not arrive */ ++static enum hrtimer_restart isotp_echo_timer_handler(struct hrtimer *hrtimer) ++{ ++ struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, ++ echotimer); ++ ++ return isotp_tx_timeout(so); ++} ++ + static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer) + { + struct isotp_sock *so = container_of(hrtimer, struct isotp_sock, + txfrtimer); + + /* start echo timeout handling and cover below protocol error */ +- hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), ++ hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0), + HRTIMER_MODE_REL_SOFT); + + /* cfecho should be consumed by isotp_rcv_echo() here */ +@@ -947,13 +1011,24 @@ static int isotp_sendmsg(struct socket * + int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; + int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0; + s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT; ++ struct hrtimer *tx_hrt = &so->echotimer; ++ u32 new_state = ISOTP_SENDING; + int off; + int err; + + if (!so->bound || so->tx.state == ISOTP_SHUTDOWN) + return -EADDRNOTAVAIL; + +- while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) { ++ /* claim the socket under so->rx_lock: this serializes the claim ++ * with the RX path and with sendmsg()'s own error paths below, so ++ * none of them can ever see a transfer mid-claim ++ */ ++ for (;;) { ++ spin_lock_bh(&so->rx_lock); ++ if (READ_ONCE(so->tx.state) == ISOTP_IDLE) ++ break; ++ spin_unlock_bh(&so->rx_lock); ++ + /* we do not support multiple buffers - for now */ + if (msg->msg_flags & MSG_DONTWAIT) + return -EAGAIN; +@@ -962,11 +1037,23 @@ static int isotp_sendmsg(struct socket * + return -EADDRNOTAVAIL; + + /* wait for complete transmission of current pdu */ +- err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE); ++ err = wait_event_interruptible(so->wait, ++ so->tx.state == ISOTP_IDLE); + if (err) +- goto err_event_drop; ++ return err; + } + ++ /* new transfer: bump so->tx_gen and drain the old one's timers, ++ * still under the so->rx_lock we just claimed the socket with ++ */ ++ WRITE_ONCE(so->tx.state, ISOTP_SENDING); ++ WRITE_ONCE(so->tx_gen, READ_ONCE(so->tx_gen) + 1); ++ hrtimer_cancel(&so->txtimer); ++ hrtimer_cancel(&so->echotimer); ++ hrtimer_cancel(&so->txfrtimer); ++ so->cfecho = 0; ++ spin_unlock_bh(&so->rx_lock); ++ + /* so->bound is only checked once above - a wakeup may have + * unbound/rebound the socket meanwhile, so re-validate it + */ +@@ -1077,18 +1164,33 @@ static int isotp_sendmsg(struct socket * + so->cfecho = *(u32 *)cf->data; + } else { + /* standard flow control check */ +- so->tx.state = ISOTP_WAIT_FIRST_FC; ++ new_state = ISOTP_WAIT_FIRST_FC; + + /* start timeout for FC */ + hrtimer_sec = ISOTP_FC_TIMEOUT; ++ tx_hrt = &so->txtimer; + + /* no CF echo tag for isotp_rcv_echo() (FF-mode) */ + so->cfecho = 0; + } + } + +- hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0), ++ spin_lock_bh(&so->rx_lock); ++ if (so->tx.state == ISOTP_SHUTDOWN) { ++ /* isotp_release() has since taken over and already drained ++ * our timers - don't send into a socket that's going away ++ */ ++ spin_unlock_bh(&so->rx_lock); ++ kfree_skb(skb); ++ dev_put(dev); ++ wake_up_interruptible(&so->wait); ++ return -EADDRNOTAVAIL; ++ } ++ /* WAIT_FIRST_FC for standard FF, else stays ISOTP_SENDING */ ++ so->tx.state = new_state; ++ hrtimer_start(tx_hrt, ktime_set(hrtimer_sec, 0), + HRTIMER_MODE_REL_SOFT); ++ spin_unlock_bh(&so->rx_lock); + + /* send the first or only CAN frame */ + cf->flags = so->ll.tx_flags; +@@ -1101,13 +1203,10 @@ static int isotp_sendmsg(struct socket * + pr_notice_once("can-isotp: %s: can_send_ret %pe\n", + __func__, ERR_PTR(err)); + ++ spin_lock_bh(&so->rx_lock); + /* no transmission -> no timeout monitoring */ +- hrtimer_cancel(&so->txtimer); +- +- /* reset consecutive frame echo tag */ +- so->cfecho = 0; +- +- goto err_out_drop; ++ hrtimer_cancel(tx_hrt); ++ goto err_out_drop_locked; + } + + if (wait_tx_done) { +@@ -1123,14 +1222,21 @@ static int isotp_sendmsg(struct socket * + + return size; + ++err_out_drop: ++ /* claimed but nothing sent yet - no timer to cancel */ ++ spin_lock_bh(&so->rx_lock); ++ goto err_out_drop_locked; + err_event_drop: +- /* got signal: force tx state machine to be idle */ +- so->tx.state = ISOTP_IDLE; ++ /* interrupted waiting on our own transfer - drain its timers */ ++ spin_lock_bh(&so->rx_lock); + hrtimer_cancel(&so->txfrtimer); + hrtimer_cancel(&so->txtimer); +-err_out_drop: +- /* drop this PDU and unlock a potential wait queue */ ++ hrtimer_cancel(&so->echotimer); ++err_out_drop_locked: ++ /* release the claim; so->rx_lock still held from above */ ++ so->cfecho = 0; + so->tx.state = ISOTP_IDLE; ++ spin_unlock_bh(&so->rx_lock); + wake_up_interruptible(&so->wait); + + return err; +@@ -1192,13 +1298,20 @@ static int isotp_release(struct socket * + so = isotp_sk(sk); + net = sock_net(sk); + +- /* wait for complete transmission of current pdu */ +- while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 && +- cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE) ++ /* best-effort: wait for a running pdu to finish, but don't block on ++ * it forever - give up after the first signal ++ */ ++ while (so->tx.state != ISOTP_IDLE && ++ wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0) + ; + +- /* force state machines to be idle also when a signal occurred */ ++ /* claim the socket under so->rx_lock like sendmsg() does, so its ++ * claim can't race the forced ISOTP_SHUTDOWN below; force it ++ * unconditionally, even when a signal cut the wait above short ++ */ ++ spin_lock_bh(&so->rx_lock); + so->tx.state = ISOTP_SHUTDOWN; ++ spin_unlock_bh(&so->rx_lock); + so->rx.state = ISOTP_IDLE; + + spin_lock(&isotp_notifier_lock); +@@ -1244,6 +1357,7 @@ static int isotp_release(struct socket * + + hrtimer_cancel(&so->txfrtimer); + hrtimer_cancel(&so->txtimer); ++ hrtimer_cancel(&so->echotimer); + hrtimer_cancel(&so->rxtimer); + + sock_orphan(sk); +@@ -1683,10 +1797,14 @@ static int isotp_init(struct sock *sk) + so->rx.buflen = ARRAY_SIZE(so->rx.sbuf); + so->tx.buflen = ARRAY_SIZE(so->tx.sbuf); + +- hrtimer_setup(&so->rxtimer, isotp_rx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); +- hrtimer_setup(&so->txtimer, isotp_tx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); +- hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler, CLOCK_MONOTONIC, +- HRTIMER_MODE_REL_SOFT); ++ hrtimer_setup(&so->rxtimer, isotp_rx_timer_handler, ++ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); ++ hrtimer_setup(&so->txtimer, isotp_tx_timer_handler, ++ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); ++ hrtimer_setup(&so->echotimer, isotp_echo_timer_handler, ++ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); ++ hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler, ++ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); + + init_waitqueue_head(&so->wait); + spin_lock_init(&so->rx_lock); diff --git a/queue-6.18/can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch b/queue-6.18/can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch new file mode 100644 index 0000000000..ae93f10508 --- /dev/null +++ b/queue-6.18/can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch @@ -0,0 +1,59 @@ +From 9b1a02e0d980ac6b0e36a90378f847062f81d7e4 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Sun, 12 Jul 2026 19:59:41 +0200 +Subject: can: isotp: use unconditional synchronize_rcu() in isotp_release() + +From: Oliver Hartkopp + +commit 9b1a02e0d980ac6b0e36a90378f847062f81d7e4 upstream. + +isotp_notify() unregisters the (RCU) CAN filters via can_rx_unregister() +and clears so->bound without waiting for a grace period. isotp_release() +uses so->bound to decide whether it needs to call synchronize_rcu() +before cancelling so->rxtimer, so when NETDEV_UNREGISTER runs first it +skips that synchronize_rcu() and can cancel the timer while an +in-flight isotp_rcv() is still executing and about to re-arm it via +isotp_send_fc(), leading to a use-after-free timer callback on the +freed socket. + +sakisho-bot remarked a problem with rtnl_lock held in isotp_notify(), +therefore make isotp_release() always call synchronize_rcu() before +cancelling the timers, regardless of so->bound. This still closes the +original race (isotp_notify() clearing so->bound without waiting for +in-flight isotp_rcv() callers before isotp_release() cancels the RX +timer) without adding any RCU wait to the netdevice notifier path. + +Fixes: 14a4696bc311 ("can: isotp: isotp_release(): omit unintended hrtimer restart on socket release") +Closes: https://lore.kernel.org/linux-can/20260707085210.6B6C01F000E9@smtp.kernel.org/ +Reported-by: Nico Yip +Signed-off-by: Oliver Hartkopp +Link: https://patch.msgid.link/20260712-isotp-fixes-v10-1-793a1b1ce17f@hartkopp.net +Cc: stable@kernel.org +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman +--- + net/can/isotp.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/net/can/isotp.c ++++ b/net/can/isotp.c +@@ -1218,11 +1218,18 @@ static int isotp_release(struct socket * + SINGLE_MASK(so->txid), + isotp_rcv_echo, sk); + dev_put(dev); +- synchronize_rcu(); + } + } + } + ++ /* Always wait for a grace period before touching the timers below. ++ * A concurrent NETDEV_UNREGISTER may have already unregistered our ++ * filters and cleared so->bound in isotp_notify() without waiting ++ * for in-flight isotp_rcv() callers to finish, so this call must not ++ * be skipped just because so->bound is already 0 here. ++ */ ++ synchronize_rcu(); ++ + hrtimer_cancel(&so->txfrtimer); + hrtimer_cancel(&so->txtimer); + hrtimer_cancel(&so->rxtimer); diff --git a/queue-6.18/dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch b/queue-6.18/dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch new file mode 100644 index 0000000000..280efd585e --- /dev/null +++ b/queue-6.18/dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch @@ -0,0 +1,39 @@ +From 422f1d4f141eaa3a6e4199ceec86cc6b9bf26570 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Fri, 10 Jul 2026 18:32:49 +0200 +Subject: dm-bufio: fix wrong count calculation in dm_bufio_issue_discard + +From: Mikulas Patocka + +commit 422f1d4f141eaa3a6e4199ceec86cc6b9bf26570 upstream. + +block_to_sector converts a block number to a sector number and adds +c->start to the result. It is inappropriate to use this function for +converting the number of blocks to a number to sectors because c->start +would be incorrectly added to the result. + +Luckily, the only target that uses dm_bufio_issue_discard is dm-ebs, +which sets c->start to 0, so this bug is latent. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4-6 +Fixes: 6fbeb0048e6b ("dm bufio: implement discard") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-bufio.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -2215,7 +2215,9 @@ int dm_bufio_issue_discard(struct dm_buf + struct dm_io_region io_reg = { + .bdev = c->bdev, + .sector = block_to_sector(c, block), +- .count = block_to_sector(c, count), ++ .count = likely(c->sectors_per_block_bits >= 0) ? ++ count << c->sectors_per_block_bits : ++ count * (c->block_size >> SECTOR_SHIFT), + }; + + if (WARN_ON_ONCE(dm_bufio_in_request())) diff --git a/queue-6.18/dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch b/queue-6.18/dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch new file mode 100644 index 0000000000..64762929dc --- /dev/null +++ b/queue-6.18/dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch @@ -0,0 +1,59 @@ +From a868196f03c2b19418ae3d2b69e195d668a271e5 Mon Sep 17 00:00:00 2001 +From: Samuel Moelius +Date: Thu, 2 Jul 2026 00:27:35 +0000 +Subject: dm era: fix out-of-bounds memory access for non-zero start sector + +From: Samuel Moelius + +commit a868196f03c2b19418ae3d2b69e195d668a271e5 upstream. + +dm-era tracks writes in target-relative blocks, but era_map() calculates +the writeset block before applying the target offset. Tables with a +non-zero start sector can therefore pass an absolute mapped-device block +to metadata_current_marked(). + +If the absolute block is beyond the current writeset size, +writeset_marked() tests past the end of the in-core bitset. KASAN reports +this as a vmalloc-out-of-bounds access. + +Apply the target offset before calculating the era block so writeset +lookups use the target-relative block number. + +Assisted-by: Codex:gpt-5.5-cyber-preview +Signed-off-by: Samuel Moelius +Reviewed-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Cc: stable@vger.kernel.org +Fixes: eec40579d848 ("dm: add era target") +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-era-target.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm-era-target.c ++++ b/drivers/md/dm-era-target.c +@@ -1231,6 +1231,7 @@ static dm_block_t get_block(struct era * + static void remap_to_origin(struct era *era, struct bio *bio) + { + bio_set_dev(bio, era->origin_dev->bdev); ++ bio->bi_iter.bi_sector = dm_target_offset(era->ti, bio->bi_iter.bi_sector); + } + + /* +@@ -1562,7 +1563,7 @@ static void era_dtr(struct dm_target *ti + static int era_map(struct dm_target *ti, struct bio *bio) + { + struct era *era = ti->private; +- dm_block_t block = get_block(era, bio); ++ dm_block_t block; + + /* + * All bios get remapped to the origin device. We do this now, but +@@ -1570,6 +1571,7 @@ static int era_map(struct dm_target *ti, + * block is marked in this era. + */ + remap_to_origin(era, bio); ++ block = get_block(era, bio); + + /* + * REQ_PREFLUSH bios carry no data, so we're not interested in them. diff --git a/queue-6.18/dm-integrity-don-t-increment-hash_offset-twice.patch b/queue-6.18/dm-integrity-don-t-increment-hash_offset-twice.patch new file mode 100644 index 0000000000..68f93fd93a --- /dev/null +++ b/queue-6.18/dm-integrity-don-t-increment-hash_offset-twice.patch @@ -0,0 +1,33 @@ +From edf025f083854f80032b73a1aad69a3c90db236f Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:24:09 +0200 +Subject: dm-integrity: don't increment hash_offset twice + +From: Mikulas Patocka + +commit edf025f083854f80032b73a1aad69a3c90db236f upstream. + +hash_offset is already incremented in the loop "for (i = 0; i < to_copy; +i++, ts--)". Do not increment it again. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Fixes: 84597a44a9d8 ("dm-integrity: dm integrity: add optional discard support") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-integrity.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -1479,9 +1479,6 @@ thorough_test: + *metadata_offset = 0; + } + +- if (unlikely(!is_power_of_2(ic->tag_size))) +- hash_offset = (hash_offset + to_copy) % ic->tag_size; +- + total_size -= to_copy; + } while (unlikely(total_size)); + diff --git a/queue-6.18/dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch b/queue-6.18/dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch new file mode 100644 index 0000000000..c9d9496676 --- /dev/null +++ b/queue-6.18/dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch @@ -0,0 +1,46 @@ +From 5a266764fadaff8b5c1fe37a186ebf9b09cb953e Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:25:39 +0200 +Subject: dm-integrity: fix a bug if the bio is out of limits + +From: Mikulas Patocka + +commit 5a266764fadaff8b5c1fe37a186ebf9b09cb953e upstream. + +If dm_integrity_check_limits fails, the code would exit with +DM_MAPIO_KILL. However, the range would be already locked at this point, +and it wouldn't be unlocked, resulting in a deadlock. Let's move the +limit check up, so that when it exits, no resources are leaked. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Fixes: fb0987682c62 ("dm-integrity: introduce the Inline mode") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-integrity.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -2522,6 +2522,9 @@ static int dm_integrity_map_inline(struc + if (unlikely((bio->bi_opf & REQ_PREFLUSH) != 0)) + return DM_MAPIO_REMAPPED; + ++ if (unlikely(!dm_integrity_check_limits(ic, bio->bi_iter.bi_sector, bio))) ++ return DM_MAPIO_KILL; ++ + retry: + if (!dio->integrity_payload) { + unsigned digest_size, extra_size; +@@ -2586,10 +2589,6 @@ skip_spinlock: + + dio->bio_details.bi_iter = bio->bi_iter; + +- if (unlikely(!dm_integrity_check_limits(ic, bio->bi_iter.bi_sector, bio))) { +- return DM_MAPIO_KILL; +- } +- + bio->bi_iter.bi_sector += ic->start + SB_SECTORS; + + bip = bio_integrity_alloc(bio, GFP_NOIO, 1); diff --git a/queue-6.18/dm-integrity-fix-leaking-uninitialized-kernel-memory.patch b/queue-6.18/dm-integrity-fix-leaking-uninitialized-kernel-memory.patch new file mode 100644 index 0000000000..574dc955b3 --- /dev/null +++ b/queue-6.18/dm-integrity-fix-leaking-uninitialized-kernel-memory.patch @@ -0,0 +1,33 @@ +From 7bb03b2b01b814a9fc14afbfc2cbb2cca5b34750 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:22:47 +0200 +Subject: dm-integrity: fix leaking uninitialized kernel memory + +From: Mikulas Patocka + +commit 7bb03b2b01b814a9fc14afbfc2cbb2cca5b34750 upstream. + +If hash size is less than device's tuple size, dm-integrity is supposed +to zero the remaining space. There was a bug in the code that zeroing +didn't work. This commit fixes it. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Fixes: fb0987682c62 ("dm-integrity: introduce the Inline mode") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-integrity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -2605,7 +2605,7 @@ skip_spinlock: + struct bio_vec bv = bio_iter_iovec(bio, dio->bio_details.bi_iter); + const char *mem = integrity_kmap(ic, bv.bv_page); + if (ic->tag_size < ic->tuple_size) +- memset(dio->integrity_payload + pos + ic->tag_size, 0, ic->tuple_size - ic->tuple_size); ++ memset(dio->integrity_payload + pos + ic->tag_size, 0, ic->tuple_size - ic->tag_size); + integrity_sector_checksum(ic, &dio->ahash_req, dio->bio_details.bi_iter.bi_sector, mem, bv.bv_offset, dio->integrity_payload + pos); + integrity_kunmap(ic, mem); + pos += ic->tuple_size; diff --git a/queue-6.18/dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch b/queue-6.18/dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch new file mode 100644 index 0000000000..124b2c1c28 --- /dev/null +++ b/queue-6.18/dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch @@ -0,0 +1,36 @@ +From 76c6f845dc0c614304a6e6ee619b552f97cf24b3 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:31:47 +0200 +Subject: dm-ioctl: fix a possible overflow in list_version_get_info + +From: Mikulas Patocka + +commit 76c6f845dc0c614304a6e6ee619b552f97cf24b3 upstream. + +sizeof(tt->version) is 12 bytes, but the code writes 16 bytes into the +output buffer - info->vers->version[0], info->vers->version[1], +info->vers->version[2] and info->vers->next. This can cause buffer +overflow. + +Fix this buffer overflow by replacing "sizeof(tt->version)" with +"sizeof(struct dm_target_versions)". + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-ioctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -683,7 +683,7 @@ static void list_version_get_info(struct + struct vers_iter *info = param; + + /* Check space - it might have changed since the first iteration */ +- if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 > info->end) { ++ if ((char *)info->vers + sizeof(struct dm_target_versions) + strlen(tt->name) + 1 > info->end) { + info->flags = DM_BUFFER_FULL_FLAG; + return; + } diff --git a/queue-6.18/dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch b/queue-6.18/dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch new file mode 100644 index 0000000000..e685841289 --- /dev/null +++ b/queue-6.18/dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch @@ -0,0 +1,45 @@ +From 9743132a41f4d9d0e54c5f2adcb821b04796bab1 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 2 Jul 2026 21:43:39 -0400 +Subject: dm-log: fix a bitset_size overflow on 32bit machines + +From: Benjamin Marzinski + +commit 9743132a41f4d9d0e54c5f2adcb821b04796bab1 upstream. + +Commit c20e36b7631d ("dm log: fix out-of-bounds write due to +region_count overflow") made sure that region_count could fit in an +unsigned int. But the bitmap memory isn't allocated based on +region_count. It uses bitset_size (a size_t variable). The first step of +calculating bitset_size is to set it to region_count, rounded up to a +multiple of BITS_PER_LONG. If region_size is less than BITS_PER_LONG +smaller than UINT_MAX, it will get rounded up to 2^32. On a 32bit +architecture, this will make bitset_size wrap around to 0 and fail, +despite region_count being valid. + +Since bitset_size gets divided by 8, it can hold any valid region_count. +It just needs a special case to handle the rollover. If it is 0, the +value rolled over, and bitset size should be set to the number of bytes +needed to hold 2^32 bits. + +Signed-off-by: Benjamin Marzinski +Signed-off-by: Mikulas Patocka +Fixes: c20e36b7631d ("dm log: fix out-of-bounds write due to region_count overflow") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-log.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -425,6 +425,9 @@ static int create_log_context(struct dm_ + */ + bitset_size = dm_round_up(region_count, BITS_PER_LONG); + bitset_size >>= BYTE_SHIFT; ++ /* Handle dm_round_up rollover on 32-bit systems */ ++ if (!bitset_size) ++ bitset_size = 1UL << (BITS_PER_LONG - BYTE_SHIFT); + + lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); + diff --git a/queue-6.18/dm-pcache-reject-option-groups-without-values.patch b/queue-6.18/dm-pcache-reject-option-groups-without-values.patch new file mode 100644 index 0000000000..1d597faac2 --- /dev/null +++ b/queue-6.18/dm-pcache-reject-option-groups-without-values.patch @@ -0,0 +1,62 @@ +From d9c631e3fbd44246a2be781d26cfacbb9b8ec127 Mon Sep 17 00:00:00 2001 +From: Samuel Moelius +Date: Mon, 29 Jun 2026 15:47:40 +0000 +Subject: dm-pcache: reject option groups without values + +From: Samuel Moelius + +commit d9c631e3fbd44246a2be781d26cfacbb9b8ec127 upstream. + +The pcache target parses optional arguments as name/value pairs. A +table that advertises one optional argument and supplies only a +recognized option name, for example "cache_mode", reaches +parse_cache_opts() with argc == 1. The parser consumes the name, +decrements argc to zero, then calls dm_shift_arg() again for the value. +dm_shift_arg() returns NULL when no arguments remain, and the following +strcmp() dereferences that NULL pointer. + +Check that each recognized option has a value before consuming it. This +keeps valid "cache_mode writeback" and "data_crc true/false" tables +unchanged while making malformed tables fail during target construction +with a precise missing-value error. + +Assisted-by: Codex:gpt-5.5-cyber-preview +Signed-off-by: Samuel Moelius +Reviewed-by: Zheng Gu +Signed-off-by: Mikulas Patocka +Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-pcache/dm_pcache.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/md/dm-pcache/dm_pcache.c b/drivers/md/dm-pcache/dm_pcache.c +index 81c795c0400e..d5cfd162c063 100644 +--- a/drivers/md/dm-pcache/dm_pcache.c ++++ b/drivers/md/dm-pcache/dm_pcache.c +@@ -168,6 +168,10 @@ static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as, + argc--; + + if (!strcmp(arg, "cache_mode")) { ++ if (!argc) { ++ *error = "Missing value for cache_mode"; ++ return -EINVAL; ++ } + arg = dm_shift_arg(as); + if (!strcmp(arg, "writeback")) { + opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK; +@@ -177,6 +181,10 @@ static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as, + } + argc--; + } else if (!strcmp(arg, "data_crc")) { ++ if (!argc) { ++ *error = "Missing value for data_crc"; ++ return -EINVAL; ++ } + arg = dm_shift_arg(as); + if (!strcmp(arg, "true")) { + opts->data_crc = true; +-- +2.55.0 + diff --git a/queue-6.18/dm-stats-fix-dm_jiffies_to_msec64.patch b/queue-6.18/dm-stats-fix-dm_jiffies_to_msec64.patch new file mode 100644 index 0000000000..afa8f3c293 --- /dev/null +++ b/queue-6.18/dm-stats-fix-dm_jiffies_to_msec64.patch @@ -0,0 +1,36 @@ +From 386df1a57b631c456d14f857cb0c0c2e11c16bef Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Fri, 10 Jul 2026 18:37:15 +0200 +Subject: dm-stats: fix dm_jiffies_to_msec64 + +From: Mikulas Patocka + +commit 386df1a57b631c456d14f857cb0c0c2e11c16bef upstream. + +There were wrong calculations in dm_jiffies_to_msec64 that produced +incorrect output when HZ was different from 1000. This commit fixes them. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4-6 +Fixes: fd2ed4d25270 ("dm: add statistics support") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-stats.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-stats.c ++++ b/drivers/md/dm-stats.c +@@ -842,10 +842,10 @@ static unsigned long long dm_jiffies_to_ + result = jiffies_to_msecs(j & 0x3fffff); + if (j >= 1 << 22) { + mult = jiffies_to_msecs(1 << 22); +- result += (unsigned long long)mult * (unsigned long long)jiffies_to_msecs((j >> 22) & 0x3fffff); ++ result += (unsigned long long)mult * ((j >> 22) & 0x3fffff); + } + if (j >= 1ULL << 44) +- result += (unsigned long long)mult * (unsigned long long)mult * (unsigned long long)jiffies_to_msecs(j >> 44); ++ result += (unsigned long long)mult * (unsigned long long)(1 << 22) * (j >> 44); + + return result; + } diff --git a/queue-6.18/dm-stats-fix-merge-accounting.patch b/queue-6.18/dm-stats-fix-merge-accounting.patch new file mode 100644 index 0000000000..4802f090ab --- /dev/null +++ b/queue-6.18/dm-stats-fix-merge-accounting.patch @@ -0,0 +1,36 @@ +From 1917eb2db750ecbdf710f79a8042eaa545a063c7 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Fri, 10 Jul 2026 18:35:49 +0200 +Subject: dm-stats: fix merge accounting + +From: Mikulas Patocka + +commit 1917eb2db750ecbdf710f79a8042eaa545a063c7 upstream. + +There were wrong parentheses when setting stats_aux->merged, so that +merging was never properly accounted. This commit fixes it. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4-6 +Fixes: fd2ed4d25270 ("dm: add statistics support") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-stats.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/md/dm-stats.c ++++ b/drivers/md/dm-stats.c +@@ -692,10 +692,8 @@ void dm_stats_account_io(struct dm_stats + */ + last = raw_cpu_ptr(stats->last); + stats_aux->merged = +- (bi_sector == (READ_ONCE(last->last_sector) && +- ((bi_rw == WRITE) == +- (READ_ONCE(last->last_rw) == WRITE)) +- )); ++ bi_sector == READ_ONCE(last->last_sector) && ++ (bi_rw == WRITE) == (READ_ONCE(last->last_rw) == WRITE); + WRITE_ONCE(last->last_sector, end_sector); + WRITE_ONCE(last->last_rw, bi_rw); + } else diff --git a/queue-6.18/dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch b/queue-6.18/dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch new file mode 100644 index 0000000000..5216c170cc --- /dev/null +++ b/queue-6.18/dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch @@ -0,0 +1,235 @@ +From 5bcd4d3058ebaf46ad2e163829d87dd4870c7a45 Mon Sep 17 00:00:00 2001 +From: Ming-Hung Tsai +Date: Tue, 30 Jun 2026 20:17:44 +0800 +Subject: dm thin metadata: fix metadata snapshot consistency on commit failure + +From: Ming-Hung Tsai + +commit 5bcd4d3058ebaf46ad2e163829d87dd4870c7a45 upstream. + +__reserve_metadata_snap() and __release_metadata_snap() modify the +superblock's held_root directly in the block_manager's buffer. If the +subsequent metadata commit fails, the held_root gets flushed to disk +through the abort_transaction path, resulting in inconsistent metadata. + +Reproducer 1: __reserve_metadata_snap() + +1. Create a 2 MiB metadata device and make the region after the 14th + block inaccessible, to trigger metadata commit failure in the + subsequent reserve_metadata_snap operation. The 14th block will be + the shadow destination for the index block. + +dmsetup create tmeta --table "0 112 linear /dev/sdc 0 +112 3984 error" + +2. Create a 16 MiB thin-pool + +dmsetup create tdata --table "0 32768 zero" +dd if=/dev/zero of=/dev/mapper/tmeta bs=4k count=1 +dmsetup create tpool --table "0 32768 thin-pool /dev/mapper/tmeta \ +/dev/mapper/tdata 128 0 1 skip_block_zeroing" + +3. Take a metadata snapshot to trigger metadata commit failure and + transaction abort. However, the held_root is written to disk, + breaking metadata consistency. + +dmsetup message tpool 0 "reserve_metadata_snap" + +thin_check v1.2.2 result: + +Bad reference count for metadata block 6. Expected 2, but space map contains 1. +Bad reference count for metadata block 7. Expected 2, but space map contains 1. +Bad reference count for metadata block 13. Expected 1, but space map contains 0. + +Reproducer 2: __release_metadata_snap() + +1. Create a 2 MiB metadata device and make the region after the 16th + block inaccessible, to trigger metadata commit failure in the + subsequent release_metadata_snap operation. The 16th block will be + the shadow destination for the index block. + +dmsetup create tmeta --table "0 128 linear /dev/sdc 0 +128 3968 error" + +2. Create a 16 MiB thin-pool + +dmsetup create tdata --table "0 32768 zero" +dd if=/dev/zero of=/dev/mapper/tmeta bs=4k count=1 +dmsetup create tpool --table "0 32768 thin-pool /dev/mapper/tmeta \ +/dev/mapper/tdata 128 0 1 skip_block_zeroing" + +3. Reserve then release the metadata snapshot, to trigger metadata + commit failure and transaction abort. The held_root gets removed + from the on-disk superblock, causing inconsistent metadata. + +dmsetup message tpool 0 "reserve_metadata_snap" +dmsetup message tpool 0 "release_metadata_snap" + +thin_check v1.2.2 result: + +Bad reference count for metadata block 6. Expected 1, but space map contains 2. +Bad reference count for metadata block 7. Expected 1, but space map contains 2. +1 metadata blocks have leaked. + +Fix by deferring the held_root update to commit time. + +Additionally, move the existing-snapshot check in __reserve_metadata_snap +before the shadow operation to avoid unnecessary work. In +__release_metadata_snap, clear pmd->held_root before btree deletion so +partial failure leaks blocks rather than leaving a stale reference, and +unlock the snapshot block before decrementing its refcount. + +Fixes: 991d9fa02da0 ("dm: add thin provisioning target") +Cc: stable@vger.kernel.org +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-thin-metadata.c | 63 ++++++++++++------------------------------ + 1 file changed, 18 insertions(+), 45 deletions(-) + +--- a/drivers/md/dm-thin-metadata.c ++++ b/drivers/md/dm-thin-metadata.c +@@ -186,6 +186,7 @@ struct dm_pool_metadata { + uint32_t time; + dm_block_t root; + dm_block_t details_root; ++ dm_block_t held_root; + struct list_head thin_devices; + uint64_t trans_id; + unsigned long flags; +@@ -748,6 +749,7 @@ static int __open_metadata(struct dm_poo + */ + pmd->root = le64_to_cpu(disk_super->data_mapping_root); + pmd->details_root = le64_to_cpu(disk_super->device_details_root); ++ pmd->held_root = le64_to_cpu(disk_super->held_root); + + __setup_btree_details(pmd); + dm_bm_unlock(sblock); +@@ -838,6 +840,7 @@ static int __begin_transaction(struct dm + pmd->time = le32_to_cpu(disk_super->time); + pmd->root = le64_to_cpu(disk_super->data_mapping_root); + pmd->details_root = le64_to_cpu(disk_super->device_details_root); ++ pmd->held_root = le64_to_cpu(disk_super->held_root); + pmd->trans_id = le64_to_cpu(disk_super->trans_id); + pmd->flags = le32_to_cpu(disk_super->flags); + pmd->data_block_size = le32_to_cpu(disk_super->data_block_size); +@@ -928,6 +931,7 @@ static int __commit_transaction(struct d + disk_super->time = cpu_to_le32(pmd->time); + disk_super->data_mapping_root = cpu_to_le64(pmd->root); + disk_super->device_details_root = cpu_to_le64(pmd->details_root); ++ disk_super->held_root = cpu_to_le64(pmd->held_root); + disk_super->trans_id = cpu_to_le64(pmd->trans_id); + disk_super->flags = cpu_to_le32(pmd->flags); + +@@ -1333,9 +1337,14 @@ static int __reserve_metadata_snap(struc + { + int r, inc; + struct thin_disk_superblock *disk_super; +- struct dm_block *copy, *sblock; ++ struct dm_block *copy; + dm_block_t held_root; + ++ if (pmd->held_root) { ++ DMWARN("Pool metadata snapshot already exists: release this before taking another."); ++ return -EBUSY; ++ } ++ + /* + * We commit to ensure the btree roots which we increment in a + * moment are up to date. +@@ -1363,14 +1372,6 @@ static int __reserve_metadata_snap(struc + held_root = dm_block_location(copy); + disk_super = dm_block_data(copy); + +- if (le64_to_cpu(disk_super->held_root)) { +- DMWARN("Pool metadata snapshot already exists: release this before taking another."); +- +- dm_tm_dec(pmd->tm, held_root); +- dm_tm_unlock(pmd->tm, copy); +- return -EBUSY; +- } +- + /* + * Wipe the spacemap since we're not publishing this. + */ +@@ -1386,18 +1387,8 @@ static int __reserve_metadata_snap(struc + dm_tm_inc(pmd->tm, le64_to_cpu(disk_super->device_details_root)); + dm_tm_unlock(pmd->tm, copy); + +- /* +- * Write the held root into the superblock. +- */ +- r = superblock_lock(pmd, &sblock); +- if (r) { +- dm_tm_dec(pmd->tm, held_root); +- return r; +- } ++ pmd->held_root = held_root; + +- disk_super = dm_block_data(sblock); +- disk_super->held_root = cpu_to_le64(held_root); +- dm_bm_unlock(sblock); + return 0; + } + +@@ -1417,18 +1408,10 @@ static int __release_metadata_snap(struc + { + int r; + struct thin_disk_superblock *disk_super; +- struct dm_block *sblock, *copy; ++ struct dm_block *copy; + dm_block_t held_root; + +- r = superblock_lock(pmd, &sblock); +- if (r) +- return r; +- +- disk_super = dm_block_data(sblock); +- held_root = le64_to_cpu(disk_super->held_root); +- disk_super->held_root = cpu_to_le64(0); +- +- dm_bm_unlock(sblock); ++ held_root = pmd->held_root; + + if (!held_root) { + DMWARN("No pool metadata snapshot found: nothing to release."); +@@ -1439,13 +1422,15 @@ static int __release_metadata_snap(struc + if (r) + return r; + ++ pmd->held_root = 0; ++ + disk_super = dm_block_data(copy); + dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root)); + dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root)); +- dm_sm_dec_block(pmd->metadata_sm, held_root); +- + dm_tm_unlock(pmd->tm, copy); + ++ dm_sm_dec_block(pmd->metadata_sm, held_root); ++ + return 0; + } + +@@ -1464,19 +1449,7 @@ int dm_pool_release_metadata_snap(struct + static int __get_metadata_snap(struct dm_pool_metadata *pmd, + dm_block_t *result) + { +- int r; +- struct thin_disk_superblock *disk_super; +- struct dm_block *sblock; +- +- r = dm_bm_read_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION, +- &sb_validator, &sblock); +- if (r) +- return r; +- +- disk_super = dm_block_data(sblock); +- *result = le64_to_cpu(disk_super->held_root); +- +- dm_bm_unlock(sblock); ++ *result = pmd->held_root; + + return 0; + } diff --git a/queue-6.18/dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch b/queue-6.18/dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch new file mode 100644 index 0000000000..6b756847d0 --- /dev/null +++ b/queue-6.18/dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch @@ -0,0 +1,38 @@ +From 4b22d0801fadfcae2e106e6ba32e49439c7c7ebf Mon Sep 17 00:00:00 2001 +From: Genjian Zhang +Date: Sat, 11 Jul 2026 18:05:26 +0800 +Subject: dm thin metadata: fix superblock refcount leak on snapshot shadow failure + +From: Genjian Zhang + +commit 4b22d0801fadfcae2e106e6ba32e49439c7c7ebf upstream. + +__reserve_metadata_snap() increments THIN_SUPERBLOCK_LOCATION in the +metadata space map before shadowing it. When dm_tm_shadow_block() +fails, a reference is leaked in the metadata space map. + +Fix by adding the missing dm_sm_dec_block(). + +Signed-off-by: Genjian Zhang +Signed-off-by: Mikulas Patocka +Fixes: cc8394d86f04 ("dm thin: provide userspace access to pool metadata") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-thin-metadata.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm-thin-metadata.c ++++ b/drivers/md/dm-thin-metadata.c +@@ -1353,8 +1353,10 @@ static int __reserve_metadata_snap(struc + dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION); + r = dm_tm_shadow_block(pmd->tm, THIN_SUPERBLOCK_LOCATION, + &sb_validator, ©, &inc); +- if (r) ++ if (r) { ++ dm_sm_dec_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION); + return r; ++ } + + BUG_ON(!inc); + diff --git a/queue-6.18/dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch b/queue-6.18/dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch new file mode 100644 index 0000000000..1e526fd408 --- /dev/null +++ b/queue-6.18/dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch @@ -0,0 +1,37 @@ +From 72e9ec2fe32b00994f41719cf77423fca67d48b2 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:33:16 +0200 +Subject: dm-verity: avoid double increment of &use_bh_wq_enabled + +From: Mikulas Patocka + +commit 72e9ec2fe32b00994f41719cf77423fca67d48b2 upstream. + +verity_parse_opt_args is called twice, first with the only_modifier_opts, +first with only_modifier_opts == true and then with only_modifier_opts == +false. Thus, the static branch &use_bh_wq_enabled was incremented twice +and the destructor verity_dtr would only decrement it once. + +Fix tihs bug by only incrementing it on the first call, on the second +call, when v->use_bh_wq is true, do nothing. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4-6 +Cc: stable@vger.kernel.org +Fixes: df326e7a0699 ("dm verity: allow optional args to alter primary args handling") +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-verity-target.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -1194,6 +1194,8 @@ static int verity_parse_opt_args(struct + continue; + + } else if (!strcasecmp(arg_name, DM_VERITY_OPT_TASKLET_VERIFY)) { ++ if (v->use_bh_wq) ++ continue; + v->use_bh_wq = true; + static_branch_inc(&use_bh_wq_enabled); + continue; diff --git a/queue-6.18/dm-verity-fix-a-possible-null-pointer-dereference.patch b/queue-6.18/dm-verity-fix-a-possible-null-pointer-dereference.patch new file mode 100644 index 0000000000..55da5b6bbc --- /dev/null +++ b/queue-6.18/dm-verity-fix-a-possible-null-pointer-dereference.patch @@ -0,0 +1,32 @@ +From e72b793ae440f6900fb17a4b8518c707b5cd3e17 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:35:06 +0200 +Subject: dm-verity: fix a possible NULL pointer dereference + +From: Mikulas Patocka + +commit e72b793ae440f6900fb17a4b8518c707b5cd3e17 upstream. + +Fix a possible NULL pointer dereference dm_verity_loadpin_is_bdev_trusted +if the device has no table. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4-6 +Fixes: b6c1c5745ccc ("dm: Add verity helpers for LoadPin") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-verity-loadpin.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/md/dm-verity-loadpin.c ++++ b/drivers/md/dm-verity-loadpin.c +@@ -70,7 +70,7 @@ bool dm_verity_loadpin_is_bdev_trusted(s + + table = dm_get_live_table(md, &srcu_idx); + +- if (table->num_targets != 1) ++ if (!table || table->num_targets != 1) + goto out; + + ti = dm_table_get_target(table, 0); diff --git a/queue-6.18/dm-verity-increase-sprintf-buffer-size.patch b/queue-6.18/dm-verity-increase-sprintf-buffer-size.patch new file mode 100644 index 0000000000..36e8dce381 --- /dev/null +++ b/queue-6.18/dm-verity-increase-sprintf-buffer-size.patch @@ -0,0 +1,35 @@ +From 88dd117c92a142253fb7a17e791773902b3babc6 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:36:01 +0200 +Subject: dm-verity: increase sprintf buffer size + +From: Mikulas Patocka + +commit 88dd117c92a142253fb7a17e791773902b3babc6 upstream. + +The prefix "DM_VERITY_ERR_BLOCK_NR" is 22 chars. Add '=', one digit for +type, ',', up to 20 digits for a u64 block number, and a NUL terminator: +that's 46 bytes. The buffer is 42 bytes. For block numbers >= 16 decimal +digits (devices larger than ~16 EB with 4K blocks), snprintf silently +truncates the uevent environment variable. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Fixes: 65ff5b7ddf05 ("dm verity: add error handling modes for corrupted blocks") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-verity-target.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -25,7 +25,7 @@ + + #define DM_MSG_PREFIX "verity" + +-#define DM_VERITY_ENV_LENGTH 42 ++#define DM_VERITY_ENV_LENGTH 46 + #define DM_VERITY_ENV_VAR_NAME "DM_VERITY_ERR_BLOCK_NR" + + #define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144 diff --git a/queue-6.18/dm-verity-make-error-counter-atomic.patch b/queue-6.18/dm-verity-make-error-counter-atomic.patch new file mode 100644 index 0000000000..7f25eefdd8 --- /dev/null +++ b/queue-6.18/dm-verity-make-error-counter-atomic.patch @@ -0,0 +1,67 @@ +From 8ec4d9c5a5cf4b61fc087f871465b1f79b393325 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:37:38 +0200 +Subject: dm-verity: make error counter atomic + +From: Mikulas Patocka + +commit 8ec4d9c5a5cf4b61fc087f871465b1f79b393325 upstream. + +The error counter "v->corrupted_errs" was not atomic, thus it could be +subject to race conditions. The call to +dm_audit_log_target("max-corrupted-errors") may be skipped due to the +races. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Fixes: 65ff5b7ddf05 ("dm verity: add error handling modes for corrupted blocks") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-verity-target.c | 12 +++++++----- + drivers/md/dm-verity.h | 2 +- + 2 files changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -165,14 +165,16 @@ static int verity_handle_err(struct dm_v + char *envp[] = { verity_env, NULL }; + const char *type_str = ""; + struct mapped_device *md = dm_table_get_md(v->ti->table); ++ int ce; + + /* Corruption should be visible in device status in all modes */ + v->hash_failed = true; + +- if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS) +- goto out; +- +- v->corrupted_errs++; ++ ce = atomic_read(&v->corrupted_errs); ++ do { ++ if (ce >= DM_VERITY_MAX_CORRUPTED_ERRS) ++ goto out; ++ } while (!atomic_try_cmpxchg(&v->corrupted_errs, &ce, ce + 1)); + + switch (type) { + case DM_VERITY_BLOCK_TYPE_DATA: +@@ -188,7 +190,7 @@ static int verity_handle_err(struct dm_v + DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name, + type_str, block); + +- if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) { ++ if (ce + 1 == DM_VERITY_MAX_CORRUPTED_ERRS) { + DMERR("%s: reached maximum errors", v->data_dev->name); + dm_audit_log_target(DM_MSG_PREFIX, "max-corrupted-errors", v->ti, 0); + } +--- a/drivers/md/dm-verity.h ++++ b/drivers/md/dm-verity.h +@@ -62,7 +62,7 @@ struct dm_verity { + unsigned int digest_size; /* digest size for the current hash algorithm */ + enum verity_mode mode; /* mode for handling verification errors */ + enum verity_mode error_mode;/* mode for handling I/O errors */ +- unsigned int corrupted_errs;/* Number of errors for corrupted blocks */ ++ atomic_t corrupted_errs;/* Number of errors for corrupted blocks */ + + struct workqueue_struct *verify_wq; + diff --git a/queue-6.18/dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch b/queue-6.18/dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch new file mode 100644 index 0000000000..a5aefde6e4 --- /dev/null +++ b/queue-6.18/dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch @@ -0,0 +1,34 @@ +From 366665416f20527ff7cad548a32d1ddf23195740 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 9 Jul 2026 21:29:11 +0200 +Subject: dm_early_create: fix freeing used table on dm_resume failure + +From: Mikulas Patocka + +commit 366665416f20527ff7cad548a32d1ddf23195740 upstream. + +If dm_resume fails, the kernel attempts to free table with +dm_table_destroy, but the table was already instantiated with +dm_swap_table. This commit skips the call to dm_table_destroy in this +case. + +Signed-off-by: Mikulas Patocka +Assisted-by: Claude:claude-opus-4.6 +Fixes: 6bbc923dfcf5 ("dm: add support to directly boot to a mapped device") +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-ioctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -2341,7 +2341,7 @@ int __init dm_early_create(struct dm_ioc + /* resume device */ + r = dm_resume(md); + if (r) +- goto err_destroy_table; ++ goto err_hash_remove; + + DMINFO("%s (%s) is ready", md->disk->disk_name, dmi->name); + dm_put(md); diff --git a/queue-6.18/dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch b/queue-6.18/dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch new file mode 100644 index 0000000000..d148e7b48f --- /dev/null +++ b/queue-6.18/dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch @@ -0,0 +1,50 @@ +From 77a9298741f8f9e8b963c977f5582ab21c6d3427 Mon Sep 17 00:00:00 2001 +From: Baineng Shou +Date: Mon, 29 Jun 2026 11:13:46 +0800 +Subject: dma-fence: Make dma_fence_dedup_array() robust against 0-count input +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Baineng Shou + +commit 77a9298741f8f9e8b963c977f5582ab21c6d3427 upstream. + +dma_fence_dedup_array() returns 1 when called with num_fences == 0: +the for-loop body never executes, j stays at 0, and the final +`return ++j` yields 1. This contradicts both the kernel-doc ("Return: +Number of unique fences remaining in the array") and the natural +expectation that 0 input gives 0 output. + +The caller __dma_fence_unwrap_merge() bails out via the +`if (count == 0 || count == 1)` fast path and so is save. + +But amdgpu_userq_wait_*() could reach the dedup call with a zero local +count and dereference an uninitialized fence slot in the array. + +Make the contract match the documentation by returning 0 early. This +also skips an unnecessary sort() call on an empty array. + +Cc: stable@vger.kernel.org +Signed-off-by: Baineng Shou +Reviewed-by: Christian König +Fixes: 575ec9b0c2f1 ("dma-fence: Add helper to sort and deduplicate dma_fence arrays") +Signed-off-by: Christian König +Link: https://lore.kernel.org/r/20260629031346.3875683-1-shoubaineng@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/dma-buf/dma-fence-unwrap.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/dma-buf/dma-fence-unwrap.c ++++ b/drivers/dma-buf/dma-fence-unwrap.c +@@ -97,6 +97,9 @@ int dma_fence_dedup_array(struct dma_fen + { + int i, j; + ++ if (!num_fences) ++ return 0; ++ + sort(fences, num_fences, sizeof(*fences), fence_cmp, NULL); + + /* diff --git a/queue-6.18/dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch b/queue-6.18/dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch new file mode 100644 index 0000000000..a5d1ca0824 --- /dev/null +++ b/queue-6.18/dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch @@ -0,0 +1,72 @@ +From 8ffba0171c6bbce5f093c6dba5a02c0805b31203 Mon Sep 17 00:00:00 2001 +From: Frank Li +Date: Thu, 21 May 2026 23:21:53 +0900 +Subject: dmaengine: dw-edma: Add spinlock to protect DONE_INT_MASK and ABORT_INT_MASK + +From: Frank Li + +commit 8ffba0171c6bbce5f093c6dba5a02c0805b31203 upstream. + +The DONE_INT_MASK and ABORT_INT_MASK registers are shared by all DMA +channels, and modifying them requires a read-modify-write sequence. +Because this operation is not atomic, concurrent calls to +dw_edma_v0_core_start() can introduce race conditions if two channels +update these registers simultaneously. + +Add a spinlock to serialize access to these registers and prevent race +conditions. + +Fixes: 7e4b8a4fbe2c ("dmaengine: Add Synopsys eDMA IP version 0 support") +Cc: stable@vger.kernel.org +Signed-off-by: Frank Li +[den: update dw_edma.lock comment] +Link: https://lore.kernel.org/dmaengine/20260109-edma_ll-v2-1-5c0b27b2c664@nxp.com/ +Signed-off-by: Koichiro Den +Link: https://patch.msgid.link/20260521142153.2957432-5-den@valinux.co.jp +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/dma/dw-edma/dw-edma-core.h | 2 +- + drivers/dma/dw-edma/dw-edma-v0-core.c | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/dma/dw-edma/dw-edma-core.h ++++ b/drivers/dma/dw-edma/dw-edma-core.h +@@ -108,7 +108,7 @@ struct dw_edma { + + struct dw_edma_chan *chan; + +- raw_spinlock_t lock; /* Only for legacy */ ++ raw_spinlock_t lock; /* Protect v0 shared registers */ + + struct dw_edma_chip *chip; + +--- a/drivers/dma/dw-edma/dw-edma-v0-core.c ++++ b/drivers/dma/dw-edma/dw-edma-v0-core.c +@@ -364,6 +364,7 @@ static void dw_edma_v0_core_start(struct + { + struct dw_edma_chan *chan = chunk->chan; + struct dw_edma *dw = chan->dw; ++ unsigned long flags; + u32 tmp; + + dw_edma_v0_core_write_chunk(chunk); +@@ -408,6 +409,8 @@ static void dw_edma_v0_core_start(struct + } + } + /* Interrupt unmask - done, abort */ ++ raw_spin_lock_irqsave(&dw->lock, flags); ++ + tmp = GET_RW_32(dw, chan->dir, int_mask); + tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)); + tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)); +@@ -416,6 +419,9 @@ static void dw_edma_v0_core_start(struct + tmp = GET_RW_32(dw, chan->dir, linked_list_err_en); + tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id)); + SET_RW_32(dw, chan->dir, linked_list_err_en, tmp); ++ ++ raw_spin_unlock_irqrestore(&dw->lock, flags); ++ + /* Channel control */ + SET_CH_32(dw, chan->dir, chan->id, ch_control1, + (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE)); diff --git a/queue-6.18/dmaengine-tegra-fix-burst-size-calculation.patch b/queue-6.18/dmaengine-tegra-fix-burst-size-calculation.patch new file mode 100644 index 0000000000..df3bd94268 --- /dev/null +++ b/queue-6.18/dmaengine-tegra-fix-burst-size-calculation.patch @@ -0,0 +1,51 @@ +From 4651df83b6c796daead3447e8fd874322918ee4f Mon Sep 17 00:00:00 2001 +From: Kartik Rajput +Date: Wed, 22 Apr 2026 12:11:34 +0530 +Subject: dmaengine: tegra: Fix burst size calculation + +From: Kartik Rajput + +commit 4651df83b6c796daead3447e8fd874322918ee4f upstream. + +Currently, the Tegra GPC DMA hardware requires the transfer length to +be a multiple of the max burst size configured for the channel. When a +client requests a transfer where the length is not evenly divisible by +the configured max burst size, the DMA hangs with partial burst at +the end. + +Fix this by reducing the burst size to the largest power-of-2 value +that evenly divides the transfer length. For example, a 40-byte +transfer with a 16-byte max burst will now use an 8-byte burst +(40 / 8 = 5 complete bursts) instead of causing a hang. + +This issue was observed with the PL011 UART driver where TX DMA +transfers of arbitrary lengths were stuck. + +Fixes: ee17028009d4 ("dmaengine: tegra: Add tegra gpcdma driver") +Cc: stable@vger.kernel.org +Signed-off-by: Kartik Rajput +Reviewed-by: Frank Li +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260422064134.1323610-1-kkartik@nvidia.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/dma/tegra186-gpc-dma.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/dma/tegra186-gpc-dma.c ++++ b/drivers/dma/tegra186-gpc-dma.c +@@ -825,6 +825,13 @@ static unsigned int get_burst_size(struc + * len to calculate the optimum burst size + */ + burst_byte = burst_size ? burst_size * slave_bw : len; ++ ++ /* ++ * Find the largest burst size that evenly divides the transfer length. ++ * The hardware requires the transfer length to be a multiple of the ++ * burst size - partial bursts are not supported. ++ */ ++ burst_byte = min(burst_byte, 1U << __ffs(len)); + burst_mmio_width = burst_byte / 4; + + if (burst_mmio_width < TEGRA_GPCDMA_MMIOSEQ_BURST_MIN) diff --git a/queue-6.18/fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch b/queue-6.18/fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch new file mode 100644 index 0000000000..947e1a21a3 --- /dev/null +++ b/queue-6.18/fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch @@ -0,0 +1,43 @@ +From 9e8bc49f91f3f81d957c4f1c1f09fe94e2f88f6a Mon Sep 17 00:00:00 2001 +From: Sebastian Alba Vives +Date: Mon, 18 May 2026 13:07:40 -0600 +Subject: fpga: dfl: add bounds check in dfh_get_param_size() + +From: Sebastian Alba Vives + +commit 9e8bc49f91f3f81d957c4f1c1f09fe94e2f88f6a upstream. + +dfh_get_param_size() can return a parameter size larger than the feature +region because the loop bounds check is evaluated before incrementing +size. If the EOP (End of Parameters) bit is set in the same iteration, +the inflated size is returned without re-validation against max. + +This can cause create_feature_instance() to call memcpy_fromio() with a +size exceeding the ioremap'd region when a malicious FPGA device provides +crafted DFHv1 parameter headers. + +Add a bounds check after the size increment to ensure the accumulated +size never exceeds the feature boundary. + +Fixes: 4747ab89b4a6 ("fpga: dfl: add basic support for DFHv1") +Cc: stable@vger.kernel.org +Signed-off-by: Sebastian Alba Vives +Reviewed-by: Xu Yilun +Link: https://lore.kernel.org/r/20260518190742.61426-2-sebasjosue84@gmail.com +Signed-off-by: Xu Yilun +Signed-off-by: Greg Kroah-Hartman +--- + drivers/fpga/dfl.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -1133,6 +1133,8 @@ static int dfh_get_param_size(void __iom + return -EINVAL; + + size += next * sizeof(u64); ++ if (size > max) ++ return -EINVAL; + + if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v)) + return size; diff --git a/queue-6.18/fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch b/queue-6.18/fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch new file mode 100644 index 0000000000..8f8ac0f63a --- /dev/null +++ b/queue-6.18/fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch @@ -0,0 +1,41 @@ +From 43a1974da6bc7ce8f4d1dc1d03d56997428c29c3 Mon Sep 17 00:00:00 2001 +From: Sebastian Alba Vives +Date: Mon, 18 May 2026 13:07:42 -0600 +Subject: fpga: microchip-spi: fix zero header_size OOB read in mpf_ops_parse_header() + +From: Sebastian Alba Vives + +commit 43a1974da6bc7ce8f4d1dc1d03d56997428c29c3 upstream. + +mpf_ops_parse_header() reads header_size from the bitstream at +MPF_HEADER_SIZE_OFFSET (24). When header_size is zero, the expression +*(buf + header_size - 1) reads one byte before the buffer start. + +Since initial_header_size is set to 71 in mpf_ops, the fpga-mgr core +guarantees the buffer is large enough to reach MPF_HEADER_SIZE_OFFSET. +The only real gap is the zero header_size case, which cannot be +resolved by providing a larger buffer, so return -EINVAL. + +Fixes: 5f8d4a900830 ("fpga: microchip-spi: add Microchip MPF FPGA manager") +Cc: stable@vger.kernel.org +Signed-off-by: Sebastian Alba Vives +Reviewed-by: Xu Yilun +Link: https://lore.kernel.org/r/20260518190742.61426-4-sebasjosue84@gmail.com +Signed-off-by: Xu Yilun +Signed-off-by: Greg Kroah-Hartman +--- + drivers/fpga/microchip-spi.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/fpga/microchip-spi.c ++++ b/drivers/fpga/microchip-spi.c +@@ -116,6 +116,9 @@ static int mpf_ops_parse_header(struct f + } + + header_size = *(buf + MPF_HEADER_SIZE_OFFSET); ++ if (!header_size) ++ return -EINVAL; ++ + if (header_size > count) { + info->header_size = header_size; + return -EAGAIN; diff --git a/queue-6.18/hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch b/queue-6.18/hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch new file mode 100644 index 0000000000..35f33592bc --- /dev/null +++ b/queue-6.18/hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch @@ -0,0 +1,33 @@ +From a35a6f1b20100057c66b7be5a8f6864661c3945c Mon Sep 17 00:00:00 2001 +From: Joshua Crofts +Date: Mon, 29 Jun 2026 21:17:40 +0200 +Subject: hwmon: (ltc2992) add missing 'select REGMAP_I2C' to Kconfig + +From: Joshua Crofts + +commit a35a6f1b20100057c66b7be5a8f6864661c3945c upstream. + +The Kconfig entry for the LTC2992 sensor doesn't contain a +`select REGMAP_I2C` parameter, causing build failures if regmap +isn't selected previously during the build process. + +Fixes: b0bd407e94b0 ("hwmon: (ltc2992) Add support") +Cc: stable@vger.kernel.org +Signed-off-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260629-add-kconfig-deps-v1-2-8104df929b1a@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1086,6 +1086,7 @@ config SENSORS_LTC2992 + tristate "Linear Technology LTC2992" + depends on I2C + depends on GPIOLIB ++ select REGMAP_I2C + help + If you say yes here you get support for Linear Technology LTC2992 + I2C System Monitor. The LTC2992 measures current, voltage, and diff --git a/queue-6.18/hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch b/queue-6.18/hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch new file mode 100644 index 0000000000..9d57134981 --- /dev/null +++ b/queue-6.18/hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch @@ -0,0 +1,33 @@ +From ed576f2f4eef8cbe2c110da503825a8dc4717030 Mon Sep 17 00:00:00 2001 +From: Joshua Crofts +Date: Mon, 29 Jun 2026 21:17:41 +0200 +Subject: hwmon: (max6697) add missing 'select REGMAP_I2C' to Kconfig + +From: Joshua Crofts + +commit ed576f2f4eef8cbe2c110da503825a8dc4717030 upstream. + +The Kconfig entry for the MAX6697 sensor doesn't contain a +`select REGMAP_I2C` parameter, causing build failures if regmap +isn't selected previously during the build process. + +Fixes: 3a2a8cc3fe24 ("hwmon: (max6697) Convert to use regmap") +Cc: stable@vger.kernel.org +Signed-off-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260629-add-kconfig-deps-v1-3-8104df929b1a@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1331,6 +1331,7 @@ config SENSORS_MAX6650 + config SENSORS_MAX6697 + tristate "Maxim MAX6697 and compatibles" + depends on I2C ++ select REGMAP_I2C + help + If you say yes here you get support for MAX6581, MAX6602, MAX6622, + MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699 diff --git a/queue-6.18/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch b/queue-6.18/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch new file mode 100644 index 0000000000..8684c34d44 --- /dev/null +++ b/queue-6.18/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch @@ -0,0 +1,83 @@ +From cb2fc37857693b55909fb77dc2c87cfbc1cdc476 Mon Sep 17 00:00:00 2001 +From: Vincent Jardin +Date: Mon, 13 Jul 2026 20:11:59 +0200 +Subject: i2c: imx: fix locked bus on SMBus block-read of 0 (atomic) + +From: Vincent Jardin + +commit cb2fc37857693b55909fb77dc2c87cfbc1cdc476 upstream. + +SMBus 3.1 6.5.7 allows a Block Read byte count of 0, but the atomic +(polling) path rejects it as -EPROTO. Worse, it returns without a +NACK+STOP: the next receive cycle has already started, so the target +keeps holding SDA and the bus stays stuck until a power cycle for +this i2c controller. + +Reading I2DR to obtain the count likewise arms the next byte on the +count > I2C_SMBUS_BLOCK_MAX path, which also returned -EPROTO directly +and left the bus held. + +Handle both: NACK the in-flight dummy byte (TXAK) and extend msgs->len so +the existing last-byte handling emits STOP; the dummy byte is discarded. +A count of 0 is a valid empty block read; a count above +I2C_SMBUS_BLOCK_MAX is still reported as -EPROTO, but only after the bus +has been released. + +The interrupt-driven path has the same flaw from a later commit and is +fixed separately, as it carries a different Fixes: tag and stable range. + +Fixes: 8e8782c71595 ("i2c: imx: add SMBus block read support") +Signed-off-by: Vincent Jardin +Cc: # v3.16+ +Acked-by: Oleksij Rempel +Acked-by: Carlos Song +Reviewed-by: Stefan Eichenberger +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260713-for-upstream-i2c-lx2160-fix-v1-v3-1-073ac9e103a5@free.fr +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i2c/busses/i2c-imx.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +--- a/drivers/i2c/busses/i2c-imx.c ++++ b/drivers/i2c/busses/i2c-imx.c +@@ -1415,6 +1415,7 @@ static int i2c_imx_atomic_read(struct im + int i, result; + unsigned int temp; + int block_data = msgs->flags & I2C_M_RECV_LEN; ++ int block_err = 0; + + result = i2c_imx_prepare_read(i2c_imx, msgs, false); + if (result) +@@ -1436,8 +1437,20 @@ static int i2c_imx_atomic_read(struct im + */ + if ((!i) && block_data) { + len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); +- if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) +- return -EPROTO; ++ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) { ++ /* ++ * SMBus 3.1 6.5.7: support count byte of 0. ++ * I2C_SMBUS_BLOCK_MAX case should not hold the SDA either. ++ */ ++ if (len > I2C_SMBUS_BLOCK_MAX) ++ block_err = -EPROTO; ++ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); ++ temp |= I2CR_TXAK; ++ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); ++ msgs->buf[0] = 0; ++ msgs->len = 2; ++ continue; ++ } + dev_dbg(&i2c_imx->adapter.dev, + "<%s> read length: 0x%X\n", + __func__, len); +@@ -1485,7 +1498,7 @@ static int i2c_imx_atomic_read(struct im + "<%s> read byte: B%d=0x%X\n", + __func__, i, msgs->buf[i]); + } +- return 0; ++ return block_err; + } + + static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, diff --git a/queue-6.18/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch b/queue-6.18/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch new file mode 100644 index 0000000000..989548898d --- /dev/null +++ b/queue-6.18/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch @@ -0,0 +1,72 @@ +From 07fd9385f0d87dff4b34f355f68adf701080cb24 Mon Sep 17 00:00:00 2001 +From: Vincent Jardin +Date: Mon, 13 Jul 2026 20:12:00 +0200 +Subject: i2c: imx: fix locked bus on SMBus block-read of 0 (IRQ) + +From: Vincent Jardin + +commit 07fd9385f0d87dff4b34f355f68adf701080cb24 upstream. + +SMBus 3.1 6.5.7 allows a Block Read byte count of 0, but the +interrupt-driven block-read state machine rejects it as -EPROTO. Worse, +it returns without a NACK+STOP: the next receive cycle has already +started, so the target keeps holding SDA and the bus stays stuck until a +power cycle of this i2c controller. + +Accept count=0: NACK the in-flight dummy byte (TXAK) and set msg->len to +2 so i2c_imx_isr_read_continue() emits STOP via its normal last-byte +path. The dummy byte is discarded; block-read callers only consume +buf[0..count-1]. + +Reading I2DR has likewise already armed the next byte on the +count > I2C_SMBUS_BLOCK_MAX error path, so NACK it (TXAK) before aborting +with -EPROTO; otherwise the failing transfer's STOP cannot complete and +the bus stays held. + +The atomic path regressed earlier (v3.16) and is fixed separately; this +patch covers only the v6.13 state-machine rework. + +Fixes: 5f5c2d4579ca ("i2c: imx: prevent rescheduling in non dma mode") +Signed-off-by: Vincent Jardin +Cc: # v6.13+ +Acked-by: Oleksij Rempel +Acked-by: Carlos Song +Reviewed-by: Stefan Eichenberger +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260713-for-upstream-i2c-lx2160-fix-v1-v3-2-073ac9e103a5@free.fr +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i2c/busses/i2c-imx.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/i2c/busses/i2c-imx.c ++++ b/drivers/i2c/busses/i2c-imx.c +@@ -1061,11 +1061,28 @@ static inline enum imx_i2c_state i2c_imx + static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx) + { + u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); ++ unsigned int temp; + + if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) { ++ /* ++ * SMBus 3.1 6.5.7: support count byte of 0. ++ * I2C_SMBUS_BLOCK_MAX case should not hold the SDA either. ++ * So NACK it (TXAK) to not hold the bus. ++ */ ++ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); ++ temp |= I2CR_TXAK; ++ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); ++ ++ if (len == 0) { ++ i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = 0; ++ i2c_imx->msg->len = 2; ++ return; ++ } ++ + i2c_imx->isr_result = -EPROTO; + i2c_imx->state = IMX_I2C_STATE_FAILED; + wake_up(&i2c_imx->queue); ++ return; + } + i2c_imx->msg->len += len; + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = len; diff --git a/queue-6.18/i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch b/queue-6.18/i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch new file mode 100644 index 0000000000..52bb3cc53a --- /dev/null +++ b/queue-6.18/i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch @@ -0,0 +1,37 @@ +From deb35336b5bfed5db9231b5348bc1514db930797 Mon Sep 17 00:00:00 2001 +From: Roman Vivchar +Date: Thu, 9 Jul 2026 16:31:29 +0300 +Subject: i2c: mediatek: fix WRRD for SoCs without auto_restart option + +From: Roman Vivchar + +commit deb35336b5bfed5db9231b5348bc1514db930797 upstream. + +MediaTek mt65xx family SoCs have no auto restart, however, they still +support the WRRD mode in the hardware. Because auto_restart is set to 0, +the WRRD mode will be never enabled, leading to read errors. + +Fix this by removing auto_restart check from the WRRD enable path. + +Fixes: b49218365280 ("i2c: mediatek: fix potential incorrect use of I2C_MASTER_WRRD") +Signed-off-by: Roman Vivchar +Cc: # v6.18+ +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260709-6572-6595-i2c-v2-1-b2fb8510d1d3@protonmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i2c/busses/i2c-mt65xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/i2c/busses/i2c-mt65xx.c ++++ b/drivers/i2c/busses/i2c-mt65xx.c +@@ -1250,7 +1250,7 @@ static int mtk_i2c_transfer(struct i2c_a + i2c->auto_restart = i2c->dev_comp->auto_restart; + + /* checking if we can skip restart and optimize using WRRD mode */ +- if (i2c->auto_restart && num == 2) { ++ if (num == 2) { + if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) && + msgs[0].addr == msgs[1].addr) { + i2c->auto_restart = 0; diff --git a/queue-6.18/i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch b/queue-6.18/i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch new file mode 100644 index 0000000000..d4f75fb067 --- /dev/null +++ b/queue-6.18/i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch @@ -0,0 +1,39 @@ +From 71356737a7a55c76fee847563e3d33f8e6dc6b6d Mon Sep 17 00:00:00 2001 +From: Xuanqiang Luo +Date: Tue, 14 Jul 2026 23:08:08 +0800 +Subject: i2c: mlxbf: Fix use-after-free in mlxbf_i2c_init_resource() + +From: Xuanqiang Luo + +commit 71356737a7a55c76fee847563e3d33f8e6dc6b6d upstream. + +If devm_platform_get_and_ioremap_resource() returns an error, +mlxbf_i2c_init_resource() frees tmp_res before reading tmp_res->io to +get the error code. This results in a use-after-free. + +Save the error code before freeing tmp_res. + +Fixes: b5b5b32081cd ("i2c: mlxbf: I2C SMBus driver for Mellanox BlueField SoC") +Signed-off-by: Xuanqiang Luo +Cc: # v5.10+ +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260714150808.85045-1-xuanqiang.luo@linux.dev +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i2c/busses/i2c-mlxbf.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -1058,8 +1058,10 @@ static int mlxbf_i2c_init_resource(struc + + tmp_res->io = devm_platform_get_and_ioremap_resource(pdev, type, &tmp_res->params); + if (IS_ERR(tmp_res->io)) { ++ int ret = PTR_ERR(tmp_res->io); ++ + devm_kfree(dev, tmp_res); +- return PTR_ERR(tmp_res->io); ++ return ret; + } + + tmp_res->type = type; diff --git a/queue-6.18/i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch b/queue-6.18/i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch new file mode 100644 index 0000000000..b00e9d9e14 --- /dev/null +++ b/queue-6.18/i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch @@ -0,0 +1,39 @@ +From 9db20d23aac7916ff49be409a4bfd48fe7cbbfb4 Mon Sep 17 00:00:00 2001 +From: Pei Xiao +Date: Fri, 10 Jul 2026 15:21:13 +0800 +Subject: i2c: spacemit: fix spurious IRQ handling returning IRQ_HANDLED + +From: Pei Xiao + +commit 9db20d23aac7916ff49be409a4bfd48fe7cbbfb4 upstream. + +When the interrupt status register reads zero, the handler should +return IRQ_NONE instead of IRQ_HANDLED. What the return value +actually feeds into is the spurious interrupt accounting in +note_interrupt(): falsely claiming IRQ_HANDLED defeats the "irq XX: +nobody cared" detection, so a stuck interrupt source would never be +caught. + +Fixes: 5ea558473fa3 ("i2c: spacemit: add support for SpacemiT K1 SoC") +Signed-off-by: Pei Xiao +Cc: # v6.15+ +Reviewed-by: Troy Mitchell +Reviewed-by: Mukesh Savaliya +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/ef8b623f45d4e430721e46572c2598d882044aed.1783667875.git.xiaopei01@kylinos.cn +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i2c/busses/i2c-k1.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/i2c/busses/i2c-k1.c ++++ b/drivers/i2c/busses/i2c-k1.c +@@ -425,7 +425,7 @@ static irqreturn_t spacemit_i2c_irq_hand + + status = readl(i2c->base + SPACEMIT_ISR); + if (!status) +- return IRQ_HANDLED; ++ return IRQ_NONE; + + i2c->status = status; + diff --git a/queue-6.18/ice-fix-ice_init_link-error-return-preventing-probe.patch b/queue-6.18/ice-fix-ice_init_link-error-return-preventing-probe.patch new file mode 100644 index 0000000000..49fa568d2e --- /dev/null +++ b/queue-6.18/ice-fix-ice_init_link-error-return-preventing-probe.patch @@ -0,0 +1,91 @@ +From eb509638686b0f8a98a0dd9c809f6a8db4d73a45 Mon Sep 17 00:00:00 2001 +From: Paul Greenwalt +Date: Wed, 8 Apr 2026 16:11:05 +0200 +Subject: ice: fix ice_init_link() error return preventing probe + +From: Paul Greenwalt + +commit eb509638686b0f8a98a0dd9c809f6a8db4d73a45 upstream. + +ice_init_link() can return an error status from ice_update_link_info() +or ice_init_phy_user_cfg(), causing probe to fail. + +An incorrect NVM update procedure can result in link/PHY errors, and +the recommended resolution is to update the NVM using the correct +procedure. If the driver fails probe due to link errors, the user +cannot update the NVM to recover. The link/PHY errors logged are +non-fatal: they are already annotated as 'not a fatal error if this +fails'. + +Since none of the errors inside ice_init_link() should prevent probe +from completing, convert it to void and remove the error check in the +caller. All failures are already logged; callers have no meaningful +recovery path for link init errors. + +Fixes: 5b246e533d01 ("ice: split probe into smaller functions") +Cc: stable@vger.kernel.org +Signed-off-by: Paul Greenwalt +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Alexander Nowlin +Signed-off-by: Tony Nguyen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/ice/ice_main.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -4871,16 +4871,14 @@ static void ice_init_wakeup(struct ice_p + device_set_wakeup_enable(ice_pf_to_dev(pf), false); + } + +-static int ice_init_link(struct ice_pf *pf) ++static void ice_init_link(struct ice_pf *pf) + { + struct device *dev = ice_pf_to_dev(pf); + int err; + + err = ice_init_link_events(pf->hw.port_info); +- if (err) { ++ if (err) + dev_err(dev, "ice_init_link_events failed: %d\n", err); +- return err; +- } + + /* not a fatal error if this fails */ + err = ice_init_nvm_phy_type(pf->hw.port_info); +@@ -4914,8 +4912,6 @@ static int ice_init_link(struct ice_pf * + } else { + set_bit(ICE_FLAG_NO_MEDIA, pf->flags); + } +- +- return err; + } + + static int ice_init_pf_sw(struct ice_pf *pf) +@@ -5058,13 +5054,11 @@ static int ice_init(struct ice_pf *pf) + + ice_init_wakeup(pf); + +- err = ice_init_link(pf); +- if (err) +- goto err_init_link; ++ ice_init_link(pf); + + err = ice_send_version(pf); + if (err) +- goto err_init_link; ++ goto err_deinit_pf_sw; + + ice_verify_cacheline_size(pf); + +@@ -5083,7 +5077,7 @@ static int ice_init(struct ice_pf *pf) + + return 0; + +-err_init_link: ++err_deinit_pf_sw: + ice_deinit_pf_sw(pf); + err_init_pf_sw: + ice_dealloc_vsis(pf); diff --git a/queue-6.18/irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch b/queue-6.18/irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch new file mode 100644 index 0000000000..df8b4d5435 --- /dev/null +++ b/queue-6.18/irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch @@ -0,0 +1,52 @@ +From 043db005a8d6932dc7d217c86307e9af0bc10ddc Mon Sep 17 00:00:00 2001 +From: Bhargav Joshi +Date: Sat, 20 Jun 2026 17:39:16 +0530 +Subject: irqchip/crossbar: Use correct index in crossbar_domain_free() + +From: Bhargav Joshi + +commit 043db005a8d6932dc7d217c86307e9af0bc10ddc upstream. + +crossbar_domain_free() resets the domain data and then uses the nulled +out irq_data->hwirq member as index to reset the irq_map[] entry and to +write the relevant crossbar register with a safe entry. That means it +never frees the correct index and keeps the crossbar register connection +to the source interrupt active. + +If it would not reset the domain data, then this would be even worse as +irq_data->hwirq holds the source interrupt number, but both the map and +register index need the corresponding GIC SPI number and not the source +interrupt number. This might even result in an out of bounds access as +the source interrupt number can be higher than the maximal index space. + +Fix this by using the GIC SPI index from the parent domain's irq_data. + +Fixes: 783d31863fb82 ("irqchip: crossbar: Convert dra7 crossbar to stacked domains") +Signed-off-by: Bhargav Joshi +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260620-irq-crossbar-fix-v2-1-b8e8499f468a@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-crossbar.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/irqchip/irq-crossbar.c ++++ b/drivers/irqchip/irq-crossbar.c +@@ -158,9 +158,14 @@ static void crossbar_domain_free(struct + for (i = 0; i < nr_irqs; i++) { + struct irq_data *d = irq_domain_get_irq_data(domain, virq + i); + ++ /* ++ * irq_map[] is indexed by GIC SPI number. The parent domain's ++ * hwirq contains the GIC interrupt number (GIC SPI + ++ * GIC_IRQ_START). ++ */ ++ cb->irq_map[d->parent_data->hwirq - GIC_IRQ_START] = IRQ_FREE; ++ cb->write(d->parent_data->hwirq - GIC_IRQ_START, cb->safe_map); + irq_domain_reset_irq_data(d); +- cb->irq_map[d->hwirq] = IRQ_FREE; +- cb->write(d->hwirq, cb->safe_map); + } + raw_spin_unlock(&cb->lock); + irq_domain_free_irqs_parent(domain, virq, nr_irqs); diff --git a/queue-6.18/ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch b/queue-6.18/ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch new file mode 100644 index 0000000000..27e1129946 --- /dev/null +++ b/queue-6.18/ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch @@ -0,0 +1,104 @@ +From 1c0ae3df692ea2a4ce992f786346154e75a3f0d5 Mon Sep 17 00:00:00 2001 +From: Ibrahim Hashimov +Date: Thu, 9 Jul 2026 17:05:30 +0200 +Subject: ksmbd: fix integer overflow in set_file_allocation_info() + +From: Ibrahim Hashimov + +commit 1c0ae3df692ea2a4ce992f786346154e75a3f0d5 upstream. + +set_file_allocation_info() converts the client-supplied +FILE_ALLOCATION_INFORMATION::AllocationSize into a 512-byte block +count with: + + alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9; + +AllocationSize is a fully client-controlled __le64 field; the only +validation performed by the caller (smb2_set_info_file(), case +FILE_ALLOCATION_INFORMATION) is that the fixed buffer is at least +sizeof(struct smb2_file_alloc_info) == 8 bytes. The value itself is +never range-checked before this arithmetic. + +When AllocationSize is close to U64_MAX (e.g. 0xffffffffffffffff), +"AllocationSize + 511" wraps around mod 2^64 to a small number +(0xffffffffffffffff + 511 = 510), so alloc_blks becomes 0. Since any +existing regular file has stat.blocks > 0, the function then takes +the "shrink" branch and calls: + + ksmbd_vfs_truncate(work, fp, alloc_blks * 512); /* == 0 */ + +silently truncating the file to size 0, even though the client asked +to grow the allocation to (what looks like) the maximum possible +size. The trailing "if (size < alloc_blks * 512) i_size_write(inode, +size);" restore is guarded by a comparison that is never true once +alloc_blks == 0, so the truncation is not undone. This lets an +authenticated SMB client that already holds an open handle with +FILE_WRITE_DATA on a file silently truncate that same file to size 0 +via a single crafted SET_INFO(FILE_ALLOCATION_INFORMATION) request +advertising a near-U64_MAX AllocationSize, even though the request +asks to grow the file's allocation rather than shrink it. This is a +functional/data-loss bug, not a privilege-boundary +violation: the same client could already truncate the file via +FILE_END_OF_FILE_INFORMATION or a plain write. + +Fix it by validating AllocationSize against MAX_LFS_FILESIZE, the +same upper bound the VFS itself uses to reject unrepresentable file +sizes, before doing the "+511" rounding, and rejecting oversized +values with -EINVAL. Bounding AllocationSize to +MAX_LFS_FILESIZE - 511 guarantees the "+511" addition cannot wrap, +and that the subsequent "alloc_blks * 512" values passed to +vfs_fallocate() and ksmbd_vfs_truncate() stay within a representable +loff_t as well. + +No legitimate SMB client asks for an allocation size anywhere near +2^64 bytes, so this only rejects a value that was previously +silently misinterpreted as zero. + +Runtime-verified on a v6.19 KASAN test stand: sending SET_INFO +(FILE_ALLOCATION_INFORMATION) with AllocationSize = 0xffffffffffffffff +against ksmbd now returns -EINVAL and leaves the target file's size +unchanged, where the unpatched kernel truncated it from 4096 to 0 +bytes. + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Cc: stable@vger.kernel.org +Signed-off-by: Ibrahim Hashimov +Assisted-by: AuditCode-AI:2026.07 +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smb2pdu.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6347,6 +6347,7 @@ static int set_file_allocation_info(stru + */ + + loff_t alloc_blks; ++ u64 alloc_size; + struct inode *inode; + struct kstat stat; + int rc; +@@ -6362,7 +6363,19 @@ static int set_file_allocation_info(stru + if (rc) + return rc; + +- alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9; ++ /* ++ * AllocationSize is fully client-controlled (the caller only ++ * validates the fixed 8-byte buffer length). Reject values that ++ * would overflow the "round up to 512-byte blocks" conversion ++ * below instead of silently wrapping it to a tiny block count, ++ * which would truncate the file to a size the client never ++ * asked for. ++ */ ++ alloc_size = le64_to_cpu(file_alloc_info->AllocationSize); ++ if (alloc_size > MAX_LFS_FILESIZE - 511) ++ return -EINVAL; ++ ++ alloc_blks = (alloc_size + 511) >> 9; + inode = file_inode(fp->filp); + + if (alloc_blks > stat.blocks) { diff --git a/queue-6.18/mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch b/queue-6.18/mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch new file mode 100644 index 0000000000..6e9e78b24a --- /dev/null +++ b/queue-6.18/mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch @@ -0,0 +1,32 @@ +From 357e3b8e3a8769ba36eb8ec5e053e4825f1a9329 Mon Sep 17 00:00:00 2001 +From: Florian Fuchs +Date: Mon, 18 May 2026 13:45:21 +0200 +Subject: mtd: maps: vmu-flash: fix NULL pointer dereference in initialization + +From: Florian Fuchs + +commit 357e3b8e3a8769ba36eb8ec5e053e4825f1a9329 upstream. + +The mtd_info contains a struct device, which must be linked to its +parent. Without this, the initialization of the MTD fails with a NULL +pointer dereference. + +Fixes: 47a72688fae7 ("mtd: flash mapping support for Dreamcast VMU.") +Cc: stable@vger.kernel.org +Signed-off-by: Florian Fuchs +Signed-off-by: Miquel Raynal +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/maps/vmu-flash.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/maps/vmu-flash.c ++++ b/drivers/mtd/maps/vmu-flash.c +@@ -547,6 +547,7 @@ static void vmu_queryblocks(struct maple + mpart->partition = card->partition; + mtd_cur->priv = mpart; + mtd_cur->owner = THIS_MODULE; ++ mtd_cur->dev.parent = &mdev->dev; + + pcache = kzalloc(sizeof(struct vmu_cache), GFP_KERNEL); + if (!pcache) diff --git a/queue-6.18/mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch b/queue-6.18/mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch new file mode 100644 index 0000000000..dd8c5fde3e --- /dev/null +++ b/queue-6.18/mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch @@ -0,0 +1,68 @@ +From 8e4531667d718e2e9b193928cf9b2497fa0d01ef Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Fri, 22 May 2026 11:17:39 +0200 +Subject: mtd: rawnand: Pause continuous reads at block boundaries + +From: Miquel Raynal + +commit 8e4531667d718e2e9b193928cf9b2497fa0d01ef upstream. + +Some chips do not support sequential cached reads past block +boundaries, like Winbond. In practice when using UBI, this should very +rarely happen, but let's make sure it never happens. + +Cc: stable@vger.kernel.org +Fixes: 003fe4b9545b ("mtd: rawnand: Support for sequential cache reads") +Signed-off-by: Miquel Raynal +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/nand/raw/nand_base.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +--- a/drivers/mtd/nand/raw/nand_base.c ++++ b/drivers/mtd/nand/raw/nand_base.c +@@ -1215,32 +1215,32 @@ static int nand_lp_exec_read_page_op(str + return nand_exec_op(chip, &op); + } + +-static unsigned int rawnand_last_page_of_lun(unsigned int pages_per_lun, unsigned int lun) ++static unsigned int rawnand_last_page_of_block(unsigned int ppb, unsigned int block) + { +- /* lun is expected to be very small */ +- return (lun * pages_per_lun) + pages_per_lun - 1; ++ /* block is expected to be very small */ ++ return (block * ppb) + ppb - 1; + } + + static void rawnand_cap_cont_reads(struct nand_chip *chip) + { + struct nand_memory_organization *memorg; +- unsigned int ppl, first_lun, last_lun; ++ unsigned int ppb, first_block, last_block; + + memorg = nanddev_get_memorg(&chip->base); +- ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun; +- first_lun = chip->cont_read.first_page / ppl; +- last_lun = chip->cont_read.last_page / ppl; +- +- /* Prevent sequential cache reads across LUN boundaries */ +- if (first_lun != last_lun) +- chip->cont_read.pause_page = rawnand_last_page_of_lun(ppl, first_lun); ++ ppb = memorg->pages_per_eraseblock; ++ first_block = chip->cont_read.first_page / ppb; ++ last_block = chip->cont_read.last_page / ppb; ++ ++ /* Prevent sequential cache reads across block boundaries */ ++ if (first_block != last_block) ++ chip->cont_read.pause_page = rawnand_last_page_of_block(ppb, first_block); + else + chip->cont_read.pause_page = chip->cont_read.last_page; + + if (chip->cont_read.first_page == chip->cont_read.pause_page) { + chip->cont_read.first_page++; + chip->cont_read.pause_page = min(chip->cont_read.last_page, +- rawnand_last_page_of_lun(ppl, first_lun + 1)); ++ rawnand_last_page_of_block(ppb, first_block + 1)); + } + + if (chip->cont_read.first_page >= chip->cont_read.last_page) diff --git a/queue-6.18/mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch b/queue-6.18/mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch new file mode 100644 index 0000000000..acafc625ea --- /dev/null +++ b/queue-6.18/mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch @@ -0,0 +1,41 @@ +From 306e443156b82a2a14a3f33da908c303be45529c Mon Sep 17 00:00:00 2001 +From: Takahiro Kuwano +Date: Wed, 27 May 2026 18:05:39 +0900 +Subject: mtd: spi-nor: spansion: use die erase for multi-die devices only + +From: Takahiro Kuwano + +commit 306e443156b82a2a14a3f33da908c303be45529c upstream. + +Die erase opcode is supported in multi-die devices only. For single die +devices, default chip erase opcode must be used. + +In s25hx_t_late_init(), die erase opcode is set only when the device is +multi-die. + +Fixes: 461d0babb544 ("mtd: spi-nor: spansion: enable die erase for multi die flashes") +Cc: stable@kernel.org +Reviewed-by: Pratyush Yadav +Reviewed-by: Tudor Ambarus +Reviewed-by: Miquel Raynal +Signed-off-by: Takahiro Kuwano +Reviewed-by: Michael Walle +Signed-off-by: Pratyush Yadav +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/spansion.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/spi-nor/spansion.c ++++ b/drivers/mtd/spi-nor/spansion.c +@@ -674,7 +674,9 @@ static int s25hx_t_late_init(struct spi_ + params->ready = cypress_nor_sr_ready_and_clear; + cypress_nor_ecc_init(nor); + +- params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE; ++ if (params->n_dice > 1) ++ params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE; ++ + return 0; + } + diff --git a/queue-6.18/mtd-spi-nor-swp-improve-locking-user-experience.patch b/queue-6.18/mtd-spi-nor-swp-improve-locking-user-experience.patch new file mode 100644 index 0000000000..ed64415e41 --- /dev/null +++ b/queue-6.18/mtd-spi-nor-swp-improve-locking-user-experience.patch @@ -0,0 +1,57 @@ +From e1d456b26bf23e30db305a6184e8abd9ab68bbf2 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 26 May 2026 16:56:26 +0200 +Subject: mtd: spi-nor: swp: Improve locking user experience + +From: Miquel Raynal + +commit e1d456b26bf23e30db305a6184e8abd9ab68bbf2 upstream. + +In the case of the first block being locked (or the few first blocks), +if the user want to fully unlock the device it has two possibilities: +- either it asks to unlock the entire device, and this works; +- or it asks to unlock just the block(s) that are currently locked, + which fails. + +It fails because the conditions "can_be_top" and "can_be_bottom" are +true. Indeed, in this case, we unlock everything, so the TB bit does not +matter. However in the current implementation, use_top would be true (as +this is the favourite option) and lock_len, which in practice should be +reduced down to 0, is set to "nor->params->size - (ofs + len)" which is +a positive number. This is wrong. + +An easy way is to simply add an extra condition. In the unlock() path, +if we can achieve the same result from both sides, it means we unlock +everything and lock_len must simply be 0. A comment is added to clarify +that logic. + +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Cc: stable@kernel.org +Signed-off-by: Miquel Raynal +Reviewed-by: Michael Walle +Signed-off-by: Pratyush Yadav +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/swp.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -282,8 +282,15 @@ static int spi_nor_sr_unlock(struct spi_ + /* Prefer top, if both are valid */ + use_top = can_be_top; + +- /* lock_len: length of region that should remain locked */ +- if (use_top) ++ /* ++ * lock_len: length of region that should remain locked. ++ * ++ * When can_be_top and can_be_bottom booleans are true, both adjacent ++ * regions are unlocked, thus the entire flash can be unlocked. ++ */ ++ if (can_be_top && can_be_bottom) ++ lock_len = 0; ++ else if (use_top) + lock_len = nor->params->size - (ofs + len); + else + lock_len = ofs; diff --git a/queue-6.18/net-sparx5-unregister-blocking-notifier-on-init-failure.patch b/queue-6.18/net-sparx5-unregister-blocking-notifier-on-init-failure.patch new file mode 100644 index 0000000000..739ce28b91 --- /dev/null +++ b/queue-6.18/net-sparx5-unregister-blocking-notifier-on-init-failure.patch @@ -0,0 +1,45 @@ +From 483be61b4a9a6df3b7cb277e8f189e082dee4cb8 Mon Sep 17 00:00:00 2001 +From: Haoxiang Li +Date: Tue, 23 Jun 2026 19:57:14 +0800 +Subject: net: sparx5: unregister blocking notifier on init failure + +From: Haoxiang Li + +commit 483be61b4a9a6df3b7cb277e8f189e082dee4cb8 upstream. + +sparx5_register_notifier_blocks() registers the switchdev blocking +notifier before allocating the ordered workqueue. If the workqueue +allocation fails, the error path unregisters the switchdev and netdevice +notifiers, but leaves the blocking notifier registered. + +Add a separate error label for the workqueue allocation failure path and +unregister the switchdev blocking notifier there. + +Fixes: d6fce5141929 ("net: sparx5: add switching support") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260623115714.2192074-1-haoxiang_li2024@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c ++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c +@@ -765,11 +765,13 @@ int sparx5_register_notifier_blocks(stru + sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0); + if (!sparx5_owq) { + err = -ENOMEM; +- goto err_switchdev_blocking_nb; ++ goto err_alloc_workqueue; + } + + return 0; + ++err_alloc_workqueue: ++ unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); + err_switchdev_blocking_nb: + unregister_switchdev_notifier(&s5->switchdev_nb); + err_switchdev_nb: diff --git a/queue-6.18/net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch b/queue-6.18/net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch new file mode 100644 index 0000000000..e6e9b7d7f1 --- /dev/null +++ b/queue-6.18/net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch @@ -0,0 +1,58 @@ +From 55d9895f89970501fe126d1026b586b04a224c27 Mon Sep 17 00:00:00 2001 +From: Maoyi Xie +Date: Wed, 17 Jun 2026 01:38:41 +0800 +Subject: net: thunderbolt: Fix frags[] overflow by bounding frame_count + +From: Maoyi Xie + +commit 55d9895f89970501fe126d1026b586b04a224c27 upstream. + +tbnet_poll() assembles a multi-frame ThunderboltIP packet into one skb. The +first frame goes into the skb linear area and every further frame is added as +a page fragment. + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + page, hdr_size, frame_size, + TBNET_RX_PAGE_SIZE - hdr_size); + +A packet of frame_count frames therefore ends up with frame_count - 1 +fragments. tbnet_check_frame() only bounds the peer supplied frame_count to +TBNET_RING_SIZE / 4 (64), which is far above MAX_SKB_FRAGS (17 by default). A +peer that sends a packet of 19 or more small frames pushes nr_frags past +MAX_SKB_FRAGS, so skb_add_rx_frag() writes past skb_shinfo()->frags[] and +corrupts memory after the shared info. + +Tighten the start of packet bound to MAX_SKB_FRAGS + 1 so a packet can never +produce more fragments than frags[] can hold. This matches the recent skb +frags overflow fixes in other receive paths, for example f0813bcd2d9d ("net: +wwan: t7xx: fix potential skb->frags overflow in RX path") and 600dc40554dc +("net: usb: cdc-phonet: fix skb frags[] overflow in rx_complete()"). + +Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable") +Cc: stable@vger.kernel.org +Signed-off-by: Maoyi Xie +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/178163152194.2486768.14724194232649760778@maoyixie.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/thunderbolt/main.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/net/thunderbolt/main.c ++++ b/drivers/net/thunderbolt/main.c +@@ -786,8 +786,12 @@ static bool tbnet_check_frame(struct tbn + return true; + } + +- /* Start of packet, validate the frame header */ +- if (frame_count == 0 || frame_count > TBNET_RING_SIZE / 4) { ++ /* Start of packet, validate the frame header. tbnet_poll() puts the ++ * first frame in the skb linear area and every further frame in a page ++ * fragment, so a packet may not span more than MAX_SKB_FRAGS + 1 frames ++ * without overflowing skb_shinfo()->frags[]. ++ */ ++ if (frame_count == 0 || frame_count > MAX_SKB_FRAGS + 1) { + net->stats.rx_length_errors++; + return false; + } diff --git a/queue-6.18/netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch b/queue-6.18/netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch new file mode 100644 index 0000000000..b5e9930b55 --- /dev/null +++ b/queue-6.18/netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch @@ -0,0 +1,55 @@ +From 1f24c0d01db214c9e661915e9972404c96ca73c0 Mon Sep 17 00:00:00 2001 +From: Maoyi Xie +Date: Tue, 16 Jun 2026 01:17:36 +0800 +Subject: netdev-genl: report NAPI thread PID in the caller's pid namespace + +From: Maoyi Xie + +commit 1f24c0d01db214c9e661915e9972404c96ca73c0 upstream. + +netdev_nl_napi_fill_one() reports the NAPI kthread PID in NETDEV_A_NAPI_PID +using task_pid_nr(), which returns the PID in the initial pid namespace. + +NETDEV_CMD_NAPI_GET does not have GENL_ADMIN_PERM and the netdev genl family +is netnsok, so a caller in a child pid namespace can issue it. That caller +then sees the kthread's global PID, even though the kthread is not visible +in its pid namespace, where the value should be 0. + +Translate the PID through the caller's pid namespace, the same way commit +3799c2570982 ("io_uring/fdinfo: translate SqThread PID through caller's +pid_ns") did for the io_uring SQPOLL thread. The doit and dumpit paths both +run synchronously in the caller's context, so task_active_pid_ns(current) is +the caller's pid namespace. + +Fixes: db4704f4e4df ("netdev-genl: Add PID for the NAPI thread") +Cc: stable@vger.kernel.org +Signed-off-by: Maoyi Xie +Reviewed-by: Joe Damato +Reviewed-by: Samiullah Khawaja +Link: https://patch.msgid.link/20260615171736.1709318-1-maoyixie.tju@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/core/netdev-genl.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/net/core/netdev-genl.c ++++ b/net/core/netdev-genl.c +@@ -2,6 +2,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -189,7 +190,8 @@ netdev_nl_napi_fill_one(struct sk_buff * + goto nla_put_failure; + + if (napi->thread) { +- pid = task_pid_nr(napi->thread); ++ pid = task_pid_nr_ns(napi->thread, ++ task_active_pid_ns(current)); + if (nla_put_u32(rsp, NETDEV_A_NAPI_PID, pid)) + goto nla_put_failure; + } diff --git a/queue-6.18/nfs-charge-unstable-writes-by-request-size-not-folio-size.patch b/queue-6.18/nfs-charge-unstable-writes-by-request-size-not-folio-size.patch new file mode 100644 index 0000000000..daec328d70 --- /dev/null +++ b/queue-6.18/nfs-charge-unstable-writes-by-request-size-not-folio-size.patch @@ -0,0 +1,129 @@ +From 27934d02cbeb8a957dd11c985a579e58d30c5270 Mon Sep 17 00:00:00 2001 +From: Benjamin Coddington +Date: Tue, 7 Jul 2026 11:07:16 -0400 +Subject: NFS: Charge unstable writes by request size, not folio size + +From: Benjamin Coddington + +commit 27934d02cbeb8a957dd11c985a579e58d30c5270 upstream. + +nfs_folio_mark_unstable() and nfs_folio_clear_commit() charge and +uncharge NR_WRITEBACK/WB_WRITEBACK by folio_nr_pages(folio) once per +*request* added to or removed from a commit list. This is correct only +when a folio has a single associated request. When pg_test splits a +folio into N sub-folio requests (e.g. pNFS flexfiles striping with a +stripe unit smaller than the folio size, or plain wsize-limited +splitting), each of the N requests independently charges the whole +folio's page count, inflating the accounting by a factor of N per +folio. With large folios and small stripe units this reaches multiple +orders of magnitude: a 2 MiB folio split into 512 4 KiB requests can +charge up to 512x its real size, pushing global dirty+writeback +accounting past the system's dirty threshold and forcing every +buffered writer on the host into the hard-throttle path, including +unrelated in-kernel NFS server threads sharing the box. + +Charge each request only for the pages it actually covers. + +Fixes: 0c493b5cf16e ("NFS: Convert buffered writes to use folios") +Cc: stable@vger.kernel.org +Signed-off-by: Benjamin Coddington +Assisted-By: Claude Sonnet 5 +Signed-off-by: Anna Schumaker +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/internal.h | 12 +++++++----- + fs/nfs/pnfs_nfs.c | 2 +- + fs/nfs/write.c | 14 ++++++++------ + 3 files changed, 16 insertions(+), 12 deletions(-) + +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -854,17 +854,19 @@ void nfs_super_set_maxbytes(struct super + } + + /* +- * Record the page as unstable (an extra writeback period) and mark its +- * inode as dirty. ++ * Record the request's range as unstable (an extra writeback period) and ++ * mark its inode as dirty. + */ +-static inline void nfs_folio_mark_unstable(struct folio *folio, ++static inline void nfs_folio_mark_unstable(struct nfs_page *req, + struct nfs_commit_info *cinfo) + { ++ struct folio *folio = nfs_page_to_folio(req); ++ + if (folio && !cinfo->dreq) { + struct inode *inode = folio->mapping->host; +- long nr = folio_nr_pages(folio); ++ long nr = DIV_ROUND_UP(req->wb_bytes, PAGE_SIZE); + +- /* This page is really still in write-back - just that the ++ /* This range is really still in write-back - just that the + * writeback is happening on the server now. + */ + node_stat_mod_folio(folio, NR_WRITEBACK, nr); +--- a/fs/nfs/pnfs_nfs.c ++++ b/fs/nfs/pnfs_nfs.c +@@ -1199,7 +1199,7 @@ pnfs_layout_mark_request_commit(struct n + + nfs_request_add_commit_list_locked(req, list, cinfo); + mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); +- nfs_folio_mark_unstable(nfs_page_to_folio(req), cinfo); ++ nfs_folio_mark_unstable(req, cinfo); + return; + out_resched: + mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -807,7 +807,7 @@ nfs_request_add_commit_list(struct nfs_p + mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); + nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo); + mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); +- nfs_folio_mark_unstable(nfs_page_to_folio(req), cinfo); ++ nfs_folio_mark_unstable(req, cinfo); + } + EXPORT_SYMBOL_GPL(nfs_request_add_commit_list); + +@@ -866,10 +866,12 @@ nfs_mark_request_commit(struct nfs_page + nfs_request_add_commit_list(req, cinfo); + } + +-static void nfs_folio_clear_commit(struct folio *folio) ++static void nfs_folio_clear_commit(struct nfs_page *req) + { ++ struct folio *folio = nfs_page_to_folio(req); ++ + if (folio) { +- long nr = folio_nr_pages(folio); ++ long nr = DIV_ROUND_UP(req->wb_bytes, PAGE_SIZE); + + node_stat_mod_folio(folio, NR_WRITEBACK, -nr); + wb_stat_mod(&inode_to_bdi(folio->mapping->host)->wb, +@@ -890,7 +892,7 @@ static void nfs_clear_request_commit(str + nfs_request_remove_commit_list(req, cinfo); + } + mutex_unlock(&NFS_I(inode)->commit_mutex); +- nfs_folio_clear_commit(nfs_page_to_folio(req)); ++ nfs_folio_clear_commit(req); + } + } + +@@ -1735,7 +1737,7 @@ void nfs_retry_commit(struct list_head * + req = nfs_list_entry(page_list->next); + nfs_list_remove_request(req); + nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx); +- nfs_folio_clear_commit(nfs_page_to_folio(req)); ++ nfs_folio_clear_commit(req); + nfs_unlock_and_release_request(req); + } + } +@@ -1807,7 +1809,7 @@ static void nfs_commit_release_pages(str + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); + folio = nfs_page_to_folio(req); +- nfs_folio_clear_commit(folio); ++ nfs_folio_clear_commit(req); + + dprintk("NFS: commit (%s/%llu %d@%lld)", + nfs_req_openctx(req)->dentry->d_sb->s_id, diff --git a/queue-6.18/nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch b/queue-6.18/nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch new file mode 100644 index 0000000000..fcdca2def5 --- /dev/null +++ b/queue-6.18/nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch @@ -0,0 +1,68 @@ +From 6fe0687245e8406bf26143bd45eb16441bbe5280 Mon Sep 17 00:00:00 2001 +From: Nick Chan +Date: Sun, 7 Jun 2026 14:10:58 +0800 +Subject: nvme-apple: Prevent shared tags across queues on Apple A11 + +From: Nick Chan + +commit 6fe0687245e8406bf26143bd45eb16441bbe5280 upstream. + +On Apple A11, tags of pending commands must be unique across the admin +and IO queues, else the firmware crashes with +"duplicate tag error for tag N", with N being the tag. + +Apply the existing workaround for M1 of reserving two tags for the admin +queue to A11. + +Cc: stable@vger.kernel.org +Fixes: 04d8ecf37b5e ("nvme: apple: Add Apple A11 support") +Reviewed-by: Sven Peter +Signed-off-by: Nick Chan +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/apple.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- a/drivers/nvme/host/apple.c ++++ b/drivers/nvme/host/apple.c +@@ -225,7 +225,7 @@ static unsigned int apple_nvme_queue_dep + { + struct apple_nvme *anv = queue_to_apple_nvme(q); + +- if (q->is_adminq && anv->hw->has_lsq_nvmmu) ++ if (q->is_adminq) + return APPLE_NVME_AQ_DEPTH; + + return anv->hw->max_queue_depth; +@@ -303,7 +303,7 @@ static void apple_nvme_submit_cmd_t8015( + memcpy((void *)q->sqes + (q->sq_tail << APPLE_NVME_IOSQES), + cmd, sizeof(*cmd)); + +- if (++q->sq_tail == anv->hw->max_queue_depth) ++ if (++q->sq_tail == apple_nvme_queue_depth(q)) + q->sq_tail = 0; + + writel(q->sq_tail, q->sq_db); +@@ -1139,10 +1139,7 @@ static void apple_nvme_reset_work(struct + } + + /* Setup the admin queue */ +- if (anv->hw->has_lsq_nvmmu) +- aqa = APPLE_NVME_AQ_DEPTH - 1; +- else +- aqa = anv->hw->max_queue_depth - 1; ++ aqa = APPLE_NVME_AQ_DEPTH - 1; + aqa |= aqa << 16; + writel(aqa, anv->mmio_nvme + NVME_REG_AQA); + writeq(anv->adminq.sq_dma_addr, anv->mmio_nvme + NVME_REG_ASQ); +@@ -1324,8 +1321,7 @@ static int apple_nvme_alloc_tagsets(stru + * both queues. The admin queue gets the first APPLE_NVME_AQ_DEPTH which + * must be marked as reserved in the IO queue. + */ +- if (anv->hw->has_lsq_nvmmu) +- anv->tagset.reserved_tags = APPLE_NVME_AQ_DEPTH; ++ anv->tagset.reserved_tags = APPLE_NVME_AQ_DEPTH; + anv->tagset.queue_depth = anv->hw->max_queue_depth - 1; + anv->tagset.timeout = NVME_IO_TIMEOUT; + anv->tagset.numa_node = NUMA_NO_NODE; diff --git a/queue-6.18/nvmet-auth-reject-short-auth_receive-buffers.patch b/queue-6.18/nvmet-auth-reject-short-auth_receive-buffers.patch new file mode 100644 index 0000000000..7445a30a94 --- /dev/null +++ b/queue-6.18/nvmet-auth-reject-short-auth_receive-buffers.patch @@ -0,0 +1,81 @@ +From 779575bc35c687697ba69e904f2cd22e60112534 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Tue, 9 Jun 2026 14:24:31 -0400 +Subject: nvmet-auth: reject short AUTH_RECEIVE buffers + +From: Michael Bommarito + +commit 779575bc35c687697ba69e904f2cd22e60112534 upstream. + +nvmet_execute_auth_receive() trusts the AUTH_RECEIVE allocation length +after checking only that it is nonzero and matches the transfer length. +In the SUCCESS1 and FAILURE1/default states, that lets a remote NVMe-oF +initiator reach the fixed-size DH-HMAC-CHAP response builders with a +kmalloc() buffer shorter than the response, so nvmet_auth_success1() and +nvmet_auth_failure1() write past the allocation; both only WARN_ON the +short length and then format the message anyway. + +Impact: A remote NVMe-oF initiator with access to an auth-enabled target +can trigger a 16-byte heap out-of-bounds write via a one-byte +AUTH_RECEIVE allocation length. + +Compute the minimum response length for the current DH-HMAC-CHAP step in +nvmet_auth_receive_data_len() and report a zero data length when the +host-supplied allocation length is shorter, so the existing zero-length +check in nvmet_execute_auth_receive() rejects the command before any +builder runs. The SUCCESS1 minimum is sizeof(struct +nvmf_auth_dhchap_success1_data) plus the HMAC hash length, because the +response hash is written into the rval[] flexible-array tail, so the +minimum is state dependent rather than a flat sizeof. CHALLENGE keeps its +existing variable-length guard in nvmet_auth_challenge(). + +This is reachable only when in-band DH-HMAC-CHAP authentication is +configured on the target. + +Fixes: db1312dd9548 ("nvmet: implement basic In-Band Authentication") +Cc: stable@vger.kernel.org +Assisted-by: Codex:gpt-5-5-xhigh +Assisted-by: Claude:claude-opus-4-8 +Reviewed-by: Hannes Reinecke +Signed-off-by: Michael Bommarito +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/target/fabrics-cmd-auth.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -494,7 +494,31 @@ static void nvmet_auth_failure1(struct n + + u32 nvmet_auth_receive_data_len(struct nvmet_req *req) + { +- return le32_to_cpu(req->cmd->auth_receive.al); ++ struct nvmet_ctrl *ctrl = req->sq->ctrl; ++ u32 al = le32_to_cpu(req->cmd->auth_receive.al); ++ u32 min_len; ++ ++ /* ++ * Reject too-short al before kmalloc(al), since the SUCCESS1 and ++ * FAILURE1/default builders write fixed response headers into it. ++ */ ++ switch (req->sq->dhchap_step) { ++ case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE: ++ return al; ++ case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1: ++ min_len = sizeof(struct nvmf_auth_dhchap_success1_data); ++ if (req->sq->dhchap_c2) ++ min_len += nvme_auth_hmac_hash_len(ctrl->shash_id); ++ break; ++ default: ++ min_len = sizeof(struct nvmf_auth_dhchap_failure_data); ++ break; ++ } ++ ++ if (al < min_len) ++ return 0; ++ ++ return al; + } + + void nvmet_execute_auth_receive(struct nvmet_req *req) diff --git a/queue-6.18/nvmet-fix-refcount-leak-in-nvmet_sq_create.patch b/queue-6.18/nvmet-fix-refcount-leak-in-nvmet_sq_create.patch new file mode 100644 index 0000000000..349dbdc114 --- /dev/null +++ b/queue-6.18/nvmet-fix-refcount-leak-in-nvmet_sq_create.patch @@ -0,0 +1,38 @@ +From 34b9a83c50660148bde01cde16451dbe78369749 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Tue, 9 Jun 2026 09:55:05 +0000 +Subject: nvmet: fix refcount leak in nvmet_sq_create() + +From: Wentao Liang + +commit 34b9a83c50660148bde01cde16451dbe78369749 upstream. + +In nvmet_sq_create(), a reference on the ctrl is taken +via kref_get_unless_zero() before calling nvmet_check_sqid(). +If nvmet_check_sqid() fails, the function returns the error +directly without releasing the reference, leading to a leak. + +Fix this by jumping to the "ctrl_put" label, which already +performs the necessary nvmet_ctrl_put(ctrl). This ensures the +reference is properly released on this error path. + +Cc: stable@vger.kernel.org +Fixes: 1eb380caf527 ("nvmet: Introduce nvmet_sq_create() and nvmet_cq_create()") +Signed-off-by: Wentao Liang +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/target/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -935,7 +935,7 @@ u16 nvmet_sq_create(struct nvmet_ctrl *c + + status = nvmet_check_sqid(ctrl, sqid, true); + if (status != NVME_SC_SUCCESS) +- return status; ++ goto ctrl_put; + + ret = nvmet_sq_init(sq, cq); + if (ret) { diff --git a/queue-6.18/nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch b/queue-6.18/nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch new file mode 100644 index 0000000000..91748d5c73 --- /dev/null +++ b/queue-6.18/nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch @@ -0,0 +1,89 @@ +From 48c0162f647bb47e6084ffbc71b8f213f5e2f4f8 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Thu, 4 Jun 2026 19:36:54 +0000 +Subject: nvmet-rdma: handle inline data with a nonzero offset + +From: Bryam Vargas + +commit 48c0162f647bb47e6084ffbc71b8f213f5e2f4f8 upstream. + +nvmet_rdma_use_inline_sg() maps the host-controlled inline data offset +into the per-command inline scatterlist. The bounds check admits any +offset with off + len <= inline_data_size, but the mapping still assumes +the data begins in the first inline page: + + sg->offset = off; + sg->length = min_t(int, len, PAGE_SIZE - off); + +When a port is configured with inline_data_size > PAGE_SIZE (settable up +to max(SZ_16K, PAGE_SIZE)), an offset in (PAGE_SIZE, inline_data_size] +makes "PAGE_SIZE - off" underflow, so sg->length is set to ~4 GiB and +the block backend reads far past the first inline page. num_pages(len) +also ignores the offset, so an in-bounds offset whose [off, off+len) +span crosses a page boundary under-counts the scatterlist. + +Map the offset properly: split it into a page index and an in-page +offset, start the scatterlist at that page, and size the page count from +page_off + len. Because the request scatterlist may now start at +inline_sg[page_idx] rather than inline_sg[0], generalize the inline-SGL +identity test in nvmet_rdma_release_rsp() to a range test; otherwise the +persistent inline scatterlist is mistaken for an allocated one and +nvmet_req_free_sgls() frees an inline page (and warns in +free_large_kmalloc()). + +Fixes: 0d5ee2b2ab4f ("nvmet-rdma: support max(16KB, PAGE_SIZE) inline data") +Cc: stable@vger.kernel.org +Suggested-by: Keith Busch +Reported-by: Bryam Vargas +Signed-off-by: Bryam Vargas +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/target/rdma.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/nvme/target/rdma.c ++++ b/drivers/nvme/target/rdma.c +@@ -667,7 +667,8 @@ static void nvmet_rdma_release_rsp(struc + if (rsp->n_rdma) + nvmet_rdma_rw_ctx_destroy(rsp); + +- if (rsp->req.sg != rsp->cmd->inline_sg) ++ if (rsp->req.sg < rsp->cmd->inline_sg || ++ rsp->req.sg >= rsp->cmd->inline_sg + queue->dev->inline_page_count) + nvmet_req_free_sgls(&rsp->req); + + if (unlikely(!list_empty_careful(&queue->rsp_wr_wait_list))) +@@ -822,24 +823,25 @@ static void nvmet_rdma_write_data_done(s + static void nvmet_rdma_use_inline_sg(struct nvmet_rdma_rsp *rsp, u32 len, + u64 off) + { +- int sg_count = num_pages(len); ++ u64 page_off = off % PAGE_SIZE; ++ u64 page_idx = off / PAGE_SIZE; ++ int sg_count = num_pages(page_off + len); + struct scatterlist *sg; + int i; + +- sg = rsp->cmd->inline_sg; ++ sg = &rsp->cmd->inline_sg[page_idx]; + for (i = 0; i < sg_count; i++, sg++) { + if (i < sg_count - 1) + sg_unmark_end(sg); + else + sg_mark_end(sg); +- sg->offset = off; +- sg->length = min_t(int, len, PAGE_SIZE - off); ++ sg->offset = page_off; ++ sg->length = min_t(u64, len, PAGE_SIZE - page_off); + len -= sg->length; +- if (!i) +- off = 0; ++ page_off = 0; + } + +- rsp->req.sg = rsp->cmd->inline_sg; ++ rsp->req.sg = &rsp->cmd->inline_sg[page_idx]; + rsp->req.sg_cnt = sg_count; + } + diff --git a/queue-6.18/openrisc-fix-jump_label-smp-syncing.patch b/queue-6.18/openrisc-fix-jump_label-smp-syncing.patch new file mode 100644 index 0000000000..322e379430 --- /dev/null +++ b/queue-6.18/openrisc-fix-jump_label-smp-syncing.patch @@ -0,0 +1,61 @@ +From aca063c9024522e4e5b9a9d1927433f6a01785a3 Mon Sep 17 00:00:00 2001 +From: Stafford Horne +Date: Fri, 22 May 2026 17:28:31 +0100 +Subject: openrisc: Fix jump_label smp syncing + +From: Stafford Horne + +commit aca063c9024522e4e5b9a9d1927433f6a01785a3 upstream. + +The original commit 8c30b0018f9d ("openrisc: Add jump label support") +copies from arm64 and does not properly consider how icache invalidation +on remote cores works in OpenRISC. On OpenRISC remote icaches need to +be invalidated otherwise static key's may remain state after updating. + +Fix SMP cache syncing by: + + 1. Properly invalidate remote core icaches on SMP systems by using + icache_all_inv. The old code uses kick_all_cpus_sync() which runs a + no-op IPI function call on remote CPU's which does execute a lot of + code and flushes many cache lines in the process, but does not flush + all and it's not correct on OpenRISC. + 2. For architectures that do not have WRITETHROUGH caches be sure + to flush the dcache after patching. + +To test this I first reproduced the issue using a custom test module +[0]. The test confirmed that some icache lines maintained stale +static_key code sequences after calling static_branch_enable(). After +this patch there are no longer jump_label coherency issues. + +[0] https://github.com/stffrdhrn/or1k-utils/tree/master/tests/smp_static_key_test + +Cc: stable@vger.kernel.org # depends on openrisc: Add icache_all_inv +Fixes: 8c30b0018f9d ("openrisc: Add jump label support") +Signed-off-by: Stafford Horne +Signed-off-by: Greg Kroah-Hartman +--- + arch/openrisc/kernel/jump_label.c | 2 +- + arch/openrisc/kernel/patching.c | 3 +++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +--- a/arch/openrisc/kernel/jump_label.c ++++ b/arch/openrisc/kernel/jump_label.c +@@ -47,5 +47,5 @@ bool arch_jump_label_transform_queue(str + + void arch_jump_label_transform_apply(void) + { +- kick_all_cpus_sync(); ++ icache_all_inv(); + } +--- a/arch/openrisc/kernel/patching.c ++++ b/arch/openrisc/kernel/patching.c +@@ -49,6 +49,9 @@ static int __patch_insn_write(void *addr + waddr = patch_map(addr, FIX_TEXT_POKE0); + + ret = copy_to_kernel_nofault(waddr, &insn, OPENRISC_INSN_SIZE); ++ if (!IS_ENABLED(CONFIG_DCACHE_WRITETHROUGH)) ++ local_dcache_range_flush((unsigned long)waddr, ++ (unsigned long)waddr + OPENRISC_INSN_SIZE); + local_icache_range_inv((unsigned long)waddr, + (unsigned long)waddr + OPENRISC_INSN_SIZE); + diff --git a/queue-6.18/pkey-move-keytype-check-from-pkey-api-to-handler.patch b/queue-6.18/pkey-move-keytype-check-from-pkey-api-to-handler.patch new file mode 100644 index 0000000000..b86ed4e2a6 --- /dev/null +++ b/queue-6.18/pkey-move-keytype-check-from-pkey-api-to-handler.patch @@ -0,0 +1,72 @@ +From 754e9e49b76fd5be339172aa98544182ed3ca75e Mon Sep 17 00:00:00 2001 +From: Holger Dengler +Date: Tue, 23 Jun 2026 16:20:31 +0200 +Subject: pkey: Move keytype check from pkey api to handler + +From: Holger Dengler + +commit 754e9e49b76fd5be339172aa98544182ed3ca75e upstream. + +The PKEY_VERIFYPROTK ioctl takes data from user-space and verifies the +contained protected key. While checking the integrity of the ioctl +request structure is the responsibility of the generic pkey_api code, +the verification of the contained protected key is the responsibility +of the pkey handler. + +The keytype verification (based on the calculated bitsize of the key) +is part of the protected key verification and therefore the +responsibility of the pkey handler (which already verifies +it). Therefore the keytype verification is removed from the generic +pkey_api code. + +As the calculation of the key bitsize is currently wrong, the removal +of the keytype check in pkey_api also removes this wrong +calculation. For this reason, the commit is flagged with the Fixes: +tag. + +Cc: stable@kernel.org # 6.12+ +Fixes: 8fcc231ce3be ("s390/pkey: Introduce pkey base with handler registry and handler modules") +Reviewed-by: Ingo Franzki +Reviewed-by: Harald Freudenberger +Signed-off-by: Holger Dengler +Signed-off-by: Alexander Gordeev +Signed-off-by: Vasily Gorbik +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/crypto/pkey_api.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +--- a/drivers/s390/crypto/pkey_api.c ++++ b/drivers/s390/crypto/pkey_api.c +@@ -328,7 +328,6 @@ static int pkey_ioctl_verifyprotk(struct + { + struct pkey_verifyprotk kvp; + struct protaeskeytoken *t; +- u32 keytype; + u8 *tmpbuf; + int rc; + +@@ -342,14 +341,6 @@ static int pkey_ioctl_verifyprotk(struct + return -EINVAL; + } + +- keytype = pkey_aes_bitsize_to_keytype(8 * kvp.protkey.len); +- if (!keytype) { +- PKEY_DBF_ERR("%s unknown/unsupported protkey length %u\n", +- __func__, kvp.protkey.len); +- memzero_explicit(&kvp, sizeof(kvp)); +- return -EINVAL; +- } +- + /* build a 'protected key token' from the raw protected key */ + tmpbuf = kzalloc(sizeof(*t), GFP_KERNEL); + if (!tmpbuf) { +@@ -359,7 +350,7 @@ static int pkey_ioctl_verifyprotk(struct + t = (struct protaeskeytoken *)tmpbuf; + t->type = TOKTYPE_NON_CCA; + t->version = TOKVER_PROTECTED_KEY; +- t->keytype = keytype; ++ t->keytype = kvp.protkey.type; + t->len = kvp.protkey.len; + memcpy(t->protkey, kvp.protkey.protkey, kvp.protkey.len); + diff --git a/queue-6.18/platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch b/queue-6.18/platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch new file mode 100644 index 0000000000..c4a57a9e41 --- /dev/null +++ b/queue-6.18/platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch @@ -0,0 +1,93 @@ +From 428b9fd2dce50b4dc5cd9ade10b92efcf57ce7aa Mon Sep 17 00:00:00 2001 +From: Daniel Gibson +Date: Thu, 11 Jun 2026 17:04:25 +0200 +Subject: platform/x86/amd/pmc: Add delay_suspend module parameter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Gibson + +commit 428b9fd2dce50b4dc5cd9ade10b92efcf57ce7aa upstream. + +Enabling the new delay_suspend module parameter delays suspend for +2.5 seconds which is known to help for some AMD-based Lenovo Laptops +that otherwise failed to send/receive events for key presses or the +lid switch after s2idle. Apparently the EC needs to do some things +in the background before suspend or it gets into a bad state. + +There are many reports of AMD-based laptops (mostly but not exclusively +IdeaPads) about similar issues on the web; this parameter gives +affected users an easy way to try out if their issues have the same +root cause and to work around them until their specific device is added +to the quirks list. + +The parameter description has a note encouraging users to report +their device so it can be added to the quirks list, inspired by a +similar request in parameter descriptions of the ideapad-laptop module. + +The module parameter can be set to "1" to explicitly enable it, +"0" to disable it even on devices that are assumed to be affected, +or -1 (the default) to enable it if the device is assumed to be affected +(according to fwbug_list[]) + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221383 +Reviewed-by: Hans de Goede +Signed-off-by: Daniel Gibson +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260611150426.3683372-4-daniel@gibson.sh +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/amd/pmc/pmc.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,6 +90,11 @@ static bool disable_workarounds; + module_param(disable_workarounds, bool, 0644); + MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs"); + ++static int delay_suspend = -1; ++module_param(delay_suspend, int, 0644); ++MODULE_PARM_DESC(delay_suspend, ++ "Delays s2idle by 2.5 seconds to work around buggy ECs, often causing keyboard issues after suspend. 0: don't delay, 1: do delay, -1 (default): let amd_pmc decide. If you need this please report this to: platform-driver-x86@vger.kernel.org"); ++ + static struct amd_pmc_dev pmc; + + static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) +@@ -625,8 +631,23 @@ static bool amd_pmc_want_suspend_delay(s + * + * See https://bugzilla.kernel.org/show_bug.cgi?id=221383 + */ +- if (!disable_workarounds && amd_pmc_quirk_need_suspend_delay(pdev)) { +- dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); ++ if (amd_pmc_quirk_need_suspend_delay(pdev)) { ++ /* ++ * delay_suspend=1 force-enables this, otherwise it can be ++ * disabled with disable_workarounds or delay_suspend=0 ++ */ ++ if (delay_suspend == 1 || (delay_suspend == -1 && !disable_workarounds)) { ++ dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); ++ return true; ++ } ++ dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n"); ++ } else if (delay_suspend == 1) { ++ dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: platform-driver-x86@vger.kernel.org so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n", ++ dmi_get_system_info(DMI_SYS_VENDOR), ++ dmi_get_system_info(DMI_PRODUCT_NAME), ++ dmi_get_system_info(DMI_PRODUCT_FAMILY), ++ dmi_get_system_info(DMI_BOARD_VENDOR), ++ dmi_get_system_info(DMI_BOARD_NAME)); + return true; + } + return false; diff --git a/queue-6.18/platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch b/queue-6.18/platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch new file mode 100644 index 0000000000..9f53eff0cc --- /dev/null +++ b/queue-6.18/platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch @@ -0,0 +1,61 @@ +From 3bdd6fc11fbfa8249483f4b716ead51e43e3a0cd Mon Sep 17 00:00:00 2001 +From: Daniel Gibson +Date: Thu, 11 Jun 2026 17:04:23 +0200 +Subject: platform/x86/amd/pmc: Check for intermediate wakeup in function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Gibson + +commit 3bdd6fc11fbfa8249483f4b716ead51e43e3a0cd upstream. + +Refactor code introduced by commit 9f5595d5f03f ("pmc: Require at +least 2.5 seconds between HW sleep cycles") to allow adding different +conditions for that delay in an upcoming change. + +Signed-off-by: Daniel Gibson +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260611150426.3683372-2-daniel@gibson.sh +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/amd/pmc/pmc.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -598,6 +598,19 @@ static int amd_pmc_verify_czn_rtc(struct + return rc; + } + ++static bool amd_pmc_intermediate_wakeup_need_delay(struct amd_pmc_dev *pdev) ++{ ++ /* ++ * Starting a new HW sleep cycle right after waking from one ++ * can cause electrical problems triggering the over voltage protection. ++ * That is avoided by delaying the next suspend a bit, see also ++ * https://lore.kernel.org/all/20250414162446.3853194-1-superm1@kernel.org/ ++ */ ++ struct smu_metrics table; ++ ++ return get_metrics_table(pdev, &table) == 0 && table.s0i3_last_entry_status; ++} ++ + static void amd_pmc_s2idle_prepare(void) + { + struct amd_pmc_dev *pdev = &pmc; +@@ -632,11 +645,9 @@ static void amd_pmc_s2idle_prepare(void) + static void amd_pmc_s2idle_check(void) + { + struct amd_pmc_dev *pdev = &pmc; +- struct smu_metrics table; + int rc; + +- /* Avoid triggering OVP */ +- if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status) ++ if (amd_pmc_intermediate_wakeup_need_delay(pdev)) + msleep(2500); + + /* Dump the IdleMask before we add to the STB */ diff --git a/queue-6.18/platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch b/queue-6.18/platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch new file mode 100644 index 0000000000..69320af4e0 --- /dev/null +++ b/queue-6.18/platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch @@ -0,0 +1,164 @@ +From 9b9e60dd31da054a37d601e9fcabdfd8a2bff354 Mon Sep 17 00:00:00 2001 +From: Daniel Gibson +Date: Thu, 11 Jun 2026 17:04:24 +0200 +Subject: platform/x86/amd/pmc: Delay suspend for some Lenovo Laptops +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Gibson + +commit 9b9e60dd31da054a37d601e9fcabdfd8a2bff354 upstream. + +Some IdeaPad Slim 3 devices and similar with AMD CPUs have a +nonfunctional keyboard and lid switch after s2idle. + +It helps to delay suspend by 2.5 seconds so the EC has some time +to do whatever it needs to get done before suspend - unfortunately +at least on my 16ABR8 waking it with a timer (wakealarm) still +triggers the issue, but at least normal resume via keypress or +lid works fine. On the 14ARP10 wakealarm has been reported to also +work fine with this patch. + +This issue has been reported for many different devices, this patch +has been tested with the Zen3-based IdeaPad Slim 3 16ABR8 (82XR) +and the Zen3+-based IdeaPad Slim 3 14ARP10 (83K6) and IdeaPad Slim 3 +15ARP10 (83MM). + +Reported-by: Sindre Henriksen +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221383 +Tested-by: Sindre Henriksen +Suggested-by: Mario Limonciello (AMD) +Reviewed-by: Mario Limonciello (AMD) +Reviewed-by: Ilpo Järvinen +Reviewed-by: Hans de Goede +Signed-off-by: Daniel Gibson +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260611150426.3683372-3-daniel@gibson.sh +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/amd/pmc/pmc-quirks.c | 39 ++++++++++++++++++++++++++++++ + drivers/platform/x86/amd/pmc/pmc.c | 24 +++++++++++++++++- + drivers/platform/x86/amd/pmc/pmc.h | 1 + 3 files changed, 63 insertions(+), 1 deletion(-) + +--- a/drivers/platform/x86/amd/pmc/pmc-quirks.c ++++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c +@@ -18,6 +18,7 @@ + struct quirk_entry { + u32 s2idle_bug_mmio; + bool spurious_8042; ++ bool need_suspend_delay; + }; + + static struct quirk_entry quirk_s2idle_bug = { +@@ -33,6 +34,10 @@ static struct quirk_entry quirk_s2idle_s + .spurious_8042 = true, + }; + ++static struct quirk_entry quirk_s2idle_need_suspend_delay = { ++ .need_suspend_delay = true, ++}; ++ + static const struct dmi_system_id fwbug_list[] = { + { + .ident = "L14 Gen2 AMD", +@@ -203,6 +208,35 @@ static const struct dmi_system_id fwbug_ + DMI_MATCH(DMI_PRODUCT_NAME, "82XQ"), + } + }, ++ /* https://bugzilla.kernel.org/show_bug.cgi?id=221383 */ ++ { ++ .ident = "Zen3-based IdeaPad Slim and similar", ++ .driver_data = &quirk_s2idle_need_suspend_delay, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ /* ++ * Note: there are also some Zen2-based 82X* devices that ++ * need different quirks, they're already handled above ++ */ ++ DMI_MATCH(DMI_PRODUCT_NAME, "82X"), ++ } ++ }, ++ { ++ .ident = "Zen3+-based IdeaPad Slim and similar", ++ .driver_data = &quirk_s2idle_need_suspend_delay, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83K"), ++ } ++ }, ++ { ++ .ident = "IdeaPad Slim 3 15ARP10 (83MM)", ++ .driver_data = &quirk_s2idle_need_suspend_delay, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83MM"), ++ } ++ }, + /* https://bugzilla.kernel.org/show_bug.cgi?id=221273 */ + { + .ident = "Thinkpad L14 Gen3", +@@ -356,6 +390,11 @@ void amd_pmc_process_restore_quirks(stru + amd_pmc_skip_nvme_smi_handler(dev->quirks->s2idle_bug_mmio); + } + ++bool amd_pmc_quirk_need_suspend_delay(struct amd_pmc_dev *dev) ++{ ++ return dev->quirks && dev->quirks->need_suspend_delay; ++} ++ + void amd_pmc_quirks_init(struct amd_pmc_dev *dev) + { + const struct dmi_system_id *dmi_id; +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -611,6 +611,27 @@ static bool amd_pmc_intermediate_wakeup_ + return get_metrics_table(pdev, &table) == 0 && table.s0i3_last_entry_status; + } + ++static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev) ++{ ++ /* ++ * Some Lenovo Laptops (like different IdeaPad 3 Slims) need some ++ * me-time before sleeping or they get uncooperative after waking ++ * up and don't send events for keyboard and lid switch anymore. ++ * ++ * Unfortunately this doesn't entirely fix the problem: It can still ++ * happen when resuming with a timer (wakealarm), but at least the ++ * more common usecases (wakeup by opening lid or pressing a key) ++ * work fine with this workaround. ++ * ++ * See https://bugzilla.kernel.org/show_bug.cgi?id=221383 ++ */ ++ if (!disable_workarounds && amd_pmc_quirk_need_suspend_delay(pdev)) { ++ dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); ++ return true; ++ } ++ return false; ++} ++ + static void amd_pmc_s2idle_prepare(void) + { + struct amd_pmc_dev *pdev = &pmc; +@@ -647,7 +668,8 @@ static void amd_pmc_s2idle_check(void) + struct amd_pmc_dev *pdev = &pmc; + int rc; + +- if (amd_pmc_intermediate_wakeup_need_delay(pdev)) ++ if (amd_pmc_intermediate_wakeup_need_delay(pdev) || ++ amd_pmc_want_suspend_delay(pdev)) + msleep(2500); + + /* Dump the IdleMask before we add to the STB */ +--- a/drivers/platform/x86/amd/pmc/pmc.h ++++ b/drivers/platform/x86/amd/pmc/pmc.h +@@ -147,6 +147,7 @@ enum amd_pmc_def { + }; + + void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); ++bool amd_pmc_quirk_need_suspend_delay(struct amd_pmc_dev *dev); + void amd_pmc_quirks_init(struct amd_pmc_dev *dev); + void amd_mp2_stb_init(struct amd_pmc_dev *dev); + void amd_mp2_stb_deinit(struct amd_pmc_dev *dev); diff --git a/queue-6.18/platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch b/queue-6.18/platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch new file mode 100644 index 0000000000..abb8b34ef8 --- /dev/null +++ b/queue-6.18/platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch @@ -0,0 +1,118 @@ +From 037f0b03c663a247366673a807834389107995b7 Mon Sep 17 00:00:00 2001 +From: Daniel Gibson +Date: Thu, 11 Jun 2026 17:04:26 +0200 +Subject: platform/x86/amd/pmc: Don't log during intermediate wakeups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Gibson + +commit 037f0b03c663a247366673a807834389107995b7 upstream. + +The ECs in the IdeaPads that need the delay_suspend quirk send lots +of messages when charging, which not only causes intermediate wakeups +when suspended, but also prevents the device from reaching the deepest +suspend state. + +Because of this amd_pmc_intermediate_wakeup_need_delay() returns false +during intermediate wakeups and amd_pmc_want_suspend_delay() is called. +So far it always logged its "Delaying suspend by 2.5s ..." messages +then, which spams dmesg. This commit makes sure that those messages are +only logged once per suspend. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221383 +Reviewed-by: Hans de Goede +Signed-off-by: Daniel Gibson +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260611150426.3683372-5-daniel@gibson.sh +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/amd/pmc/pmc.c | 39 +++++++++++++++++++++++++++++-------- + drivers/platform/x86/amd/pmc/pmc.h | 1 + 2 files changed, 32 insertions(+), 8 deletions(-) + +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -620,6 +620,20 @@ static bool amd_pmc_intermediate_wakeup_ + static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev) + { + /* ++ * intermediate_wakeup implies that the machine didn't get to deepest sleep ++ * state before - otherwise this function isn't called in amd_pmc_s2idle_check() ++ * because amd_pmc_intermediate_wakeup_need_delay() returns true first. ++ * On some IdeaPads that happens when charging, because the EC seems ++ * to send lots of messages then that wake the machine. ++ * ++ * But even in that case, the sleep here is necessary (on those IdeaPads), ++ * otherwise they wake up completely (resume) after a few seconds. ++ * So this variable is only used to avoid spamming dmesg on each ++ * intermediate wakeup. ++ */ ++ bool intermediate_wakeup = !pdev->is_first_check_after_suspend; ++ ++ /* + * Some Lenovo Laptops (like different IdeaPad 3 Slims) need some + * me-time before sleeping or they get uncooperative after waking + * up and don't send events for keyboard and lid switch anymore. +@@ -637,17 +651,20 @@ static bool amd_pmc_want_suspend_delay(s + * disabled with disable_workarounds or delay_suspend=0 + */ + if (delay_suspend == 1 || (delay_suspend == -1 && !disable_workarounds)) { +- dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); ++ if (!intermediate_wakeup) ++ dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); + return true; + } +- dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n"); ++ if (!intermediate_wakeup) ++ dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n"); + } else if (delay_suspend == 1) { +- dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: platform-driver-x86@vger.kernel.org so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n", +- dmi_get_system_info(DMI_SYS_VENDOR), +- dmi_get_system_info(DMI_PRODUCT_NAME), +- dmi_get_system_info(DMI_PRODUCT_FAMILY), +- dmi_get_system_info(DMI_BOARD_VENDOR), +- dmi_get_system_info(DMI_BOARD_NAME)); ++ if (!intermediate_wakeup) ++ dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: platform-driver-x86@vger.kernel.org so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n", ++ dmi_get_system_info(DMI_SYS_VENDOR), ++ dmi_get_system_info(DMI_PRODUCT_NAME), ++ dmi_get_system_info(DMI_PRODUCT_FAMILY), ++ dmi_get_system_info(DMI_BOARD_VENDOR), ++ dmi_get_system_info(DMI_BOARD_NAME)); + return true; + } + return false; +@@ -660,6 +677,9 @@ static void amd_pmc_s2idle_prepare(void) + u8 msg; + u32 arg = 1; + ++ /* Reset this variable because this is a fresh suspend */ ++ pdev->is_first_check_after_suspend = true; ++ + /* Reset and Start SMU logging - to monitor the s0i3 stats */ + amd_pmc_setup_smu_logging(pdev); + +@@ -699,6 +719,9 @@ static void amd_pmc_s2idle_check(void) + rc = amd_stb_write(pdev, AMD_PMC_STB_S2IDLE_CHECK); + if (rc) + dev_err(pdev->dev, "error writing to STB: %d\n", rc); ++ ++ /* remember that first check after suspend is done (until next prepare) */ ++ pdev->is_first_check_after_suspend = false; + } + + static int amd_pmc_dump_data(struct amd_pmc_dev *pdev) +--- a/drivers/platform/x86/amd/pmc/pmc.h ++++ b/drivers/platform/x86/amd/pmc/pmc.h +@@ -114,6 +114,7 @@ struct amd_pmc_dev { + struct dentry *dbgfs_dir; + struct quirk_entry *quirks; + bool disable_8042_wakeup; ++ bool is_first_check_after_suspend; + struct amd_mp2_dev *mp2; + struct stb_arg stb_arg; + }; diff --git a/queue-6.18/platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch b/queue-6.18/platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch new file mode 100644 index 0000000000..63cbaa9073 --- /dev/null +++ b/queue-6.18/platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch @@ -0,0 +1,52 @@ +From 6e9cab2247e5b243ae2d907ce7c948a8a9c8d61a Mon Sep 17 00:00:00 2001 +From: Haoxiang Li +Date: Tue, 9 Jun 2026 16:14:19 +0800 +Subject: platform/x86: dell-laptop: fix missing cleanups in init error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Haoxiang Li + +commit 6e9cab2247e5b243ae2d907ce7c948a8a9c8d61a upstream. + +dell_init() initializes several resources after dell_setup_rfkill(), +including the optional touchpad LED, keyboard backlight LED, battery +hook, debugfs directory and dell-laptop notifier. + +If a later LED or backlight registration fails, the error path only +tears down the battery hook and rfkill resources. This leaves the +notifier, debugfs directory, keyboard backlight LED and optional +touchpad LED registered after dell_init() returns an error. + +Add the missing cleanup calls before tearing down rfkill. + +Fixes: 9c656b07997f ("platform/x86: dell-*: Call new led hw_changed API on kbd brightness change") +Fixes: 037accfa14b2 ("dell-laptop: Add debugfs support") +Fixes: 2d8b90be4f1c ("dell-laptop: support Synaptics/Alps touchpad led") +Fixes: 6cff8d60aa0a ("platform: x86: dell-laptop: Add support for keyboard backlight") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Link: https://patch.msgid.link/20260609081419.1995169-1-lihaoxiang@isrc.iscas.ac.cn +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/dell/dell-laptop.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/platform/x86/dell/dell-laptop.c ++++ b/drivers/platform/x86/dell/dell-laptop.c +@@ -2551,7 +2551,12 @@ fail_backlight: + if (mute_led_registered) + led_classdev_unregister(&mute_led_cdev); + fail_led: ++ dell_laptop_unregister_notifier(&dell_laptop_notifier); ++ debugfs_remove_recursive(dell_laptop_dir); + dell_battery_exit(); ++ kbd_led_exit(); ++ if (quirks && quirks->touchpad_led) ++ touchpad_led_exit(); + dell_cleanup_rfkill(); + fail_rfkill: + platform_device_del(platform_device); diff --git a/queue-6.18/platform-x86-isst-restore-sst-pp-control-to-all-domains.patch b/queue-6.18/platform-x86-isst-restore-sst-pp-control-to-all-domains.patch new file mode 100644 index 0000000000..d97b3726eb --- /dev/null +++ b/queue-6.18/platform-x86-isst-restore-sst-pp-control-to-all-domains.patch @@ -0,0 +1,42 @@ +From 2565a28cdcdcb035e151d285efcba26bccb3726e Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 28 May 2026 13:45:21 -0700 +Subject: platform/x86: ISST: Restore SST-PP control to all domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivas Pandruvada + +commit 2565a28cdcdcb035e151d285efcba26bccb3726e upstream. + +The SST-PP control offset is only restored to power domain 0 after +resume. During suspend, control values are read and stored for all +power domains. + +Use pd_info->sst_base instead of power_domain_info->sst_base, which +only points to power domain 0 base address. + +Fixes: dc7901b5a156 ("platform/x86: ISST: Store and restore all domains data") +Reported-by: Yi Lai +Signed-off-by: Srinivas Pandruvada +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260528204521.3531456-1-srinivas.pandruvada@linux.intel.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c ++++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +@@ -1786,7 +1786,7 @@ void tpmi_sst_dev_resume(struct auxiliar + memcpy_toio(cp_base + SST_CLOS_ASSOC_0_OFFSET, pd_info->saved_clos_assocs, + sizeof(pd_info->saved_clos_assocs)); + +- writeq(pd_info->saved_pp_control, power_domain_info->sst_base + ++ writeq(pd_info->saved_pp_control, pd_info->sst_base + + pd_info->sst_header.pp_offset + SST_PP_CONTROL_OFFSET); + } + } diff --git a/queue-6.18/s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch b/queue-6.18/s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch new file mode 100644 index 0000000000..097e682631 --- /dev/null +++ b/queue-6.18/s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch @@ -0,0 +1,38 @@ +From 1ac287e2af9a9112fe271427ef45eceb26bce8b4 Mon Sep 17 00:00:00 2001 +From: Holger Dengler +Date: Wed, 17 Jun 2026 19:06:39 +0200 +Subject: s390/pkey: Check length in pkey_pckmo handler implementation + +From: Holger Dengler + +commit 1ac287e2af9a9112fe271427ef45eceb26bce8b4 upstream. + +Explicitly check the length of the target buffer in the pkey_pckmo +implementation of the key_to_protkey() handler function. The handler +function fails, if the generated output data exceeds the length of the +provided target buffer. + +Cc: stable@vger.kernel.org +Fixes: 8fcc231ce3be ("s390/pkey: Introduce pkey base with handler registry and handler modules") +Reported-by: Christian Borntraeger +Reviewed-by: Harald Freudenberger +Signed-off-by: Holger Dengler +Signed-off-by: Alexander Gordeev +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/crypto/pkey_pckmo.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/s390/crypto/pkey_pckmo.c ++++ b/drivers/s390/crypto/pkey_pckmo.c +@@ -257,6 +257,10 @@ static int pckmo_key2protkey(const u8 *k + goto out; + break; + } ++ if (t->len > *protkeylen) { ++ rc = -EINVAL; ++ goto out; ++ } + memcpy(protkey, t->protkey, t->len); + *protkeylen = t->len; + *protkeytype = t->keytype; diff --git a/queue-6.18/s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch b/queue-6.18/s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch new file mode 100644 index 0000000000..613c6314e9 --- /dev/null +++ b/queue-6.18/s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch @@ -0,0 +1,40 @@ +From b3d4ab2d7df9426f7f1d3671d7e2108f2ca6e970 Mon Sep 17 00:00:00 2001 +From: Holger Dengler +Date: Mon, 15 Jun 2026 17:39:12 +0200 +Subject: s390/pkey: Check length in PKEY_VERIFYPROTK ioctl + +From: Holger Dengler + +commit b3d4ab2d7df9426f7f1d3671d7e2108f2ca6e970 upstream. + +Explicitly check the buffer length request structure provided by +user-space and fail, if it exceeds the buffer size. + +Cc: stable@vger.kernel.org +Fixes: 8fcc231ce3be ("s390/pkey: Introduce pkey base with handler registry and handler modules") +Reported-by: Christian Borntraeger +Reviewed-by: Harald Freudenberger +Reviewed-by: Ingo Franzki +Signed-off-by: Holger Dengler +Signed-off-by: Alexander Gordeev +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/crypto/pkey_api.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/s390/crypto/pkey_api.c ++++ b/drivers/s390/crypto/pkey_api.c +@@ -335,6 +335,13 @@ static int pkey_ioctl_verifyprotk(struct + if (copy_from_user(&kvp, uvp, sizeof(kvp))) + return -EFAULT; + ++ if (kvp.protkey.len > sizeof(kvp.protkey.protkey)) { ++ PKEY_DBF_ERR("%s protkey length %u exceeds protkey buffer size\n", ++ __func__, kvp.protkey.len); ++ memzero_explicit(&kvp, sizeof(kvp)); ++ return -EINVAL; ++ } ++ + keytype = pkey_aes_bitsize_to_keytype(8 * kvp.protkey.len); + if (!keytype) { + PKEY_DBF_ERR("%s unknown/unsupported protkey length %u\n", diff --git a/queue-6.18/scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch b/queue-6.18/scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch new file mode 100644 index 0000000000..00df079071 --- /dev/null +++ b/queue-6.18/scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch @@ -0,0 +1,36 @@ +From 9cb2d5291dbfe7bed565ead3337047dee9ed1064 Mon Sep 17 00:00:00 2001 +From: Haoxiang Li +Date: Mon, 22 Jun 2026 15:58:44 +0800 +Subject: scsi: elx: efct: Fix I/O leak on unsupported additional CDB + +From: Haoxiang Li + +commit 9cb2d5291dbfe7bed565ead3337047dee9ed1064 upstream. + +efct_dispatch_fcp_cmd() allocates an efct_io before dispatching an +unsolicited FCP command. If the command has an unsupported additional +CDB, the function returns -EIO before handing the IO to the SCSI layer. + +Free the allocated IO before returning from this error path. + +Fixes: f45ae6aac0a0 ("scsi: elx: efct: Unsolicited FC frame processing routines") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Reviewed-by: Daniel Wagner +Link: https://patch.msgid.link/20260622075844.832871-1-haoxiang_li2024@163.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/elx/efct/efct_unsol.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/scsi/elx/efct/efct_unsol.c ++++ b/drivers/scsi/elx/efct/efct_unsol.c +@@ -385,6 +385,7 @@ efct_dispatch_fcp_cmd(struct efct_node * + + if (cmnd->fc_flags & FCP_CFL_LEN_MASK) { + efc_log_err(efct, "Additional CDB not supported\n"); ++ efct_scsi_io_free(io); + return -EIO; + } + /* diff --git a/queue-6.18/scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch b/queue-6.18/scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch new file mode 100644 index 0000000000..9c09468d8d --- /dev/null +++ b/queue-6.18/scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch @@ -0,0 +1,46 @@ +From 2c007acf7b31c39c08ce4959451ad00b19be4c1f Mon Sep 17 00:00:00 2001 +From: WenTao Liang +Date: Thu, 11 Jun 2026 13:30:37 +0800 +Subject: scsi: elx: efct: Fix refcount leak in efct_hw_io_abort() + +From: WenTao Liang + +commit 2c007acf7b31c39c08ce4959451ad00b19be4c1f upstream. + +When efct_hw_reqtag_alloc() fails in efct_hw_io_abort(), the error path +returns -ENOSPC without releasing the reference obtained via +kref_get_unless_zero() earlier in the function. All other error paths +correctly drop the reference. This causes a permanent reference leak on the +io_to_abort object. + +Additionally, the abort_in_progress flag is left set to true on this path, +which means future abort attempts for the same I/O will immediately return +-EINPROGRESS even though the abort was never submitted, effectively +blocking recovery. + +Fix this by adding the missing kref_put() call and reset abort_in_progress +to false, matching the cleanup done in the efct_hw_wq_write() failure path +below. + +Cc: stable@vger.kernel.org +Fixes: 63de51327a64 ("scsi: elx: efct: Hardware I/O and SGL initialization") +Signed-off-by: WenTao Liang +Reviewed-by: Daniel Wagner +Link: https://patch.msgid.link/20260611053037.63756-1-vulab@iscas.ac.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/elx/efct/efct_hw.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/scsi/elx/efct/efct_hw.c ++++ b/drivers/scsi/elx/efct/efct_hw.c +@@ -1998,6 +1998,8 @@ efct_hw_io_abort(struct efct_hw *hw, str + wqcb = efct_hw_reqtag_alloc(hw, efct_hw_wq_process_abort, io_to_abort); + if (!wqcb) { + efc_log_err(hw->os, "can't allocate request tag\n"); ++ io_to_abort->abort_in_progress = false; ++ kref_put(&io_to_abort->ref, io_to_abort->release); + return -ENOSPC; + } + diff --git a/queue-6.18/scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch b/queue-6.18/scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch new file mode 100644 index 0000000000..2a58ef8f49 --- /dev/null +++ b/queue-6.18/scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch @@ -0,0 +1,39 @@ +From e166bafc483e927150cb9b5f286c9191ea0df84e Mon Sep 17 00:00:00 2001 +From: Haoxiang Li +Date: Tue, 23 Jun 2026 00:00:28 +0800 +Subject: scsi: hpsa: Fix DMA mapping leak on IOACCEL2 reset path + +From: Haoxiang Li + +commit e166bafc483e927150cb9b5f286c9191ea0df84e upstream. + +If phys_disk->in_reset is set, the function returns directly without +undoing the resources acquired for the command. Add the missing error +cleanup by unmapping the IOACCEL2 SG chain block when needed, unmapping +the SCSI command, and dropping the outstanding IOACCEL command count +before returning. + +Fixes: c5dfd106414f ("scsi: hpsa: correct device resets") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Acked-by: Don Brace +Link: https://patch.msgid.link/20260622160028.1240496-1-haoxiang_li2024@163.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/hpsa.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/scsi/hpsa.c ++++ b/drivers/scsi/hpsa.c +@@ -5020,6 +5020,10 @@ static int hpsa_scsi_ioaccel2_queue_comm + + if (phys_disk->in_reset) { + cmd->result = DID_RESET << 16; ++ atomic_dec(&phys_disk->ioaccel_cmds_out); ++ scsi_dma_unmap(cmd); ++ if (use_sg > h->ioaccel_maxsg) ++ hpsa_unmap_ioaccel2_sg_chain_block(h, cp); + return -1; + } + diff --git a/queue-6.18/scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch b/queue-6.18/scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch new file mode 100644 index 0000000000..25661e3843 --- /dev/null +++ b/queue-6.18/scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch @@ -0,0 +1,43 @@ +From 1bd28625e25be549ee7c47532e7c3ef91c682410 Mon Sep 17 00:00:00 2001 +From: Abdun Nihaal +Date: Tue, 7 Jul 2026 12:23:02 +0530 +Subject: scsi: lpfc: Fix memory leak in lpfc_sli4_driver_resource_setup() + +From: Abdun Nihaal + +commit 1bd28625e25be549ee7c47532e7c3ef91c682410 upstream. + +The memory allocated for mboxq using mempool_alloc() is not freed in +some of the early exit error paths. Fix that by moving the +mempool_free() call to an earlier point after last use. + +Fixes: d79c9e9d4b3d ("scsi: lpfc: Support dynamic unbounded SGL lists on G7 hardware.") +Cc: stable@vger.kernel.org +Signed-off-by: Abdun Nihaal +Reviewed-by: Justin Tee +Link: https://patch.msgid.link/20260707065304.949135-1-nihaal@cse.iitm.ac.in +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/lpfc/lpfc_init.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -8194,6 +8194,7 @@ lpfc_sli4_driver_resource_setup(struct l + mempool_free(mboxq, phba->mbox_mem_pool); + goto out_free_bsmbx; + } ++ mempool_free(mboxq, phba->mbox_mem_pool); + + /* + * 1 for cmd, 1 for rsp, NVME adds an extra one +@@ -8316,8 +8317,6 @@ lpfc_sli4_driver_resource_setup(struct l + goto out_free_sg_dma_buf; + } + +- mempool_free(mboxq, phba->mbox_mem_pool); +- + /* Verify OAS is supported */ + lpfc_sli4_oas_verify(phba); + diff --git a/queue-6.18/scsi-sg-report-request-table-problems-when-any-status-is-set.patch b/queue-6.18/scsi-sg-report-request-table-problems-when-any-status-is-set.patch new file mode 100644 index 0000000000..972f944115 --- /dev/null +++ b/queue-6.18/scsi-sg-report-request-table-problems-when-any-status-is-set.patch @@ -0,0 +1,49 @@ +From 1d3a742afeb761eaead774691bde1ced699e9a5d Mon Sep 17 00:00:00 2001 +From: Xu Rao +Date: Tue, 7 Jul 2026 11:08:45 +0800 +Subject: scsi: sg: Report request-table problems when any status is set + +From: Xu Rao + +commit 1d3a742afeb761eaead774691bde1ced699e9a5d upstream. + +SG_GET_REQUEST_TABLE reports per-request diagnostic state through +sg_req_info::problem. The field is meant to indicate whether there is an +error to report for a completed request. + +sg_fill_request_table() currently combines masked_status, host_status +and driver_status with bitwise AND. This only reports a problem when all +three status fields are non-zero at the same time. A normal target check +condition, for example, has masked_status set while host_status and +driver_status may both be zero, so the request is incorrectly reported +as clean. + +Use the same condition as sg_new_read(), which sets SG_INFO_CHECK when +any of the three status fields is non-zero. + +Cc: stable@vger.kernel.org +Signed-off-by: Xu Rao +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/54B60C19F7DB8889+20260707030845.970018-1-raoxu@uniontech.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/sg.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -862,10 +862,9 @@ sg_fill_request_table(Sg_fd *sfp, sg_req + if (val >= SG_MAX_QUEUE) + break; + rinfo[val].req_state = srp->done + 1; +- rinfo[val].problem = +- srp->header.masked_status & +- srp->header.host_status & +- srp->header.driver_status; ++ rinfo[val].problem = srp->header.masked_status || ++ srp->header.host_status || ++ srp->header.driver_status; + if (srp->done) + rinfo[val].duration = + srp->header.duration; diff --git a/queue-6.18/scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch b/queue-6.18/scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch new file mode 100644 index 0000000000..6a2b6a774b --- /dev/null +++ b/queue-6.18/scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch @@ -0,0 +1,250 @@ +From d04a179085c262c9ed577d0a4cbc6482ff1fd9a3 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Thu, 11 Jun 2026 13:42:26 -0500 +Subject: scsi: target: Bound PR-OUT TransportID parsing to the received buffer + +From: Bryam Vargas + +commit d04a179085c262c9ed577d0a4cbc6482ff1fd9a3 upstream. + +core_scsi3_decode_spec_i_port() and core_scsi3_emulate_register_and_move() +hand the raw PERSISTENT RESERVE OUT parameter buffer to +target_parse_pr_out_transport_id() without telling it how many bytes are +valid. For an iSCSI TransportID (FORMAT CODE 01b), +iscsi_parse_pr_out_transport_id() locates the ",i,0x" ISID separator with +an unbounded strstr() (and on the error path prints the name with a further +unbounded "%s"). An initiator can submit a TransportID whose iSCSI name +contains neither a ",i,0x" substring nor a NUL terminator, filling the +parameter list to its end, so the scan runs off the end of the buffer. + +When the parameter list spans more than one page the buffer is a multi-page +vmap (transport_kmap_data_sg()), so the over-read walks into the trailing +vmalloc guard page and oopses (KASAN: vmalloc-out-of-bounds in strstr). It +is reachable by any fabric that delivers a PR OUT to a device exported +through an iSCSI TPG, including a guest via vhost-scsi. + +Pass the number of received bytes down to the parser and validate the iSCSI +TransportID's own self-described length (ADDITIONAL LENGTH + 4) once, up +front: reject it if it is below the spc4r17 minimum or larger than the +received buffer, then bound the separator search, the ISID walk and the +name copy by that length. This is the length check the callers already +perform after the parse (core_scsi3_decode_spec_i_port() compares tid_len +against tpdl, core_scsi3_emulate_register_and_move() validates it against +data_length), moved ahead of the scan. Also drop the unbounded "%s" of the +unterminated name. + +Add per-format explicit name-length checks before copying into i_str, +rather than silently truncating with min_t: for FORMAT CODE 00b reject if +the descriptor body (tid_len - 4 bytes) cannot fit in +i_str[TRANSPORT_IQN_LEN]; for FORMAT CODE 01b reject if the name portion +(from &buf[4] up to the separator) cannot fit. Both checks make the bounds +intent explicit at each format branch. + +While here, also reject a FORMAT CODE 01b TransportID whose ",i,0x" +separator sits at the very end of the descriptor: that leaves an empty ISID +and points the returned port nexus pointer at buf + tid_len, one past the +descriptor, which the registration code (__core_scsi3_locate_pr_reg(), +__core_scsi3_alloc_registration()) then dereferences as the ISID string -- +the same over-read of the parameter buffer for a malformed descriptor. + +Fixes: c66ac9db8d4a ("[SCSI] target: Add LIO target core v4.0.0-rc6") +Cc: stable@vger.kernel.org +Signed-off-by: Bryam Vargas +Reviewed-by: John Garry +Reviewed-by: David Disseldorp +Link: https://patch.msgid.link/20260611-b4-disp-9f20739e-v6-1-f6630e2aae44@proton.me +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/target/target_core_fabric_lib.c | 89 ++++++++++++++++++++++++-------- + drivers/target/target_core_internal.h | 3 - + drivers/target/target_core_pr.c | 4 - + 3 files changed, 73 insertions(+), 23 deletions(-) + +--- a/drivers/target/target_core_fabric_lib.c ++++ b/drivers/target/target_core_fabric_lib.c +@@ -289,13 +289,24 @@ static void sbp_parse_pr_out_transport_i + static bool iscsi_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + char *buf, ++ u32 buf_len, + u32 *out_tid_len, + char **port_nexus_ptr, + char *i_str) + { + char *p; ++ u32 tid_len; + int i; +- u8 format_code = (buf[0] & 0xc0); ++ u8 format_code; ++ ++ /* ++ * The 4-byte iSCSI TransportID header (FORMAT CODE + 2-byte ADDITIONAL ++ * LENGTH) must be present before any of it can be parsed. ++ */ ++ if (buf_len < 4) ++ return false; ++ ++ format_code = buf[0] & 0xc0; + /* + * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6: + * +@@ -315,15 +326,17 @@ static bool iscsi_parse_pr_out_transport + return false; + } + /* +- * If the caller wants the TransportID Length, we set that value for the +- * entire iSCSI Tarnsport ID now. ++ * Reconstruct the self-described TransportID length from the ADDITIONAL ++ * LENGTH field plus the 4-byte header. Reject it if it is below the ++ * spc4r17 section 7.5.4.6 minimum (ADDITIONAL LENGTH shall be at least ++ * 20) or if it runs past the bytes actually received, so that every ++ * access below stays inside the TransportID. + */ +- if (out_tid_len) { +- /* The shift works thanks to integer promotion rules */ +- *out_tid_len = get_unaligned_be16(&buf[2]); +- /* Add four bytes for iSCSI Transport ID header */ +- *out_tid_len += 4; +- } ++ tid_len = get_unaligned_be16(&buf[2]) + 4; ++ if (tid_len < 24 || tid_len > buf_len) ++ return false; ++ if (out_tid_len) ++ *out_tid_len = tid_len; + + /* + * Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator +@@ -331,16 +344,32 @@ static bool iscsi_parse_pr_out_transport + * format. + */ + if (format_code == 0x40) { +- p = strstr(&buf[4], ",i,0x"); ++ p = strnstr(&buf[4], ",i,0x", tid_len - 4); + if (!p) { +- pr_err("Unable to locate \",i,0x\" separator" +- " for Initiator port identifier: %s\n", +- &buf[4]); ++ pr_err("Unable to locate \",i,0x\" separator in iSCSI TransportID\n"); ++ return false; ++ } ++ /* ++ * The iSCSI name runs from &buf[4] up to the separator; reject it ++ * if it cannot fit in i_str[TRANSPORT_IQN_LEN]. ++ */ ++ if (p - &buf[4] >= TRANSPORT_IQN_LEN) { ++ pr_err("iSCSI Initiator port name too long in TransportID\n"); + return false; + } + *p = '\0'; /* Terminate iSCSI Name */ + p += 5; /* Skip over ",i,0x" separator */ + ++ /* ++ * The ISID must follow the separator. A ",i,0x" sitting at the ++ * very end of the TransportID leaves no ISID and would point the ++ * port nexus at buf + tid_len, i.e. past the descriptor, which ++ * the registration code then reads as the ISID string. ++ */ ++ if (p >= buf + tid_len) { ++ pr_err("Missing ISID in iSCSI Initiator port TransportID\n"); ++ return false; ++ } + *port_nexus_ptr = p; + /* + * Go ahead and do the lower case conversion of the received +@@ -348,7 +377,7 @@ static bool iscsi_parse_pr_out_transport + * for comparison against the running iSCSI session's ISID from + * iscsi_target.c:lio_sess_get_initiator_sid() + */ +- for (i = 0; i < 12; i++) { ++ for (i = 0; i < 12 && p < buf + tid_len; i++) { + /* + * The first ISCSI INITIATOR SESSION ID field byte + * containing an ASCII null character terminates the +@@ -366,10 +395,22 @@ static bool iscsi_parse_pr_out_transport + *p = tolower(*p); + p++; + } +- } else ++ strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN); ++ } else { + *port_nexus_ptr = NULL; +- +- strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN); ++ /* ++ * FORMAT CODE 00b: the name occupies buf[4..tid_len-1]. The ++ * declared length tid_len - 4 must fit in i_str[TRANSPORT_IQN_LEN]. ++ * (For 01b the same tid_len bound would be over-restrictive: the ++ * descriptor also carries the separator and ISID, so a legal ++ * <=223-byte name gives tid_len up to 244.) ++ */ ++ if (tid_len - 4 >= TRANSPORT_IQN_LEN) { ++ pr_err("iSCSI Initiator port name too long in TransportID\n"); ++ return false; ++ } ++ strscpy(i_str, &buf[4], tid_len - 4); ++ } + return true; + } + +@@ -419,8 +460,16 @@ int target_get_pr_transport_id(struct se + } + + bool target_parse_pr_out_transport_id(struct se_portal_group *tpg, +- char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str) ++ char *buf, u32 buf_len, u32 *out_tid_len, ++ char **port_nexus_ptr, char *i_str) + { ++ /* ++ * The fixed-length SAS/SRP/FCP/SBP TransportIDs are 24 bytes; the iSCSI ++ * format is variable and bounds itself against buf_len below. ++ */ ++ if (tpg->proto_id != SCSI_PROTOCOL_ISCSI && buf_len < 24) ++ return false; ++ + switch (tpg->proto_id) { + case SCSI_PROTOCOL_SAS: + /* +@@ -439,8 +488,8 @@ bool target_parse_pr_out_transport_id(st + sbp_parse_pr_out_transport_id(buf, i_str); + break; + case SCSI_PROTOCOL_ISCSI: +- return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len, +- port_nexus_ptr, i_str); ++ return iscsi_parse_pr_out_transport_id(tpg, buf, buf_len, ++ out_tid_len, port_nexus_ptr, i_str); + default: + pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id); + return false; +--- a/drivers/target/target_core_internal.h ++++ b/drivers/target/target_core_internal.h +@@ -104,7 +104,8 @@ int target_get_pr_transport_id(struct se + struct t10_pr_registration *pr_reg, int *format_code, + unsigned char *buf); + bool target_parse_pr_out_transport_id(struct se_portal_group *tpg, +- char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str); ++ char *buf, u32 buf_len, u32 *out_tid_len, ++ char **port_nexus_ptr, char *i_str); + + /* target_core_hba.c */ + struct se_hba *core_alloc_hba(const char *, u32, u32); +--- a/drivers/target/target_core_pr.c ++++ b/drivers/target/target_core_pr.c +@@ -1573,7 +1573,7 @@ core_scsi3_decode_spec_i_port( + + iport_ptr = NULL; + tid_found = target_parse_pr_out_transport_id(tmp_tpg, +- ptr, &tid_len, &iport_ptr, i_str); ++ ptr, tpdl, &tid_len, &iport_ptr, i_str); + if (!tid_found) + continue; + /* +@@ -3281,7 +3281,7 @@ core_scsi3_emulate_pro_register_and_move + goto out; + } + tid_found = target_parse_pr_out_transport_id(dest_se_tpg, +- &buf[24], &tmp_tid_len, &iport_ptr, initiator_str); ++ &buf[24], tid_len, &tmp_tid_len, &iport_ptr, initiator_str); + if (!tid_found) { + pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" + " initiator_str from Transport ID\n"); diff --git a/queue-6.18/scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch b/queue-6.18/scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch new file mode 100644 index 0000000000..fd5c23dc8b --- /dev/null +++ b/queue-6.18/scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch @@ -0,0 +1,69 @@ +From fda6a1f3c3d7047b5ce5654487649c2daa738bfc Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Wed, 10 Jun 2026 04:22:48 +0000 +Subject: scsi: target: core: Fix iSCSI ISID use-after-free in REGISTER AND MOVE + +From: Bryam Vargas + +commit fda6a1f3c3d7047b5ce5654487649c2daa738bfc upstream. + +core_scsi3_emulate_pro_register_and_move() maps the PERSISTENT RESERVE OUT +parameter list with transport_kmap_data_sg() and parses the destination +TransportID with target_parse_pr_out_transport_id(). For an iSCSI +TransportID (FORMAT CODE 01b), iscsi_parse_pr_out_transport_id() returns +the ISID in iport_ptr as a raw pointer into that mapped buffer. + +The function then unmaps the buffer with transport_kunmap_data_sg() before +dereferencing iport_ptr in strcmp(), __core_scsi3_locate_pr_reg() and +core_scsi3_alloc_registration(). When the parameter list spans more than +one page (PARAMETER LIST LENGTH > 4096), transport_kmap_data_sg() uses +vmap() and transport_kunmap_data_sg() does vunmap(), so the kernel virtual +address backing iport_ptr is torn down and every subsequent dereference is +a use-after-free read of the unmapped region. + +Keep the parameter list mapped until iport_ptr is no longer needed: drop +the early transport_kunmap_data_sg() and unmap once on the success path, +right before returning. The error paths already unmap through the existing +"if (buf) transport_kunmap_data_sg(cmd)" at the out: label, which now runs +on every post-map error exit because buf is no longer cleared early. Only +reads of the mapping happen while spinlocks are held; the map and unmap +calls remain outside any lock. The sibling caller +core_scsi3_decode_spec_i_port() already uses the buffer before unmapping it +and is left unchanged. + +Fixes: 4949314c7283 ("target: Allow control CDBs with data > 1 page") +Cc: stable@vger.kernel.org +Signed-off-by: Bryam Vargas +Reviewed-by: John Garry +Reviewed-by: David Disseldorp +Link: https://patch.msgid.link/20260610042245.35473-1-hexlabsecurity@proton.me +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/target/target_core_pr.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/target/target_core_pr.c ++++ b/drivers/target/target_core_pr.c +@@ -3289,9 +3289,6 @@ core_scsi3_emulate_pro_register_and_move + goto out; + } + +- transport_kunmap_data_sg(cmd); +- buf = NULL; +- + pr_debug("SPC-3 PR [%s] Extracted initiator %s identifier: %s" + " %s\n", dest_tf_ops->fabric_name, (iport_ptr != NULL) ? + "port" : "device", initiator_str, (iport_ptr != NULL) ? +@@ -3528,6 +3525,11 @@ after_iport_check: + core_scsi3_update_and_write_aptpl(cmd->se_dev, aptpl); + + core_scsi3_put_pr_reg(dest_pr_reg); ++ /* ++ * iport_ptr aliases the PR-OUT parameter list mapped above, so the ++ * buffer is unmapped only here on success (and at out: on error). ++ */ ++ transport_kunmap_data_sg(cmd); + return 0; + out: + if (buf) diff --git a/queue-6.18/scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch b/queue-6.18/scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch new file mode 100644 index 0000000000..576d0e4f4b --- /dev/null +++ b/queue-6.18/scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch @@ -0,0 +1,52 @@ +From 66aefc277ebb796ec285d550305535dc3fc0179f Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Thu, 11 Jun 2026 08:30:46 -0400 +Subject: scsi: xen: scsiback: Free the command tag on the TMR submit-failure path + +From: Michael Bommarito + +commit 66aefc277ebb796ec285d550305535dc3fc0179f upstream. + +scsiback_device_action() obtains a command tag in +scsiback_get_pend_req() and submits a task-management request with +target_submit_tmr(). When target_submit_tmr() fails it returns < 0 and +scsiback jumps to the err: label, which sends a response but frees +nothing, leaking the tag. + +Impact: a pvSCSI guest can leak the command tags of a LUN's session, +stopping the LUN, by issuing VSCSIIF_ACT_SCSI_ABORT or RESET requests +whenever target_submit_tmr() fails. + +transport_generic_free_cmd() cannot be used here. By the time +target_submit_tmr() returns an error it has already run +__target_init_cmd() (so se_cmd->cmd_kref is one, not zero), and on its +target_get_sess_cmd() error path it has freed se_cmd->se_tmr_req via +core_tmr_release_req() while leaving SCF_SCSI_TMR_CDB set and the +pointer dangling. Letting the command release run target_free_cmd_mem() +would then double-free se_tmr_req. + +Use the same helper, which returns just the tag, on this path too. + +Fixes: 2dbcdf33dbf6 ("xen-scsiback: Convert to percpu_ida tag allocation") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Michael Bommarito +Reviewed-by: Juergen Gross +Link: https://patch.msgid.link/20260611123046.2323342-3-michael.bommarito@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/xen/xen-scsiback.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/xen/xen-scsiback.c ++++ b/drivers/xen/xen-scsiback.c +@@ -640,7 +640,7 @@ static void scsiback_device_action(struc + return; + + err: +- scsiback_do_resp_with_sense(NULL, err, 0, pending_req); ++ scsiback_resp_and_free(pending_req, err); + } + + /* diff --git a/queue-6.18/scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch b/queue-6.18/scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch new file mode 100644 index 0000000000..5fd98c946c --- /dev/null +++ b/queue-6.18/scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch @@ -0,0 +1,94 @@ +From ca978f8a93d4d36841839bf2847d29b88c2591d6 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Thu, 11 Jun 2026 08:30:45 -0400 +Subject: scsi: xen: scsiback: Free unsubmitted command instead of double-putting it + +From: Michael Bommarito + +commit ca978f8a93d4d36841839bf2847d29b88c2591d6 upstream. + +scsiback_get_pend_req() obtains a command tag and returns a vscsibk_pend +whose embedded se_cmd has only been memset to 0, so its cmd_kref is 0; +the se_cmd is initialised (kref_init() via target_init_cmd()) only +later, in scsiback_cmd_exec(), on the successful VSCSIIF_ACT_SCSI_CDB +path. The two error paths in scsiback_do_cmd_fn() taken before the +command is submitted -- a failed scsiback_gnttab_data_map() and an +unknown ring_req.act -- call +transport_generic_free_cmd(&pending_req->se_cmd, 0), which kref_put()s a +refcount of 0. That underflows it ("refcount_t: underflow; +use-after-free") and, as the release function is not run, leaks the +command tag. + +Impact: a pvSCSI guest can leak every command tag of a LUN's session, +stopping the LUN, by submitting requests with a bad grant reference or +an unknown request type; under panic_on_warn the refcount underflow +panics the host. + +Add a helper that just returns the tag with target_free_tag() and sends +the error response. It frees the tag while the v2p reference still pins +the session, and snapshots the response fields beforehand because +freeing the tag can let another ring reuse the pending_req slot. + +Fixes: 2dbcdf33dbf6 ("xen-scsiback: Convert to percpu_ida tag allocation") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Michael Bommarito +Reviewed-by: Juergen Gross +Link: https://patch.msgid.link/20260611123046.2323342-2-michael.bommarito@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/xen/xen-scsiback.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +--- a/drivers/xen/xen-scsiback.c ++++ b/drivers/xen/xen-scsiback.c +@@ -612,6 +612,25 @@ static void scsiback_disconnect(struct v + xenbus_unmap_ring_vfree(info->dev, info->ring.sring); + } + ++/* ++ * Send the error response for a request that did not reach the target core ++ * and return its tag. Free the tag before the response drops the v2p ++ * reference that keeps the session alive, and snapshot what the response ++ * needs since returning the tag can let the slot be reused. ++ */ ++static void scsiback_resp_and_free(struct vscsibk_pend *pending_req, ++ int32_t result) ++{ ++ struct vscsibk_info *info = pending_req->info; ++ struct v2p_entry *v2p = pending_req->v2p; ++ struct se_session *se_sess = v2p->tpg->tpg_nexus->tvn_se_sess; ++ u16 rqid = pending_req->rqid; ++ ++ target_free_tag(se_sess, &pending_req->se_cmd); ++ scsiback_send_response(info, NULL, result, 0, rqid); ++ kref_put(&v2p->kref, scsiback_free_translation_entry); ++} ++ + static void scsiback_device_action(struct vscsibk_pend *pending_req, + enum tcm_tmreq_table act, int tag) + { +@@ -793,9 +812,8 @@ static int scsiback_do_cmd_fn(struct vsc + case VSCSIIF_ACT_SCSI_CDB: + if (scsiback_gnttab_data_map(&ring_req, pending_req)) { + scsiback_fast_flush_area(pending_req); +- scsiback_do_resp_with_sense(NULL, +- DID_ERROR << 16, 0, pending_req); +- transport_generic_free_cmd(&pending_req->se_cmd, 0); ++ scsiback_resp_and_free(pending_req, ++ DID_ERROR << 16); + } else { + scsiback_cmd_exec(pending_req); + } +@@ -809,9 +827,7 @@ static int scsiback_do_cmd_fn(struct vsc + break; + default: + pr_err_ratelimited("invalid request\n"); +- scsiback_do_resp_with_sense(NULL, DID_ERROR << 16, 0, +- pending_req); +- transport_generic_free_cmd(&pending_req->se_cmd, 0); ++ scsiback_resp_and_free(pending_req, DID_ERROR << 16); + break; + } + diff --git a/queue-6.18/sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch b/queue-6.18/sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch new file mode 100644 index 0000000000..5f4a1d0763 --- /dev/null +++ b/queue-6.18/sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch @@ -0,0 +1,103 @@ +From 1cd23ca80784223fa2204e16203f754da4e821f8 Mon Sep 17 00:00:00 2001 +From: Weiming Shi +Date: Fri, 3 Jul 2026 20:35:46 -0700 +Subject: sctp: validate STALE_COOKIE cause length before reading staleness + +From: Weiming Shi + +commit 1cd23ca80784223fa2204e16203f754da4e821f8 upstream. + +When an ERROR chunk with a STALE_COOKIE cause is received in the +COOKIE_ECHOED state, sctp_sf_do_5_2_6_stale() reads the 4-byte Measure +of Staleness that follows the cause header: + + err = (struct sctp_errhdr *)(chunk->skb->data); + stale = ntohl(*(__be32 *)((u8 *)err + sizeof(*err))); + +err is the first cause in the chunk, not the STALE_COOKIE cause that +caused the dispatch, and nothing guarantees the staleness field is +present. sctp_walk_errors() only requires a cause to be as long as the +4-byte header, so for a STALE_COOKIE cause of length 4 the read runs +past the cause, and for a minimal ERROR chunk past skb->tail. The value +is echoed to the peer in the Cookie Preservative of the reply INIT, +leaking uninitialized memory. + +sctp_sf_cookie_echoed_err() already walks to the STALE_COOKIE cause, so +check its length there and pass it to sctp_sf_do_5_2_6_stale(), which +reads that cause instead of the first one. A STALE_COOKIE cause too +short to hold the staleness field is discarded. + +The read is reachable by any peer that can drive an association into +COOKIE_ECHOED, including an unprivileged process using a raw SCTP socket +in a user and network namespace. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Cc: stable@vger.kernel.org +Signed-off-by: Weiming Shi +Acked-by: Xin Long +Link: https://patch.msgid.link/20260704033545.2438373-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/sm_statefuns.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -74,7 +74,8 @@ static enum sctp_disposition sctp_sf_do_ + const struct sctp_association *asoc, + const union sctp_subtype type, + void *arg, +- struct sctp_cmd_seq *commands); ++ struct sctp_cmd_seq *commands, ++ struct sctp_errhdr *err); + static enum sctp_disposition sctp_sf_shut_8_4_5( + struct net *net, + const struct sctp_endpoint *ep, +@@ -2524,9 +2525,15 @@ enum sctp_disposition sctp_sf_cookie_ech + * errors. + */ + sctp_walk_errors(err, chunk->chunk_hdr) { +- if (SCTP_ERROR_STALE_COOKIE == err->cause) +- return sctp_sf_do_5_2_6_stale(net, ep, asoc, type, +- arg, commands); ++ if (err->cause != SCTP_ERROR_STALE_COOKIE) ++ continue; ++ /* The staleness is only meaningful if the cause is long ++ * enough to hold it; a shorter one is malformed. ++ */ ++ if (ntohs(err->length) < sizeof(*err) + sizeof(__be32)) ++ break; ++ return sctp_sf_do_5_2_6_stale(net, ep, asoc, type, ++ arg, commands, err); + } + + /* It is possible to have malformed error causes, and that +@@ -2568,13 +2575,13 @@ static enum sctp_disposition sctp_sf_do_ + const struct sctp_association *asoc, + const union sctp_subtype type, + void *arg, +- struct sctp_cmd_seq *commands) ++ struct sctp_cmd_seq *commands, ++ struct sctp_errhdr *err) + { + int attempts = asoc->init_err_counter + 1; +- struct sctp_chunk *chunk = arg, *reply; + struct sctp_cookie_preserve_param bht; + struct sctp_bind_addr *bp; +- struct sctp_errhdr *err; ++ struct sctp_chunk *reply; + u32 stale; + + if (attempts > asoc->max_init_attempts) { +@@ -2585,8 +2592,6 @@ static enum sctp_disposition sctp_sf_do_ + return SCTP_DISPOSITION_DELETE_TCB; + } + +- err = (struct sctp_errhdr *)(chunk->skb->data); +- + /* When calculating the time extension, an implementation + * SHOULD use the RTT information measured based on the + * previous COOKIE ECHO / ERROR exchange, and should add no diff --git a/queue-6.18/selftests-bpf-cover-negative-buffer-pointer-offsets.patch b/queue-6.18/selftests-bpf-cover-negative-buffer-pointer-offsets.patch new file mode 100644 index 0000000000..c7318c8bb7 --- /dev/null +++ b/queue-6.18/selftests-bpf-cover-negative-buffer-pointer-offsets.patch @@ -0,0 +1,216 @@ +From 6f59deb32efa4673fc3b1fef9f3a0da48e9d8494 Mon Sep 17 00:00:00 2001 +From: Sun Jian +Date: Tue, 14 Jul 2026 02:38:46 -0700 +Subject: selftests/bpf: Cover negative buffer pointer offsets + +From: Sun Jian + +commit 6f59deb32efa4673fc3b1fef9f3a0da48e9d8494 upstream. + +Add verifier coverage for constant negative offsets on PTR_TO_TP_BUFFER +and PTR_TO_BUF pointers. Both programs adjust the buffer pointer by -8 +and access it at offset zero, so the negative effective start must be +rejected at load time. + +Switch the raw tracepoint writable attach checks from nbd_send_request +to bpf_testmod_test_writable_bare_tp, avoiding a dependency on the NBD +tracepoint. Keep the existing past-end case and add a case with a +negative var_off compensated by a positive instruction offset. The +effective start remains non-negative, so the program loads, but its +access end exceeds the writable context size and +bpf_raw_tracepoint_open() must return -EINVAL. + +Cc: stable@vger.kernel.org # 5.2.0 +Signed-off-by: Sun Jian +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260714093846.18159-3-sun.jian.kdev@gmail.com +Signed-off-by: Eduard Zingerman +Signed-off-by: Greg Kroah-Hartman +--- + tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_bad_access.c | 57 ++++++++++ + tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c | 43 ------- + tools/testing/selftests/bpf/prog_tests/verifier.c | 2 + tools/testing/selftests/bpf/progs/verifier_ptr_to_buf.c | 27 ++++ + tools/testing/selftests/bpf/progs/verifier_raw_tp_writable.c | 16 ++ + 5 files changed, 102 insertions(+), 43 deletions(-) + create mode 100644 tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_bad_access.c + delete mode 100644 tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c + create mode 100644 tools/testing/selftests/bpf/progs/verifier_ptr_to_buf.c + +--- /dev/null ++++ b/tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_bad_access.c +@@ -0,0 +1,57 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include "test_kmods/bpf_testmod.h" ++#include "bpf_util.h" ++ ++static void check_attach_reject(const struct bpf_insn *program, size_t prog_len) ++{ ++ LIBBPF_OPTS(bpf_prog_load_opts, opts); ++ char error[4096]; ++ int bpf_fd, tp_fd; ++ ++ opts.log_level = 2; ++ opts.log_buf = error; ++ opts.log_size = sizeof(error); ++ ++ bpf_fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, NULL, "GPL v2", ++ program, prog_len, &opts); ++ if (!ASSERT_GE(bpf_fd, 0, "prog_load")) ++ return; ++ ++ tp_fd = bpf_raw_tracepoint_open("bpf_testmod_test_writable_bare_tp", bpf_fd); ++ ASSERT_EQ(tp_fd, -EINVAL, "bpf_raw_tracepoint_open"); ++ if (tp_fd >= 0) ++ close(tp_fd); ++ ++ close(bpf_fd); ++} ++ ++void test_raw_tp_writable_reject_bad_access(void) ++{ ++ const struct bpf_insn program[] = { ++ /* r6 is our tp buffer */ ++ BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), ++ /* one byte beyond the end of the writable context */ ++ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6, ++ sizeof(struct bpf_testmod_test_writable_ctx)), ++ BPF_EXIT_INSN(), ++ }; ++ ++ const struct bpf_insn negative_var_off_program[] = { ++ BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), ++ /* make var_off negative, but keep the effective access offset non-negative */ ++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), ++ /* one byte beyond the end of the writable context */ ++ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6, ++ sizeof(struct bpf_testmod_test_writable_ctx) + 8), ++ BPF_EXIT_INSN(), ++ }; ++ ++ if (test__start_subtest("past_end")) ++ check_attach_reject(program, ARRAY_SIZE(program)); ++ ++ if (test__start_subtest("negative_var_off_past_end")) ++ check_attach_reject(negative_var_off_program, ++ ARRAY_SIZE(negative_var_off_program)); ++} +--- a/tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c ++++ /dev/null +@@ -1,43 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-#include +-#include +-#include "bpf_util.h" +- +-void test_raw_tp_writable_reject_nbd_invalid(void) +-{ +- __u32 duration = 0; +- char error[4096]; +- int bpf_fd = -1, tp_fd = -1; +- +- const struct bpf_insn program[] = { +- /* r6 is our tp buffer */ +- BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), +- /* one byte beyond the end of the nbd_request struct */ +- BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6, +- sizeof(struct nbd_request)), +- BPF_EXIT_INSN(), +- }; +- +- LIBBPF_OPTS(bpf_prog_load_opts, opts, +- .log_level = 2, +- .log_buf = error, +- .log_size = sizeof(error), +- ); +- +- bpf_fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, NULL, "GPL v2", +- program, ARRAY_SIZE(program), +- &opts); +- if (CHECK(bpf_fd < 0, "bpf_raw_tracepoint_writable load", +- "failed: %d errno %d\n", bpf_fd, errno)) +- return; +- +- tp_fd = bpf_raw_tracepoint_open("nbd_send_request", bpf_fd); +- if (CHECK(tp_fd >= 0, "bpf_raw_tracepoint_writable open", +- "erroneously succeeded\n")) +- goto out_bpffd; +- +- close(tp_fd); +-out_bpffd: +- close(bpf_fd); +-} +--- a/tools/testing/selftests/bpf/prog_tests/verifier.c ++++ b/tools/testing/selftests/bpf/prog_tests/verifier.c +@@ -68,6 +68,7 @@ + #include "verifier_precision.skel.h" + #include "verifier_prevent_map_lookup.skel.h" + #include "verifier_private_stack.skel.h" ++#include "verifier_ptr_to_buf.skel.h" + #include "verifier_raw_stack.skel.h" + #include "verifier_raw_tp_writable.skel.h" + #include "verifier_reg_equal.skel.h" +@@ -205,6 +206,7 @@ void test_verifier_or_jmp32_k(void) + void test_verifier_precision(void) { RUN(verifier_precision); } + void test_verifier_prevent_map_lookup(void) { RUN(verifier_prevent_map_lookup); } + void test_verifier_private_stack(void) { RUN(verifier_private_stack); } ++void test_verifier_ptr_to_buf(void) { RUN(verifier_ptr_to_buf); } + void test_verifier_raw_stack(void) { RUN(verifier_raw_stack); } + void test_verifier_raw_tp_writable(void) { RUN(verifier_raw_tp_writable); } + void test_verifier_reg_equal(void) { RUN(verifier_reg_equal); } +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/verifier_ptr_to_buf.c +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include "bpf_misc.h" ++ ++SEC("iter/bpf_map_elem") ++__description("PTR_TO_BUF: reject negative const offset") ++__failure ++__msg("invalid negative rdwr buffer offset") ++__naked void ptr_to_buf_reject_negative_const_offset(void) ++{ ++ asm volatile ("r0 = 0; \ ++ r2 = *(u64 *)(r1 + %[value_off]); \ ++ if r2 == 0 goto l0_%=; \ ++ r2 += -8; \ ++ r0 = *(u64 *)(r2 + 0); \ ++l0_%=: \ ++ exit; \ ++ " ++ : ++ : __imm_const(value_off, ++ offsetof(struct bpf_iter__bpf_map_elem, value)) ++ : __clobber_all); ++} ++ ++char _license[] SEC("license") = "GPL"; +--- a/tools/testing/selftests/bpf/progs/verifier_raw_tp_writable.c ++++ b/tools/testing/selftests/bpf/progs/verifier_raw_tp_writable.c +@@ -47,4 +47,20 @@ l0_%=: /* shift the buffer pointer to a + : __clobber_all); + } + ++SEC("raw_tracepoint.w") ++__description("raw_tracepoint_writable: reject negative const offset") ++__failure ++__msg("invalid negative tracepoint buffer offset") ++__naked void tracepoint_writable_reject_negative_const_offset(void) ++{ ++ asm volatile (" \ ++ r6 = *(u64 *)(r1 + 0); \ ++ r6 += -8; \ ++ r0 = *(u64 *)(r6 + 0); \ ++ exit; \ ++" : ++ : ++ : __clobber_all); ++} ++ + char _license[] SEC("license") = "GPL"; diff --git a/queue-6.18/series b/queue-6.18/series index 503a9a0ee4..d7384ec73d 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -1276,3 +1276,102 @@ ocfs2-add-journal-null-check-in-ocfs2_checkpoint_inode.patch ocfs2-reject-dinodes-with-non-canonical-i_mode-type.patch ocfs2-reject-dinodes-whose-i_rdev-disagrees-with-the-file-type.patch ocfs2-reject-non-inline-dinodes-with-i_size-and-zero-i_clusters.patch +fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch +bus-mhi-host-pci_generic-fix-the-physical-function-check.patch +bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch +net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch +fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch +s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch +s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch +mtd-spi-nor-swp-improve-locking-user-experience.patch +mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch +mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch +openrisc-fix-jump_label-smp-syncing.patch +mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch +taskstats-retain-dead-thread-stats-in-tgid-queries.patch +irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch +tpm-restore-timeout-for-key-creation-commands.patch +tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch +tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch +sunrpc-fix-uninitialized-xprt_create_args-structure.patch +dmaengine-tegra-fix-burst-size-calculation.patch +dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch +platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch +platform-x86-isst-restore-sst-pp-control-to-all-domains.patch +platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch +platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch +platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch +platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch +pkey-move-keytype-check-from-pkey-api-to-handler.patch +smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch +ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch +hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch +hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch +i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch +i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch +i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch +i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch +i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch +ice-fix-ice_init_link-error-return-preventing-probe.patch +tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch +tcp-decrement-tcp_md5_needed-static-branch.patch +ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch +xen-gntdev-fix-error-handling-in-ioctl.patch +xfrm-nat_keepalive-avoid-double-free-on-send-error.patch +xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch +xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch +tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch +tpm-make-the-tpm-character-devices-non-seekable.patch +time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch +spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch +sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch +nfs-charge-unstable-writes-by-request-size-not-folio-size.patch +nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch +nvmet-auth-reject-short-auth_receive-buffers.patch +nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch +nvmet-fix-refcount-leak-in-nvmet_sq_create.patch +netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch +can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch +can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch +can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch +can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch +can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch +can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch +can-bcm-add-missing-rcu-list-annotations-and-operations.patch +bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch +bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch +bpf-add-missing-access_ok-call-to-copy_user_syms.patch +selftests-bpf-cover-negative-buffer-pointer-offsets.patch +block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch +block-fix-race-in-blk_time_get_ns-returning-0.patch +block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch +net-sparx5-unregister-blocking-notifier-on-init-failure.patch +dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch +dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch +dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch +dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch +dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch +dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch +dm-pcache-reject-option-groups-without-values.patch +dm-stats-fix-dm_jiffies_to_msec64.patch +dm-stats-fix-merge-accounting.patch +dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch +dm-integrity-fix-leaking-uninitialized-kernel-memory.patch +dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch +dm-integrity-don-t-increment-hash_offset-twice.patch +dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch +dm-verity-fix-a-possible-null-pointer-dereference.patch +dm-verity-increase-sprintf-buffer-size.patch +dm-verity-make-error-counter-atomic.patch +dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch +accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch +accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch +scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch +scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch +scsi-sg-report-request-table-problems-when-any-status-is-set.patch +scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch +scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch +scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch +scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch +scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch +scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch diff --git a/queue-6.18/smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch b/queue-6.18/smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch new file mode 100644 index 0000000000..e8cc985527 --- /dev/null +++ b/queue-6.18/smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch @@ -0,0 +1,75 @@ +From 806c00c23e3ce8eae397a40ced536ef88ae4e012 Mon Sep 17 00:00:00 2001 +From: Fredric Cover +Date: Sat, 11 Jul 2026 19:54:02 -0700 +Subject: smb: client: use kvzalloc() for megabyte buffer in simple fallocate + +From: Fredric Cover + +commit 806c00c23e3ce8eae397a40ced536ef88ae4e012 upstream. + +Currently in smb3_simple_fallocate_range(), a 1 MB buffer is allocated +using kzalloc(). Under heavy memory fragmentation, a contiguous 1 MB block +of physical memory (an order-8 allocation) may not be available, +causing the allocation to fail. + +This failure was observed during xfstests generic/013 on a 4GB RAM +test machine running fsstress: + +fsstress: page allocation failure: order:8, +mode:0x40dc0(GFP_KERNEL|__GFP_ZERO|__GFP_COMP), +nodemask=(null),cpuset=/,mems_allowed=0 + +Call Trace: + + dump_stack_lvl+0x5d/0x80 + warn_alloc+0x163/0x190 + __alloc_pages_slowpath.constprop.0+0x71b/0x12f0 + __alloc_frozen_pages_noprof+0x2f6/0x340 + alloc_pages_mpol+0xb6/0x170 + ___kmalloc_large_node+0xb3/0xd0 + __kmalloc_large_noprof+0x1e/0xc0 + smb3_simple_falloc.isra.0+0x62b/0x960 + cifs_fallocate+0xed/0x180 + vfs_fallocate+0x165/0x3c0 + __x64_sys_fallocate+0x48/0xa0 + do_syscall_64+0xe1/0x640 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + +Node 0 Normal: 3375*4kB ... 7*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB + +Since this scratch buffer does not require physically contiguous memory, +switch the allocation to kvzalloc(). This retains the performance +benefits of kmalloc() under normal conditions, while gracefully falling +back to virtually contiguous memory when physical allocation fails. + +Fixes: 966a3cb7c7db ("cifs: improve fallocate emulation") +Cc: stable@vger.kernel.org +Signed-off-by: Fredric Cover +Tested-by: Fredric Cover +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2ops.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -3560,7 +3560,7 @@ static int smb3_simple_fallocate_range(u + if (rc) + goto out; + +- buf = kzalloc(1024 * 1024, GFP_KERNEL); ++ buf = kvzalloc(1024 * 1024, GFP_KERNEL); + if (buf == NULL) { + rc = -ENOMEM; + goto out; +@@ -3617,7 +3617,7 @@ static int smb3_simple_fallocate_range(u + + out: + kfree(out_data); +- kfree(buf); ++ kvfree(buf); + return rc; + } + diff --git a/queue-6.18/spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch b/queue-6.18/spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch new file mode 100644 index 0000000000..f183ec647c --- /dev/null +++ b/queue-6.18/spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch @@ -0,0 +1,52 @@ +From f3ad1c87d8201e54b66bd6072442f0b5d5a308ee Mon Sep 17 00:00:00 2001 +From: Kunihiko Hayashi +Date: Tue, 16 Jun 2026 10:12:23 +0900 +Subject: spi: uniphier: Fix completion initialization order before devm_request_irq() + +From: Kunihiko Hayashi + +commit f3ad1c87d8201e54b66bd6072442f0b5d5a308ee upstream. + +The driver calls devm_request_irq() before initializing the completion +used by the interrupt handler. Because the interrupt may occur immediately +after devm_request_irq(), the handler may execute before init_completion(). + +This may result in calling complete() on an uninitialized completion, +causing undefined behavior. This has been observed with KASAN. + +Fix this by initializing the completion before registering the IRQ. + +Reported-by: Sangyun Kim +Reported-by: Kyungwook Boo +Fixes: 5ba155a4d4cc ("spi: add SPI controller driver for UniPhier SoC") +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Signed-off-by: Kunihiko Hayashi +Reviewed-by: Masami Hiramatsu (Google) +Link: https://patch.msgid.link/20260616011223.201357-1-hayashi.kunihiko@socionext.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -659,6 +659,8 @@ static int uniphier_spi_probe(struct pla + priv->host = host; + priv->is_save_param = false; + ++ init_completion(&priv->xfer_done); ++ + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); +@@ -686,8 +688,6 @@ static int uniphier_spi_probe(struct pla + goto out_host_put; + } + +- init_completion(&priv->xfer_done); +- + clk_rate = clk_get_rate(priv->clk); + + host->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); diff --git a/queue-6.18/sunrpc-fix-uninitialized-xprt_create_args-structure.patch b/queue-6.18/sunrpc-fix-uninitialized-xprt_create_args-structure.patch new file mode 100644 index 0000000000..03535531b5 --- /dev/null +++ b/queue-6.18/sunrpc-fix-uninitialized-xprt_create_args-structure.patch @@ -0,0 +1,44 @@ +From 17d90b68c3a3d7d7e95b49e1fe9381a723f637a8 Mon Sep 17 00:00:00 2001 +From: Hongling Zeng +Date: Wed, 3 Jun 2026 09:36:52 +0800 +Subject: sunrpc: fix uninitialized xprt_create_args structure + +From: Hongling Zeng + +commit 17d90b68c3a3d7d7e95b49e1fe9381a723f637a8 upstream. + +The xprt_create_args structure is allocated on the stack without +initialization in rpc_sysfs_xprt_switch_add_xprt_store(). While some +fields are manually populated, critical fields like srcaddr, bc_xps, +and flags contain uninitialized stack garbage. + +This can lead to: +1. Kernel panic when xs_setup_xprt() dereferences garbage srcaddr +2. Information leak if srcaddr points to sensitive stack data +3. Unpredictable behavior if flags has random bits set + +The fix is to zero-initialize the structure to ensure all unused +fields are NULL/0, preventing the transport setup code from acting +on garbage data. + +Cc: stable@vger.kernel.org +Suggested-by: Jeff Layton +Reviewed-by: Jeff Layton +Signed-off-by: Hongling Zeng +Signed-off-by: Anna Schumaker +Signed-off-by: Greg Kroah-Hartman +--- + net/sunrpc/sysfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sunrpc/sysfs.c ++++ b/net/sunrpc/sysfs.c +@@ -326,7 +326,7 @@ static ssize_t rpc_sysfs_xprt_switch_add + { + struct rpc_xprt_switch *xprt_switch = + rpc_sysfs_xprt_switch_kobj_get_xprt(kobj); +- struct xprt_create xprt_create_args; ++ struct xprt_create xprt_create_args = {}; + struct rpc_xprt *xprt, *new; + + if (!xprt_switch) diff --git a/queue-6.18/taskstats-retain-dead-thread-stats-in-tgid-queries.patch b/queue-6.18/taskstats-retain-dead-thread-stats-in-tgid-queries.patch new file mode 100644 index 0000000000..d99843020b --- /dev/null +++ b/queue-6.18/taskstats-retain-dead-thread-stats-in-tgid-queries.patch @@ -0,0 +1,167 @@ +From b3e4fbb04220efc3bc022bcf31b5689d39c6b111 Mon Sep 17 00:00:00 2001 +From: Yiyang Chen +Date: Mon, 13 Apr 2026 23:45:44 +0800 +Subject: taskstats: retain dead thread stats in TGID queries + +From: Yiyang Chen + +commit b3e4fbb04220efc3bc022bcf31b5689d39c6b111 upstream. + +Patch series "taskstats: fix TGID dead-thread stat retention", v3. + +This series fixes a taskstats TGID aggregation bug where fields added in +the TGID query path were not preserved after thread exit, and adds a +kselftest covering the regression. + +The first patch keeps the cached TGID aggregate used for dead threads in +step with the fields already accumulated for live threads, and also fixes +the final TGID exit notification emitted when group_dead is true. + +The second patch adds a kselftest that verifies TGID CPU stats do not +regress after a worker thread exits and has been reaped. + + +This patch (of 2): + +fill_stats_for_tgid() builds TGID stats from two sources: the cached +aggregate in signal->stats and a scan of the live threads in the group. + +However, fill_tgid_exit() only accumulates delay accounting into +signal->stats. This means that once a thread exits, TGID queries lose the +fields that fill_stats_for_tgid() adds for live threads. + +This gap was introduced incrementally by two earlier changes that extended +fill_stats_for_tgid() but did not make the corresponding update to +fill_tgid_exit(): + +- commit 8c733420bdd5 ("taskstats: add e/u/stime for TGID command") + added ac_etime, ac_utime, and ac_stime to the TGID query path. +- commit b663a79c1915 ("taskstats: add context-switch counters") + added nvcsw and nivcsw to the TGID query path. + +As a result, those fields were accounted for live threads in TGID queries, +but were dropped from the cached TGID aggregate after thread exit. The +final TGID exit notification emitted when group_dead is true also copies +that cached aggregate, so it loses the same fields. + +Factor the per-task TGID accumulation into tgid_stats_add_task() and use +it in both fill_stats_for_tgid() and fill_tgid_exit(). This keeps the +cached aggregate used for dead threads aligned with the live-thread +accumulation used by TGID queries. + +Link: https://lore.kernel.org/cover.1776094300.git.cyyzero16@gmail.com +Link: https://lore.kernel.org/abd2a15d33343636ab5ba43d540bcfe508bd66c7.1776094300.git.cyyzero16@gmail.com +Fixes: 8c733420bdd5 ("taskstats: add e/u/stime for TGID command") +Fixes: b663a79c1915 ("taskstats: add context-switch counters") +Signed-off-by: Yiyang Chen +Acked-by: Balbir Singh +Cc: Dr. Thomas Orgis +Cc: Oleg Nesterov +Cc: Wang Yaxin +Cc: Yang Yang +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + kernel/taskstats.c | 62 ++++++++++++++++++++++++++++------------------------- + 1 file changed, 33 insertions(+), 29 deletions(-) + +--- a/kernel/taskstats.c ++++ b/kernel/taskstats.c +@@ -210,13 +210,39 @@ static int fill_stats_for_pid(pid_t pid, + return 0; + } + ++static void tgid_stats_add_task(struct taskstats *stats, ++ struct task_struct *tsk, u64 now_ns) ++{ ++ u64 delta, utime, stime; ++ ++ /* ++ * Each accounting subsystem calls its functions here to ++ * accumulate its per-task stats for tsk, into the per-tgid structure ++ * ++ * per-task-foo(stats, tsk); ++ */ ++ delayacct_add_tsk(stats, tsk); ++ ++ /* calculate task elapsed time in nsec */ ++ delta = now_ns - tsk->start_time; ++ /* Convert to micro seconds */ ++ do_div(delta, NSEC_PER_USEC); ++ stats->ac_etime += delta; ++ ++ task_cputime(tsk, &utime, &stime); ++ stats->ac_utime += div_u64(utime, NSEC_PER_USEC); ++ stats->ac_stime += div_u64(stime, NSEC_PER_USEC); ++ ++ stats->nvcsw += tsk->nvcsw; ++ stats->nivcsw += tsk->nivcsw; ++} ++ + static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats) + { + struct task_struct *tsk, *first; + unsigned long flags; + int rc = -ESRCH; +- u64 delta, utime, stime; +- u64 start_time; ++ u64 now_ns; + + /* + * Add additional stats from live tasks except zombie thread group +@@ -233,30 +259,12 @@ static int fill_stats_for_tgid(pid_t tgi + else + memset(stats, 0, sizeof(*stats)); + +- start_time = ktime_get_ns(); ++ now_ns = ktime_get_ns(); + for_each_thread(first, tsk) { + if (tsk->exit_state) + continue; +- /* +- * Accounting subsystem can call its functions here to +- * fill in relevant parts of struct taskstsats as follows +- * +- * per-task-foo(stats, tsk); +- */ +- delayacct_add_tsk(stats, tsk); +- +- /* calculate task elapsed time in nsec */ +- delta = start_time - tsk->start_time; +- /* Convert to micro seconds */ +- do_div(delta, NSEC_PER_USEC); +- stats->ac_etime += delta; +- +- task_cputime(tsk, &utime, &stime); +- stats->ac_utime += div_u64(utime, NSEC_PER_USEC); +- stats->ac_stime += div_u64(stime, NSEC_PER_USEC); + +- stats->nvcsw += tsk->nvcsw; +- stats->nivcsw += tsk->nivcsw; ++ tgid_stats_add_task(stats, tsk, now_ns); + } + + unlock_task_sighand(first, &flags); +@@ -275,18 +283,14 @@ out: + static void fill_tgid_exit(struct task_struct *tsk) + { + unsigned long flags; ++ u64 now_ns; + + spin_lock_irqsave(&tsk->sighand->siglock, flags); + if (!tsk->signal->stats) + goto ret; + +- /* +- * Each accounting subsystem calls its functions here to +- * accumalate its per-task stats for tsk, into the per-tgid structure +- * +- * per-task-foo(tsk->signal->stats, tsk); +- */ +- delayacct_add_tsk(tsk->signal->stats, tsk); ++ now_ns = ktime_get_ns(); ++ tgid_stats_add_task(tsk->signal->stats, tsk, now_ns); + ret: + spin_unlock_irqrestore(&tsk->sighand->siglock, flags); + return; diff --git a/queue-6.18/tcp-decrement-tcp_md5_needed-static-branch.patch b/queue-6.18/tcp-decrement-tcp_md5_needed-static-branch.patch new file mode 100644 index 0000000000..21fb181556 --- /dev/null +++ b/queue-6.18/tcp-decrement-tcp_md5_needed-static-branch.patch @@ -0,0 +1,40 @@ +From 6f6e860e370c9e4e919b92118a25e9e1f82e9180 Mon Sep 17 00:00:00 2001 +From: Dmitry Safonov <0x7f454c46@gmail.com> +Date: Thu, 25 Jun 2026 19:21:41 +0100 +Subject: tcp: Decrement tcp_md5_needed static branch + +From: Dmitry Safonov <0x7f454c46@gmail.com> + +commit 6f6e860e370c9e4e919b92118a25e9e1f82e9180 upstream. + +In case of early freeing an unwanted TCP-MD5 key on TCP-AO connect(), +md5sig_info is freed right away (and set to NULL). Later, at +the moment of socket destruction, the static branch counter +is not getting decremented. + +Add a missing decrement for TCP-MD5 static branch. + +Reported-by: Qihang +Fixes: 0aadc73995d0 ("net/tcp: Prevent TCP-MD5 with TCP-AO being set") +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> +Link: https://patch.msgid.link/20260625-tcp-md5-connect-v3-3-1fd313d6c1e0@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_output.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -4268,8 +4268,8 @@ int tcp_connect(struct sock *sk) + tcp_clear_md5_list(sk); + md5sig = rcu_replace_pointer(tp->md5sig_info, NULL, + lockdep_sock_is_held(sk)); +- if (md5sig) +- kfree_rcu(md5sig, rcu); ++ kfree_rcu(md5sig, rcu); ++ static_branch_slow_dec_deferred(&tcp_md5_needed); + } + } + #endif diff --git a/queue-6.18/tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch b/queue-6.18/tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch new file mode 100644 index 0000000000..9bb6119466 --- /dev/null +++ b/queue-6.18/tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch @@ -0,0 +1,123 @@ +From b74cd55038905d5e74c1de109ab78a30b2ea0e1f Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Thu, 25 Jun 2026 19:21:40 +0100 +Subject: tcp: defer md5sig_info kfree past RCU grace period in tcp_connect + +From: Michael Bommarito + +commit b74cd55038905d5e74c1de109ab78a30b2ea0e1f upstream. + +The md5+ao reconciliation in tcp_connect() (net/ipv4/tcp_output.c) +has two symmetric branches: + + if (needs_md5) { + tcp_ao_destroy_sock(sk, false); + } else if (needs_ao) { + tcp_clear_md5_list(sk); + kfree(rcu_replace_pointer(tp->md5sig_info, NULL, ...)); + } + +Both branches free a per-socket auth-info object while the socket is +in TCP_SYN_SENT and is already on the inet ehash (inserted by +inet_hash_connect() in tcp_v4_connect()). Both branches are reachable +by softirq RX-path readers that load the corresponding info pointer +via implicit RCU before bh_lock_sock_nested() is taken. + +The needs_md5 branch is fixed in the prior patch by re-introducing +the call_rcu() free in tcp_ao_destroy_sock(): the equivalent per-key +loop runs inside tcp_ao_info_free_rcu(), the RCU callback, so by the +time it frees each tcp_ao_key all softirq readers that captured the +container have already completed rcu_read_unlock(). + +The needs_ao branch is not symmetric in the same way. The container +free can be deferred via kfree_rcu(md5sig, rcu) -- struct +tcp_md5sig_info already has the required rcu member +(include/net/tcp.h:1999-2002), and the rest of the tree already does +this in the tcp_md5sig_info_add() rollback paths +(net/ipv4/tcp_ipv4.c:1410, 1436). But the per-key teardown is done +by tcp_clear_md5_list() in process context BEFORE the container's +RCU grace period: it walks &md5sig->head and frees each +tcp_md5sig_key with bare hlist_del + kfree. A concurrent softirq +reader in __tcp_md5_do_lookup() / __tcp_md5_do_lookup_exact() +(tcp_ipv4.c:1253, 1298) walks the same list via +hlist_for_each_entry_rcu() and races with that bare kfree on the +keys themselves -- a per-key slab use-after-free of the same class +as the TCP-AO bug, on the same race window. + +Fix this in two halves: + + 1. Convert the bare kfree() in tcp_connect() to kfree_rcu() so the + md5sig_info container joins the rest of the md5sig lifecycle. + The local-variable lift is mechanical and required because + kfree_rcu() is a macro that expects an lvalue. + + 2. Make tcp_clear_md5_list() RCU-safe by replacing hlist_del + + kfree(key) with hlist_del_rcu + kfree_rcu(key, rcu). struct + tcp_md5sig_key already carries the rcu member + (include/net/tcp.h:1995) and tcp_md5_do_del() + (net/ipv4/tcp_ipv4.c:1456) already uses kfree_rcu, so this + restores the lifecycle invariant the rest of the file follows + rather than introducing a one-off. + +The other caller of tcp_clear_md5_list() is tcp_md5_destruct_sock() +(net/ipv4/tcp.c:412), which runs from the sock destructor when the +socket is already unhashed and unreachable; the extra grace period +there is unnecessary but harmless. Making the helper unconditionally +RCU-safe is the cleaner contract. + +The needs_ao branch is not reachable by the userns reproducer used +to demonstrate the AO-side splat (the repro installs both keys but +ends up in the needs_md5 branch because the connect peer matches +the MD5 key, not the AO key); however the symmetric race exists +and a maintainer touching this code should not have to think about +which branch escapes RCU and which one does not. + +Fixes: 51e547e8c89c ("tcp: Free TCP-AO/TCP-MD5 info/keys without RCU") +Cc: stable@vger.kernel.org # v6.18+ +Suggested-by: Eric Dumazet +Signed-off-by: Michael Bommarito +Reviewed-by: Dmitry Safonov +Reviewed-by: Eric Dumazet +[also credits to Qihang, who found that this races with tcp-diag] +Reported-by: Qihang +Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> +Link: https://patch.msgid.link/20260625-tcp-md5-connect-v3-2-1fd313d6c1e0@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_ipv4.c | 4 ++-- + net/ipv4/tcp_output.c | 8 ++++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -1505,9 +1505,9 @@ void tcp_clear_md5_list(struct sock *sk) + md5sig = rcu_dereference_protected(tp->md5sig_info, 1); + + hlist_for_each_entry_safe(key, n, &md5sig->head, node) { +- hlist_del(&key->node); ++ hlist_del_rcu(&key->node); + atomic_sub(sizeof(*key), &sk->sk_omem_alloc); +- kfree(key); ++ kfree_rcu(key, rcu); + } + } + +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -4263,9 +4263,13 @@ int tcp_connect(struct sock *sk) + if (needs_md5) { + tcp_ao_destroy_sock(sk, false); + } else if (needs_ao) { ++ struct tcp_md5sig_info *md5sig; ++ + tcp_clear_md5_list(sk); +- kfree(rcu_replace_pointer(tp->md5sig_info, NULL, +- lockdep_sock_is_held(sk))); ++ md5sig = rcu_replace_pointer(tp->md5sig_info, NULL, ++ lockdep_sock_is_held(sk)); ++ if (md5sig) ++ kfree_rcu(md5sig, rcu); + } + } + #endif diff --git a/queue-6.18/time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch b/queue-6.18/time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch new file mode 100644 index 0000000000..6042d7f59f --- /dev/null +++ b/queue-6.18/time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch @@ -0,0 +1,44 @@ +From 269f2b43fae692d1f3988c9f888a6301aa537b82 Mon Sep 17 00:00:00 2001 +From: Wang Yan +Date: Mon, 22 Jun 2026 18:33:48 +0800 +Subject: time: Fix off-by-one in compat settimeofday() usec validation + +From: Wang Yan + +commit 269f2b43fae692d1f3988c9f888a6301aa537b82 upstream. + +The compat version of settimeofday() uses '>' instead of '>=' when +validating tv_usec against USEC_PER_SEC, allowing the value 1000000 to pass +the check. After the subsequent conversion to nanoseconds (tv_nsec *= +NSEC_PER_USEC), this results in tv_nsec == NSEC_PER_SEC, which violates the +timespec invariant that tv_nsec must be strictly less than NSEC_PER_SEC. + +The native settimeofday() was already fixed in commit ce4abda5e126 ("time: +Fix off-by-one in settimeofday() usec validation"), but the compat +counterpart was missed. + +Fix it by using '>=' to reject tv_usec values outside the valid range [0, +USEC_PER_SEC - 1]. + +Fixes: 5e0fb1b57bea ("y2038: time: avoid timespec usage in settimeofday()") +Signed-off-by: Wang Yan +Signed-off-by: Thomas Gleixner +Acked-by: Arnd Bergmann +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260622103348.120255-1-wangyan01@kylinos.cn +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/time.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/time/time.c ++++ b/kernel/time/time.c +@@ -251,7 +251,7 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, str + get_user(new_ts.tv_nsec, &tv->tv_usec)) + return -EFAULT; + +- if (new_ts.tv_nsec > USEC_PER_SEC || new_ts.tv_nsec < 0) ++ if (new_ts.tv_nsec >= USEC_PER_SEC || new_ts.tv_nsec < 0) + return -EINVAL; + + new_ts.tv_nsec *= NSEC_PER_USEC; diff --git a/queue-6.18/tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch b/queue-6.18/tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch new file mode 100644 index 0000000000..4af27d61f1 --- /dev/null +++ b/queue-6.18/tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch @@ -0,0 +1,51 @@ +From 1a58f6115bfb34eabcc7de8a3a9745b219179781 Mon Sep 17 00:00:00 2001 +From: Thorsten Blum +Date: Mon, 15 Jun 2026 15:02:05 +0300 +Subject: tpm: fix event_size output in tpm1_binary_bios_measurements_show + +From: Thorsten Blum + +commit 1a58f6115bfb34eabcc7de8a3a9745b219179781 upstream. + +Commit 186d124f07da ("tpm_eventlog.c: fix binary_bios_measurements") +split the output to write the endian-converted event header first and +then the variable-length event data. + +However, the split was at sizeof(struct tcpa_event) - 1, even though +event_data was a zero-length array, and later a flexible array member, +both of which already excluded the event data. + +Therefore, the current code writes the first three bytes of event_size +from the endian-converted header and then the last byte from the raw +header, which can emit a corrupted event_size on PPC64, where +do_endian_conversion() maps to be32_to_cpu(). + +Split one byte later to write the full endian-converted header first, +followed by the variable-length event->event_data. + +Fixes: 186d124f07da ("tpm_eventlog.c: fix binary_bios_measurements") +Cc: stable@vger.kernel.org # v5.10+ +Signed-off-by: Thorsten Blum +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/tpm/eventlog/tpm1.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/char/tpm/eventlog/tpm1.c ++++ b/drivers/char/tpm/eventlog/tpm1.c +@@ -236,12 +236,12 @@ static int tpm1_binary_bios_measurements + + temp_ptr = (char *) &temp_event; + +- for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++) ++ for (i = 0; i < sizeof(struct tcpa_event); i++) + seq_putc(m, temp_ptr[i]); + + temp_ptr = (char *) v; + +- for (i = (sizeof(struct tcpa_event) - 1); ++ for (i = sizeof(struct tcpa_event); + i < (sizeof(struct tcpa_event) + temp_event.event_size); i++) + seq_putc(m, temp_ptr[i]); + diff --git a/queue-6.18/tpm-make-the-tpm-character-devices-non-seekable.patch b/queue-6.18/tpm-make-the-tpm-character-devices-non-seekable.patch new file mode 100644 index 0000000000..c41e831d3c --- /dev/null +++ b/queue-6.18/tpm-make-the-tpm-character-devices-non-seekable.patch @@ -0,0 +1,75 @@ +From f20d61c22bcaf172d6790b6500e3838e532e71c8 Mon Sep 17 00:00:00 2001 +From: Jaewon Yang +Date: Mon, 13 Jul 2026 02:11:47 +0900 +Subject: tpm: Make the TPM character devices non-seekable + +From: Jaewon Yang + +commit f20d61c22bcaf172d6790b6500e3838e532e71c8 upstream. + +The TPM character devices expose a sequential command/response +interface, but their open handlers leave FMODE_PREAD and FMODE_PWRITE +enabled. + +After a command leaves a response pending, pread(fd, buf, 16, 0x1400) +passes 0x1400 as *off to tpm_common_read(). The transfer length is +bounded by response_length, but the offset is used unchecked when +forming data_buffer + *off. A sufficiently large offset therefore causes +an out-of-bounds heap read through copy_to_user() and, if the copy +succeeds, an out-of-bounds zero-write through the following memset(). + +Positional I/O does not provide coherent semantics for this interface. +An arbitrary pread offset cannot represent how much of a response has +been consumed sequentially. The write callback always stores a command +at the start of data_buffer, while pwrite() does not update file->f_pos +and can leave the sequential read cursor stale. + +Call nonseekable_open() from both open handlers. This removes +FMODE_PREAD and FMODE_PWRITE, causing positional reads and writes to +fail with -ESPIPE before reaching the TPM callbacks, and explicitly +marks the files non-seekable. Normal read() and write() continue to use +the existing sequential f_pos cursor, leaving the response state machine +unchanged. + +Tested on Linux 6.12 with KASAN and a swtpm TPM2 device: + + - sequential partial reads returned the complete response + - pread() and preadv() with offset 0x1400 returned -ESPIPE + - pwrite() and pwritev() with offset zero returned -ESPIPE + - the pending response remained intact after the rejected operations + - a subsequent normal command/response cycle completed normally + - no KASAN report was produced. + +Fixes: 9488585b21be ("tpm: add support for partial reads") +Link: https://lore.kernel.org/all/20260710090217.191289-1-yong010301@gmail.com/ +Cc: stable@vger.kernel.org +Signed-off-by: Jaewon Yang +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/tpm/tpm-dev.c | 2 +- + drivers/char/tpm/tpmrm-dev.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/char/tpm/tpm-dev.c ++++ b/drivers/char/tpm/tpm-dev.c +@@ -36,7 +36,7 @@ static int tpm_open(struct inode *inode, + + tpm_common_open(file, chip, priv, NULL); + +- return 0; ++ return nonseekable_open(inode, file); + + out: + clear_bit(0, &chip->is_open); +--- a/drivers/char/tpm/tpmrm-dev.c ++++ b/drivers/char/tpm/tpmrm-dev.c +@@ -29,7 +29,7 @@ static int tpmrm_open(struct inode *inod + + tpm_common_open(file, chip, &priv->priv, &priv->space); + +- return 0; ++ return nonseekable_open(inode, file); + } + + static int tpmrm_release(struct inode *inode, struct file *file) diff --git a/queue-6.18/tpm-restore-timeout-for-key-creation-commands.patch b/queue-6.18/tpm-restore-timeout-for-key-creation-commands.patch new file mode 100644 index 0000000000..c8dbcf648c --- /dev/null +++ b/queue-6.18/tpm-restore-timeout-for-key-creation-commands.patch @@ -0,0 +1,46 @@ +From de59d78e64039baa5fed455ddb905ba8263e7ede Mon Sep 17 00:00:00 2001 +From: Baoli Zhang +Date: Tue, 21 Apr 2026 08:50:20 +0800 +Subject: tpm: restore timeout for key creation commands + +From: Baoli Zhang + +commit de59d78e64039baa5fed455ddb905ba8263e7ede upstream. + +Commit 207696b17f38 ("tpm: use a map for tpm2_calc_ordinal_duration()") +inadvertently reduced the timeout for TPM2 key creation commands +(`CREATE_PRIMARY`, `CREATE`, `CREATE_LOADED`) from 300 seconds to 30 +seconds. + +This causes intermittent timeout failures, with several failures observed +across hundreds of test runs on some Intel platforms using Infineon +SLB9670 and SLB9672 TPM modules. Restore the timeout to 300 seconds to +avoid spurious failures. + +Cc: stable@vger.kernel.org # v6.18+ +Fixes: 207696b17f38 ("tpm: use a map for tpm2_calc_ordinal_duration()") +Co-developed-by: Lili Li +Signed-off-by: Lili Li +Signed-off-by: Baoli Zhang +Link: https://lore.kernel.org/r/20260421005021.13765-1-baoli.zhang@linux.intel.com +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/tpm/tpm2-cmd.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/char/tpm/tpm2-cmd.c ++++ b/drivers/char/tpm/tpm2-cmd.c +@@ -59,9 +59,9 @@ static const struct { + {TPM2_CC_HIERARCHY_CHANGE_AUTH, 2000}, + {TPM2_CC_GET_CAPABILITY, 750}, + {TPM2_CC_NV_READ, 2000}, +- {TPM2_CC_CREATE_PRIMARY, 30000}, +- {TPM2_CC_CREATE, 30000}, +- {TPM2_CC_CREATE_LOADED, 30000}, ++ {TPM2_CC_CREATE_PRIMARY, 300000}, ++ {TPM2_CC_CREATE, 300000}, ++ {TPM2_CC_CREATE_LOADED, 300000}, + }; + + /** diff --git a/queue-6.18/tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch b/queue-6.18/tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch new file mode 100644 index 0000000000..78799c95a9 --- /dev/null +++ b/queue-6.18/tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch @@ -0,0 +1,141 @@ +From 73851a7c43dfa52d2ed9415889b33daf85da0ed9 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 31 May 2026 08:44:28 -0400 +Subject: tpm: tpm2-sessions: wait for async KPP completion in tpm_buf_append_salt + +From: Michael Bommarito + +commit 73851a7c43dfa52d2ed9415889b33daf85da0ed9 upstream. + +tpm_buf_append_salt() in drivers/char/tpm/tpm2-sessions.c calls +crypto_kpp_generate_public_key() and crypto_kpp_compute_shared_secret() +without installing a completion callback, discards both return values, +and immediately frees the kpp_request via kpp_request_free(). When the +resolved ecdh-nist-p256 KPP backend is asynchronous (atmel-ecc, HPRE, +keembay-ocs), either operation returns -EINPROGRESS and the deferred +completion worker dereferences the freed request. + +The path fires automatically from the hwrng_fillfn kernel thread via +tpm_get_random -> tpm2_get_random -> tpm2_start_auth_session -> +tpm_buf_append_salt on every entropy poll, without any userland action. + +Install crypto_req_done as the completion callback, wrap both KPP +operations in crypto_wait_req(), and propagate errors to the caller. +The wait is a no-op for synchronous backends. + +Fixes: 1085b8276bb4 ("tpm: Add the rest of the session HMAC API") +Cc: stable@vger.kernel.org # v6.10+ +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/tpm/tpm2-sessions.c | 45 +++++++++++++++++++++++++++++---------- + 1 file changed, 34 insertions(+), 11 deletions(-) + +--- a/drivers/char/tpm/tpm2-sessions.c ++++ b/drivers/char/tpm/tpm2-sessions.c +@@ -490,15 +490,17 @@ static void tpm2_KDFe(u8 z[EC_PT_SZ], co + sha256_final(&sctx, out); + } + +-static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip, +- struct tpm2_auth *auth) ++static int tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip, ++ struct tpm2_auth *auth) + { + struct crypto_kpp *kpp; + struct kpp_request *req; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist s[2], d[1]; + struct ecdh p = {0}; + u8 encoded_key[EC_PT_SZ], *x, *y; + unsigned int buf_len; ++ int rc; + + /* secret is two sized points */ + tpm_buf_append_u16(buf, (EC_PT_SZ + 2)*2); +@@ -521,14 +523,15 @@ static void tpm_buf_append_salt(struct t + kpp = crypto_alloc_kpp("ecdh-nist-p256", CRYPTO_ALG_INTERNAL, 0); + if (IS_ERR(kpp)) { + dev_err(&chip->dev, "crypto ecdh allocation failed\n"); +- return; ++ return PTR_ERR(kpp); + } + + buf_len = crypto_ecdh_key_len(&p); + if (sizeof(encoded_key) < buf_len) { + dev_err(&chip->dev, "salt buffer too small needs %d\n", + buf_len); +- goto out; ++ rc = -EINVAL; ++ goto err_free_kpp; + } + crypto_ecdh_encode_key(encoded_key, buf_len, &p); + /* this generates a random private key */ +@@ -536,11 +539,17 @@ static void tpm_buf_append_salt(struct t + + /* salt is now the public point of this private key */ + req = kpp_request_alloc(kpp, GFP_KERNEL); +- if (!req) +- goto out; ++ if (!req) { ++ rc = -ENOMEM; ++ goto err_free_kpp; ++ } ++ kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &wait); + kpp_request_set_input(req, NULL, 0); + kpp_request_set_output(req, s, EC_PT_SZ*2); +- crypto_kpp_generate_public_key(req); ++ rc = crypto_wait_req(crypto_kpp_generate_public_key(req), &wait); ++ if (rc) ++ goto err_free_req; + /* + * we're not done: now we have to compute the shared secret + * which is our private key multiplied by the tpm_key public +@@ -552,8 +561,9 @@ static void tpm_buf_append_salt(struct t + kpp_request_set_input(req, s, EC_PT_SZ*2); + sg_init_one(d, auth->salt, EC_PT_SZ); + kpp_request_set_output(req, d, EC_PT_SZ); +- crypto_kpp_compute_shared_secret(req); +- kpp_request_free(req); ++ rc = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait); ++ if (rc) ++ goto err_free_req; + + /* + * pass the shared secret through KDFe for salt. Note salt +@@ -563,8 +573,16 @@ static void tpm_buf_append_salt(struct t + */ + tpm2_KDFe(auth->salt, "SECRET", x, chip->null_ec_key_x, auth->salt); + +- out: ++ kpp_request_free(req); + crypto_free_kpp(kpp); ++ return 0; ++ ++err_free_req: ++ kpp_request_free(req); ++ ++err_free_kpp: ++ crypto_free_kpp(kpp); ++ return rc; + } + + /** +@@ -1019,7 +1037,12 @@ int tpm2_start_auth_session(struct tpm_c + tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce)); + + /* append encrypted salt and squirrel away unencrypted in auth */ +- tpm_buf_append_salt(&buf, chip, auth); ++ rc = tpm_buf_append_salt(&buf, chip, auth); ++ if (rc) { ++ tpm2_flush_context(chip, null_key); ++ tpm_buf_destroy(&buf); ++ goto out; ++ } + /* session type (HMAC, audit or policy) */ + tpm_buf_append_u8(&buf, TPM2_SE_HMAC); + diff --git a/queue-6.18/tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch b/queue-6.18/tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch new file mode 100644 index 0000000000..be6e7cd2e6 --- /dev/null +++ b/queue-6.18/tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch @@ -0,0 +1,95 @@ +From c0c9cfb3b75def8bf200a2d4db09015806acfeaf Mon Sep 17 00:00:00 2001 +From: Jarkko Sakkinen +Date: Sat, 9 May 2026 21:51:07 +0300 +Subject: tpm: tpm_tis_spi: Use wait_woken() in wait_for_tmp_stat() + +From: Jarkko Sakkinen + +commit c0c9cfb3b75def8bf200a2d4db09015806acfeaf upstream. + +wait_event_interruptible_timeout() evaluates its condition after setting +the current task state to TASK_INTERRUPTIBLE. + +With CONFIG_DEBUG_ATOMIC_SLEEP this triggers a warning when the IRQ wait +path is used: + + tpm_tis_status() + tpm_tis_spi_read_bytes() + tpm_tis_spi_transfer_full() + spi_bus_lock() + mutex_lock() + +Address this with the following measures: + +1. Call wait_tpm_stat_cond() only while tasking is running. +2. Use wait_woken() to wait for changes. + +Cc: stable@vger.kernel.org # v4.19+ +Cc: Linus Walleij +Reported-by: Stefan Wahren +Closes: https://lore.kernel.org/linux-integrity/6964bec7-3dbb-453b-89ef-9b990217a8b9@gmx.net/ +Fixes: 1a339b658d9d ("tpm_tis_spi: Pass the SPI IRQ down to the driver") +Reviewed-by: Linus Walleij +Tested-by: Stefan Wahren +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/tpm/tpm_tis_core.c | 35 +++++++++++++++++++++-------------- + 1 file changed, 21 insertions(+), 14 deletions(-) + +--- a/drivers/char/tpm/tpm_tis_core.c ++++ b/drivers/char/tpm/tpm_tis_core.c +@@ -66,8 +66,8 @@ static int wait_for_tpm_stat(struct tpm_ + bool check_cancel) + { + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); ++ DEFINE_WAIT_FUNC(wait, woken_wake_function); + unsigned long stop; +- long rc; + u8 status; + bool canceled = false; + u8 sts_mask; +@@ -87,23 +87,30 @@ static int wait_for_tpm_stat(struct tpm_ + /* process status changes with irq support */ + if (sts_mask) { + ret = -ETIME; ++ add_wait_queue(queue, &wait); + again: ++ if (wait_for_tpm_stat_cond(chip, sts_mask, check_cancel, ++ &canceled)) { ++ ret = canceled ? -ECANCELED : 0; ++ goto out; ++ } ++ + timeout = stop - jiffies; + if ((long)timeout <= 0) +- return -ETIME; +- rc = wait_event_interruptible_timeout(*queue, +- wait_for_tpm_stat_cond(chip, sts_mask, check_cancel, +- &canceled), +- timeout); +- if (rc > 0) { +- if (canceled) +- return -ECANCELED; +- ret = 0; +- } +- if (rc == -ERESTARTSYS && freezing(current)) { +- clear_thread_flag(TIF_SIGPENDING); +- goto again; ++ goto out; ++ ++ if (signal_pending(current)) { ++ if (freezing(current)) { ++ clear_thread_flag(TIF_SIGPENDING); ++ goto again; ++ } ++ goto out; + } ++ ++ wait_woken(&wait, TASK_INTERRUPTIBLE, timeout); ++ goto again; ++out: ++ remove_wait_queue(queue, &wait); + } + + if (ret) diff --git a/queue-6.18/ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch b/queue-6.18/ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch new file mode 100644 index 0000000000..dfc185e420 --- /dev/null +++ b/queue-6.18/ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch @@ -0,0 +1,252 @@ +From 535fcf4b8a261fbb8cc4f91e4597343c135a90f2 Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Tue, 30 Jun 2026 18:54:12 -0400 +Subject: ufs: core: tracing: Do not dereference pointers in TP_printk() + +From: Steven Rostedt + +commit 535fcf4b8a261fbb8cc4f91e4597343c135a90f2 upstream. + +The trace events in drivers/ufs/core/ufs_trace.h were converted to take a +pointer to the hba structure as an argument for the tracepoint and then in +TP_printk() the printing of the dev_name from the ring buffer was +converted to using the dev dereferenced pointer from the hba saved +pointer. + +This is not allowed as the TP_printk() is executed at the time the trace +event is read from /sys/kernel/tracing/trace file. That can happen +literally, seconds, minutes, hours, weeks, days, or even months later! +There is no guarantee that the hba pointer will still exist by the time it +is dereferenced when the "trace" file is read. + +Instead, save the device name from the hba pointer at the time the +tracepoint is called and place it into the ring buffer event. Then the +TP_printk() can read the name directly from the ring buffer and remove the +possibility that it will read a freed pointer and crash the kernel. + +This was detected when testing the trace event code that looks for +TP_printk() parameters doing illegal derferences[1] + +[1] https://lore.kernel.org/all/20260630184836.74d477b6@gandalf.local.home/ + +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260630185412.283c26c5@gandalf.local.home +Fixes: 583e518e71003 ("scsi: ufs: core: Add hba parameter to trace events") +Reviewed-by: Peter Wang +Reviewed-by: Bart Van Assche +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ufs/core/ufs_trace.h | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +--- a/drivers/ufs/core/ufs_trace.h ++++ b/drivers/ufs/core/ufs_trace.h +@@ -90,16 +90,18 @@ TRACE_EVENT(ufshcd_clk_gating, + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __field(int, state) + ), + + TP_fast_assign( ++ __assign_str(dev_name); + __entry->hba = hba; + __entry->state = state; + ), + + TP_printk("%s: gating state changed to %s", +- dev_name(__entry->hba->dev), ++ __get_str(dev_name), + __print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES)) + ); + +@@ -112,6 +114,7 @@ TRACE_EVENT(ufshcd_clk_scaling, + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __string(state, state) + __string(clk, clk) + __field(u32, prev_state) +@@ -120,6 +123,7 @@ TRACE_EVENT(ufshcd_clk_scaling, + + TP_fast_assign( + __entry->hba = hba; ++ __assign_str(dev_name); + __assign_str(state); + __assign_str(clk); + __entry->prev_state = prev_state; +@@ -127,7 +131,7 @@ TRACE_EVENT(ufshcd_clk_scaling, + ), + + TP_printk("%s: %s %s from %u to %u Hz", +- dev_name(__entry->hba->dev), __get_str(state), __get_str(clk), ++ __get_str(dev_name), __get_str(state), __get_str(clk), + __entry->prev_state, __entry->curr_state) + ); + +@@ -139,16 +143,18 @@ TRACE_EVENT(ufshcd_auto_bkops_state, + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __string(state, state) + ), + + TP_fast_assign( + __entry->hba = hba; ++ __assign_str(dev_name); + __assign_str(state); + ), + + TP_printk("%s: auto bkops - %s", +- dev_name(__entry->hba->dev), __get_str(state)) ++ __get_str(dev_name), __get_str(state)) + ); + + DECLARE_EVENT_CLASS(ufshcd_profiling_template, +@@ -159,6 +165,7 @@ DECLARE_EVENT_CLASS(ufshcd_profiling_tem + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __string(profile_info, profile_info) + __field(s64, time_us) + __field(int, err) +@@ -166,13 +173,14 @@ DECLARE_EVENT_CLASS(ufshcd_profiling_tem + + TP_fast_assign( + __entry->hba = hba; ++ __assign_str(dev_name); + __assign_str(profile_info); + __entry->time_us = time_us; + __entry->err = err; + ), + + TP_printk("%s: %s: took %lld usecs, err %d", +- dev_name(__entry->hba->dev), __get_str(profile_info), ++ __get_str(dev_name), __get_str(profile_info), + __entry->time_us, __entry->err) + ); + +@@ -201,6 +209,7 @@ DECLARE_EVENT_CLASS(ufshcd_template, + __field(s64, usecs) + __field(int, err) + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __field(int, dev_state) + __field(int, link_state) + ), +@@ -209,13 +218,14 @@ DECLARE_EVENT_CLASS(ufshcd_template, + __entry->usecs = usecs; + __entry->err = err; + __entry->hba = hba; ++ __assign_str(dev_name); + __entry->dev_state = dev_state; + __entry->link_state = link_state; + ), + + TP_printk( + "%s: took %lld usecs, dev_state: %s, link_state: %s, err %d", +- dev_name(__entry->hba->dev), ++ __get_str(dev_name), + __entry->usecs, + __print_symbolic(__entry->dev_state, UFS_PWR_MODES), + __print_symbolic(__entry->link_state, UFS_LINK_STATES), +@@ -280,6 +290,7 @@ TRACE_EVENT(ufshcd_command, + TP_STRUCT__entry( + __field(struct scsi_device *, sdev) + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(&sdev->sdev_dev)) + __field(enum ufs_trace_str_t, str_t) + __field(unsigned int, tag) + __field(u32, doorbell) +@@ -292,6 +303,7 @@ TRACE_EVENT(ufshcd_command, + ), + + TP_fast_assign( ++ __assign_str(dev_name); + __entry->sdev = sdev; + __entry->hba = hba; + __entry->str_t = str_t; +@@ -308,7 +320,7 @@ TRACE_EVENT(ufshcd_command, + TP_printk( + "%s: %s: tag: %u, DB: 0x%x, size: %d, IS: %u, LBA: %llu, opcode: 0x%x (%s), group_id: 0x%x, hwq_id: %d", + show_ufs_cmd_trace_str(__entry->str_t), +- dev_name(&__entry->sdev->sdev_dev), __entry->tag, ++ __get_str(dev_name), __entry->tag, + __entry->doorbell, __entry->transfer_len, __entry->intr, + __entry->lba, (u32)__entry->opcode, str_opcode(__entry->opcode), + (u32)__entry->group_id, __entry->hwq_id +@@ -323,6 +335,7 @@ TRACE_EVENT(ufshcd_uic_command, + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __field(enum ufs_trace_str_t, str_t) + __field(u32, cmd) + __field(u32, arg1) +@@ -332,6 +345,7 @@ TRACE_EVENT(ufshcd_uic_command, + + TP_fast_assign( + __entry->hba = hba; ++ __assign_str(dev_name); + __entry->str_t = str_t; + __entry->cmd = cmd; + __entry->arg1 = arg1; +@@ -341,7 +355,7 @@ TRACE_EVENT(ufshcd_uic_command, + + TP_printk( + "%s: %s: cmd: 0x%x, arg1: 0x%x, arg2: 0x%x, arg3: 0x%x", +- show_ufs_cmd_trace_str(__entry->str_t), dev_name(__entry->hba->dev), ++ show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name), + __entry->cmd, __entry->arg1, __entry->arg2, __entry->arg3 + ) + ); +@@ -354,6 +368,7 @@ TRACE_EVENT(ufshcd_upiu, + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __field(enum ufs_trace_str_t, str_t) + __array(unsigned char, hdr, 12) + __array(unsigned char, tsf, 16) +@@ -362,6 +377,7 @@ TRACE_EVENT(ufshcd_upiu, + + TP_fast_assign( + __entry->hba = hba; ++ __assign_str(dev_name); + __entry->str_t = str_t; + memcpy(__entry->hdr, hdr, sizeof(__entry->hdr)); + memcpy(__entry->tsf, tsf, sizeof(__entry->tsf)); +@@ -370,7 +386,7 @@ TRACE_EVENT(ufshcd_upiu, + + TP_printk( + "%s: %s: HDR:%s, %s:%s", +- show_ufs_cmd_trace_str(__entry->str_t), dev_name(__entry->hba->dev), ++ show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name), + __print_hex(__entry->hdr, sizeof(__entry->hdr)), + show_ufs_cmd_trace_tsf(__entry->tsf_t), + __print_hex(__entry->tsf, sizeof(__entry->tsf)) +@@ -385,16 +401,18 @@ TRACE_EVENT(ufshcd_exception_event, + + TP_STRUCT__entry( + __field(struct ufs_hba *, hba) ++ __string(dev_name, dev_name(hba->dev)) + __field(u16, status) + ), + + TP_fast_assign( + __entry->hba = hba; ++ __assign_str(dev_name); + __entry->status = status; + ), + + TP_printk("%s: status 0x%x", +- dev_name(__entry->hba->dev), __entry->status ++ __get_str(dev_name), __entry->status + ) + ); + diff --git a/queue-6.18/xen-gntdev-fix-error-handling-in-ioctl.patch b/queue-6.18/xen-gntdev-fix-error-handling-in-ioctl.patch new file mode 100644 index 0000000000..a0eb815f1b --- /dev/null +++ b/queue-6.18/xen-gntdev-fix-error-handling-in-ioctl.patch @@ -0,0 +1,61 @@ +From 45ca1afe2fd14c04e37227e79d3f8455831d8408 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Mon, 22 Jun 2026 19:25:41 +0800 +Subject: xen/gntdev: fix error handling in ioctl + +From: Wentao Liang + +commit 45ca1afe2fd14c04e37227e79d3f8455831d8408 upstream. + +When gntdev_ioctl_map_grant_ref() fails to copy the operation result +back to userspace after successfully adding the mapping to the list, +the error path returns -EFAULT without releasing the reference +acquired by gntdev_alloc_map(). The mapping remains in priv->maps +with a refcount of 1, causing a memory leak and a dangling list +entry. + +Additionally, gntdev_add_map() may modify map->index to avoid overlap +with existing mappings. Therefore, the index returned to userspace +must be obtained after gntdev_add_map() completes. + +Fix this by holding the mutex across gntdev_add_map(), retrieving +the correct index, and copy_to_user(). If copy_to_user() fails, +remove the mapping from the list and release the reference while +still holding the lock. + +Cc: stable@vger.kernel.org + +Fix these issues by properly handling all error cases. + +Fixes: 1401c00e59ea ("xen/gntdev: convert priv->lock to a mutex") +Fixes: 68b025c813c2 ("xen-gntdev: Add reference counting to maps") + +Signed-off-by: Wentao Liang +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <20260622112541.38194-1-vulab@iscas.ac.cn> +Signed-off-by: Greg Kroah-Hartman +--- + drivers/xen/gntdev.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/xen/gntdev.c ++++ b/drivers/xen/gntdev.c +@@ -676,11 +676,15 @@ static long gntdev_ioctl_map_grant_ref(s + mutex_lock(&priv->lock); + gntdev_add_map(priv, map); + op.index = map->index << PAGE_SHIFT; +- mutex_unlock(&priv->lock); + +- if (copy_to_user(u, &op, sizeof(op)) != 0) ++ if (copy_to_user(u, &op, sizeof(op)) != 0) { ++ list_del(&map->next); ++ mutex_unlock(&priv->lock); ++ gntdev_put_map(priv, map); + return -EFAULT; ++ } + ++ mutex_unlock(&priv->lock); + return 0; + } + diff --git a/queue-6.18/xfrm-nat_keepalive-avoid-double-free-on-send-error.patch b/queue-6.18/xfrm-nat_keepalive-avoid-double-free-on-send-error.patch new file mode 100644 index 0000000000..2b4bd4d982 --- /dev/null +++ b/queue-6.18/xfrm-nat_keepalive-avoid-double-free-on-send-error.patch @@ -0,0 +1,87 @@ +From 226f4a490d1a938fc838d8f8c46a4eca864c0d78 Mon Sep 17 00:00:00 2001 +From: Qianyu Luo +Date: Thu, 25 Jun 2026 13:55:08 +0800 +Subject: xfrm: nat_keepalive: avoid double free on send error + +From: Qianyu Luo + +commit 226f4a490d1a938fc838d8f8c46a4eca864c0d78 upstream. + +nat_keepalive_send() frees the keepalive skb whenever the IPv4 or IPv6 +send helper reports an error. + +That cleanup is only correct before the skb is handed to the output +path. Once ip_build_and_send_pkt() or ip6_xmit() takes ownership, the +networking stack may already have consumed the skb before returning an +error, so freeing it again is unsafe. + +Handle the pre-handoff failure cases inside nat_keepalive_send_ipv4() +and nat_keepalive_send_ipv6(), where the caller still owns the skb, and +keep nat_keepalive_send() responsible only for family dispatch and the +unsupported-family cleanup path. + +Fixes: f531d13bdfe3 ("xfrm: support sending NAT keepalives in ESP in UDP states") +Cc: stable@vger.kernel.org +Reported-by: Yuan Tan +Reported-by: Xin Liu +Signed-off-by: Qianyu Luo +Signed-off-by: Ren Wei +Reviewed-by: Eyal Birger +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_nat_keepalive.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/net/xfrm/xfrm_nat_keepalive.c ++++ b/net/xfrm/xfrm_nat_keepalive.c +@@ -55,8 +55,10 @@ static int nat_keepalive_send_ipv4(struc + ka->encap_sport, sock_net_uid(net, NULL)); + + rt = ip_route_output_key(net, &fl4); +- if (IS_ERR(rt)) ++ if (IS_ERR(rt)) { ++ kfree_skb(skb); + return PTR_ERR(rt); ++ } + + skb_dst_set(skb, &rt->dst); + +@@ -101,6 +103,7 @@ static int nat_keepalive_send_ipv6(struc + dst = ipv6_stub->ipv6_dst_lookup_flow(net, sk, &fl6, NULL); + if (IS_ERR(dst)) { + local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock); ++ kfree_skb(skb); + return PTR_ERR(dst); + } + +@@ -118,7 +121,6 @@ static void nat_keepalive_send(struct na + sizeof(struct ipv6hdr)) + + sizeof(struct udphdr); + const u8 nat_ka_payload = 0xFF; +- int err = -EAFNOSUPPORT; + struct sk_buff *skb; + struct udphdr *uh; + +@@ -140,16 +142,17 @@ static void nat_keepalive_send(struct na + + switch (ka->family) { + case AF_INET: +- err = nat_keepalive_send_ipv4(skb, ka); ++ nat_keepalive_send_ipv4(skb, ka); + break; + #if IS_ENABLED(CONFIG_IPV6) + case AF_INET6: +- err = nat_keepalive_send_ipv6(skb, ka, uh); ++ nat_keepalive_send_ipv6(skb, ka, uh); + break; + #endif +- } +- if (err) ++ default: + kfree_skb(skb); ++ break; ++ } + } + + struct nat_keepalive_work_ctx { diff --git a/queue-6.18/xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch b/queue-6.18/xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch new file mode 100644 index 0000000000..32db83e920 --- /dev/null +++ b/queue-6.18/xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch @@ -0,0 +1,88 @@ +From 355fbcbdc2539cca7890b0d0914d4ce0f985ad74 Mon Sep 17 00:00:00 2001 +From: Sanman Pradhan +Date: Sun, 7 Jun 2026 16:47:34 +0000 +Subject: xfrm: use compat translator only for u64 alignment mismatch + +From: Sanman Pradhan + +commit 355fbcbdc2539cca7890b0d0914d4ce0f985ad74 upstream. + +The XFRM compat layer (CONFIG_XFRM_USER_COMPAT) translates 32-bit xfrm +netlink and setsockopt messages into the native 64-bit layout. It is +only needed on architectures where the 32-bit and 64-bit ABIs disagree +on u64 alignment, which the kernel encodes as COMPAT_FOR_U64_ALIGNMENT. + +That symbol is defined only by arch/x86. XFRM_USER_COMPAT depends on it, +so the translator can never be built on any other architecture, +including arm64, which still provides a 32-bit compat ABI (CONFIG_COMPAT) +for AArch32 EL0 userspace. On arm64 the AArch32 EABI already aligns u64 +to 8 bytes, identical to the AArch64 ABI, so no translation is required +and the native code path is correct for 32-bit tasks. + +However, xfrm_user_rcv_msg() and xfrm_user_policy() gate on +in_compat_syscall() alone and then call xfrm_get_translator(), which +returns NULL when no translator is registered. On arm64 that is always +the case, so every xfrm netlink message and the XFRM_POLICY setsockopt +issued by a 32-bit task returns -EOPNOTSUPP. A 32-bit userspace process +on arm64 (and on any other arch with CONFIG_COMPAT but without +COMPAT_FOR_U64_ALIGNMENT) therefore cannot configure XFRM state or +policy through the XFRM_USER netlink API, and cannot use the XFRM_POLICY +setsockopt path, because both fail before reaching the native parser. + +The translator series replaced the blanket compat rejection with a +translator lookup. That made the path usable on x86 when the translator +is available, but left architectures that cannot build the translator +permanently rejected even when their compat layout already matches the +native layout. Let those architectures use the native parser instead. + +Gate the translator requirement on COMPAT_FOR_U64_ALIGNMENT instead of +on in_compat_syscall() alone. Gating on the ABI property rather than on +CONFIG_XFRM_USER_COMPAT is deliberate: on x86 with IA32_EMULATION=y but +XFRM_USER_COMPAT=n, a 32-bit task must still be rejected rather than +routed through the native parser, which would misread genuinely +4-byte-aligned x86-32 messages. COMPAT_FOR_U64_ALIGNMENT is the ABI +property that makes the XFRM translator mandatory. + +Only the receive/input direction needs the guard. The send, dump and +notification paths already call the translator as "if (xtr) { ... }" +with no error on NULL, so on arches without a translator they no-op and +the kernel emits native 64-bit-layout messages, which is what an AArch32 +task expects. + +Tested on Juniper SRX hardware: with the fix, 32-bit IPsec userspace +netlink and XFRM_POLICY setsockopt operations that previously failed +with -EOPNOTSUPP now succeed; x86 behaviour is unchanged by inspection. + +Fixes: 5106f4a8acff ("xfrm/compat: Add 32=>64-bit messages translator") +Fixes: 96392ee5a13b ("xfrm/compat: Translate 32-bit user_policy from sockptr") +Cc: stable@vger.kernel.org +Signed-off-by: Sanman Pradhan +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_state.c | 2 +- + net/xfrm/xfrm_user.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2983,7 +2983,7 @@ int xfrm_user_policy(struct sock *sk, in + if (IS_ERR(data)) + return PTR_ERR(data); + +- if (in_compat_syscall()) { ++ if (IS_ENABLED(CONFIG_COMPAT_FOR_U64_ALIGNMENT) && in_compat_syscall()) { + struct xfrm_translator *xtr = xfrm_get_translator(); + + if (!xtr) { +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -3463,7 +3463,7 @@ static int xfrm_user_rcv_msg(struct sk_b + if (!netlink_net_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + +- if (in_compat_syscall()) { ++ if (IS_ENABLED(CONFIG_COMPAT_FOR_U64_ALIGNMENT) && in_compat_syscall()) { + struct xfrm_translator *xtr = xfrm_get_translator(); + + if (!xtr) diff --git a/queue-6.18/xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch b/queue-6.18/xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch new file mode 100644 index 0000000000..b772f259d6 --- /dev/null +++ b/queue-6.18/xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch @@ -0,0 +1,44 @@ +From 095515d89b19b6cc19dfcdc846f97403ed1ebce3 Mon Sep 17 00:00:00 2001 +From: Maoyi Xie +Date: Fri, 12 Jun 2026 16:59:41 +0800 +Subject: xfrm: xfrm_interface: require CAP_NET_ADMIN in the device netns for changelink + +From: Maoyi Xie + +commit 095515d89b19b6cc19dfcdc846f97403ed1ebce3 upstream. + +xfrmi_changelink() operates on at most two netns, dev_net(dev) and the +interface link netns xi->net. They differ once the device is created in +or moved to a netns other than the one the request runs in. The rtnl +changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a +caller privileged there but not in xi->net can rewrite an interface that +lives in xi->net. + +Gate xfrmi_changelink() on rtnl_dev_link_net_capable() at its top, +before any attribute is parsed. + +Reported-by: Xiao Liang +Closes: https://lore.kernel.org/netdev/CABAhCOSzP1vaThGV35_VnsRCb=87_CPjPVsTHbq905k8A+BuUg@mail.gmail.com/ +Fixes: f203b76d7809 ("xfrm: Add virtual xfrm interfaces") +Cc: stable@vger.kernel.org +Signed-off-by: Maoyi Xie +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260612085941.3158249-8-maoyixie.tju@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_interface_core.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/xfrm/xfrm_interface_core.c ++++ b/net/xfrm/xfrm_interface_core.c +@@ -869,6 +869,9 @@ static int xfrmi_changelink(struct net_d + struct net *net = xi->net; + struct xfrm_if_parms p = {}; + ++ if (!rtnl_dev_link_net_capable(dev, net)) ++ return -EPERM; ++ + xfrmi_netlink_parms(data, &p); + if (!p.if_id) { + NL_SET_ERR_MSG(extack, "if_id must be non zero");