]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
7.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Jul 2026 15:24:01 +0000 (17:24 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Jul 2026 15:24:01 +0000 (17:24 +0200)
added patches:
accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch
accel-amdxdna-reject-command-submission-on-devices-without-a-submit-op.patch
accel-amdxdna-reject-user-command-submission-without-a-command-bo.patch
accel-amdxdna-use-caller-client-for-debug-bo-sync.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-locking-when-updating-filter-and-timer-values.patch
can-bcm-add-missing-device-refcount-for-can-filter-removal.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-extend-bcm_tx_lock-usage-for-data-and-timer-updates.patch
can-bcm-fix-can-frame-rx-tx-statistics.patch
can-bcm-fix-data-race-on-rx_stamp-rx_ifindex-in-bcm_rx_handler.patch
can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch
can-bcm-fix-stale-rx-tx-ops-after-device-removal.patch
can-bcm-track-a-single-source-interface-for-anydev-timeout-throttle-ops.patch
can-bcm-validate-frame-length-in-bcm_rx_setup-for-rtr-replies.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-avoid-leaking-the-caller-s-thread-keyring-via-the-table-device-file.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-fix-buffer-overflow-in-fec-calculation.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-buf-dma-fence-fix-potential-null-pointer-dereference.patch
dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch
dma-fence-use-correct-callback-in-dma_fence_timeline_name.patch
dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch
dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch
dmaengine-sh-rz-dmac-fix-incorrect-null-check-for-list_first_entry.patch
dmaengine-sh-rz-dmac-move-interrupt-request-after-everything-is-set-up.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
io_uring-bpf-ops-reject-re-registration-of-an-already-bound-ops.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
ovl-use-linked-upper-dentry-in-copy-up-tmpfile.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-hp-wmi-add-support-for-omen-16-ap0xxx-8d26.patch
platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8e35.patch
platform-x86-intel-tpmi-use-cleanup-helpers-in-mem_write.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-imx-reconfigure-for-pio-when-dma-cannot-be-started.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

124 files changed:
queue-7.1/accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch [new file with mode: 0644]
queue-7.1/accel-amdxdna-reject-command-submission-on-devices-without-a-submit-op.patch [new file with mode: 0644]
queue-7.1/accel-amdxdna-reject-user-command-submission-without-a-command-bo.patch [new file with mode: 0644]
queue-7.1/accel-amdxdna-use-caller-client-for-debug-bo-sync.patch [new file with mode: 0644]
queue-7.1/accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch [new file with mode: 0644]
queue-7.1/block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch [new file with mode: 0644]
queue-7.1/block-fix-race-in-blk_time_get_ns-returning-0.patch [new file with mode: 0644]
queue-7.1/block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch [new file with mode: 0644]
queue-7.1/bpf-add-missing-access_ok-call-to-copy_user_syms.patch [new file with mode: 0644]
queue-7.1/bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch [new file with mode: 0644]
queue-7.1/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch [new file with mode: 0644]
queue-7.1/bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch [new file with mode: 0644]
queue-7.1/bus-mhi-host-pci_generic-fix-the-physical-function-check.patch [new file with mode: 0644]
queue-7.1/can-bcm-add-locking-when-updating-filter-and-timer-values.patch [new file with mode: 0644]
queue-7.1/can-bcm-add-missing-device-refcount-for-can-filter-removal.patch [new file with mode: 0644]
queue-7.1/can-bcm-add-missing-rcu-list-annotations-and-operations.patch [new file with mode: 0644]
queue-7.1/can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch [new file with mode: 0644]
queue-7.1/can-bcm-extend-bcm_tx_lock-usage-for-data-and-timer-updates.patch [new file with mode: 0644]
queue-7.1/can-bcm-fix-can-frame-rx-tx-statistics.patch [new file with mode: 0644]
queue-7.1/can-bcm-fix-data-race-on-rx_stamp-rx_ifindex-in-bcm_rx_handler.patch [new file with mode: 0644]
queue-7.1/can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch [new file with mode: 0644]
queue-7.1/can-bcm-fix-stale-rx-tx-ops-after-device-removal.patch [new file with mode: 0644]
queue-7.1/can-bcm-track-a-single-source-interface-for-anydev-timeout-throttle-ops.patch [new file with mode: 0644]
queue-7.1/can-bcm-validate-frame-length-in-bcm_rx_setup-for-rtr-replies.patch [new file with mode: 0644]
queue-7.1/can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch [new file with mode: 0644]
queue-7.1/can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch [new file with mode: 0644]
queue-7.1/can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch [new file with mode: 0644]
queue-7.1/can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch [new file with mode: 0644]
queue-7.1/dm-avoid-leaking-the-caller-s-thread-keyring-via-the-table-device-file.patch [new file with mode: 0644]
queue-7.1/dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch [new file with mode: 0644]
queue-7.1/dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch [new file with mode: 0644]
queue-7.1/dm-integrity-don-t-increment-hash_offset-twice.patch [new file with mode: 0644]
queue-7.1/dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch [new file with mode: 0644]
queue-7.1/dm-integrity-fix-leaking-uninitialized-kernel-memory.patch [new file with mode: 0644]
queue-7.1/dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch [new file with mode: 0644]
queue-7.1/dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch [new file with mode: 0644]
queue-7.1/dm-pcache-reject-option-groups-without-values.patch [new file with mode: 0644]
queue-7.1/dm-stats-fix-dm_jiffies_to_msec64.patch [new file with mode: 0644]
queue-7.1/dm-stats-fix-merge-accounting.patch [new file with mode: 0644]
queue-7.1/dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch [new file with mode: 0644]
queue-7.1/dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch [new file with mode: 0644]
queue-7.1/dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch [new file with mode: 0644]
queue-7.1/dm-verity-fix-a-possible-null-pointer-dereference.patch [new file with mode: 0644]
queue-7.1/dm-verity-fix-buffer-overflow-in-fec-calculation.patch [new file with mode: 0644]
queue-7.1/dm-verity-increase-sprintf-buffer-size.patch [new file with mode: 0644]
queue-7.1/dm-verity-make-error-counter-atomic.patch [new file with mode: 0644]
queue-7.1/dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch [new file with mode: 0644]
queue-7.1/dma-buf-dma-fence-fix-potential-null-pointer-dereference.patch [new file with mode: 0644]
queue-7.1/dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch [new file with mode: 0644]
queue-7.1/dma-fence-use-correct-callback-in-dma_fence_timeline_name.patch [new file with mode: 0644]
queue-7.1/dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch [new file with mode: 0644]
queue-7.1/dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch [new file with mode: 0644]
queue-7.1/dmaengine-sh-rz-dmac-fix-incorrect-null-check-for-list_first_entry.patch [new file with mode: 0644]
queue-7.1/dmaengine-sh-rz-dmac-move-interrupt-request-after-everything-is-set-up.patch [new file with mode: 0644]
queue-7.1/dmaengine-tegra-fix-burst-size-calculation.patch [new file with mode: 0644]
queue-7.1/fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch [new file with mode: 0644]
queue-7.1/fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch [new file with mode: 0644]
queue-7.1/hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch [new file with mode: 0644]
queue-7.1/hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch [new file with mode: 0644]
queue-7.1/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch [new file with mode: 0644]
queue-7.1/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch [new file with mode: 0644]
queue-7.1/i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch [new file with mode: 0644]
queue-7.1/i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch [new file with mode: 0644]
queue-7.1/i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch [new file with mode: 0644]
queue-7.1/ice-fix-ice_init_link-error-return-preventing-probe.patch [new file with mode: 0644]
queue-7.1/io_uring-bpf-ops-reject-re-registration-of-an-already-bound-ops.patch [new file with mode: 0644]
queue-7.1/irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch [new file with mode: 0644]
queue-7.1/ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch [new file with mode: 0644]
queue-7.1/mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch [new file with mode: 0644]
queue-7.1/mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch [new file with mode: 0644]
queue-7.1/mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch [new file with mode: 0644]
queue-7.1/mtd-spi-nor-swp-improve-locking-user-experience.patch [new file with mode: 0644]
queue-7.1/net-sparx5-unregister-blocking-notifier-on-init-failure.patch [new file with mode: 0644]
queue-7.1/net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch [new file with mode: 0644]
queue-7.1/netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch [new file with mode: 0644]
queue-7.1/nfs-charge-unstable-writes-by-request-size-not-folio-size.patch [new file with mode: 0644]
queue-7.1/nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch [new file with mode: 0644]
queue-7.1/nvmet-auth-reject-short-auth_receive-buffers.patch [new file with mode: 0644]
queue-7.1/nvmet-fix-refcount-leak-in-nvmet_sq_create.patch [new file with mode: 0644]
queue-7.1/nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch [new file with mode: 0644]
queue-7.1/openrisc-fix-jump_label-smp-syncing.patch [new file with mode: 0644]
queue-7.1/ovl-use-linked-upper-dentry-in-copy-up-tmpfile.patch [new file with mode: 0644]
queue-7.1/pkey-move-keytype-check-from-pkey-api-to-handler.patch [new file with mode: 0644]
queue-7.1/platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch [new file with mode: 0644]
queue-7.1/platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch [new file with mode: 0644]
queue-7.1/platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch [new file with mode: 0644]
queue-7.1/platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch [new file with mode: 0644]
queue-7.1/platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch [new file with mode: 0644]
queue-7.1/platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8d26.patch [new file with mode: 0644]
queue-7.1/platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8e35.patch [new file with mode: 0644]
queue-7.1/platform-x86-intel-tpmi-use-cleanup-helpers-in-mem_write.patch [new file with mode: 0644]
queue-7.1/platform-x86-isst-restore-sst-pp-control-to-all-domains.patch [new file with mode: 0644]
queue-7.1/s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch [new file with mode: 0644]
queue-7.1/s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch [new file with mode: 0644]
queue-7.1/scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch [new file with mode: 0644]
queue-7.1/scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch [new file with mode: 0644]
queue-7.1/scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch [new file with mode: 0644]
queue-7.1/scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch [new file with mode: 0644]
queue-7.1/scsi-sg-report-request-table-problems-when-any-status-is-set.patch [new file with mode: 0644]
queue-7.1/scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch [new file with mode: 0644]
queue-7.1/scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch [new file with mode: 0644]
queue-7.1/scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch [new file with mode: 0644]
queue-7.1/scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch [new file with mode: 0644]
queue-7.1/sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch [new file with mode: 0644]
queue-7.1/selftests-bpf-cover-negative-buffer-pointer-offsets.patch [new file with mode: 0644]
queue-7.1/series
queue-7.1/smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch [new file with mode: 0644]
queue-7.1/spi-imx-reconfigure-for-pio-when-dma-cannot-be-started.patch [new file with mode: 0644]
queue-7.1/spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch [new file with mode: 0644]
queue-7.1/sunrpc-fix-uninitialized-xprt_create_args-structure.patch [new file with mode: 0644]
queue-7.1/taskstats-retain-dead-thread-stats-in-tgid-queries.patch [new file with mode: 0644]
queue-7.1/tcp-decrement-tcp_md5_needed-static-branch.patch [new file with mode: 0644]
queue-7.1/tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch [new file with mode: 0644]
queue-7.1/time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch [new file with mode: 0644]
queue-7.1/tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch [new file with mode: 0644]
queue-7.1/tpm-make-the-tpm-character-devices-non-seekable.patch [new file with mode: 0644]
queue-7.1/tpm-restore-timeout-for-key-creation-commands.patch [new file with mode: 0644]
queue-7.1/tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch [new file with mode: 0644]
queue-7.1/tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch [new file with mode: 0644]
queue-7.1/ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch [new file with mode: 0644]
queue-7.1/xen-gntdev-fix-error-handling-in-ioctl.patch [new file with mode: 0644]
queue-7.1/xfrm-nat_keepalive-avoid-double-free-on-send-error.patch [new file with mode: 0644]
queue-7.1/xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch [new file with mode: 0644]
queue-7.1/xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch [new file with mode: 0644]

diff --git a/queue-7.1/accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch b/queue-7.1/accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch
new file mode 100644 (file)
index 0000000..b455040
--- /dev/null
@@ -0,0 +1,46 @@
+From 63bbf9ac5dde2ba85e7b39d0a0b7d540e6252ba4 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+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 <vulab@iscas.ac.cn>
+
+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 <vulab@iscas.ac.cn>
+Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patch.msgid.link/20260625113239.49764-1-vulab@iscas.ac.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -480,6 +480,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-7.1/accel-amdxdna-reject-command-submission-on-devices-without-a-submit-op.patch b/queue-7.1/accel-amdxdna-reject-command-submission-on-devices-without-a-submit-op.patch
new file mode 100644 (file)
index 0000000..5cc0388
--- /dev/null
@@ -0,0 +1,45 @@
+From 38953513d7313992676d4136cd425cdb70c6278e Mon Sep 17 00:00:00 2001
+From: Doruk Tan Ozturk <doruk@0sec.ai>
+Date: Mon, 13 Jul 2026 19:30:29 +0200
+Subject: accel/amdxdna: reject command submission on devices without a submit op
+
+From: Doruk Tan Ozturk <doruk@0sec.ai>
+
+commit 38953513d7313992676d4136cd425cdb70c6278e upstream.
+
+amdxdna_cmd_submit() calls xdna->dev_info->ops->cmd_submit()
+unconditionally, but only aie2_dev_ops defines that callback.
+aie4_vf_ops (the AIE4 SR-IOV virtual function) does not, so a user
+AMDXDNA_EXEC_CMD ioctl on an AIE4 device reaches a NULL function-pointer
+call and oopses the kernel. AIE4 submits work through a mapped user queue
+and doorbell, not this ioctl path.
+
+Reject the submission early with -EOPNOTSUPP when the device provides no
+cmd_submit op, so the shared EXEC ioctl is a clean no-op on such devices.
+
+Fixes: aac243092b70 ("accel/amdxdna: Add command execution")
+Cc: stable@vger.kernel.org
+Found by 0sec automated security-research tooling (https://0sec.ai).
+Assisted-by: 0sec:claude-opus-4-8
+Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
+Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patch.msgid.link/20260713173030.87541-3-doruk@0sec.ai
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/accel/amdxdna/amdxdna_ctx.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/accel/amdxdna/amdxdna_ctx.c
++++ b/drivers/accel/amdxdna/amdxdna_ctx.c
+@@ -496,6 +496,10 @@ int amdxdna_cmd_submit(struct amdxdna_cl
+       int ret, idx;
+       XDNA_DBG(xdna, "Command BO hdl %d, Arg BO count %d", cmd_bo_hdl, arg_bo_cnt);
++
++      if (!xdna->dev_info->ops->cmd_submit)
++              return -EOPNOTSUPP;
++
+       job = kzalloc_flex(*job, bos, arg_bo_cnt);
+       if (!job)
+               return -ENOMEM;
diff --git a/queue-7.1/accel-amdxdna-reject-user-command-submission-without-a-command-bo.patch b/queue-7.1/accel-amdxdna-reject-user-command-submission-without-a-command-bo.patch
new file mode 100644 (file)
index 0000000..d9455da
--- /dev/null
@@ -0,0 +1,60 @@
+From 261c1fe3327ad24508f54552c6366e3e4db82c15 Mon Sep 17 00:00:00 2001
+From: Doruk Tan Ozturk <doruk@0sec.ai>
+Date: Mon, 13 Jul 2026 19:30:28 +0200
+Subject: accel/amdxdna: reject user command submission without a command BO
+
+From: Doruk Tan Ozturk <doruk@0sec.ai>
+
+commit 261c1fe3327ad24508f54552c6366e3e4db82c15 upstream.
+
+amdxdna_drm_submit_execbuf() passes the user-supplied command BO handle
+straight into amdxdna_cmd_submit() with drv_cmd == NULL. When the handle
+is AMDXDNA_INVALID_BO_HANDLE (0), the block that fetches job->cmd_bo is
+skipped, leaving it NULL, and no check rejects it on the user path (the
+!job->cmd_bo guard lives inside the != INVALID branch).
+
+The job is then armed and pushed to the DRM scheduler.
+aie2_sched_job_run() takes the drv_cmd == NULL path and calls
+amdxdna_cmd_set_state(job->cmd_bo) -> amdxdna_gem_vmap(NULL) ->
+to_gobj(NULL)->dev, a NULL pointer dereference in the drm_sched worker.
+A process with access to the accel node on a system with a probed AMD NPU
+can trigger a kernel oops with a single AMDXDNA_EXEC_CMD ioctl
+(cmd_handles = 0).
+
+Only internal driver commands (SYNC_DEBUG_BO / ATTACH_DEBUG_BO)
+legitimately pass AMDXDNA_INVALID_BO_HANDLE, and they always set drv_cmd.
+Reject the invalid handle for user submissions (drv_cmd == NULL) at the
+submit choke point so every user path is covered.
+
+Fixes: aac243092b70 ("accel/amdxdna: Add command execution")
+Cc: stable@vger.kernel.org
+Found by 0sec automated security-research tooling (https://0sec.ai).
+Assisted-by: 0sec:claude-opus-4-8
+Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
+Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patch.msgid.link/20260713173030.87541-2-doruk@0sec.ai
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/accel/amdxdna/amdxdna_ctx.c |   10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/accel/amdxdna/amdxdna_ctx.c
++++ b/drivers/accel/amdxdna/amdxdna_ctx.c
+@@ -513,6 +513,16 @@ int amdxdna_cmd_submit(struct amdxdna_cl
+                       ret = -EINVAL;
+                       goto free_job;
+               }
++      } else if (!drv_cmd) {
++              /*
++               * Only internal driver commands (drv_cmd != NULL) may omit a
++               * command BO. A user command submission with the invalid handle
++               * would leave job->cmd_bo NULL and later fault when the scheduler
++               * dereferences it in amdxdna_cmd_set_state().
++               */
++              XDNA_DBG(xdna, "Command BO handle required for user submission");
++              ret = -EINVAL;
++              goto free_job;
+       }
+       ret = amdxdna_arg_bos_lookup(client, job, arg_bo_hdls, arg_bo_cnt);
diff --git a/queue-7.1/accel-amdxdna-use-caller-client-for-debug-bo-sync.patch b/queue-7.1/accel-amdxdna-use-caller-client-for-debug-bo-sync.patch
new file mode 100644 (file)
index 0000000..c930b1e
--- /dev/null
@@ -0,0 +1,50 @@
+From 7caf2a2351d4053075670ff3e26a6815da0a9e1e Mon Sep 17 00:00:00 2001
+From: Shuvam Pandey <shuvampandey1@gmail.com>
+Date: Tue, 16 Jun 2026 02:03:00 +0545
+Subject: accel/amdxdna: Use caller client for debug BO sync
+
+From: Shuvam Pandey <shuvampandey1@gmail.com>
+
+commit 7caf2a2351d4053075670ff3e26a6815da0a9e1e upstream.
+
+amdxdna_drm_sync_bo_ioctl() looks up args->handle in the ioctl caller's
+drm_file. For SYNC_DIRECT_FROM_DEVICE, it then calls
+amdxdna_hwctx_sync_debug_bo(), but passes abo->client.
+
+amdxdna_hwctx_sync_debug_bo() uses the passed client both as the handle
+namespace for debug_bo_hdl and as the owner of the hardware context xarray.
+Those must match the file that supplied args->handle. The BO's stored
+client pointer is object state, not the ioctl context.
+
+Pass filp->driver_priv instead, matching the original handle lookup.
+
+Fixes: 7ea046838021 ("accel/amdxdna: Support firmware debug buffer")
+Cc: stable@vger.kernel.org # v6.19+
+Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com>
+Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patch.msgid.link/178155468039.81818.12173237984867749651@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/accel/amdxdna/amdxdna_gem.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/accel/amdxdna/amdxdna_gem.c
++++ b/drivers/accel/amdxdna/amdxdna_gem.c
+@@ -1039,6 +1039,7 @@ int amdxdna_drm_get_bo_info_ioctl(struct
+ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *filp)
+ {
++      struct amdxdna_client *client = filp->driver_priv;
+       struct amdxdna_dev *xdna = to_xdna_dev(dev);
+       struct amdxdna_drm_sync_bo *args = data;
+       struct amdxdna_gem_obj *abo;
+@@ -1073,7 +1074,7 @@ int amdxdna_drm_sync_bo_ioctl(struct drm
+                args->handle, args->offset, args->size);
+       if (args->direction == SYNC_DIRECT_FROM_DEVICE)
+-              ret = amdxdna_hwctx_sync_debug_bo(abo->client, args->handle);
++              ret = amdxdna_hwctx_sync_debug_bo(client, args->handle);
+ put_obj:
+       drm_gem_object_put(gobj);
diff --git a/queue-7.1/accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch b/queue-7.1/accel-ivpu-reject-firmware-log-with-size-smaller-than-header.patch
new file mode 100644 (file)
index 0000000..018f4f2
--- /dev/null
@@ -0,0 +1,50 @@
+From ddb44baed257560f192b145ed36cf8c0a412de47 Mon Sep 17 00:00:00 2001
+From: Jhonraushan <raushan.jhon@gmail.com>
+Date: Wed, 15 Jul 2026 13:12:06 +0530
+Subject: accel/ivpu: Reject firmware log with size smaller than header
+
+From: Jhonraushan <raushan.jhon@gmail.com>
+
+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 <raushan.jhon@gmail.com>
+Reviewed-by: Karol Wachowski <karol.wachowski@linux.intel.com>
+Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
+Link: https://patch.msgid.link/20260715074206.867712-1-raushan.jhon@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch b/queue-7.1/block-fix-ioring_uring_cmd_reissue-flags-check-in-blkdev_uring_cmd.patch
new file mode 100644 (file)
index 0000000..ecd6e47
--- /dev/null
@@ -0,0 +1,41 @@
+From 4f919141be38ea2b1314e3a531b7b998eb64e8bc Mon Sep 17 00:00:00 2001
+From: Yitang Yang <yi1tang.yang@gmail.com>
+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 <yi1tang.yang@gmail.com>
+
+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 <yi1tang.yang@gmail.com>
+Link: https://patch.msgid.link/20260616155129.406057-1-yi1tang.yang@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/ioctl.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/block/ioctl.c
++++ b/block/ioctl.c
+@@ -951,7 +951,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-7.1/block-fix-race-in-blk_time_get_ns-returning-0.patch b/queue-7.1/block-fix-race-in-blk_time_get_ns-returning-0.patch
new file mode 100644 (file)
index 0000000..c957639
--- /dev/null
@@ -0,0 +1,90 @@
+From 691b052139c94ee6640ac39e0b764dd3867897c0 Mon Sep 17 00:00:00 2001
+From: Mike Waychison <mike@waychison.com>
+Date: Wed, 15 Jul 2026 15:29:50 -0400
+Subject: block: fix race in blk_time_get_ns() returning 0
+
+From: Mike Waychison <mike@waychison.com>
+
+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 <mike@waychison.com>
+Assisted-by: Claude:claude-opus-4.8
+Link: https://patch.msgid.link/20260715192950.2488921-1-mike@waychison.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk.h |   13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/block/blk.h
++++ b/block/blk.h
+@@ -689,6 +689,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();
+@@ -697,12 +698,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-7.1/block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch b/queue-7.1/block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch
new file mode 100644 (file)
index 0000000..0020ee6
--- /dev/null
@@ -0,0 +1,61 @@
+From 181bb9c9eae4f69fe510a62a42c2932d0314a800 Mon Sep 17 00:00:00 2001
+From: Connor Williamson <connordw@amazon.com>
+Date: Mon, 15 Jun 2026 13:07:15 +0000
+Subject: block: remove redundant GD_NEED_PART_SCAN in add_disk_final()
+
+From: Connor Williamson <connordw@amazon.com>
+
+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 <connordw@amazon.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://patch.msgid.link/20260615130715.53693-1-connordw@amazon.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/bpf-add-missing-access_ok-call-to-copy_user_syms.patch b/queue-7.1/bpf-add-missing-access_ok-call-to-copy_user_syms.patch
new file mode 100644 (file)
index 0000000..7928017
--- /dev/null
@@ -0,0 +1,58 @@
+From d5dc200c3a3f217de072af269dd90adddf90e48d Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Tue, 16 Jun 2026 10:30:56 +0200
+Subject: bpf: Add missing access_ok call to copy_user_syms
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+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 <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/bpf/20260611115503.AC16D1F00893@smtp.kernel.org/
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
+Link: https://lore.kernel.org/r/20260616083056.405652-1-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2331,9 +2331,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)
+@@ -2358,10 +2361,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-7.1/bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch b/queue-7.1/bpf-fork-wipe-bpf_storage-before-bailouts-that-access-it.patch
new file mode 100644 (file)
index 0000000..38195ff
--- /dev/null
@@ -0,0 +1,66 @@
+From 9b51a6155d14389876916726430da30eabb1d4ed Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Fri, 26 Jun 2026 17:52:52 +0200
+Subject: bpf,fork: wipe ->bpf_storage before bailouts that access it
+
+From: Jann Horn <jannh@google.com>
+
+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 <jannh@google.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/fork.c |    9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -1004,6 +1004,11 @@ static struct task_struct *dup_task_stru
+       tsk->mm_cid.active = 0;
+       INIT_HLIST_NODE(&tsk->mm_cid.node);
+ #endif
++
++#ifdef CONFIG_BPF_SYSCALL
++      RCU_INIT_POINTER(tsk->bpf_storage, NULL);
++      tsk->bpf_ctx = NULL;
++#endif
+       return tsk;
+ free_stack:
+@@ -2223,10 +2228,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-7.1/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch b/queue-7.1/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch
new file mode 100644 (file)
index 0000000..df2522c
--- /dev/null
@@ -0,0 +1,47 @@
+From 5e0b273e0a62cc04ec338c7b502797c66c2ed42a Mon Sep 17 00:00:00 2001
+From: Tristan Madani <tristan@talencesecurity.com>
+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 <tristan@talencesecurity.com>
+
+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 <tristan@talencesecurity.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20260622230123.3695446-2-tristmd@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -6454,6 +6454,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-7.1/bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch b/queue-7.1/bus-mhi-ep-protect-mhi_ep_handle_syserr-in-the-error-path.patch
new file mode 100644 (file)
index 0000000..a1c8e14
--- /dev/null
@@ -0,0 +1,34 @@
+From 519ddf194b158b91439319f6b977b8a465fda0fb Mon Sep 17 00:00:00 2001
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+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 <manivannan.sadhasivam@oss.qualcomm.com>
+
+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 <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260302085612.18725-1-manivannan.sadhasivam@oss.qualcomm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/bus/mhi/ep/main.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- 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(struc
+                       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;
+                       }
+               }
diff --git a/queue-7.1/bus-mhi-host-pci_generic-fix-the-physical-function-check.patch b/queue-7.1/bus-mhi-host-pci_generic-fix-the-physical-function-check.patch
new file mode 100644 (file)
index 0000000..5b1dc37
--- /dev/null
@@ -0,0 +1,121 @@
+From 32845111e8ea6ef5e837b6d25080e69e99bd4561 Mon Sep 17 00:00:00 2001
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Date: Wed, 27 May 2026 10:46:13 +0200
+Subject: bus: mhi: host: pci_generic: Fix the physical function check
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+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 <slark_xiao@163.com>
+Tested-by: Slark Xiao <slark_xiao@163.com>
+Fixes: b4d01c5b9a9d ("bus: mhi: host: pci_generic: Read SUBSYSTEM_VENDOR_ID for VF's to check status")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1247,7 +1247,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);
+@@ -1277,7 +1277,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;
+@@ -1368,7 +1368,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;
+@@ -1390,7 +1390,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)
+@@ -1439,7 +1439,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 */
+@@ -1468,7 +1468,7 @@ static void mhi_pci_remove(struct pci_de
+       pm_runtime_forbid(&pdev->dev);
+       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);
+@@ -1500,7 +1500,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 */
+@@ -1546,7 +1546,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);
+ }
+@@ -1612,7 +1612,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);
+@@ -1665,7 +1665,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-7.1/can-bcm-add-locking-when-updating-filter-and-timer-values.patch b/queue-7.1/can-bcm-add-locking-when-updating-filter-and-timer-values.patch
new file mode 100644 (file)
index 0000000..3a47bb4
--- /dev/null
@@ -0,0 +1,412 @@
+From 749179c2e25b95d22499ed29096b3e02d6dfd2b4 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:25 +0200
+Subject: can: bcm: add locking when updating filter and timer values
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit 749179c2e25b95d22499ed29096b3e02d6dfd2b4 upstream.
+
+KCSAN detected a simultaneous access to timer values that can be
+overwritten in bcm_rx_setup() when updating timer and filter content
+while bcm_rx_handler(), bcm_rx_timeout_handler() or bcm_rx_thr_handler()
+run concurrently on incoming CAN traffic.
+
+Protect the timer (ival1/ival2/kt_ival1/kt_ival2/kt_lastmsg) and filter
+(nframes/flags/frames/last_frames) updates in bcm_rx_setup() with a new
+per-op bcm_rx_update_lock, taken with the matching scope in the RX
+handlers. memcpy_from_msg() is staged into a temporary buffer before the
+lock is taken, since it can sleep and must not run under a spinlock.
+
+hrtimer_cancel() is always called without bcm_rx_update_lock held, since
+bcm_rx_timeout_handler()/bcm_rx_thr_handler() take the same lock and a
+running callback would otherwise deadlock against the canceller.
+
+Also close a related race: bcm_rx_setup() cleared the RTR flag in the
+stored reply frame's can_id as a separate, unprotected step after the
+frame content was already installed, so a concurrent bcm_rx_handler()
+could transmit a stale reply with CAN_RTR_FLAG still set. Fold that
+normalization into the initial frame preparation instead (on the staged
+buffer for updates, directly on op->frames pre-registration for new
+ops), so the installed frame is always atomically self-consistent.
+
+bcm_rx_handler()'s RX_RTR_FRAME check now takes a lock-protected
+snapshot of op->flags before deciding whether to call bcm_can_tx(),
+but does not hold the lock across that call.
+
+Also take a lock-protected snapshot of the currframe in bcm_can_tx()
+to avoid partly overwrites by content updates in bcm_tx_setup().
+Finally check if a TX_RESET_MULTI_IDX/SETTIMER might have reset
+op->currframe between the two locked sections in bcm_can_tx().
+
+Omit calling hrtimer_forward() with zero interval in bcm_rx_thr_handler().
+kt_ival2 may have been concurrently cleared by bcm_rx_setup() before it
+cancels this timer, so check kt_ival2 inside the bcm_rx_update_lock.
+
+Fixes: c2aba69d0c36 ("can: bcm: add locking for bcm_op runtime updates")
+Reported-by: syzbot+75e5e4ae00c3b4bb544e@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/linux-can/6975d5cf.a00a0220.33ccc7.0022.GAE@google.com/
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-3-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |  176 +++++++++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 133 insertions(+), 43 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -129,6 +129,7 @@ struct bcm_op {
+       struct sock *sk;
+       struct net_device *rx_reg_dev;
+       spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */
++      spinlock_t bcm_rx_update_lock; /* protect filter/timer data updates */
+ };
+ struct bcm_sock {
+@@ -293,22 +294,28 @@ static int bcm_proc_show(struct seq_file
+  * bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface
+  *              of the given bcm tx op
+  */
+-static void bcm_can_tx(struct bcm_op *op)
++static void bcm_can_tx(struct bcm_op *op, struct canfd_frame *cf)
+ {
+       struct sk_buff *skb;
+       struct can_skb_ext *csx;
+       struct net_device *dev;
+-      struct canfd_frame *cf;
++      struct canfd_frame cframe;
++      bool cyclic = !cf;
++      unsigned int idx = 0;
+       int err;
+       /* no target device? => exit */
+       if (!op->ifindex)
+               return;
+-      /* read currframe under lock protection */
+-      spin_lock_bh(&op->bcm_tx_lock);
+-      cf = op->frames + op->cfsiz * op->currframe;
+-      spin_unlock_bh(&op->bcm_tx_lock);
++      if (cyclic) {
++              /* read currframe under lock protection */
++              spin_lock_bh(&op->bcm_tx_lock);
++              idx = op->currframe;
++              memcpy(&cframe, op->frames + op->cfsiz * idx, op->cfsiz);
++              cf = &cframe;
++              spin_unlock_bh(&op->bcm_tx_lock);
++      }
+       dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
+       if (!dev) {
+@@ -341,14 +348,20 @@ static void bcm_can_tx(struct bcm_op *op
+       if (!err)
+               op->frames_abs++;
+-      op->currframe++;
++      /* only advance the cyclic sequence if nothing reset currframe while
++       * we were sending - a concurrent TX_RESET_MULTI_IDX means this
++       * frame's bookkeeping belongs to a sequence that no longer exists
++       */
++      if (!cyclic || op->currframe == idx) {
++              op->currframe++;
+-      /* reached last frame? */
+-      if (op->currframe >= op->nframes)
+-              op->currframe = 0;
++              /* reached last frame? */
++              if (op->currframe >= op->nframes)
++                      op->currframe = 0;
+-      if (op->count > 0)
+-              op->count--;
++              if (op->count > 0)
++                      op->count--;
++      }
+       spin_unlock_bh(&op->bcm_tx_lock);
+ out:
+@@ -461,7 +474,7 @@ static enum hrtimer_restart bcm_tx_timeo
+       struct bcm_msg_head msg_head;
+       if (op->kt_ival1 && (op->count > 0)) {
+-              bcm_can_tx(op);
++              bcm_can_tx(op, NULL);
+               if (!op->count && (op->flags & TX_COUNTEVT)) {
+                       /* create notification to user */
+@@ -478,7 +491,7 @@ static enum hrtimer_restart bcm_tx_timeo
+               }
+       } else if (op->kt_ival2) {
+-              bcm_can_tx(op);
++              bcm_can_tx(op, NULL);
+       }
+       return bcm_tx_set_expiry(op, &op->timer) ?
+@@ -622,6 +635,8 @@ static enum hrtimer_restart bcm_rx_timeo
+       struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
+       struct bcm_msg_head msg_head;
++      spin_lock_bh(&op->bcm_rx_update_lock);
++
+       /* if user wants to be informed, when cyclic CAN-Messages come back */
+       if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
+               /* clear received CAN frames to indicate 'nothing received' */
+@@ -638,6 +653,8 @@ static enum hrtimer_restart bcm_rx_timeo
+       msg_head.can_id  = op->can_id;
+       msg_head.nframes = 0;
++      spin_unlock_bh(&op->bcm_rx_update_lock);
++
+       bcm_send_to_user(op, &msg_head, NULL, 0);
+       return HRTIMER_NORESTART;
+@@ -686,15 +703,26 @@ static int bcm_rx_thr_flush(struct bcm_o
+ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
+ {
+       struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
++      enum hrtimer_restart ret;
+-      if (bcm_rx_thr_flush(op)) {
++      spin_lock_bh(&op->bcm_rx_update_lock);
++
++      /* kt_ival2 may have been concurrently cleared by bcm_rx_setup()
++       * before it cancels this timer - never forward with a zero
++       * interval in that case.
++       */
++      if (bcm_rx_thr_flush(op) && op->kt_ival2) {
+               hrtimer_forward_now(hrtimer, op->kt_ival2);
+-              return HRTIMER_RESTART;
++              ret = HRTIMER_RESTART;
+       } else {
+               /* rearm throttle handling */
+               op->kt_lastmsg = 0;
+-              return HRTIMER_NORESTART;
++              ret = HRTIMER_NORESTART;
+       }
++
++      spin_unlock_bh(&op->bcm_rx_update_lock);
++
++      return ret;
+ }
+ /*
+@@ -704,8 +732,10 @@ static void bcm_rx_handler(struct sk_buf
+ {
+       struct bcm_op *op = (struct bcm_op *)data;
+       const struct canfd_frame *rxframe = (struct canfd_frame *)skb->data;
++      struct canfd_frame rtrframe;
+       unsigned int i;
+       unsigned char traffic_flags;
++      bool rtr_frame;
+       if (op->can_id != rxframe->can_id)
+               return;
+@@ -729,9 +759,18 @@ static void bcm_rx_handler(struct sk_buf
+       /* update statistics */
+       op->frames_abs++;
+-      if (op->flags & RX_RTR_FRAME) {
++      /* snapshot the flag under lock: op->flags/op->frames may be updated
++       * concurrently by bcm_rx_setup().
++       */
++      spin_lock_bh(&op->bcm_rx_update_lock);
++      rtr_frame = op->flags & RX_RTR_FRAME;
++      if (rtr_frame)
++              memcpy(&rtrframe, op->frames, op->cfsiz);
++      spin_unlock_bh(&op->bcm_rx_update_lock);
++
++      if (rtr_frame) {
+               /* send reply for RTR-request (placed in op->frames[0]) */
+-              bcm_can_tx(op);
++              bcm_can_tx(op, &rtrframe);
+               return;
+       }
+@@ -743,6 +782,8 @@ static void bcm_rx_handler(struct sk_buf
+                       traffic_flags |= RX_OWN;
+       }
++      spin_lock_bh(&op->bcm_rx_update_lock);
++
+       if (op->flags & RX_FILTER_ID) {
+               /* the easiest case */
+               bcm_rx_update_and_send(op, op->last_frames, rxframe,
+@@ -778,6 +819,8 @@ static void bcm_rx_handler(struct sk_buf
+ rx_starttimer:
+       bcm_rx_starttimer(op);
++
++      spin_unlock_bh(&op->bcm_rx_update_lock);
+ }
+ /*
+@@ -1116,7 +1159,7 @@ static int bcm_tx_setup(struct bcm_msg_h
+       }
+       if (op->flags & TX_ANNOUNCE)
+-              bcm_can_tx(op);
++              bcm_can_tx(op, NULL);
+       if (op->flags & STARTTIMER)
+               bcm_tx_start_timer(op);
+@@ -1130,6 +1173,24 @@ free_op:
+       return err;
+ }
++static void bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
++                                 struct bcm_op *op, void *new_frames)
++{
++      /* funny feature in RX(!)_SETUP only for RTR-mode:
++       * copy can_id into frame BUT without RTR-flag to
++       * prevent a full-load-loopback-test ... ;-]
++       * normalize this on the staged buffer, before it is
++       * ever installed into op->frames.
++       */
++      if (msg_head->flags & RX_RTR_FRAME) {
++              struct canfd_frame *frame0 = new_frames;
++
++              if ((msg_head->flags & TX_CP_CAN_ID) ||
++                  frame0->can_id == op->can_id)
++                      frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
++      }
++}
++
+ /*
+  * bcm_rx_setup - create or update a bcm rx op (for bcm_sendmsg)
+  */
+@@ -1164,6 +1225,8 @@ static int bcm_rx_setup(struct bcm_msg_h
+       /* check the given can_id */
+       op = bcm_find_op(&bo->rx_ops, msg_head, ifindex);
+       if (op) {
++              void *new_frames = NULL;
++
+               /* update existing BCM operation */
+               /*
+@@ -1175,19 +1238,48 @@ static int bcm_rx_setup(struct bcm_msg_h
+                       return -E2BIG;
+               if (msg_head->nframes) {
+-                      /* update CAN frames content */
+-                      err = memcpy_from_msg(op->frames, msg,
++                      /* get new CAN frames content before locking */
++                      new_frames = kmalloc(msg_head->nframes * op->cfsiz,
++                                           GFP_KERNEL);
++                      if (!new_frames)
++                              return -ENOMEM;
++
++                      err = memcpy_from_msg(new_frames, msg,
+                                             msg_head->nframes * op->cfsiz);
+-                      if (err < 0)
++                      if (err < 0) {
++                              kfree(new_frames);
+                               return err;
++                      }
+-                      /* clear last_frames to indicate 'nothing received' */
+-                      memset(op->last_frames, 0, msg_head->nframes * op->cfsiz);
++                      bcm_rx_setup_rtr_check(msg_head, op, new_frames);
+               }
++              spin_lock_bh(&op->bcm_rx_update_lock);
+               op->nframes = msg_head->nframes;
+               op->flags = msg_head->flags;
++              if (msg_head->nframes) {
++                      /* update CAN frames content */
++                      memcpy(op->frames, new_frames,
++                             msg_head->nframes * op->cfsiz);
++
++                      /* clear last_frames to indicate 'nothing received' */
++                      memset(op->last_frames, 0,
++                             msg_head->nframes * op->cfsiz);
++              }
++
++              if (msg_head->flags & SETTIMER) {
++                      op->ival1 = msg_head->ival1;
++                      op->ival2 = msg_head->ival2;
++                      op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
++                      op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++                      op->kt_lastmsg = 0;
++              }
++              spin_unlock_bh(&op->bcm_rx_update_lock);
++
++              /* free temporary frames / kfree(NULL) is safe */
++              kfree(new_frames);
++
+               /* Only an update -> do not call can_rx_register() */
+               do_rx_register = 0;
+@@ -1198,6 +1290,7 @@ static int bcm_rx_setup(struct bcm_msg_h
+                       return -ENOMEM;
+               spin_lock_init(&op->bcm_tx_lock);
++              spin_lock_init(&op->bcm_rx_update_lock);
+               op->can_id = msg_head->can_id;
+               op->nframes = msg_head->nframes;
+               op->cfsiz = CFSIZ(msg_head->flags);
+@@ -1239,6 +1332,8 @@ static int bcm_rx_setup(struct bcm_msg_h
+                               kfree(op);
+                               return err;
+                       }
++
++                      bcm_rx_setup_rtr_check(msg_head, op, op->frames);
+               }
+               /* bcm_can_tx / bcm_tx_timeout_handler needs this */
+@@ -1266,29 +1361,22 @@ static int bcm_rx_setup(struct bcm_msg_h
+       /* check flags */
+       if (op->flags & RX_RTR_FRAME) {
+-              struct canfd_frame *frame0 = op->frames;
+-
+               /* no timers in RTR-mode */
+               hrtimer_cancel(&op->thrtimer);
+               hrtimer_cancel(&op->timer);
+-
+-              /*
+-               * funny feature in RX(!)_SETUP only for RTR-mode:
+-               * copy can_id into frame BUT without RTR-flag to
+-               * prevent a full-load-loopback-test ... ;-]
+-               */
+-              if ((op->flags & TX_CP_CAN_ID) ||
+-                  (frame0->can_id == op->can_id))
+-                      frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
+-
+       } else {
+               if (op->flags & SETTIMER) {
+-                      /* set timer value */
+-                      op->ival1 = msg_head->ival1;
+-                      op->ival2 = msg_head->ival2;
+-                      op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
+-                      op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++                      /* set timers (locked) for newly created op */
++                      if (do_rx_register) {
++                              spin_lock_bh(&op->bcm_rx_update_lock);
++                              op->ival1 = msg_head->ival1;
++                              op->ival2 = msg_head->ival2;
++                              op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
++                              op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++                              op->kt_lastmsg = 0;
++                              spin_unlock_bh(&op->bcm_rx_update_lock);
++                      }
+                       /* disable an active timer due to zero value? */
+                       if (!op->kt_ival1)
+@@ -1298,9 +1386,11 @@ static int bcm_rx_setup(struct bcm_msg_h
+                        * In any case cancel the throttle timer, flush
+                        * potentially blocked msgs and reset throttle handling
+                        */
+-                      op->kt_lastmsg = 0;
+                       hrtimer_cancel(&op->thrtimer);
++
++                      spin_lock_bh(&op->bcm_rx_update_lock);
+                       bcm_rx_thr_flush(op);
++                      spin_unlock_bh(&op->bcm_rx_update_lock);
+               }
+               if ((op->flags & STARTTIMER) && op->kt_ival1)
diff --git a/queue-7.1/can-bcm-add-missing-device-refcount-for-can-filter-removal.patch b/queue-7.1/can-bcm-add-missing-device-refcount-for-can-filter-removal.patch
new file mode 100644 (file)
index 0000000..1802e1e
--- /dev/null
@@ -0,0 +1,125 @@
+From d59948293ea34b6337ce2b5febab8510de70048c Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:30 +0200
+Subject: can: bcm: add missing device refcount for CAN filter removal
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit d59948293ea34b6337ce2b5febab8510de70048c upstream.
+
+sashiko-bot remarked a problem with a concurrent device unregistration
+in isotp.c which also is present in the bcm.c code. A former fix for raw.c
+commit c275a176e4b6 ("can: raw: add missing refcount for memory leak fix")
+introduced a netdevice_tracker which solves the issue for bcm.c too.
+
+bcm_release(), bcm_delete_rx_op() and bcm_notifier() relied on
+dev_get_by_index(ifindex) to re-find the device for an rx_op before
+unregistering its filter. If a concurrent NETDEV_UNREGISTER has already
+unlisted the device from the ifindex table, that lookup fails and
+can_rx_unregister() is silently skipped, leaving a stale CAN filter
+pointing at the soon-to-be-freed bcm_op/socket.
+
+Hold a netdev_hold()/netdev_put() tracked reference on op->rx_reg_dev
+from the moment the rx filter is registered in bcm_rx_setup() until it
+is unregistered in bcm_rx_unreg(), and use that reference directly in
+bcm_release() and bcm_delete_rx_op() instead of re-looking the device
+up by ifindex.
+
+Reported-by: sashiko-bot@kernel.org
+Closes: https://sashiko.dev/#/patchset/20260707094716.63578-1-socketcan@hartkopp.net
+Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-8-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   47 +++++++++++++++++++++++++++--------------------
+ 1 file changed, 27 insertions(+), 20 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -129,6 +129,7 @@ struct bcm_op {
+       struct canfd_frame last_sframe;
+       struct sock *sk;
+       struct net_device *rx_reg_dev;
++      netdevice_tracker rx_reg_dev_tracker;
+       spinlock_t bcm_tx_lock; /* protect tx data and timer updates */
+       spinlock_t bcm_rx_update_lock; /* protect filter/timer data updates */
+ };
+@@ -967,6 +968,7 @@ static void bcm_rx_unreg(struct net_devi
+               /* mark as removed subscription */
+               op->rx_reg_dev = NULL;
++              netdev_put(dev, &op->rx_reg_dev_tracker);
+       } else
+               printk(KERN_ERR "can-bcm: bcm_rx_unreg: registered device "
+                      "mismatch %p %p\n", op->rx_reg_dev, dev);
+@@ -997,17 +999,14 @@ static int bcm_delete_rx_op(struct list_
+                                * Only remove subscriptions that had not
+                                * been removed due to NETDEV_UNREGISTER
+                                * in bcm_notifier()
++                               *
++                               * op->rx_reg_dev is a tracked reference taken
++                               * when the subscription was registered, so it
++                               * stays valid here even if a concurrent
++                               * NETDEV_UNREGISTER already unlisted the dev.
+                                */
+-                              if (op->rx_reg_dev) {
+-                                      struct net_device *dev;
+-
+-                                      dev = dev_get_by_index(sock_net(op->sk),
+-                                                             op->ifindex);
+-                                      if (dev) {
+-                                              bcm_rx_unreg(dev, op);
+-                                              dev_put(dev);
+-                                      }
+-                              }
++                              if (op->rx_reg_dev)
++                                      bcm_rx_unreg(op->rx_reg_dev, op);
+                       } else
+                               can_rx_unregister(sock_net(op->sk), NULL,
+                                                 op->can_id,
+@@ -1539,7 +1538,17 @@ static int bcm_rx_setup(struct bcm_msg_h
+                                                     bcm_rx_handler, op,
+                                                     "bcm", sk);
+-                              op->rx_reg_dev = dev;
++                              /* keep a tracked reference so that a later
++                               * unregister can safely reach the device even
++                               * if a concurrent NETDEV_UNREGISTER has
++                               * already unlisted it by ifindex
++                               */
++                              if (!err) {
++                                      op->rx_reg_dev = dev;
++                                      netdev_hold(dev,
++                                                  &op->rx_reg_dev_tracker,
++                                                  GFP_KERNEL);
++                              }
+                               dev_put(dev);
+                       } else {
+                               /* the requested device is gone - do not
+@@ -1949,16 +1958,14 @@ static int bcm_release(struct socket *so
+                        * Only remove subscriptions that had not
+                        * been removed due to NETDEV_UNREGISTER
+                        * in bcm_notifier()
++                       *
++                       * op->rx_reg_dev is a tracked reference taken
++                       * when the subscription was registered, so it
++                       * stays valid here even if a concurrent
++                       * NETDEV_UNREGISTER already unlisted the device.
+                        */
+-                      if (op->rx_reg_dev) {
+-                              struct net_device *dev;
+-
+-                              dev = dev_get_by_index(net, op->ifindex);
+-                              if (dev) {
+-                                      bcm_rx_unreg(dev, op);
+-                                      dev_put(dev);
+-                              }
+-                      }
++                      if (op->rx_reg_dev)
++                              bcm_rx_unreg(op->rx_reg_dev, op);
+               } else
+                       can_rx_unregister(net, NULL, op->can_id,
+                                         REGMASK(op->can_id),
diff --git a/queue-7.1/can-bcm-add-missing-rcu-list-annotations-and-operations.patch b/queue-7.1/can-bcm-add-missing-rcu-list-annotations-and-operations.patch
new file mode 100644 (file)
index 0000000..d707b02
--- /dev/null
@@ -0,0 +1,122 @@
+From 7b2c3eabc4dafc062a25e10711154f2107526a78 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:27 +0200
+Subject: can: bcm: add missing rcu list annotations and operations
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+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 <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-5-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   25 ++++++++++++++++---------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -262,7 +262,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));
+@@ -994,6 +994,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;
+@@ -1135,8 +1136,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))) */
+@@ -1158,6 +1158,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, NULL);
+@@ -1350,9 +1354,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;
+@@ -1426,10 +1427,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;
+@@ -1763,8 +1766,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) {
+               /*
+@@ -1795,8 +1800,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-7.1/can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch b/queue-7.1/can-bcm-defer-rx_op-deallocation-to-workqueue-to-fix-thrtimer-uaf.patch
new file mode 100644 (file)
index 0000000..fd36c5c
--- /dev/null
@@ -0,0 +1,169 @@
+From 68973f9db76144825e4f35dfdc80fb8279eb2d57 Mon Sep 17 00:00:00 2001
+From: Lee Jones <lee@kernel.org>
+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 <lee@kernel.org>
+
+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 <feng.xue@outlook.com>
+Tested-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-1-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/can/skb.h>
+ #include <linux/can/bcm.h>
+ #include <linux/slab.h>
++#include <linux/workqueue.h>
+ #include <linux/spinlock.h>
+ #include <net/can.h>
+ #include <net/sock.h>
+@@ -92,6 +93,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
+@@ -105,6 +108,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;
+@@ -793,9 +797,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);
+@@ -803,9 +810,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);
+@@ -1060,6 +1081,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 */
+@@ -1221,6 +1243,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 */
+@@ -1839,11 +1862,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)
+@@ -1861,6 +1888,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;
+ }
+@@ -1869,6 +1898,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-7.1/can-bcm-extend-bcm_tx_lock-usage-for-data-and-timer-updates.patch b/queue-7.1/can-bcm-extend-bcm_tx_lock-usage-for-data-and-timer-updates.patch
new file mode 100644 (file)
index 0000000..1ab2b2d
--- /dev/null
@@ -0,0 +1,224 @@
+From 12ce799f7ab1e05bd8fbf79e46f403bfe5597ebc Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:28 +0200
+Subject: can: bcm: extend bcm_tx_lock usage for data and timer updates
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit 12ce799f7ab1e05bd8fbf79e46f403bfe5597ebc upstream.
+
+Stage new CAN frame content for an existing tx op into a kmalloc()'d
+buffer and validate it there, mirroring the approach already used in
+bcm_rx_setup(). Only copy the validated data into op->frames while
+holding op->bcm_tx_lock, so bcm_can_tx() and bcm_tx_timeout_handler()
+can no longer observe a partially updated or unvalidated frame.
+
+Add a missing error path for memcpy_from_msg() when copying CAN frame
+data from userspace.
+
+Also move the kt_ival1/kt_ival2/ival1/ival2 updates in bcm_tx_setup()
+under op->bcm_tx_lock, and read kt_ival1/kt_ival2/count under the same
+lock in bcm_tx_set_expiry() and bcm_tx_timeout_handler(), closing the
+torn 64-bit ktime_t read on 32-bit platforms.
+
+Fixes: c2aba69d0c36 ("can: bcm: add locking for bcm_op runtime updates")
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-6-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |  104 +++++++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 75 insertions(+), 29 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -128,7 +128,7 @@ struct bcm_op {
+       struct canfd_frame last_sframe;
+       struct sock *sk;
+       struct net_device *rx_reg_dev;
+-      spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */
++      spinlock_t bcm_tx_lock; /* protect tx data and timer updates */
+       spinlock_t bcm_rx_update_lock; /* protect filter/timer data updates */
+ };
+@@ -450,12 +450,18 @@ static bool bcm_tx_set_expiry(struct bcm
+ {
+       ktime_t ival;
++      spin_lock_bh(&op->bcm_tx_lock);
++
+       if (op->kt_ival1 && op->count)
+               ival = op->kt_ival1;
+-      else if (op->kt_ival2)
++      else if (op->kt_ival2) {
+               ival = op->kt_ival2;
+-      else
++      } else {
++              spin_unlock_bh(&op->bcm_tx_lock);
+               return false;
++      }
++
++      spin_unlock_bh(&op->bcm_tx_lock);
+       hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival));
+       return true;
+@@ -472,25 +478,47 @@ static enum hrtimer_restart bcm_tx_timeo
+ {
+       struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
+       struct bcm_msg_head msg_head;
++      bool tx_ival1, tx_ival2;
++
++      /* snapshot kt_ival1/kt_ival2/count under lock to avoid torn
++       * ktime_t reads racing with concurrent bcm_tx_setup() updates
++       */
++      spin_lock_bh(&op->bcm_tx_lock);
++      tx_ival1 = op->kt_ival1 && (op->count > 0);
++      tx_ival2 = !!op->kt_ival2;
++      spin_unlock_bh(&op->bcm_tx_lock);
++
++      if (tx_ival1) {
++              u32 flags, count;
++              struct bcm_timeval ival1, ival2;
+-      if (op->kt_ival1 && (op->count > 0)) {
+               bcm_can_tx(op, NULL);
+-              if (!op->count && (op->flags & TX_COUNTEVT)) {
++              /* snapshot variables under lock to avoid torn reads racing
++               * with concurrent bcm_tx_setup() updates
++               */
++              spin_lock_bh(&op->bcm_tx_lock);
++              flags = op->flags;
++              count = op->count;
++              ival1 = op->ival1;
++              ival2 = op->ival2;
++              spin_unlock_bh(&op->bcm_tx_lock);
++
++              if (!count && (flags & TX_COUNTEVT)) {
+                       /* create notification to user */
+                       memset(&msg_head, 0, sizeof(msg_head));
+                       msg_head.opcode  = TX_EXPIRED;
+-                      msg_head.flags   = op->flags;
+-                      msg_head.count   = op->count;
+-                      msg_head.ival1   = op->ival1;
+-                      msg_head.ival2   = op->ival2;
++                      msg_head.flags   = flags;
++                      msg_head.count   = count;
++                      msg_head.ival1   = ival1;
++                      msg_head.ival2   = ival2;
+                       msg_head.can_id  = op->can_id;
+                       msg_head.nframes = 0;
+                       bcm_send_to_user(op, &msg_head, NULL, 0);
+               }
+-      } else if (op->kt_ival2) {
++      } else if (tx_ival2) {
+               bcm_can_tx(op, NULL);
+       }
+@@ -1013,6 +1041,8 @@ static int bcm_tx_setup(struct bcm_msg_h
+       /* check the given can_id */
+       op = bcm_find_op(&bo->tx_ops, msg_head, ifindex);
+       if (op) {
++              void *new_frames;
++
+               /* update existing BCM operation */
+               /*
+@@ -1023,11 +1053,23 @@ static int bcm_tx_setup(struct bcm_msg_h
+               if (msg_head->nframes > op->nframes)
+                       return -E2BIG;
+-              /* update CAN frames content */
++              /* get new CAN frames content into a staging buffer before
++               * locking: validate and normalize the frames there so that
++               * bcm_can_tx() / bcm_tx_timeout_handler() never observe a
++               * partially updated or unvalidated frame in op->frames
++               */
++              new_frames = kmalloc(msg_head->nframes * op->cfsiz, GFP_KERNEL);
++              if (!new_frames)
++                      return -ENOMEM;
++
+               for (i = 0; i < msg_head->nframes; i++) {
+-                      cf = op->frames + op->cfsiz * i;
++                      cf = new_frames + op->cfsiz * i;
+                       err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz);
++                      if (err < 0) {
++                              kfree(new_frames);
++                              return err;
++                      }
+                       if (op->flags & CAN_FD_FRAME) {
+                               if (cf->len > 64)
+@@ -1037,36 +1079,38 @@ static int bcm_tx_setup(struct bcm_msg_h
+                                       err = -EINVAL;
+                       }
+-                      if (err < 0)
++                      if (err < 0) {
++                              kfree(new_frames);
+                               return err;
++                      }
+                       if (msg_head->flags & TX_CP_CAN_ID) {
+                               /* copy can_id into frame */
+                               cf->can_id = msg_head->can_id;
+                       }
+               }
++
++              spin_lock_bh(&op->bcm_tx_lock);
++
++              /* update CAN frames content */
++              memcpy(op->frames, new_frames, msg_head->nframes * op->cfsiz);
++
+               op->flags = msg_head->flags;
+-              /* only lock for unlikely count/nframes/currframe changes */
+               if (op->nframes != msg_head->nframes ||
+-                  op->flags & TX_RESET_MULTI_IDX ||
+-                  op->flags & SETTIMER) {
+-
+-                      spin_lock_bh(&op->bcm_tx_lock);
++                  op->flags & TX_RESET_MULTI_IDX) {
++                      /* potentially update changed nframes */
++                      op->nframes = msg_head->nframes;
++                      /* restart multiple frame transmission */
++                      op->currframe = 0;
++              }
+-                      if (op->nframes != msg_head->nframes ||
+-                          op->flags & TX_RESET_MULTI_IDX) {
+-                              /* potentially update changed nframes */
+-                              op->nframes = msg_head->nframes;
+-                              /* restart multiple frame transmission */
+-                              op->currframe = 0;
+-                      }
++              if (op->flags & SETTIMER)
++                      op->count = msg_head->count;
+-                      if (op->flags & SETTIMER)
+-                              op->count = msg_head->count;
++              spin_unlock_bh(&op->bcm_tx_lock);
+-                      spin_unlock_bh(&op->bcm_tx_lock);
+-              }
++              kfree(new_frames);
+       } else {
+               /* insert new BCM operation for the given can_id */
+@@ -1142,10 +1186,12 @@ static int bcm_tx_setup(struct bcm_msg_h
+       if (op->flags & SETTIMER) {
+               /* set timer values */
++              spin_lock_bh(&op->bcm_tx_lock);
+               op->ival1 = msg_head->ival1;
+               op->ival2 = msg_head->ival2;
+               op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
+               op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++              spin_unlock_bh(&op->bcm_tx_lock);
+               /* disable an active timer due to zero values? */
+               if (!op->kt_ival1 && !op->kt_ival2)
diff --git a/queue-7.1/can-bcm-fix-can-frame-rx-tx-statistics.patch b/queue-7.1/can-bcm-fix-can-frame-rx-tx-statistics.patch
new file mode 100644 (file)
index 0000000..af50a5d
--- /dev/null
@@ -0,0 +1,194 @@
+From e6c24ba95fc3f1b5e1dcd28b1c6e59ef61a9daa5 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:26 +0200
+Subject: can: bcm: fix CAN frame rx/tx statistics
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit e6c24ba95fc3f1b5e1dcd28b1c6e59ef61a9daa5 upstream.
+
+KCSAN detected a data race within the bcm_rx_handler() when two CAN frames
+have been simultaneously received and processed in a single rx op by two
+different CPUs.
+
+Use atomic operations with (signed) long data types to access the
+statistics in the hot path to fix the KCSAN complaint.
+
+Additionally simplify the update and check of statistics overflow by
+using the atomic operations in separate bcm_update_[rx|tx]_stats()
+functions. The rx variant runs under bcm_rx_update_lock to prevent
+races when resetting the two rx counters; the tx variant runs under
+bcm_tx_lock and only needs to guard its own counter's overflow.
+
+As the rx path resets its values already at LONG_MAX / 100, there is
+no conflict between the two locking domains (bcm_rx_update_lock vs.
+bcm_tx_lock) even for ops that use both paths.
+
+The rx statistics update and the frames_filtered update in
+bcm_rx_changed() were previously performed in two separate
+bcm_rx_update_lock sections. For an rx op subscribed on all interfaces
+(ifindex == 0), bcm_rx_handler() can run concurrently on different
+CPUs, so a counter reset by one CPU between these two sections could
+leave frames_filtered larger than frames_abs on another CPU, producing
+a bogus (even negative) reduction percentage in procfs. Update the
+statistics in the same critical section as bcm_rx_changed() to close
+this gap, which also removes the now unneeded extra lock/unlock pair
+around the traffic_flags calculation.
+
+Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-4-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   69 ++++++++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 46 insertions(+), 23 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -112,7 +112,7 @@ struct bcm_op {
+       int ifindex;
+       canid_t can_id;
+       u32 flags;
+-      unsigned long frames_abs, frames_filtered;
++      atomic_long_t frames_abs, frames_filtered;
+       struct bcm_timeval ival1, ival2;
+       struct hrtimer timer, thrtimer;
+       ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
+@@ -229,10 +229,13 @@ static int bcm_proc_show(struct seq_file
+       list_for_each_entry_rcu(op, &bo->rx_ops, list) {
+-              unsigned long reduction;
++              long reduction, frames_filtered, frames_abs;
++
++              frames_filtered = atomic_long_read(&op->frames_filtered);
++              frames_abs = atomic_long_read(&op->frames_abs);
+               /* print only active entries & prevent division by zero */
+-              if (!op->frames_abs)
++              if (!frames_abs)
+                       continue;
+               seq_printf(m, "rx_op: %03X %-5s ", op->can_id,
+@@ -254,9 +257,9 @@ static int bcm_proc_show(struct seq_file
+                                  (long long)ktime_to_us(op->kt_ival2));
+               seq_printf(m, "# recv %ld (%ld) => reduction: ",
+-                         op->frames_filtered, op->frames_abs);
++                         frames_filtered, frames_abs);
+-              reduction = 100 - (op->frames_filtered * 100) / op->frames_abs;
++              reduction = 100 - (frames_filtered * 100) / frames_abs;
+               seq_printf(m, "%s%ld%%\n",
+                          (reduction == 100) ? "near " : "", reduction);
+@@ -280,7 +283,8 @@ static int bcm_proc_show(struct seq_file
+                       seq_printf(m, "t2=%lld ",
+                                  (long long)ktime_to_us(op->kt_ival2));
+-              seq_printf(m, "# sent %ld\n", op->frames_abs);
++              seq_printf(m, "# sent %ld\n",
++                         atomic_long_read(&op->frames_abs));
+       }
+       seq_putc(m, '\n');
+@@ -290,6 +294,24 @@ static int bcm_proc_show(struct seq_file
+ }
+ #endif /* CONFIG_PROC_FS */
++static void bcm_update_rx_stats(struct bcm_op *op)
++{
++      /* prevent overflow of the reduction% calculation in bcm_proc_show() */
++      if (atomic_long_inc_return(&op->frames_abs) > LONG_MAX / 100) {
++              atomic_long_set(&op->frames_filtered, 0);
++              atomic_long_set(&op->frames_abs, 0);
++      }
++}
++
++static void bcm_update_tx_stats(struct bcm_op *op)
++{
++      /* tx_op has no reduction% calculation - use the full range and
++       * just keep the displayed counter non-negative on overflow
++       */
++      if (atomic_long_inc_return(&op->frames_abs) == LONG_MAX)
++              atomic_long_set(&op->frames_abs, 0);
++}
++
+ /*
+  * bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface
+  *              of the given bcm tx op
+@@ -346,7 +368,7 @@ static void bcm_can_tx(struct bcm_op *op
+       spin_lock_bh(&op->bcm_tx_lock);
+       if (!err)
+-              op->frames_abs++;
++              bcm_update_tx_stats(op);
+       /* only advance the cyclic sequence if nothing reset currframe while
+        * we were sending - a concurrent TX_RESET_MULTI_IDX means this
+@@ -533,12 +555,9 @@ static void bcm_rx_changed(struct bcm_op
+ {
+       struct bcm_msg_head head;
+-      /* update statistics */
+-      op->frames_filtered++;
+-
+-      /* prevent statistics overflow */
+-      if (op->frames_filtered > ULONG_MAX/100)
+-              op->frames_filtered = op->frames_abs = 0;
++      /* update statistics (frames_filtered <= frames_abs) */
++      if (atomic_long_read(&op->frames_abs))
++              atomic_long_inc(&op->frames_filtered);
+       /* this element is not throttled anymore */
+       data->flags &= ~RX_THR;
+@@ -784,24 +803,30 @@ static void bcm_rx_handler(struct sk_buf
+       op->rx_stamp = skb->tstamp;
+       /* save originator for recvfrom() */
+       op->rx_ifindex = skb->dev->ifindex;
+-      /* update statistics */
+-      op->frames_abs++;
+-      /* snapshot the flag under lock: op->flags/op->frames may be updated
+-       * concurrently by bcm_rx_setup().
+-       */
++      /* op->flags/op->frames may be updated concurrently by bcm_rx_setup() */
+       spin_lock_bh(&op->bcm_rx_update_lock);
++
+       rtr_frame = op->flags & RX_RTR_FRAME;
+-      if (rtr_frame)
++      if (rtr_frame) {
++              bcm_update_rx_stats(op);
++              /* snapshot RTR content under lock */
+               memcpy(&rtrframe, op->frames, op->cfsiz);
+-      spin_unlock_bh(&op->bcm_rx_update_lock);
++              spin_unlock_bh(&op->bcm_rx_update_lock);
+-      if (rtr_frame) {
+               /* send reply for RTR-request (placed in op->frames[0]) */
+               bcm_can_tx(op, &rtrframe);
+               return;
+       }
++      /* update statistics in the same critical section as bcm_rx_changed()
++       * below: frames_filtered must never be checked/incremented against a
++       * frames_abs snapshot from a concurrent bcm_rx_handler() call on
++       * another CPU for the same (wildcard) op, or frames_filtered can end
++       * up larger than frames_abs.
++       */
++      bcm_update_rx_stats(op);
++
+       /* compute flags to distinguish between own/local/remote CAN traffic */
+       traffic_flags = 0;
+       if (skb->sk) {
+@@ -810,8 +835,6 @@ static void bcm_rx_handler(struct sk_buf
+                       traffic_flags |= RX_OWN;
+       }
+-      spin_lock_bh(&op->bcm_rx_update_lock);
+-
+       if (op->flags & RX_FILTER_ID) {
+               /* the easiest case */
+               bcm_rx_update_and_send(op, op->last_frames, rxframe,
diff --git a/queue-7.1/can-bcm-fix-data-race-on-rx_stamp-rx_ifindex-in-bcm_rx_handler.patch b/queue-7.1/can-bcm-fix-data-race-on-rx_stamp-rx_ifindex-in-bcm_rx_handler.patch
new file mode 100644 (file)
index 0000000..6a02f31
--- /dev/null
@@ -0,0 +1,68 @@
+From 58fd6cbc8541216af1d7ed272ea7ac2b66d50fd8 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:32 +0200
+Subject: can: bcm: fix data race on rx_stamp/rx_ifindex in bcm_rx_handler()
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit 58fd6cbc8541216af1d7ed272ea7ac2b66d50fd8 upstream.
+
+For an rx op subscribed on all interfaces (ifindex == 0), the same op
+is registered once in the shared per-netns wildcard filter list, so
+bcm_rx_handler() can run concurrently on different CPUs for frames
+arriving on different net devices.
+
+op->rx_stamp and op->rx_ifindex were written before bcm_rx_update_lock was
+taken, allowing concurrent writers to race each other - including a torn
+store of the 64-bit rx_stamp on 32-bit platforms.
+
+Beyond a torn store bcm_send_to_user() must report the timestamp/ifindex
+of the very same frame whose content it is delivering. So the assignment
+is placed in the same unbroken bcm_rx_update_lock section as the content
+comparison.
+
+As a side effect, the RTR-request frame feature (which never reach
+bcm_send_to_user()) no longer updates rx_stamp/rx_ifindex, since only
+the notification path needs them.
+
+Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
+Reported-by: sashiko-bot@kernel.org
+Closes: https://lore.kernel.org/linux-can/20260707145135.5BC831F00A3A@smtp.kernel.org/
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-10-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -799,11 +799,6 @@ static void bcm_rx_handler(struct sk_buf
+       /* disable timeout */
+       hrtimer_cancel(&op->timer);
+-      /* save rx timestamp */
+-      op->rx_stamp = skb->tstamp;
+-      /* save originator for recvfrom() */
+-      op->rx_ifindex = skb->dev->ifindex;
+-
+       /* op->flags/op->frames may be updated concurrently by bcm_rx_setup() */
+       spin_lock_bh(&op->bcm_rx_update_lock);
+@@ -835,6 +830,14 @@ static void bcm_rx_handler(struct sk_buf
+                       traffic_flags |= RX_OWN;
+       }
++      /* save rx timestamp and originator for recvfrom() under lock.
++       * For an op subscribed on all interfaces (ifindex == 0)
++       * bcm_rx_handler() can run concurrently on different CPUs so
++       * the CAN content and the meta data must be bundled correctly.
++       */
++      op->rx_stamp = skb->tstamp;
++      op->rx_ifindex = skb->dev->ifindex;
++
+       if (op->flags & RX_FILTER_ID) {
+               /* the easiest case */
+               bcm_rx_update_and_send(op, op->last_frames, rxframe,
diff --git a/queue-7.1/can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch b/queue-7.1/can-bcm-fix-lockless-bound-ifindex-race-and-silent-rx_setup-failure.patch
new file mode 100644 (file)
index 0000000..62b94b2
--- /dev/null
@@ -0,0 +1,186 @@
+From d9b091d9d22fee81ec53fb55d2032951993ceadb Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+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 <socketcan@hartkopp.net>
+
+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 <ginger.jzllee@gmail.com>
+Closes: https://lore.kernel.org/linux-can/CAGp+u1aBK8QVjsvAxM2Ldzep4rEbsP9x_pV3At4g=h1kVEtyhA@mail.gmail.com/
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-2-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   65 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 51 insertions(+), 14 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -1323,6 +1323,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
+@@ -1396,12 +1401,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 */
+@@ -1417,17 +1423,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;
+@@ -1436,20 +1463,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:
+@@ -1499,6 +1527,7 @@ static int bcm_sendmsg(struct socket *so
+               break;
+       }
++out_release:
+       release_sock(sk);
+       return ret;
+@@ -1535,7 +1564,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;
+               }
+@@ -1676,7 +1710,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;
+       }
+@@ -1746,7 +1780,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-7.1/can-bcm-fix-stale-rx-tx-ops-after-device-removal.patch b/queue-7.1/can-bcm-fix-stale-rx-tx-ops-after-device-removal.patch
new file mode 100644 (file)
index 0000000..71b8994
--- /dev/null
@@ -0,0 +1,158 @@
+From 3b762c0d950383ab7a002686c9136b9aa55d2d70 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:31 +0200
+Subject: can: bcm: fix stale rx/tx ops after device removal
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit 3b762c0d950383ab7a002686c9136b9aa55d2d70 upstream.
+
+RX: an RX_SETUP update(!) for an existing op skipped can_rx_register()
+unconditionally, even when a concurrent NETDEV_UNREGISTER had already
+torn down its registration (op->rx_reg_dev == NULL). This silently
+did not re-enable frame delivery for that updated filter. bcm_rx_setup()
+now re-registers in that case, while leaving rx_ops with ifindex = 0
+(all CAN devices) which never carry a tracked rx_reg_dev registered as-is.
+
+TX: bcm_notify() only handled bo->rx_ops on NETDEV_UNREGISTER, leaving
+tx_ops with an active cyclic transmission re-arming its hrtimer
+indefinitely to execute bcm_tx_timeout_handler(). Cancelling the hrtimer
+prevents the runaway timer and any injection into a later reused ifindex,
+since nothing else calls bcm_can_tx() for the op until an explicit
+TX_SETUP update re-arms it.
+
+Unlike bcm_rx_unreg(), which clears the tracked rx_reg_dev for rx_ops,
+the ifindex is intentionally left unchanged for tx_ops. bcm_tx_setup()
+always rejects ifindex 0, so clearing it would strand the op: neither a
+later TX_SETUP (bcm_find_op()) nor TX_DELETE (bcm_delete_tx_op()) could
+ever find it again, since both require an exact ifindex match.
+
+Reported-by: sashiko-bot@kernel.org
+Closes: https://lore.kernel.org/linux-can/20260708094536.DDF821F00A3A@smtp.kernel.org/
+Closes: https://lore.kernel.org/linux-can/20260708154039.347ED1F000E9@smtp.kernel.org/
+Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-9-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   54 ++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 44 insertions(+), 10 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -1276,6 +1276,7 @@ static int bcm_rx_setup(struct bcm_msg_h
+       struct bcm_sock *bo = bcm_sk(sk);
+       struct bcm_op *op;
+       int do_rx_register;
++      int new_op = 0;
+       int err = 0;
+       if ((msg_head->flags & RX_FILTER_ID) || (!(msg_head->nframes))) {
+@@ -1356,8 +1357,15 @@ static int bcm_rx_setup(struct bcm_msg_h
+               /* free temporary frames / kfree(NULL) is safe */
+               kfree(new_frames);
+-              /* Only an update -> do not call can_rx_register() */
+-              do_rx_register = 0;
++              /* Don't register a new CAN filter for the rx_op update unless
++               * a concurrent NETDEV_UNREGISTER notifier already tore down
++               * the previous registration. In this case the receiver needs
++               * to be re-registered here so that this update doesn't
++               * silently stop delivering frames for the given ifindex.
++               * Ops with ifindex = 0 (all CAN interfaces) never carry a
++               * tracked rx_reg_dev and stay registered as-is.
++               */
++              do_rx_register = (ifindex && !op->rx_reg_dev) ? 1 : 0;
+       } else {
+               /* insert new BCM operation for the given can_id */
+@@ -1428,6 +1436,7 @@ static int bcm_rx_setup(struct bcm_msg_h
+               /* call can_rx_register() */
+               do_rx_register = 1;
++              new_op = 1;
+       } /* if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) */
+@@ -1441,7 +1450,7 @@ static int bcm_rx_setup(struct bcm_msg_h
+               if (op->flags & SETTIMER) {
+                       /* set timers (locked) for newly created op */
+-                      if (do_rx_register) {
++                      if (new_op) {
+                               spin_lock_bh(&op->bcm_rx_update_lock);
+                               op->ival1 = msg_head->ival1;
+                               op->ival2 = msg_head->ival2;
+@@ -1471,7 +1480,10 @@ static int bcm_rx_setup(struct bcm_msg_h
+                                     HRTIMER_MODE_REL_SOFT);
+       }
+-      /* now we can register for can_ids, if we added a new bcm_op */
++      /* now we can register for can_ids, if we added a new bcm_op
++       * or need to re-register after a NETDEV_UNREGISTER tore down
++       * the previous registration of an existing op
++       */
+       if (do_rx_register) {
+               if (ifindex) {
+                       struct net_device *dev;
+@@ -1493,18 +1505,32 @@ static int bcm_rx_setup(struct bcm_msg_h
+                               err = -ENODEV;
+                       }
+-              } else
++              } else {
+                       err = can_rx_register(sock_net(sk), NULL, op->can_id,
+                                             REGMASK(op->can_id),
+                                             bcm_rx_handler, op, "bcm", sk);
++              }
++
+               if (err) {
+-                      /* this bcm rx op is broken -> remove it */
+-                      bcm_remove_op(op);
++                      /* newly created bcm rx op is broken -> remove it */
++                      if (new_op) {
++                              bcm_remove_op(op);
++                              return err;
++                      }
++
++                      /* an existing op just stays unregistered.
++                       * Cancel op->timer and (defensively) op->thrtimer.
++                       * Other settings can't be reached until the next
++                       * successful RX_SETUP.
++                       */
++                      hrtimer_cancel(&op->timer);
++                      hrtimer_cancel(&op->thrtimer);
+                       return err;
+               }
+-              /* add this bcm_op to the list of the rx_ops */
+-              list_add_rcu(&op->list, &bo->rx_ops);
++              /* add a new bcm_op to the list of the rx_ops */
++              if (new_op)
++                      list_add_rcu(&op->list, &bo->rx_ops);
+       }
+       return msg_head->nframes * op->cfsiz + MHSIZ;
+@@ -1716,11 +1742,19 @@ static void bcm_notify(struct bcm_sock *
+       case NETDEV_UNREGISTER:
+               lock_sock(sk);
+-              /* remove device specific receive entries */
++              /* rx_ops: remove device specific receive entries */
+               list_for_each_entry(op, &bo->rx_ops, list)
+                       if (op->rx_reg_dev == dev)
+                               bcm_rx_unreg(dev, op);
++              /* tx_ops: stop device specific cyclic transmissions on the
++               * vanishing ifindex. Cancelling the timer is enough to stop
++               * cyclic bcm_can_tx() calls as there is no re-arming.
++               */
++              list_for_each_entry(op, &bo->tx_ops, list)
++                      if (op->ifindex == dev->ifindex)
++                              hrtimer_cancel(&op->timer);
++
+               /* remove device reference, if this is our bound device */
+               if (bo->bound && bo->ifindex == dev->ifindex) {
+ #if IS_ENABLED(CONFIG_PROC_FS)
diff --git a/queue-7.1/can-bcm-track-a-single-source-interface-for-anydev-timeout-throttle-ops.patch b/queue-7.1/can-bcm-track-a-single-source-interface-for-anydev-timeout-throttle-ops.patch
new file mode 100644 (file)
index 0000000..cade5db
--- /dev/null
@@ -0,0 +1,136 @@
+From 2f5976f54a04e9f18b25283036ac3136be453b17 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:33 +0200
+Subject: can: bcm: track a single source interface for ANYDEV timeout/throttle ops
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit 2f5976f54a04e9f18b25283036ac3136be453b17 upstream.
+
+An ANYDEV rx op (ifindex == 0) with an active RX timeout and/or
+throttle timer has no defined semantics when matching frames arrive
+from several interfaces: bcm_rx_handler() can run concurrently for
+the same op on different CPUs, racing hrtimer_cancel()/
+bcm_rx_starttimer() against bcm_rx_timeout_handler() and causing
+spurious RX_TIMEOUT notifications and last_frames corruption. The
+same concurrency lets throttled multiplex frames from different
+interfaces clobber the single rx_ifindex/rx_stamp fields shared by
+the op.
+
+Add op->if_detected to track the first interface that delivers a
+matching frame while a timeout/throttle timer is configured, and
+reject frames from any other interface for that op. The claim is
+decided in bcm_rx_handler() before hrtimer_cancel() touches
+op->timer, so a rejected frame can never disturb the claimed
+interface's watchdog. RTR-mode ops are excluded via RX_RTR_FRAME,
+independent of kt_ival1/kt_ival2, since those may briefly hold a
+stale value from an earlier non-RTR configuration.
+
+The claim is released in bcm_notify() on NETDEV_UNREGISTER and in
+bcm_rx_setup() when SETTIMER reconfigures the timer values.
+
+A (re-)claim is only possible on CAN devices in NETREG_REGISTERED
+dev->reg_state to cover the release in bcm_notify() where reg_state
+becomes NETREG_UNREGISTERING until synchronize_net().
+
+Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
+Reported-by: sashiko-bot@kernel.org
+Closes: https://lore.kernel.org/linux-can/20260709105031.1A39C1F000E9@smtp.kernel.org/
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-11-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   49 ++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 44 insertions(+), 5 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -117,6 +117,7 @@ struct bcm_op {
+       struct hrtimer timer, thrtimer;
+       ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
+       int rx_ifindex;
++      int if_detected; /* first received ifindex in ANYDEV rx_op mode */
+       int cfsiz;
+       u32 count;
+       u32 nframes;
+@@ -796,6 +797,33 @@ static void bcm_rx_handler(struct sk_buf
+                       return;
+       }
++      /* An ANYDEV op with an active RX timeout and/or throttle timer
++       * tracks a single source interface: claim the first interface that
++       * delivers a matching frame and reject frames from any other one,
++       * before hrtimer_cancel() below can touch op->timer - this avoids
++       * racing bcm_rx_timeout_handler() across concurrent interfaces.
++       * RX_RTR_FRAME ops are excluded, as kt_ival1/kt_ival2 may briefly
++       * hold a stale value from an earlier non-RTR configuration.
++       */
++      if (!op->ifindex) {
++              spin_lock_bh(&op->bcm_rx_update_lock);
++
++              if (!(op->flags & RX_RTR_FRAME) &&
++                  (op->kt_ival1 || op->kt_ival2)) {
++                      /* don't claim to vanishing interface */
++                      if (!op->if_detected &&
++                          READ_ONCE(skb->dev->reg_state) == NETREG_REGISTERED)
++                              op->if_detected = skb->dev->ifindex;
++
++                      if (op->if_detected != skb->dev->ifindex) {
++                              spin_unlock_bh(&op->bcm_rx_update_lock);
++                              return;
++                      }
++              }
++
++              spin_unlock_bh(&op->bcm_rx_update_lock);
++      }
++
+       /* disable timeout */
+       hrtimer_cancel(&op->timer);
+@@ -830,10 +858,9 @@ static void bcm_rx_handler(struct sk_buf
+                       traffic_flags |= RX_OWN;
+       }
+-      /* save rx timestamp and originator for recvfrom() under lock.
+-       * For an op subscribed on all interfaces (ifindex == 0)
+-       * bcm_rx_handler() can run concurrently on different CPUs so
+-       * the CAN content and the meta data must be bundled correctly.
++      /* save rx timestamp and originator for recvfrom() under lock: an
++       * ANYDEV op without an active timer can still run concurrently on
++       * different CPUs, so content and meta data must be bundled here.
+        */
+       op->rx_stamp = skb->tstamp;
+       op->rx_ifindex = skb->dev->ifindex;
+@@ -1351,6 +1378,7 @@ static int bcm_rx_setup(struct bcm_msg_h
+                       op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
+                       op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
+                       op->kt_lastmsg = 0;
++                      op->if_detected = 0; /* reclaim ifindex in ANYDEV mode */
+               }
+               spin_unlock_bh(&op->bcm_rx_update_lock);
+@@ -1743,10 +1771,21 @@ static void bcm_notify(struct bcm_sock *
+               lock_sock(sk);
+               /* rx_ops: remove device specific receive entries */
+-              list_for_each_entry(op, &bo->rx_ops, list)
++              list_for_each_entry(op, &bo->rx_ops, list) {
+                       if (op->rx_reg_dev == dev)
+                               bcm_rx_unreg(dev, op);
++                      /* release an ANYDEV op's claim (see bcm_rx_handler())
++                       * on this now confirmed-gone interface.
++                       */
++                      if (!op->ifindex) {
++                              spin_lock_bh(&op->bcm_rx_update_lock);
++                              if (op->if_detected == dev->ifindex)
++                                      op->if_detected = 0;
++                              spin_unlock_bh(&op->bcm_rx_update_lock);
++                      }
++              }
++
+               /* tx_ops: stop device specific cyclic transmissions on the
+                * vanishing ifindex. Cancelling the timer is enough to stop
+                * cyclic bcm_can_tx() calls as there is no re-arming.
diff --git a/queue-7.1/can-bcm-validate-frame-length-in-bcm_rx_setup-for-rtr-replies.patch b/queue-7.1/can-bcm-validate-frame-length-in-bcm_rx_setup-for-rtr-replies.patch
new file mode 100644 (file)
index 0000000..fde991f
--- /dev/null
@@ -0,0 +1,122 @@
+From 62ec41f364648be79d54d94d0d240ee326948afd Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Tue, 14 Jul 2026 18:55:29 +0200
+Subject: can: bcm: validate frame length in bcm_rx_setup() for RTR replies
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+commit 62ec41f364648be79d54d94d0d240ee326948afd upstream.
+
+bcm_tx_setup() validates cf->len against the CAN/CAN FD DLC limits
+before installing frames for TX_SETUP, but bcm_rx_setup() never did
+the same for the RTR-reply frame configured via RX_SETUP with
+RX_RTR_FRAME.
+
+Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260714-bcm_fixes-v15-7-562f7e3e42da@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/bcm.c |   59 ++++++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 41 insertions(+), 18 deletions(-)
+
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -1276,22 +1276,37 @@ free_op:
+       return err;
+ }
+-static void bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
+-                                 struct bcm_op *op, void *new_frames)
++static int bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
++                                struct bcm_op *op, void *new_frames)
+ {
++      struct canfd_frame *frame0 = new_frames;
++
++      if (!(msg_head->flags & RX_RTR_FRAME))
++              return 0;
++
++      /* this frame is sent out as-is by bcm_can_tx() whenever a matching
++       * remote request is received, so validate its length the same way
++       * bcm_tx_setup() validates TX_SETUP frames before installing it
++       */
++      if (msg_head->flags & CAN_FD_FRAME) {
++              if (frame0->len > 64)
++                      return -EINVAL;
++      } else {
++              if (frame0->len > 8)
++                      return -EINVAL;
++      }
++
+       /* funny feature in RX(!)_SETUP only for RTR-mode:
+        * copy can_id into frame BUT without RTR-flag to
+        * prevent a full-load-loopback-test ... ;-]
+        * normalize this on the staged buffer, before it is
+        * ever installed into op->frames.
+        */
+-      if (msg_head->flags & RX_RTR_FRAME) {
+-              struct canfd_frame *frame0 = new_frames;
++      if ((msg_head->flags & TX_CP_CAN_ID) ||
++          frame0->can_id == op->can_id)
++              frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
+-              if ((msg_head->flags & TX_CP_CAN_ID) ||
+-                  frame0->can_id == op->can_id)
+-                      frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
+-      }
++      return 0;
+ }
+ /*
+@@ -1355,7 +1370,11 @@ static int bcm_rx_setup(struct bcm_msg_h
+                               return err;
+                       }
+-                      bcm_rx_setup_rtr_check(msg_head, op, new_frames);
++                      err = bcm_rx_setup_rtr_check(msg_head, op, new_frames);
++                      if (err < 0) {
++                              kfree(new_frames);
++                              return err;
++                      }
+               }
+               spin_lock_bh(&op->bcm_rx_update_lock);
+@@ -1436,16 +1455,12 @@ static int bcm_rx_setup(struct bcm_msg_h
+               if (msg_head->nframes) {
+                       err = memcpy_from_msg(op->frames, msg,
+                                             msg_head->nframes * op->cfsiz);
+-                      if (err < 0) {
+-                              if (op->frames != &op->sframe)
+-                                      kfree(op->frames);
+-                              if (op->last_frames != &op->last_sframe)
+-                                      kfree(op->last_frames);
+-                              kfree(op);
+-                              return err;
+-                      }
++                      if (err < 0)
++                              goto free_op;
+-                      bcm_rx_setup_rtr_check(msg_head, op, op->frames);
++                      err = bcm_rx_setup_rtr_check(msg_head, op, op->frames);
++                      if (err < 0)
++                              goto free_op;
+               }
+               /* bcm_can_tx / bcm_tx_timeout_handler needs this */
+@@ -1562,6 +1577,14 @@ static int bcm_rx_setup(struct bcm_msg_h
+       }
+       return msg_head->nframes * op->cfsiz + MHSIZ;
++
++free_op:
++      if (op->frames != &op->sframe)
++              kfree(op->frames);
++      if (op->last_frames != &op->last_sframe)
++              kfree(op->last_frames);
++      kfree(op);
++      return err;
+ }
+ /*
diff --git a/queue-7.1/can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch b/queue-7.1/can-esd_usb-kill-anchored-urbs-before-freeing-netdevs.patch
new file mode 100644 (file)
index 0000000..4ef373e
--- /dev/null
@@ -0,0 +1,54 @@
+From c43122fef328a70045fe7621c06de6b2b8e19264 Mon Sep 17 00:00:00 2001
+From: Fan Wu <fanwu01@zju.edu.cn>
+Date: Thu, 9 Jul 2026 16:41:59 +0000
+Subject: can: esd_usb: kill anchored URBs before freeing netdevs
+
+From: Fan Wu <fanwu01@zju.edu.cn>
+
+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 <fanwu01@zju.edu.cn>
+Link: https://patch.msgid.link/20260709164159.497640-1-fanwu01@zju.edu.cn
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1390,10 +1390,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-7.1/can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch b/queue-7.1/can-isotp-fix-use-after-free-race-with-concurrent-netdev_unregister.patch
new file mode 100644 (file)
index 0000000..aa61b94
--- /dev/null
@@ -0,0 +1,232 @@
+From 20bab8b88baac140ca3701116e1d486c7f51e311 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Sun, 12 Jul 2026 19:59:42 +0200
+Subject: can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+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 <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260712-isotp-fixes-v10-2-793a1b1ce17f@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/isotp.c |   87 +++++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 59 insertions(+), 28 deletions(-)
+
+--- a/net/can/isotp.c
++++ b/net/can/isotp.c
+@@ -152,6 +152,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;
+@@ -978,6 +980,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);
+@@ -1219,28 +1229,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
+@@ -1253,9 +1265,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;
+@@ -1310,6 +1319,7 @@ static int isotp_bind(struct socket *soc
+       if (!addr->can_ifindex)
+               return -ENODEV;
++      rtnl_lock();
+       lock_sock(sk);
+       if (so->bound) {
+@@ -1317,6 +1327,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;
+@@ -1329,14 +1350,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;
+@@ -1354,16 +1373,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;
+@@ -1566,7 +1594,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) {
+@@ -1582,10 +1610,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;
+@@ -1645,6 +1675,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-7.1/can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch b/queue-7.1/can-isotp-serialize-tx-state-transitions-under-so-rx_lock.patch
new file mode 100644 (file)
index 0000000..9f68573
--- /dev/null
@@ -0,0 +1,430 @@
+From cf070fe33bfbd1a4c21236078fadb35dd223a157 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Sun, 12 Jul 2026 19:59:43 +0200
+Subject: can: isotp: serialize TX state transitions under so->rx_lock
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+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 <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260712-isotp-fixes-v10-3-793a1b1ce17f@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/isotp.c |  202 ++++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 160 insertions(+), 42 deletions(-)
+
+--- a/net/can/isotp.c
++++ b/net/can/isotp.c
+@@ -158,7 +158,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;
+@@ -166,6 +166,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;
+@@ -378,6 +379,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))) {
+@@ -424,7 +434,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;
+@@ -577,6 +587,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;
+@@ -872,20 +890,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) {
+@@ -893,53 +927,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 */
+@@ -960,13 +1024,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;
+@@ -975,11 +1050,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
+        */
+@@ -1096,18 +1183,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;
+@@ -1120,13 +1222,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) {
+@@ -1142,14 +1241,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;
+@@ -1211,13 +1317,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);
+@@ -1263,6 +1376,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);
+@@ -1702,10 +1816,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-7.1/can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch b/queue-7.1/can-isotp-use-unconditional-synchronize_rcu-in-isotp_release.patch
new file mode 100644 (file)
index 0000000..5cfcfe6
--- /dev/null
@@ -0,0 +1,59 @@
+From 9b1a02e0d980ac6b0e36a90378f847062f81d7e4 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Sun, 12 Jul 2026 19:59:41 +0200
+Subject: can: isotp: use unconditional synchronize_rcu() in isotp_release()
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+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 <zdi-disclosures@trendmicro.com>
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Link: https://patch.msgid.link/20260712-isotp-fixes-v10-1-793a1b1ce17f@hartkopp.net
+Cc: stable@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/can/isotp.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/net/can/isotp.c
++++ b/net/can/isotp.c
+@@ -1237,11 +1237,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-7.1/dm-avoid-leaking-the-caller-s-thread-keyring-via-the-table-device-file.patch b/queue-7.1/dm-avoid-leaking-the-caller-s-thread-keyring-via-the-table-device-file.patch
new file mode 100644 (file)
index 0000000..54c24ca
--- /dev/null
@@ -0,0 +1,68 @@
+From 981ccd97f7153d310dfa92a534525bbaf46752c2 Mon Sep 17 00:00:00 2001
+From: Ingo Blechschmidt <iblech@speicherleck.de>
+Date: Wed, 17 Jun 2026 16:33:42 +0200
+Subject: dm: avoid leaking the caller's thread keyring via the table device file
+
+From: Ingo Blechschmidt <iblech@speicherleck.de>
+
+commit 981ccd97f7153d310dfa92a534525bbaf46752c2 upstream.
+
+The refactoring in commit a28d893eb327 ("md: port block device access to file")
+accidentally causes the caller's thread keyring to be kept alive long
+beyond the caller's lifetime.
+
+As a result, "cryptsetup luksSuspend" silently fails to wipe the
+LUKS volume key from memory.
+
+In detail: "cryptsetup luksOpen" uses its supposedly ephemeral thread
+keyring to pass the volume key to the kernel. dm-crypt's
+crypt_set_keyring_key() copies the key material into its own
+crypt_config structure and then drops its own reference to the key in
+the keyring with key_put().
+
+With this fix, restoring pre-v6.9 behavior, the copy in the thread
+keyring is then promptly garbage collected, such that exactly one copy
+of the volume key remains. This single copy is correctly wiped from
+memory on "cryptsetup luksSuspend".
+
+Without this fix, the thread keyring and the volume key in it remains.
+This second copy is only freed on "luksClose". "luksSuspend" neither
+knows about this copy nor has any way to remove it, so the key remains
+recoverable from RAM after a suspend that is documented to have wiped it.
+
+This fix should not introduce new security problems, as the code is
+anyway gated by CAP_SYS_ADMIN. The device-mapper core, not the calling
+task, is the legitimate owner of this long-lived file.
+
+Fixes: a28d893eb327 ("md: port block device access to file")
+Closes: https://gitlab.com/cryptsetup/cryptsetup/-/work_items/993
+Link: https://www.speicherleck.de/iblech/cryptsetup-luksSuspend-issue-reproduction/
+Signed-off-by: Ingo Blechschmidt <iblech@speicherleck.de>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Cc: stable@vger.kernel.org
+Tested-by: Ondrej Kozina <okozina@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm.c |   11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -735,7 +735,16 @@ static struct table_device *open_table_d
+               return ERR_PTR(-ENOMEM);
+       refcount_set(&td->count, 1);
+-      bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
++      /*
++       * Open the backing device with kernel rather than caller
++       * credentials. Otherwise the caller's credentials would be
++       * pinned in bdev_file->f_cred until the table device is closed.
++       * That would keep the caller's thread keyring alive long beyond the
++       * lifetime of the caller, breaking userspace expectation (e.g.
++       * cryptsetup(8) leaking the LUKS volume key).
++       */
++      scoped_with_kernel_creds()
++              bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
+       if (IS_ERR(bdev_file)) {
+               r = PTR_ERR(bdev_file);
+               goto out_free_td;
diff --git a/queue-7.1/dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch b/queue-7.1/dm-bufio-fix-wrong-count-calculation-in-dm_bufio_issue_discard.patch
new file mode 100644 (file)
index 0000000..92af9d9
--- /dev/null
@@ -0,0 +1,39 @@
+From 422f1d4f141eaa3a6e4199ceec86cc6b9bf26570 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Fri, 10 Jul 2026 18:32:49 +0200
+Subject: dm-bufio: fix wrong count calculation in dm_bufio_issue_discard
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Assisted-by: Claude:claude-opus-4-6
+Fixes: 6fbeb0048e6b ("dm bufio: implement discard")
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2238,7 +2238,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-7.1/dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch b/queue-7.1/dm-era-fix-out-of-bounds-memory-access-for-non-zero-start-sector.patch
new file mode 100644 (file)
index 0000000..6476292
--- /dev/null
@@ -0,0 +1,59 @@
+From a868196f03c2b19418ae3d2b69e195d668a271e5 Mon Sep 17 00:00:00 2001
+From: Samuel Moelius <sam.moelius@trailofbits.com>
+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 <sam.moelius@trailofbits.com>
+
+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 <sam.moelius@trailofbits.com>
+Reviewed-by: Ming-Hung Tsai <mtsai@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Cc: stable@vger.kernel.org
+Fixes: eec40579d848 ("dm: add era target")
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dm-integrity-don-t-increment-hash_offset-twice.patch b/queue-7.1/dm-integrity-don-t-increment-hash_offset-twice.patch
new file mode 100644 (file)
index 0000000..84aed68
--- /dev/null
@@ -0,0 +1,33 @@
+From edf025f083854f80032b73a1aad69a3c90db236f Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:24:09 +0200
+Subject: dm-integrity: don't increment hash_offset twice
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-integrity.c |    3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/md/dm-integrity.c
++++ b/drivers/md/dm-integrity.c
+@@ -1480,9 +1480,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-7.1/dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch b/queue-7.1/dm-integrity-fix-a-bug-if-the-bio-is-out-of-limits.patch
new file mode 100644 (file)
index 0000000..b6c2c4b
--- /dev/null
@@ -0,0 +1,46 @@
+From 5a266764fadaff8b5c1fe37a186ebf9b09cb953e Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+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 <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2523,6 +2523,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;
+@@ -2587,10 +2590,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-7.1/dm-integrity-fix-leaking-uninitialized-kernel-memory.patch b/queue-7.1/dm-integrity-fix-leaking-uninitialized-kernel-memory.patch
new file mode 100644 (file)
index 0000000..5faddd9
--- /dev/null
@@ -0,0 +1,33 @@
+From 7bb03b2b01b814a9fc14afbfc2cbb2cca5b34750 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:22:47 +0200
+Subject: dm-integrity: fix leaking uninitialized kernel memory
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2606,7 +2606,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-7.1/dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch b/queue-7.1/dm-ioctl-fix-a-possible-overflow-in-list_version_get_info.patch
new file mode 100644 (file)
index 0000000..733ee65
--- /dev/null
@@ -0,0 +1,36 @@
+From 76c6f845dc0c614304a6e6ee619b552f97cf24b3 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:31:47 +0200
+Subject: dm-ioctl: fix a possible overflow in list_version_get_info
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Assisted-by: Claude:claude-opus-4.6
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -698,7 +698,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-7.1/dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch b/queue-7.1/dm-log-fix-a-bitset_size-overflow-on-32bit-machines.patch
new file mode 100644 (file)
index 0000000..e685841
--- /dev/null
@@ -0,0 +1,45 @@
+From 9743132a41f4d9d0e54c5f2adcb821b04796bab1 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Thu, 2 Jul 2026 21:43:39 -0400
+Subject: dm-log: fix a bitset_size overflow on 32bit machines
+
+From: Benjamin Marzinski <bmarzins@redhat.com>
+
+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 <bmarzins@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dm-pcache-reject-option-groups-without-values.patch b/queue-7.1/dm-pcache-reject-option-groups-without-values.patch
new file mode 100644 (file)
index 0000000..5c0b0b1
--- /dev/null
@@ -0,0 +1,57 @@
+From d9c631e3fbd44246a2be781d26cfacbb9b8ec127 Mon Sep 17 00:00:00 2001
+From: Samuel Moelius <sam.moelius@trailofbits.com>
+Date: Mon, 29 Jun 2026 15:47:40 +0000
+Subject: dm-pcache: reject option groups without values
+
+From: Samuel Moelius <sam.moelius@trailofbits.com>
+
+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 <sam.moelius@trailofbits.com>
+Reviewed-by:  Zheng Gu <cengku@gmail.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper")
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-pcache/dm_pcache.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- 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_pc
+               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_pc
+                       }
+                       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;
diff --git a/queue-7.1/dm-stats-fix-dm_jiffies_to_msec64.patch b/queue-7.1/dm-stats-fix-dm_jiffies_to_msec64.patch
new file mode 100644 (file)
index 0000000..afa8f3c
--- /dev/null
@@ -0,0 +1,36 @@
+From 386df1a57b631c456d14f857cb0c0c2e11c16bef Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Fri, 10 Jul 2026 18:37:15 +0200
+Subject: dm-stats: fix dm_jiffies_to_msec64
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Assisted-by: Claude:claude-opus-4-6
+Fixes: fd2ed4d25270 ("dm: add statistics support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dm-stats-fix-merge-accounting.patch b/queue-7.1/dm-stats-fix-merge-accounting.patch
new file mode 100644 (file)
index 0000000..4802f09
--- /dev/null
@@ -0,0 +1,36 @@
+From 1917eb2db750ecbdf710f79a8042eaa545a063c7 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Fri, 10 Jul 2026 18:35:49 +0200
+Subject: dm-stats: fix merge accounting
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Assisted-by: Claude:claude-opus-4-6
+Fixes: fd2ed4d25270 ("dm: add statistics support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch b/queue-7.1/dm-thin-metadata-fix-metadata-snapshot-consistency-on-commit-failure.patch
new file mode 100644 (file)
index 0000000..5216c17
--- /dev/null
@@ -0,0 +1,235 @@
+From 5bcd4d3058ebaf46ad2e163829d87dd4870c7a45 Mon Sep 17 00:00:00 2001
+From: Ming-Hung Tsai <mtsai@redhat.com>
+Date: Tue, 30 Jun 2026 20:17:44 +0800
+Subject: dm thin metadata: fix metadata snapshot consistency on commit failure
+
+From: Ming-Hung Tsai <mtsai@redhat.com>
+
+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 <mtsai@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch b/queue-7.1/dm-thin-metadata-fix-superblock-refcount-leak-on-snapshot-shadow-failure.patch
new file mode 100644 (file)
index 0000000..6b75684
--- /dev/null
@@ -0,0 +1,38 @@
+From 4b22d0801fadfcae2e106e6ba32e49439c7c7ebf Mon Sep 17 00:00:00 2001
+From: Genjian Zhang <zhanggenjian@kylinos.cn>
+Date: Sat, 11 Jul 2026 18:05:26 +0800
+Subject: dm thin metadata: fix superblock refcount leak on snapshot shadow failure
+
+From: Genjian Zhang <zhanggenjian@kylinos.cn>
+
+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 <zhanggenjian@kylinos.cn>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Fixes: cc8394d86f04 ("dm thin: provide userspace access to pool metadata")
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &copy, &inc);
+-      if (r)
++      if (r) {
++              dm_sm_dec_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION);
+               return r;
++      }
+       BUG_ON(!inc);
diff --git a/queue-7.1/dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch b/queue-7.1/dm-verity-avoid-double-increment-of-use_bh_wq_enabled.patch
new file mode 100644 (file)
index 0000000..cf5f8cd
--- /dev/null
@@ -0,0 +1,37 @@
+From 72e9ec2fe32b00994f41719cf77423fca67d48b2 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:33:16 +0200
+Subject: dm-verity: avoid double increment of &use_bh_wq_enabled
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1262,6 +1262,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-7.1/dm-verity-fix-a-possible-null-pointer-dereference.patch b/queue-7.1/dm-verity-fix-a-possible-null-pointer-dereference.patch
new file mode 100644 (file)
index 0000000..55da5b6
--- /dev/null
@@ -0,0 +1,32 @@
+From e72b793ae440f6900fb17a4b8518c707b5cd3e17 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:35:06 +0200
+Subject: dm-verity: fix a possible NULL pointer dereference
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dm-verity-fix-buffer-overflow-in-fec-calculation.patch b/queue-7.1/dm-verity-fix-buffer-overflow-in-fec-calculation.patch
new file mode 100644 (file)
index 0000000..a3bbdf0
--- /dev/null
@@ -0,0 +1,68 @@
+From 31d6e6c0ba8d5a7bd59660035a089307100c5e8e Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 1 Jul 2026 18:13:50 +0200
+Subject: dm-verity: fix buffer overflow in FEC calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 31d6e6c0ba8d5a7bd59660035a089307100c5e8e upstream.
+
+There's a buffer overflow in dm-verity-fec:
+
+if (neras && *neras <= v->fec->roots)
+       fio->erasures[(*neras)++] = i;
+
+This allows *neras to reach roots + 1 (the post-increment pushes it past
+roots). This value is then passed as no_eras to decode_rs8(). Inside the
+RS decoder (lib/reed_solomon/decode_rs.c:113-121), the erasure locator
+polynomial loop writes lambda[j] where j can reach nroots + 1 â€” one
+element past the end of lambda[] (which is sized nroots + 1, valid
+indices 0..nroots). The out-of-bounds write lands on syn[0], corrupting
+the syndrome buffer.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Assisted-by: Claude:claude-opus-4-6
+Cc: stable@vger.kernel.org
+Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
+Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.c |    4 ++--
+ drivers/md/dm-verity-fec.h |    2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -220,7 +220,7 @@ static int fec_read_bufs(struct dm_verit
+                                    PTR_ERR(bbuf));
+                       /* assume the block is corrupted */
+-                      if (neras && *neras <= v->fec->roots)
++                      if (neras && *neras < v->fec->roots)
+                               fio->erasures[(*neras)++] = i;
+                       continue;
+@@ -238,7 +238,7 @@ static int fec_read_bufs(struct dm_verit
+                        * skip if we have already found the theoretical
+                        * maximum number (i.e. fec->roots) of erasures
+                        */
+-                      if (neras && *neras <= v->fec->roots &&
++                      if (neras && *neras < v->fec->roots &&
+                           fec_is_erasure(v, io, want_digest, bbuf))
+                               fio->erasures[(*neras)++] = i;
+               }
+--- a/drivers/md/dm-verity-fec.h
++++ b/drivers/md/dm-verity-fec.h
+@@ -47,7 +47,7 @@ struct dm_verity_fec {
+ /* per-bio data */
+ struct dm_verity_fec_io {
+       struct rs_control *rs;  /* Reed-Solomon state */
+-      int erasures[DM_VERITY_FEC_MAX_ROOTS + 1]; /* erasures for decode_rs8 */
++      int erasures[DM_VERITY_FEC_MAX_ROOTS]; /* erasures for decode_rs8 */
+       u8 *output;             /* buffer for corrected output */
+       unsigned int level;             /* recursion level */
+       unsigned int nbufs;             /* number of buffers allocated */
diff --git a/queue-7.1/dm-verity-increase-sprintf-buffer-size.patch b/queue-7.1/dm-verity-increase-sprintf-buffer-size.patch
new file mode 100644 (file)
index 0000000..c68261f
--- /dev/null
@@ -0,0 +1,35 @@
+From 88dd117c92a142253fb7a17e791773902b3babc6 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:36:01 +0200
+Subject: dm-verity: increase sprintf buffer size
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -26,7 +26,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-7.1/dm-verity-make-error-counter-atomic.patch b/queue-7.1/dm-verity-make-error-counter-atomic.patch
new file mode 100644 (file)
index 0000000..11f4e1a
--- /dev/null
@@ -0,0 +1,67 @@
+From 8ec4d9c5a5cf4b61fc087f871465b1f79b393325 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:37:38 +0200
+Subject: dm-verity: make error counter atomic
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -180,14 +180,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:
+@@ -203,7 +205,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
+@@ -68,7 +68,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-7.1/dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch b/queue-7.1/dm_early_create-fix-freeing-used-table-on-dm_resume-failure.patch
new file mode 100644 (file)
index 0000000..558987b
--- /dev/null
@@ -0,0 +1,34 @@
+From 366665416f20527ff7cad548a32d1ddf23195740 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Jul 2026 21:29:11 +0200
+Subject: dm_early_create: fix freeing used table on dm_resume failure
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+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 <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2351,7 +2351,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-7.1/dma-buf-dma-fence-fix-potential-null-pointer-dereference.patch b/queue-7.1/dma-buf-dma-fence-fix-potential-null-pointer-dereference.patch
new file mode 100644 (file)
index 0000000..1c422f7
--- /dev/null
@@ -0,0 +1,71 @@
+From 035219a760edb35ae9a9e96beba7f122e26a997b Mon Sep 17 00:00:00 2001
+From: Philipp Stanner <phasta@kernel.org>
+Date: Mon, 29 Jun 2026 09:56:37 +0200
+Subject: dma-buf: dma-fence: Fix potential NULL pointer dereference
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Philipp Stanner <phasta@kernel.org>
+
+commit 035219a760edb35ae9a9e96beba7f122e26a997b upstream.
+
+The commit mentioned in the fixes tag below introduced a mechanism
+through which fence producers can fully decouple from fence consumers.
+This, desirable, mechanism is based on the fence's signaled-bit as the
+"decoupling point".
+
+A sophisticated interaction between RCU and atomic instructions attempts
+to ensure that fence consumers can still interact with fence producers
+through the dma_fence_ops (callback pointers into the producer).
+
+This is the desired behavior: to check for decoupling, the signaled-bit
+is first checked. If it's not yet signaled, RCU ensures that the ops
+pointer cannot yet be NULL.
+
+Hereby, dma_fence_signal_timestamp_locked() first sets the signaled-bit,
+and then sets the ops pointer to NULL. Readers first load the ops
+pointer, and then check through the signaled-bit whether the pointer can
+legally be accessed.
+
+These set and load operations could occur out of order on weakly ordered
+platforms. This problem can be solved very elegantly by using the ops
+pointer itself as the synchronization point. The pointer is either NULL,
+or cannot become NULL while it is being used thanks to RCU.
+
+Replace the signaled-bit check in dma_fence_timeline_name() and
+dma_fence_driver_name().
+
+Cc: stable@vger.kernel.org
+Fixes: f4cc3ab824d6 ("dma-buf: protected fence ops by RCU v8")
+Signed-off-by: Philipp Stanner <phasta@kernel.org>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Reviewed-by: Danilo Krummrich <dakr@kernel.org>
+Link: https://lore.kernel.org/r/20260629075636.2513214-2-phasta@kernel.org
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma-buf/dma-fence.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma-buf/dma-fence.c
++++ b/drivers/dma-buf/dma-fence.c
+@@ -1168,7 +1168,7 @@ const char __rcu *dma_fence_driver_name(
+       /* RCU protection is required for safe access to returned string */
+       ops = rcu_dereference(fence->ops);
+-      if (!dma_fence_test_signaled_flag(fence))
++      if (ops)
+               return (const char __rcu *)ops->get_driver_name(fence);
+       else
+               return (const char __rcu *)"detached-driver";
+@@ -1201,7 +1201,7 @@ const char __rcu *dma_fence_timeline_nam
+       /* RCU protection is required for safe access to returned string */
+       ops = rcu_dereference(fence->ops);
+-      if (!dma_fence_test_signaled_flag(fence))
++      if (ops)
+               return (const char __rcu *)ops->get_timeline_name(fence);
+       else
+               return (const char __rcu *)"signaled-timeline";
diff --git a/queue-7.1/dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch b/queue-7.1/dma-fence-make-dma_fence_dedup_array-robust-against-0-count-input.patch
new file mode 100644 (file)
index 0000000..d148e7b
--- /dev/null
@@ -0,0 +1,50 @@
+From 77a9298741f8f9e8b963c977f5582ab21c6d3427 Mon Sep 17 00:00:00 2001
+From: Baineng Shou <shoubaineng@gmail.com>
+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 <shoubaineng@gmail.com>
+
+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 <shoubaineng@gmail.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Fixes: 575ec9b0c2f1 ("dma-fence: Add helper to sort and deduplicate dma_fence arrays")
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Link: https://lore.kernel.org/r/20260629031346.3875683-1-shoubaineng@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/dma-fence-use-correct-callback-in-dma_fence_timeline_name.patch b/queue-7.1/dma-fence-use-correct-callback-in-dma_fence_timeline_name.patch
new file mode 100644 (file)
index 0000000..1956638
--- /dev/null
@@ -0,0 +1,41 @@
+From 032a6f6ce21fc701468fd15403d2f53a30107f5b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andr=C3=A9=20Draszik?= <andre.draszik@linaro.org>
+Date: Thu, 18 Jun 2026 13:00:39 +0100
+Subject: dma-fence: use correct callback in dma_fence_timeline_name()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: André Draszik <andre.draszik@linaro.org>
+
+commit 032a6f6ce21fc701468fd15403d2f53a30107f5b upstream.
+
+dma_fence_timeline_name() is a wrapper around
+dma_fence_ops::get_timeline_name(). Since the blamed commit below, it
+calls an incorrect callback.
+
+Update it to restore functionality by calling the intended callback.
+
+Fixes: 62918542b7bf ("dma-fence: Fix sparse warnings due __rcu annotations")
+Cc: <stable@vger.kernel.org> # v7.1+
+[tursulin: added cc stable]
+Signed-off-by: André Draszik <andre.draszik@linaro.org>
+Reviewed-by: Philipp Stanner <phasta@kernel.org>
+Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
+Link: https://lore.kernel.org/r/20260618-linux-drm_crtc_fix-v1-1-801f29c9853d@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma-buf/dma-fence.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/dma-buf/dma-fence.c
++++ b/drivers/dma-buf/dma-fence.c
+@@ -1202,7 +1202,7 @@ const char __rcu *dma_fence_timeline_nam
+       /* RCU protection is required for safe access to returned string */
+       ops = rcu_dereference(fence->ops);
+       if (!dma_fence_test_signaled_flag(fence))
+-              return (const char __rcu *)ops->get_driver_name(fence);
++              return (const char __rcu *)ops->get_timeline_name(fence);
+       else
+               return (const char __rcu *)"signaled-timeline";
+ }
diff --git a/queue-7.1/dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch b/queue-7.1/dmaengine-dw-edma-add-spinlock-to-protect-done_int_mask-and-abort_int_mask.patch
new file mode 100644 (file)
index 0000000..de2cd47
--- /dev/null
@@ -0,0 +1,72 @@
+From 8ffba0171c6bbce5f093c6dba5a02c0805b31203 Mon Sep 17 00:00:00 2001
+From: Frank Li <Frank.Li@nxp.com>
+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 <Frank.Li@nxp.com>
+
+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 <Frank.Li@nxp.com>
+[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 <den@valinux.co.jp>
+Link: https://patch.msgid.link/20260521142153.2957432-5-den@valinux.co.jp
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -109,7 +109,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-7.1/dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch b/queue-7.1/dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch
new file mode 100644 (file)
index 0000000..724c90f
--- /dev/null
@@ -0,0 +1,39 @@
+From 11d7cfe0c119691b2dafbb699bbca90258c678aa Mon Sep 17 00:00:00 2001
+From: Koichiro Den <den@valinux.co.jp>
+Date: Thu, 21 May 2026 23:21:51 +0900
+Subject: dmaengine: dw-edma-pcie: Reject devices without driver data
+
+From: Koichiro Den <den@valinux.co.jp>
+
+commit 11d7cfe0c119691b2dafbb699bbca90258c678aa upstream.
+
+dw_edma_pcie_probe() treats the PCI device ID driver_data as the
+template for the controller layout and copies it unconditionally. A
+device bound dynamically via sysfs can match the driver without that
+data, which leads to a NULL pointer dereference.
+
+Reject such matches before enabling the device.
+
+Fixes: 41aaff2a2ac0 ("dmaengine: Add Synopsys eDMA IP PCIe glue-logic")
+Cc: stable@vger.kernel.org
+Signed-off-by: Koichiro Den <den@valinux.co.jp>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Link: https://patch.msgid.link/20260521142153.2957432-3-den@valinux.co.jp
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma/dw-edma/dw-edma-pcie.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/dma/dw-edma/dw-edma-pcie.c
++++ b/drivers/dma/dw-edma/dw-edma-pcie.c
+@@ -314,6 +314,9 @@ static int dw_edma_pcie_probe(struct pci
+       int i, mask;
+       bool non_ll = false;
++      if (!pdata)
++              return -ENODEV;
++
+       struct dw_edma_pcie_data *vsec_data __free(kfree) =
+               kmalloc_obj(*vsec_data);
+       if (!vsec_data)
diff --git a/queue-7.1/dmaengine-sh-rz-dmac-fix-incorrect-null-check-for-list_first_entry.patch b/queue-7.1/dmaengine-sh-rz-dmac-fix-incorrect-null-check-for-list_first_entry.patch
new file mode 100644 (file)
index 0000000..f293304
--- /dev/null
@@ -0,0 +1,43 @@
+From 5fbf3a2a3b96ef5810e6e0fbc601f82067629bc5 Mon Sep 17 00:00:00 2001
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Date: Tue, 26 May 2026 11:46:54 +0300
+Subject: dmaengine: sh: rz-dmac: Fix incorrect NULL check for list_first_entry()
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+commit 5fbf3a2a3b96ef5810e6e0fbc601f82067629bc5 upstream.
+
+list_first_entry() does not return NULL when the list is empty,
+making the existing NULL check invalid. Use list_first_entry_or_null()
+instead.
+
+Fixes: 21323b118c16 ("dmaengine: sh: rz-dmac: Add device_tx_status() callback")
+Cc: stable@vger.kernel.org
+Tested-by: John Madieu <john.madieu.xa@bp.renesas.com>
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
+Link: https://patch.msgid.link/20260526084710.3491480-3-claudiu.beznea@kernel.org
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma/sh/rz-dmac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
+index 9f206a33dcc6..6d80cb668957 100644
+--- a/drivers/dma/sh/rz-dmac.c
++++ b/drivers/dma/sh/rz-dmac.c
+@@ -723,8 +723,8 @@ static u32 rz_dmac_chan_get_residue(struct rz_dmac_chan *channel,
+       u32 crla, crtb, i;
+       /* Get current processing virtual descriptor */
+-      current_desc = list_first_entry(&channel->ld_active,
+-                                      struct rz_dmac_desc, node);
++      current_desc = list_first_entry_or_null(&channel->ld_active,
++                                              struct rz_dmac_desc, node);
+       if (!current_desc)
+               return 0;
+-- 
+2.55.0
+
diff --git a/queue-7.1/dmaengine-sh-rz-dmac-move-interrupt-request-after-everything-is-set-up.patch b/queue-7.1/dmaengine-sh-rz-dmac-move-interrupt-request-after-everything-is-set-up.patch
new file mode 100644 (file)
index 0000000..d2dacee
--- /dev/null
@@ -0,0 +1,180 @@
+From 731712403ddb39d1a76a11abf339a0615bc85de7 Mon Sep 17 00:00:00 2001
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Date: Tue, 26 May 2026 11:46:53 +0300
+Subject: dmaengine: sh: rz-dmac: Move interrupt request after everything is set up
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+commit 731712403ddb39d1a76a11abf339a0615bc85de7 upstream.
+
+Once the interrupt is requested, the interrupt handler may run immediately.
+Since the IRQ handler can access channel->ch_base, which is initialized
+only after requesting the IRQ, this may lead to invalid memory access.
+Likewise, the IRQ thread may access uninitialized data (the ld_free,
+ld_queue, and ld_active lists), which may also lead to issues.
+
+Request the interrupts only after everything is set up. To keep the error
+path simpler, use dmam_alloc_coherent() instead of dma_alloc_coherent().
+
+Fixes: 5000d37042a6 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC")
+Cc: stable@vger.kernel.org
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Tested-by: John Madieu <john.madieu.xa@bp.renesas.com>
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
+Link: https://patch.msgid.link/20260526084710.3491480-2-claudiu.beznea@kernel.org
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma/sh/rz-dmac.c |   88 +++++++++++++++++------------------------------
+ 1 file changed, 33 insertions(+), 55 deletions(-)
+
+--- a/drivers/dma/sh/rz-dmac.c
++++ b/drivers/dma/sh/rz-dmac.c
+@@ -981,25 +981,6 @@ static int rz_dmac_chan_probe(struct rz_
+       channel->index = index;
+       channel->mid_rid = -EINVAL;
+-      /* Request the channel interrupt. */
+-      scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index);
+-      irq = platform_get_irq_byname(pdev, pdev_irqname);
+-      if (irq < 0)
+-              return irq;
+-
+-      irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
+-                               dev_name(dmac->dev), index);
+-      if (!irqname)
+-              return -ENOMEM;
+-
+-      ret = devm_request_threaded_irq(dmac->dev, irq, rz_dmac_irq_handler,
+-                                      rz_dmac_irq_handler_thread, 0,
+-                                      irqname, channel);
+-      if (ret) {
+-              dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", irq, ret);
+-              return ret;
+-      }
+-
+       /* Set io base address for each channel */
+       if (index < 8) {
+               channel->ch_base = dmac->base + CHANNEL_0_7_OFFSET +
+@@ -1012,9 +993,9 @@ static int rz_dmac_chan_probe(struct rz_
+       }
+       /* Allocate descriptors */
+-      lmdesc = dma_alloc_coherent(&pdev->dev,
+-                                  sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+-                                  &channel->lmdesc.base_dma, GFP_KERNEL);
++      lmdesc = dmam_alloc_coherent(&pdev->dev,
++                                   sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
++                                   &channel->lmdesc.base_dma, GFP_KERNEL);
+       if (!lmdesc) {
+               dev_err(&pdev->dev, "Can't allocate memory (lmdesc)\n");
+               return -ENOMEM;
+@@ -1030,7 +1011,24 @@ static int rz_dmac_chan_probe(struct rz_
+       INIT_LIST_HEAD(&channel->ld_free);
+       INIT_LIST_HEAD(&channel->ld_active);
+-      return 0;
++      /* Request the channel interrupt. */
++      scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index);
++      irq = platform_get_irq_byname(pdev, pdev_irqname);
++      if (irq < 0)
++              return irq;
++
++      irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
++                               dev_name(dmac->dev), index);
++      if (!irqname)
++              return -ENOMEM;
++
++      ret = devm_request_threaded_irq(dmac->dev, irq, rz_dmac_irq_handler,
++                                      rz_dmac_irq_handler_thread, 0,
++                                      irqname, channel);
++      if (ret)
++              dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", irq, ret);
++
++      return ret;
+ }
+ static void rz_dmac_put_device(void *_dev)
+@@ -1099,7 +1097,6 @@ static int rz_dmac_probe(struct platform
+       const char *irqname = "error";
+       struct dma_device *engine;
+       struct rz_dmac *dmac;
+-      int channel_num;
+       int ret;
+       int irq;
+       u8 i;
+@@ -1132,18 +1129,6 @@ static int rz_dmac_probe(struct platform
+                       return PTR_ERR(dmac->ext_base);
+       }
+-      /* Register interrupt handler for error */
+-      irq = platform_get_irq_byname_optional(pdev, irqname);
+-      if (irq > 0) {
+-              ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0,
+-                                     irqname, NULL);
+-              if (ret) {
+-                      dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
+-                              irq, ret);
+-                      return ret;
+-              }
+-      }
+-
+       /* Initialize the channels. */
+       INIT_LIST_HEAD(&dmac->engine.channels);
+@@ -1169,6 +1154,18 @@ static int rz_dmac_probe(struct platform
+                       goto err;
+       }
++      /* Register interrupt handler for error */
++      irq = platform_get_irq_byname_optional(pdev, irqname);
++      if (irq > 0) {
++              ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0,
++                                     irqname, NULL);
++              if (ret) {
++                      dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
++                              irq, ret);
++                      goto err;
++              }
++      }
++
+       /* Register the DMAC as a DMA provider for DT. */
+       ret = of_dma_controller_register(pdev->dev.of_node, rz_dmac_of_xlate,
+                                        NULL);
+@@ -1210,16 +1207,6 @@ static int rz_dmac_probe(struct platform
+ dma_register_err:
+       of_dma_controller_free(pdev->dev.of_node);
+ err:
+-      channel_num = i ? i - 1 : 0;
+-      for (i = 0; i < channel_num; i++) {
+-              struct rz_dmac_chan *channel = &dmac->channels[i];
+-
+-              dma_free_coherent(&pdev->dev,
+-                                sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+-                                channel->lmdesc.base,
+-                                channel->lmdesc.base_dma);
+-      }
+-
+       reset_control_assert(dmac->rstc);
+ err_pm_runtime_put:
+       pm_runtime_put(&pdev->dev);
+@@ -1232,18 +1219,9 @@ err_pm_disable:
+ static void rz_dmac_remove(struct platform_device *pdev)
+ {
+       struct rz_dmac *dmac = platform_get_drvdata(pdev);
+-      unsigned int i;
+       dma_async_device_unregister(&dmac->engine);
+       of_dma_controller_free(pdev->dev.of_node);
+-      for (i = 0; i < dmac->n_channels; i++) {
+-              struct rz_dmac_chan *channel = &dmac->channels[i];
+-
+-              dma_free_coherent(&pdev->dev,
+-                                sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+-                                channel->lmdesc.base,
+-                                channel->lmdesc.base_dma);
+-      }
+       reset_control_assert(dmac->rstc);
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
diff --git a/queue-7.1/dmaengine-tegra-fix-burst-size-calculation.patch b/queue-7.1/dmaengine-tegra-fix-burst-size-calculation.patch
new file mode 100644 (file)
index 0000000..df3bd94
--- /dev/null
@@ -0,0 +1,51 @@
+From 4651df83b6c796daead3447e8fd874322918ee4f Mon Sep 17 00:00:00 2001
+From: Kartik Rajput <kkartik@nvidia.com>
+Date: Wed, 22 Apr 2026 12:11:34 +0530
+Subject: dmaengine: tegra: Fix burst size calculation
+
+From: Kartik Rajput <kkartik@nvidia.com>
+
+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 <kkartik@nvidia.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
+Link: https://patch.msgid.link/20260422064134.1323610-1-kkartik@nvidia.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch b/queue-7.1/fpga-dfl-add-bounds-check-in-dfh_get_param_size.patch
new file mode 100644 (file)
index 0000000..4bb5fb2
--- /dev/null
@@ -0,0 +1,43 @@
+From 9e8bc49f91f3f81d957c4f1c1f09fe94e2f88f6a Mon Sep 17 00:00:00 2001
+From: Sebastian Alba Vives <sebasjosue84@gmail.com>
+Date: Mon, 18 May 2026 13:07:40 -0600
+Subject: fpga: dfl: add bounds check in dfh_get_param_size()
+
+From: Sebastian Alba Vives <sebasjosue84@gmail.com>
+
+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 <sebasjosue84@gmail.com>
+Reviewed-by: Xu Yilun <yilun.xu@intel.com>
+Link: https://lore.kernel.org/r/20260518190742.61426-2-sebasjosue84@gmail.com
+Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/fpga/dfl.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/fpga/dfl.c
++++ b/drivers/fpga/dfl.c
+@@ -1132,6 +1132,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-7.1/fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch b/queue-7.1/fpga-microchip-spi-fix-zero-header_size-oob-read-in-mpf_ops_parse_header.patch
new file mode 100644 (file)
index 0000000..8f8ac0f
--- /dev/null
@@ -0,0 +1,41 @@
+From 43a1974da6bc7ce8f4d1dc1d03d56997428c29c3 Mon Sep 17 00:00:00 2001
+From: Sebastian Alba Vives <sebasjosue84@gmail.com>
+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 <sebasjosue84@gmail.com>
+
+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 <sebasjosue84@gmail.com>
+Reviewed-by: Xu Yilun <yilun.xu@intel.com>
+Link: https://lore.kernel.org/r/20260518190742.61426-4-sebasjosue84@gmail.com
+Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch b/queue-7.1/hwmon-ltc2992-add-missing-select-regmap_i2c-to-kconfig.patch
new file mode 100644 (file)
index 0000000..4f33961
--- /dev/null
@@ -0,0 +1,33 @@
+From a35a6f1b20100057c66b7be5a8f6864661c3945c Mon Sep 17 00:00:00 2001
+From: Joshua Crofts <joshua.crofts1@gmail.com>
+Date: Mon, 29 Jun 2026 21:17:40 +0200
+Subject: hwmon: (ltc2992) add missing 'select REGMAP_I2C' to Kconfig
+
+From: Joshua Crofts <joshua.crofts1@gmail.com>
+
+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 <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260629-add-kconfig-deps-v1-2-8104df929b1a@gmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hwmon/Kconfig |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -1076,6 +1076,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-7.1/hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch b/queue-7.1/hwmon-max6697-add-missing-select-regmap_i2c-to-kconfig.patch
new file mode 100644 (file)
index 0000000..5150d90
--- /dev/null
@@ -0,0 +1,33 @@
+From ed576f2f4eef8cbe2c110da503825a8dc4717030 Mon Sep 17 00:00:00 2001
+From: Joshua Crofts <joshua.crofts1@gmail.com>
+Date: Mon, 29 Jun 2026 21:17:41 +0200
+Subject: hwmon: (max6697) add missing 'select REGMAP_I2C' to Kconfig
+
+From: Joshua Crofts <joshua.crofts1@gmail.com>
+
+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 <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260629-add-kconfig-deps-v1-3-8104df929b1a@gmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hwmon/Kconfig |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -1333,6 +1333,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-7.1/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch b/queue-7.1/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-atomic.patch
new file mode 100644 (file)
index 0000000..8684c34
--- /dev/null
@@ -0,0 +1,83 @@
+From cb2fc37857693b55909fb77dc2c87cfbc1cdc476 Mon Sep 17 00:00:00 2001
+From: Vincent Jardin <vjardin@free.fr>
+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 <vjardin@free.fr>
+
+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 <vjardin@free.fr>
+Cc: <stable@vger.kernel.org> # v3.16+
+Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Acked-by: Carlos Song <carlos.song@nxp.com>
+Reviewed-by: Stefan Eichenberger <eichest@gmail.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260713-for-upstream-i2c-lx2160-fix-v1-v3-1-073ac9e103a5@free.fr
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch b/queue-7.1/i2c-imx-fix-locked-bus-on-smbus-block-read-of-0-irq.patch
new file mode 100644 (file)
index 0000000..9895488
--- /dev/null
@@ -0,0 +1,72 @@
+From 07fd9385f0d87dff4b34f355f68adf701080cb24 Mon Sep 17 00:00:00 2001
+From: Vincent Jardin <vjardin@free.fr>
+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 <vjardin@free.fr>
+
+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 <vjardin@free.fr>
+Cc: <stable@vger.kernel.org> # v6.13+
+Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Acked-by: Carlos Song <carlos.song@nxp.com>
+Reviewed-by: Stefan Eichenberger <eichest@gmail.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260713-for-upstream-i2c-lx2160-fix-v1-v3-2-073ac9e103a5@free.fr
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch b/queue-7.1/i2c-mediatek-fix-wrrd-for-socs-without-auto_restart-option.patch
new file mode 100644 (file)
index 0000000..664023b
--- /dev/null
@@ -0,0 +1,37 @@
+From deb35336b5bfed5db9231b5348bc1514db930797 Mon Sep 17 00:00:00 2001
+From: Roman Vivchar <rva333@protonmail.com>
+Date: Thu, 9 Jul 2026 16:31:29 +0300
+Subject: i2c: mediatek: fix WRRD for SoCs without auto_restart option
+
+From: Roman Vivchar <rva333@protonmail.com>
+
+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 <rva333@protonmail.com>
+Cc: <stable@vger.kernel.org> # v6.18+
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260709-6572-6595-i2c-v2-1-b2fb8510d1d3@protonmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1258,7 +1258,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-7.1/i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch b/queue-7.1/i2c-mlxbf-fix-use-after-free-in-mlxbf_i2c_init_resource.patch
new file mode 100644 (file)
index 0000000..addc16a
--- /dev/null
@@ -0,0 +1,39 @@
+From 71356737a7a55c76fee847563e3d33f8e6dc6b6d Mon Sep 17 00:00:00 2001
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Date: Tue, 14 Jul 2026 23:08:08 +0800
+Subject: i2c: mlxbf: Fix use-after-free in mlxbf_i2c_init_resource()
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+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 <luoxuanqiang@kylinos.cn>
+Cc: <stable@vger.kernel.org> # v5.10+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260714150808.85045-1-xuanqiang.luo@linux.dev
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1051,8 +1051,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-7.1/i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch b/queue-7.1/i2c-spacemit-fix-spurious-irq-handling-returning-irq_handled.patch
new file mode 100644 (file)
index 0000000..5472077
--- /dev/null
@@ -0,0 +1,39 @@
+From 9db20d23aac7916ff49be409a4bfd48fe7cbbfb4 Mon Sep 17 00:00:00 2001
+From: Pei Xiao <xiaopei01@kylinos.cn>
+Date: Fri, 10 Jul 2026 15:21:13 +0800
+Subject: i2c: spacemit: fix spurious IRQ handling returning IRQ_HANDLED
+
+From: Pei Xiao <xiaopei01@kylinos.cn>
+
+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 <xiaopei01@kylinos.cn>
+Cc: <stable@vger.kernel.org> # v6.15+
+Reviewed-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
+Reviewed-by: Mukesh Savaliya <mukesh.savaliya@oss.qualcomm.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/ef8b623f45d4e430721e46572c2598d882044aed.1783667875.git.xiaopei01@kylinos.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -596,7 +596,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-7.1/ice-fix-ice_init_link-error-return-preventing-probe.patch b/queue-7.1/ice-fix-ice_init_link-error-return-preventing-probe.patch
new file mode 100644 (file)
index 0000000..653ee0a
--- /dev/null
@@ -0,0 +1,91 @@
+From eb509638686b0f8a98a0dd9c809f6a8db4d73a45 Mon Sep 17 00:00:00 2001
+From: Paul Greenwalt <paul.greenwalt@intel.com>
+Date: Wed, 8 Apr 2026 16:11:05 +0200
+Subject: ice: fix ice_init_link() error return preventing probe
+
+From: Paul Greenwalt <paul.greenwalt@intel.com>
+
+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 <paul.greenwalt@intel.com>
+Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Tested-by: Alexander Nowlin <alexander.nowlin@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -4789,16 +4789,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);
+@@ -4838,8 +4836,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)
+@@ -4982,13 +4978,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);
+@@ -5007,7 +5001,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-7.1/io_uring-bpf-ops-reject-re-registration-of-an-already-bound-ops.patch b/queue-7.1/io_uring-bpf-ops-reject-re-registration-of-an-already-bound-ops.patch
new file mode 100644 (file)
index 0000000..1ae669f
--- /dev/null
@@ -0,0 +1,53 @@
+From 3afc64c61ce906a04f073ca350b46de10e8302f9 Mon Sep 17 00:00:00 2001
+From: Woraphat Khiaodaeng <worapat.kd2@gmail.com>
+Date: Fri, 17 Jul 2026 22:45:37 +0700
+Subject: io_uring/bpf-ops: reject re-registration of an already-bound ops
+
+From: Woraphat Khiaodaeng <worapat.kd2@gmail.com>
+
+commit 3afc64c61ce906a04f073ca350b46de10e8302f9 upstream.
+
+io_install_bpf() only rejects a second registration on the ctx side
+(ctx->bpf_ops) and sets the per-map back-pointer ops->priv
+unconditionally. The struct_ops link path never advances a map past
+BPF_STRUCT_OPS_STATE_READY, so the same io_uring_bpf_ops map can be
+registered more than once, and bpf_io_reg() re-resolves the target ring
+via fget(ops->ring_fd) on every call. A caller can therefore point the
+same ring_fd at a different io_ring_ctx between two BPF_LINK_CREATE
+calls.
+
+The second registration passes the ctx->bpf_ops check (the new ctx has
+none) and overwrites ops->priv, orphaning the first ctx. Teardown
+(io_eject_bpf()/bpf_io_unreg()) only reaches a ctx through ops->priv, so
+the orphaned ctx is never torn down: its ctx->loop_step keeps pointing
+into the struct_ops trampoline, which is freed once the map is gone. A
+later io_uring_enter() on the orphaned ring then calls the dangling
+ctx->loop_step from io_run_loop() -- a use-after-free of freed
+executable memory, reachable by a task with CAP_BPF + CAP_PERFMON.
+
+Reject registration when ops->priv is already set, as hid_bpf_reg()
+does for its struct_ops.
+
+Cc: stable@vger.kernel.org
+Fixes: 98f37634b12b ("io_uring/bpf-ops: implement bpf ops registration")
+Signed-off-by: Woraphat Khiaodaeng <worapat.kd2@gmail.com>
+Reviewed-by: Gabriel Krisman Bertazi <krisman@suse.de>
+Reviewed-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://patch.msgid.link/20260717154537.129736-1-worapat.kd2@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/bpf-ops.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/io_uring/bpf-ops.c
++++ b/io_uring/bpf-ops.c
+@@ -165,6 +165,8 @@ static int io_install_bpf(struct io_ring
+       if (ctx->bpf_ops)
+               return -EBUSY;
++      if (ops->priv)
++              return -EBUSY;
+       if (WARN_ON_ONCE(!ops->loop_step))
+               return -EINVAL;
diff --git a/queue-7.1/irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch b/queue-7.1/irqchip-crossbar-use-correct-index-in-crossbar_domain_free.patch
new file mode 100644 (file)
index 0000000..df8b4d5
--- /dev/null
@@ -0,0 +1,52 @@
+From 043db005a8d6932dc7d217c86307e9af0bc10ddc Mon Sep 17 00:00:00 2001
+From: Bhargav Joshi <j.bhargav.u@gmail.com>
+Date: Sat, 20 Jun 2026 17:39:16 +0530
+Subject: irqchip/crossbar: Use correct index in crossbar_domain_free()
+
+From: Bhargav Joshi <j.bhargav.u@gmail.com>
+
+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 <j.bhargav.u@gmail.com>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+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 <gregkh@linuxfoundation.org>
+---
+ 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-7.1/ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch b/queue-7.1/ksmbd-fix-integer-overflow-in-set_file_allocation_info.patch
new file mode 100644 (file)
index 0000000..f399ce8
--- /dev/null
@@ -0,0 +1,104 @@
+From 1c0ae3df692ea2a4ce992f786346154e75a3f0d5 Mon Sep 17 00:00:00 2001
+From: Ibrahim Hashimov <security@auditcode.ai>
+Date: Thu, 9 Jul 2026 17:05:30 +0200
+Subject: ksmbd: fix integer overflow in set_file_allocation_info()
+
+From: Ibrahim Hashimov <security@auditcode.ai>
+
+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 <security@auditcode.ai>
+Assisted-by: AuditCode-AI:2026.07
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -6382,6 +6382,7 @@ static int set_file_allocation_info(stru
+        */
+       loff_t alloc_blks;
++      u64 alloc_size;
+       struct inode *inode;
+       struct kstat stat;
+       int rc;
+@@ -6397,7 +6398,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-7.1/mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch b/queue-7.1/mtd-maps-vmu-flash-fix-null-pointer-dereference-in-initialization.patch
new file mode 100644 (file)
index 0000000..d209272
--- /dev/null
@@ -0,0 +1,32 @@
+From 357e3b8e3a8769ba36eb8ec5e053e4825f1a9329 Mon Sep 17 00:00:00 2001
+From: Florian Fuchs <fuchsfl@gmail.com>
+Date: Mon, 18 May 2026 13:45:21 +0200
+Subject: mtd: maps: vmu-flash: fix NULL pointer dereference in initialization
+
+From: Florian Fuchs <fuchsfl@gmail.com>
+
+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 <fuchsfl@gmail.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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_obj(struct vmu_cache);
+       if (!pcache)
diff --git a/queue-7.1/mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch b/queue-7.1/mtd-rawnand-pause-continuous-reads-at-block-boundaries.patch
new file mode 100644 (file)
index 0000000..c3f6120
--- /dev/null
@@ -0,0 +1,68 @@
+From 8e4531667d718e2e9b193928cf9b2497fa0d01ef Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Fri, 22 May 2026 11:17:39 +0200
+Subject: mtd: rawnand: Pause continuous reads at block boundaries
+
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+
+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 <miquel.raynal@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1216,32 +1216,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-7.1/mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch b/queue-7.1/mtd-spi-nor-spansion-use-die-erase-for-multi-die-devices-only.patch
new file mode 100644 (file)
index 0000000..acafc62
--- /dev/null
@@ -0,0 +1,41 @@
+From 306e443156b82a2a14a3f33da908c303be45529c Mon Sep 17 00:00:00 2001
+From: Takahiro Kuwano <takahiro.kuwano@infineon.com>
+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 <takahiro.kuwano@infineon.com>
+
+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 <pratyush@kernel.org>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com>
+Reviewed-by: Michael Walle <mwalle@kernel.org>
+Signed-off-by: Pratyush Yadav <pratyush@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/mtd-spi-nor-swp-improve-locking-user-experience.patch b/queue-7.1/mtd-spi-nor-swp-improve-locking-user-experience.patch
new file mode 100644 (file)
index 0000000..ed64415
--- /dev/null
@@ -0,0 +1,57 @@
+From e1d456b26bf23e30db305a6184e8abd9ab68bbf2 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Tue, 26 May 2026 16:56:26 +0200
+Subject: mtd: spi-nor: swp: Improve locking user experience
+
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+
+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 <miquel.raynal@bootlin.com>
+Reviewed-by: Michael Walle <mwalle@kernel.org>
+Signed-off-by: Pratyush Yadav <pratyush@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/net-sparx5-unregister-blocking-notifier-on-init-failure.patch b/queue-7.1/net-sparx5-unregister-blocking-notifier-on-init-failure.patch
new file mode 100644 (file)
index 0000000..739ce28
--- /dev/null
@@ -0,0 +1,45 @@
+From 483be61b4a9a6df3b7cb277e8f189e082dee4cb8 Mon Sep 17 00:00:00 2001
+From: Haoxiang Li <haoxiang_li2024@163.com>
+Date: Tue, 23 Jun 2026 19:57:14 +0800
+Subject: net: sparx5: unregister blocking notifier on init failure
+
+From: Haoxiang Li <haoxiang_li2024@163.com>
+
+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 <haoxiang_li2024@163.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260623115714.2192074-1-haoxiang_li2024@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch b/queue-7.1/net-thunderbolt-fix-frags-overflow-by-bounding-frame_count.patch
new file mode 100644 (file)
index 0000000..ae73f57
--- /dev/null
@@ -0,0 +1,58 @@
+From 55d9895f89970501fe126d1026b586b04a224c27 Mon Sep 17 00:00:00 2001
+From: Maoyi Xie <maoyixie.tju@gmail.com>
+Date: Wed, 17 Jun 2026 01:38:41 +0800
+Subject: net: thunderbolt: Fix frags[] overflow by bounding frame_count
+
+From: Maoyi Xie <maoyixie.tju@gmail.com>
+
+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 <maoyixie.tju@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/178163152194.2486768.14724194232649760778@maoyixie.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -787,8 +787,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-7.1/netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch b/queue-7.1/netdev-genl-report-napi-thread-pid-in-the-caller-s-pid-namespace.patch
new file mode 100644 (file)
index 0000000..b5e9930
--- /dev/null
@@ -0,0 +1,55 @@
+From 1f24c0d01db214c9e661915e9972404c96ca73c0 Mon Sep 17 00:00:00 2001
+From: Maoyi Xie <maoyixie.tju@gmail.com>
+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 <maoyixie.tju@gmail.com>
+
+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 <maoyixie.tju@gmail.com>
+Reviewed-by: Joe Damato <joe@dama.to>
+Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
+Link: https://patch.msgid.link/20260615171736.1709318-1-maoyixie.tju@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/netdevice.h>
+ #include <linux/notifier.h>
++#include <linux/pid_namespace.h>
+ #include <linux/rtnetlink.h>
+ #include <net/busy_poll.h>
+ #include <net/net_namespace.h>
+@@ -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-7.1/nfs-charge-unstable-writes-by-request-size-not-folio-size.patch b/queue-7.1/nfs-charge-unstable-writes-by-request-size-not-folio-size.patch
new file mode 100644 (file)
index 0000000..dde5fbf
--- /dev/null
@@ -0,0 +1,129 @@
+From 27934d02cbeb8a957dd11c985a579e58d30c5270 Mon Sep 17 00:00:00 2001
+From: Benjamin Coddington <ben.coddington@hammerspace.com>
+Date: Tue, 7 Jul 2026 11:07:16 -0400
+Subject: NFS: Charge unstable writes by request size, not folio size
+
+From: Benjamin Coddington <ben.coddington@hammerspace.com>
+
+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 <bcodding@hammerspace.com>
+Assisted-By: Claude Sonnet 5 <noreply@anthropic.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -847,17 +847,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);
+               bdi_wb_stat_mod(folio->mapping->host, WB_WRITEBACK, -nr);
+@@ -889,7 +891,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);
+       }
+ }
+@@ -1741,7 +1743,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);
+       }
+ }
+@@ -1813,7 +1815,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-7.1/nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch b/queue-7.1/nvme-apple-prevent-shared-tags-across-queues-on-apple-a11.patch
new file mode 100644 (file)
index 0000000..0e12c2f
--- /dev/null
@@ -0,0 +1,68 @@
+From 6fe0687245e8406bf26143bd45eb16441bbe5280 Mon Sep 17 00:00:00 2001
+From: Nick Chan <towinchenmi@gmail.com>
+Date: Sun, 7 Jun 2026 14:10:58 +0800
+Subject: nvme-apple: Prevent shared tags across queues on Apple A11
+
+From: Nick Chan <towinchenmi@gmail.com>
+
+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 <sven@kernel.org>
+Signed-off-by: Nick Chan <towinchenmi@gmail.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+@@ -1325,8 +1322,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-7.1/nvmet-auth-reject-short-auth_receive-buffers.patch b/queue-7.1/nvmet-auth-reject-short-auth_receive-buffers.patch
new file mode 100644 (file)
index 0000000..a0c89bd
--- /dev/null
@@ -0,0 +1,81 @@
+From 779575bc35c687697ba69e904f2cd22e60112534 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Tue, 9 Jun 2026 14:24:31 -0400
+Subject: nvmet-auth: reject short AUTH_RECEIVE buffers
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+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 <hare@kernel.org>
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -493,7 +493,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-7.1/nvmet-fix-refcount-leak-in-nvmet_sq_create.patch b/queue-7.1/nvmet-fix-refcount-leak-in-nvmet_sq_create.patch
new file mode 100644 (file)
index 0000000..e8fa598
--- /dev/null
@@ -0,0 +1,38 @@
+From 34b9a83c50660148bde01cde16451dbe78369749 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+Date: Tue, 9 Jun 2026 09:55:05 +0000
+Subject: nvmet: fix refcount leak in nvmet_sq_create()
+
+From: Wentao Liang <vulab@iscas.ac.cn>
+
+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 <vulab@iscas.ac.cn>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -944,7 +944,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-7.1/nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch b/queue-7.1/nvmet-rdma-handle-inline-data-with-a-nonzero-offset.patch
new file mode 100644 (file)
index 0000000..61e3fe0
--- /dev/null
@@ -0,0 +1,89 @@
+From 48c0162f647bb47e6084ffbc71b8f213f5e2f4f8 Mon Sep 17 00:00:00 2001
+From: Bryam Vargas <hexlabsecurity@proton.me>
+Date: Thu, 4 Jun 2026 19:36:54 +0000
+Subject: nvmet-rdma: handle inline data with a nonzero offset
+
+From: Bryam Vargas <hexlabsecurity@proton.me>
+
+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 <kbusch@kernel.org>
+Reported-by: Bryam Vargas <hexlabsecurity@proton.me>
+Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -666,7 +666,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)))
+@@ -821,24 +822,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-7.1/openrisc-fix-jump_label-smp-syncing.patch b/queue-7.1/openrisc-fix-jump_label-smp-syncing.patch
new file mode 100644 (file)
index 0000000..322e379
--- /dev/null
@@ -0,0 +1,61 @@
+From aca063c9024522e4e5b9a9d1927433f6a01785a3 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Fri, 22 May 2026 17:28:31 +0100
+Subject: openrisc: Fix jump_label smp syncing
+
+From: Stafford Horne <shorne@gmail.com>
+
+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 <shorne@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/ovl-use-linked-upper-dentry-in-copy-up-tmpfile.patch b/queue-7.1/ovl-use-linked-upper-dentry-in-copy-up-tmpfile.patch
new file mode 100644 (file)
index 0000000..d56d914
--- /dev/null
@@ -0,0 +1,103 @@
+From e348eecd4d8fa8d18a5157ff59f7be1dc59c5928 Mon Sep 17 00:00:00 2001
+From: Souvik Banerjee <souvik@amlalabs.com>
+Date: Fri, 1 May 2026 23:27:35 +0000
+Subject: ovl: use linked upper dentry in copy-up tmpfile
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Souvik Banerjee <souvik@amlalabs.com>
+
+commit e348eecd4d8fa8d18a5157ff59f7be1dc59c5928 upstream.
+
+ovl_copy_up_tmpfile() stores the disconnected O_TMPFILE dentry as the
+overlay's upper dentry reference via ovl_inode_update().  vfs_tmpfile()
+allocated this dentry via d_alloc(parentpath->dentry, &slash_name), so
+d_name is "/" and d_parent is c->workdir.  Local upper filesystems
+(ext4, btrfs, xfs, ...) immediately rename it to "#<inum>" via
+d_mark_tmpfile() inside their ->tmpfile() op; FUSE and virtiofs do
+not, so both fields stay that way.  Neither identifies the destination
+directory and filename where ovl_do_link() actually linked the file.
+
+When the upper filesystem implements ->d_revalidate() (e.g. FUSE or
+virtiofs), ovl_revalidate_real() calls it with the dentry's parent
+inode and a snapshot of d_name.  The server tries to look up "/" inside
+c->workdir, fails, and overlayfs reports -ESTALE.
+
+This causes persistent ESTALE errors for any file that was copied up via
+the tmpfile path, breaking dpkg, apt, and other tools that do
+rename-over-existing on overlayfs with a FUSE/virtiofs upper.
+
+Before commit 6b52243f633e ("ovl: fold copy-up helpers into callers"),
+the tmpfile copy-up path used a dedicated helper ovl_link_tmpfile()
+that captured the linked destination dentry returned by ovl_do_link():
+
+    err = ovl_do_link(temp, udir, upper);
+    ...
+    if (!err)
+        *newdentry = dget(upper);
+
+and published it via ovl_inode_update(d_inode(c->dentry), newdentry).
+The fold inlined ovl_do_link() into ovl_copy_up_tmpfile() but dropped
+the dget(upper) capture, and rewrote the publish line as
+ovl_inode_update(d_inode(c->dentry), dget(temp)) â€” where temp is the
+disconnected O_TMPFILE dentry.
+
+Fix by keeping a reference to the linked destination dentry after
+ovl_do_link() succeeds, and publishing that dentry at the existing
+ovl_inode_update() call site.  The non-tmpfile/workdir path continues to
+publish the renamed temporary dentry.
+
+Reproducer:
+  - Mount overlayfs with virtiofs (or a FUSE fs whose server advertises
+    FUSE_TMPFILE) as upper
+  - Run: dpkg -i <any .deb>
+  - Observe: "error installing new file '...': Stale file handle"
+
+Fixes: 6b52243f633e ("ovl: fold copy-up helpers into callers")
+Cc: stable@vger.kernel.org # v4.20+
+Signed-off-by: Souvik Banerjee <souvik@amlalabs.com>
+Link: https://patch.msgid.link/20260501232735.2610824-1-souvik@amlalabs.com
+Reviewed-by: Amir Goldstein <amir73il@gmail.com>
+Reviewed-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/overlayfs/copy_up.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -853,7 +853,7 @@ static int ovl_copy_up_tmpfile(struct ov
+ {
+       struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+       struct inode *udir = d_inode(c->destdir);
+-      struct dentry *temp, *upper;
++      struct dentry *temp, *upper, *newdentry = NULL;
+       struct file *tmpfile;
+       int err;
+@@ -889,6 +889,14 @@ static int ovl_copy_up_tmpfile(struct ov
+       err = PTR_ERR(upper);
+       if (!IS_ERR(upper)) {
+               err = ovl_do_link(ofs, temp, udir, upper);
++              if (!err) {
++                      /*
++                       * Record the linked dentry -- not the disconnected
++                       * O_TMPFILE dentry -- so that ->d_revalidate() on
++                       * the upper fs sees the real parent/name.
++                       */
++                      newdentry = dget(upper);
++              }
+               end_creating(upper);
+       }
+@@ -903,7 +911,7 @@ static int ovl_copy_up_tmpfile(struct ov
+       if (!c->metacopy)
+               ovl_set_upperdata(d_inode(c->dentry));
+-      ovl_inode_update(d_inode(c->dentry), dget(temp));
++      ovl_inode_update(d_inode(c->dentry), newdentry);
+ out:
+       ovl_end_write(c->dentry);
diff --git a/queue-7.1/pkey-move-keytype-check-from-pkey-api-to-handler.patch b/queue-7.1/pkey-move-keytype-check-from-pkey-api-to-handler.patch
new file mode 100644 (file)
index 0000000..824e425
--- /dev/null
@@ -0,0 +1,72 @@
+From 754e9e49b76fd5be339172aa98544182ed3ca75e Mon Sep 17 00:00:00 2001
+From: Holger Dengler <dengler@linux.ibm.com>
+Date: Tue, 23 Jun 2026 16:20:31 +0200
+Subject: pkey: Move keytype check from pkey api to handler
+
+From: Holger Dengler <dengler@linux.ibm.com>
+
+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 <ifranzki@linux.ibm.com>
+Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
+Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -327,7 +327,6 @@ static int pkey_ioctl_verifyprotk(struct
+ {
+       struct pkey_verifyprotk kvp;
+       struct protaeskeytoken *t;
+-      u32 keytype;
+       u8 *tmpbuf;
+       int rc;
+@@ -341,14 +340,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) {
+@@ -358,7 +349,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-7.1/platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch b/queue-7.1/platform-x86-amd-pmc-add-delay_suspend-module-parameter.patch
new file mode 100644 (file)
index 0000000..c4a57a9
--- /dev/null
@@ -0,0 +1,93 @@
+From 428b9fd2dce50b4dc5cd9ade10b92efcf57ce7aa Mon Sep 17 00:00:00 2001
+From: Daniel Gibson <daniel@gibson.sh>
+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 <daniel@gibson.sh>
+
+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 <johannes.goede@oss.qualcomm.com>
+Signed-off-by: Daniel Gibson <daniel@gibson.sh>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260611150426.3683372-4-daniel@gibson.sh
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/bits.h>
+ #include <linux/debugfs.h>
+ #include <linux/delay.h>
++#include <linux/dmi.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+ #include <linux/limits.h>
+@@ -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-7.1/platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch b/queue-7.1/platform-x86-amd-pmc-check-for-intermediate-wakeup-in-function.patch
new file mode 100644 (file)
index 0000000..9f53eff
--- /dev/null
@@ -0,0 +1,61 @@
+From 3bdd6fc11fbfa8249483f4b716ead51e43e3a0cd Mon Sep 17 00:00:00 2001
+From: Daniel Gibson <daniel@gibson.sh>
+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 <daniel@gibson.sh>
+
+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 <daniel@gibson.sh>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260611150426.3683372-2-daniel@gibson.sh
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch b/queue-7.1/platform-x86-amd-pmc-delay-suspend-for-some-lenovo-laptops.patch
new file mode 100644 (file)
index 0000000..69320af
--- /dev/null
@@ -0,0 +1,164 @@
+From 9b9e60dd31da054a37d601e9fcabdfd8a2bff354 Mon Sep 17 00:00:00 2001
+From: Daniel Gibson <daniel@gibson.sh>
+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 <daniel@gibson.sh>
+
+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 <sindrehenriksen93@gmail.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221383
+Tested-by: Sindre Henriksen <sindrehenriksen93@gmail.com>
+Suggested-by: Mario Limonciello (AMD) <superm1@kernel.org>
+Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
+Signed-off-by: Daniel Gibson <daniel@gibson.sh>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260611150426.3683372-3-daniel@gibson.sh
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch b/queue-7.1/platform-x86-amd-pmc-don-t-log-during-intermediate-wakeups.patch
new file mode 100644 (file)
index 0000000..abb8b34
--- /dev/null
@@ -0,0 +1,118 @@
+From 037f0b03c663a247366673a807834389107995b7 Mon Sep 17 00:00:00 2001
+From: Daniel Gibson <daniel@gibson.sh>
+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 <daniel@gibson.sh>
+
+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 <johannes.goede@oss.qualcomm.com>
+Signed-off-by: Daniel Gibson <daniel@gibson.sh>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260611150426.3683372-5-daniel@gibson.sh
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch b/queue-7.1/platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch
new file mode 100644 (file)
index 0000000..63cbaa9
--- /dev/null
@@ -0,0 +1,52 @@
+From 6e9cab2247e5b243ae2d907ce7c948a8a9c8d61a Mon Sep 17 00:00:00 2001
+From: Haoxiang Li <lihaoxiang@isrc.iscas.ac.cn>
+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 <lihaoxiang@isrc.iscas.ac.cn>
+
+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 <lihaoxiang@isrc.iscas.ac.cn>
+Link: https://patch.msgid.link/20260609081419.1995169-1-lihaoxiang@isrc.iscas.ac.cn
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8d26.patch b/queue-7.1/platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8d26.patch
new file mode 100644 (file)
index 0000000..acafe48
--- /dev/null
@@ -0,0 +1,48 @@
+From 0aab31d47c2e857ca05028d718d1e0d239e683ad Mon Sep 17 00:00:00 2001
+From: Krishna Chomal <krishna.chomal108@gmail.com>
+Date: Mon, 25 May 2026 15:52:26 +0530
+Subject: platform/x86: hp-wmi: Add support for Omen 16-ap0xxx (8D26)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Krishna Chomal <krishna.chomal108@gmail.com>
+
+commit 0aab31d47c2e857ca05028d718d1e0d239e683ad upstream.
+
+The HP Omen 16-ap0xxx (board ID: 8D26) has the same WMI interface as
+other Victus S boards, but requires quirks for correctly switching
+thermal profile.
+
+Add the DMI board name to victus_s_thermal_profile_boards[] table and
+map it to omen_v1_legacy_thermal_params.
+
+Testing on board 8D26 confirmed that platform profile is registered
+successfully and fan RPMs are readable and controllable.
+
+Tested-by: Alberto Escaño <alberto_e_88@yahoo.es>
+Reported-by: Alberto Escaño <alberto_e_88@yahoo.es>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221514
+Cc: stable@vger.kernel.org # v6.18+
+Signed-off-by: Krishna Chomal <krishna.chomal108@gmail.com>
+Link: https://patch.msgid.link/20260525102226.56300-1-krishna.chomal108@gmail.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/hp/hp-wmi.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/platform/x86/hp/hp-wmi.c
++++ b/drivers/platform/x86/hp/hp-wmi.c
+@@ -250,6 +250,10 @@ static const struct dmi_system_id victus
+               .driver_data = (void *)&victus_s_thermal_params,
+       },
+       {
++              .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D26") },
++              .driver_data = (void *)&omen_v1_legacy_thermal_params,
++      },
++      {
+               .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D41") },
+               .driver_data = (void *)&omen_v1_no_ec_thermal_params,
+       },
diff --git a/queue-7.1/platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8e35.patch b/queue-7.1/platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8e35.patch
new file mode 100644 (file)
index 0000000..ee6f6d6
--- /dev/null
@@ -0,0 +1,48 @@
+From 56b7981c6f21670c0a1a62e6d2f9afb380e2596d Mon Sep 17 00:00:00 2001
+From: Krishna Chomal <krishna.chomal108@gmail.com>
+Date: Mon, 8 Jun 2026 19:12:55 +0530
+Subject: platform/x86: hp-wmi: Add support for Omen 16-ap0xxx (8E35)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Krishna Chomal <krishna.chomal108@gmail.com>
+
+commit 56b7981c6f21670c0a1a62e6d2f9afb380e2596d upstream.
+
+The HP Omen 16-ap0xxx (board ID: 8E35) has the same WMI interface as
+other Victus S boards, but requires quirks for correctly switching
+thermal profile.
+
+Add the DMI board name to victus_s_thermal_profile_boards[] table and
+map it to omen_v1_legacy_thermal_params.
+
+Testing on board 8E35 confirmed that platform profile is registered
+successfully and fan RPMs are readable and controllable.
+
+Tested-by: Ahmet Ã–ztürk <sivasli-ahmet@gmx.de>
+Reported-by: Ahmet Ã–ztürk <sivasli-ahmet@gmx.de>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221523
+Cc: stable@vger.kernel.org # v6.18+
+Signed-off-by: Krishna Chomal <krishna.chomal108@gmail.com>
+Link: https://patch.msgid.link/20260608134255.36280-1-krishna.chomal108@gmail.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/hp/hp-wmi.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/platform/x86/hp/hp-wmi.c
++++ b/drivers/platform/x86/hp/hp-wmi.c
+@@ -261,6 +261,10 @@ static const struct dmi_system_id victus
+               .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D87") },
+               .driver_data = (void *)&omen_v1_no_ec_thermal_params,
+       },
++      {
++              .matches = { DMI_MATCH(DMI_BOARD_NAME, "8E35") },
++              .driver_data = (void *)&omen_v1_legacy_thermal_params,
++      },
+       {},
+ };
diff --git a/queue-7.1/platform-x86-intel-tpmi-use-cleanup-helpers-in-mem_write.patch b/queue-7.1/platform-x86-intel-tpmi-use-cleanup-helpers-in-mem_write.patch
new file mode 100644 (file)
index 0000000..2965c00
--- /dev/null
@@ -0,0 +1,105 @@
+From a221557958e3a82d8565729d445a7385963f30b6 Mon Sep 17 00:00:00 2001
+From: ZhaoJinming <zhaojinming@uniontech.com>
+Date: Thu, 21 May 2026 21:08:47 +0800
+Subject: platform/x86/intel/tpmi: use cleanup helpers in mem_write()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: ZhaoJinming <zhaojinming@uniontech.com>
+
+commit a221557958e3a82d8565729d445a7385963f30b6 upstream.
+
+In mem_write(), the temporary array returned by
+parse_int_array_user() must be released on all exit paths.
+Convert the array variable to use cleanup.h scope-based
+cleanup so it is freed automatically on return.
+
+This also moves the array declaration next to
+parse_int_array_user() as required by cleanup.h usage
+guidelines.
+
+Fixes: 8e0a2fc68ec3 ("platform/x86/intel/tpmi: Use 32 bit aligned address for debugfs mem write")
+Cc: stable@vger.kernel.org
+Signed-off-by: ZhaoJinming <zhaojinming@uniontech.com>
+Link: https://patch.msgid.link/20260521130848.2860219-1-zhaojinming@uniontech.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/intel/vsec_tpmi.c | 25 +++++++++----------------
+ 1 file changed, 9 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/platform/x86/intel/vsec_tpmi.c b/drivers/platform/x86/intel/vsec_tpmi.c
+index 8c4e2474b30c..3b76cccb975f 100644
+--- a/drivers/platform/x86/intel/vsec_tpmi.c
++++ b/drivers/platform/x86/intel/vsec_tpmi.c
+@@ -50,6 +50,7 @@
+ #include <linux/auxiliary_bus.h>
+ #include <linux/bitfield.h>
+ #include <linux/debugfs.h>
++#include <linux/cleanup.h>
+ #include <linux/delay.h>
+ #include <linux/intel_tpmi.h>
+ #include <linux/intel_vsec.h>
+@@ -473,7 +474,7 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
+       struct seq_file *m = file->private_data;
+       struct intel_tpmi_pm_feature *pfs = m->private;
+       u32 addr, value, punit, size;
+-      u32 num_elems, *array;
++      u32 num_elems;
+       void __iomem *mem;
+       int ret;
+@@ -481,15 +482,14 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
+       if (!size)
+               return -EIO;
++      u32 *array __free(kfree) = NULL;
+       ret = parse_int_array_user(userbuf, len, (int **)&array);
+       if (ret < 0)
+               return ret;
+       num_elems = *array;
+-      if (num_elems != 3) {
+-              ret = -EINVAL;
+-              goto exit_write;
+-      }
++      if (num_elems != 3)
++              return -EINVAL;
+       punit = array[1];
+       addr = array[2];
+@@ -498,15 +498,11 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
+       if (!IS_ALIGNED(addr, sizeof(u32)))
+               return -EINVAL;
+-      if (punit >= pfs->pfs_header.num_entries) {
+-              ret = -EINVAL;
+-              goto exit_write;
+-      }
++      if (punit >= pfs->pfs_header.num_entries)
++              return -EINVAL;
+-      if (addr >= size) {
+-              ret = -EINVAL;
+-              goto exit_write;
+-      }
++      if (addr >= size)
++              return -EINVAL;
+       mutex_lock(&tpmi_dev_lock);
+@@ -525,9 +521,6 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
+ unlock_mem_write:
+       mutex_unlock(&tpmi_dev_lock);
+-exit_write:
+-      kfree(array);
+-
+       return ret;
+ }
+-- 
+2.55.0
+
diff --git a/queue-7.1/platform-x86-isst-restore-sst-pp-control-to-all-domains.patch b/queue-7.1/platform-x86-isst-restore-sst-pp-control-to-all-domains.patch
new file mode 100644 (file)
index 0000000..2f5202c
--- /dev/null
@@ -0,0 +1,42 @@
+From 2565a28cdcdcb035e151d285efcba26bccb3726e Mon Sep 17 00:00:00 2001
+From: Srinivas Pandruvada <srinivas.pandruvada@intel.com>
+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 <srinivas.pandruvada@intel.com>
+
+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 <yi1.lai@intel.com>
+Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@intel.com>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260528204521.3531456-1-srinivas.pandruvada@linux.intel.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1804,7 +1804,7 @@ process_pp_resume:
+               if (!(pd_info->sst_header.cap_mask & SST_PP_CAP_PP_ENABLE))
+                       continue;
+-              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-7.1/s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch b/queue-7.1/s390-pkey-check-length-in-pkey_pckmo-handler-implementation.patch
new file mode 100644 (file)
index 0000000..097e682
--- /dev/null
@@ -0,0 +1,38 @@
+From 1ac287e2af9a9112fe271427ef45eceb26bce8b4 Mon Sep 17 00:00:00 2001
+From: Holger Dengler <dengler@linux.ibm.com>
+Date: Wed, 17 Jun 2026 19:06:39 +0200
+Subject: s390/pkey: Check length in pkey_pckmo handler implementation
+
+From: Holger Dengler <dengler@linux.ibm.com>
+
+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 <borntraeger@linux.ibm.com>
+Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
+Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch b/queue-7.1/s390-pkey-check-length-in-pkey_verifyprotk-ioctl.patch
new file mode 100644 (file)
index 0000000..cdd6481
--- /dev/null
@@ -0,0 +1,40 @@
+From b3d4ab2d7df9426f7f1d3671d7e2108f2ca6e970 Mon Sep 17 00:00:00 2001
+From: Holger Dengler <dengler@linux.ibm.com>
+Date: Mon, 15 Jun 2026 17:39:12 +0200
+Subject: s390/pkey: Check length in PKEY_VERIFYPROTK ioctl
+
+From: Holger Dengler <dengler@linux.ibm.com>
+
+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 <borntraeger@linux.ibm.com>
+Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
+Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
+Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -334,6 +334,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-7.1/scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch b/queue-7.1/scsi-elx-efct-fix-i-o-leak-on-unsupported-additional-cdb.patch
new file mode 100644 (file)
index 0000000..00df079
--- /dev/null
@@ -0,0 +1,36 @@
+From 9cb2d5291dbfe7bed565ead3337047dee9ed1064 Mon Sep 17 00:00:00 2001
+From: Haoxiang Li <haoxiang_li2024@163.com>
+Date: Mon, 22 Jun 2026 15:58:44 +0800
+Subject: scsi: elx: efct: Fix I/O leak on unsupported additional CDB
+
+From: Haoxiang Li <haoxiang_li2024@163.com>
+
+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 <haoxiang_li2024@163.com>
+Reviewed-by: Daniel Wagner <dwagner@suse.de>
+Link: https://patch.msgid.link/20260622075844.832871-1-haoxiang_li2024@163.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch b/queue-7.1/scsi-elx-efct-fix-refcount-leak-in-efct_hw_io_abort.patch
new file mode 100644 (file)
index 0000000..b8fd8bc
--- /dev/null
@@ -0,0 +1,46 @@
+From 2c007acf7b31c39c08ce4959451ad00b19be4c1f Mon Sep 17 00:00:00 2001
+From: WenTao Liang <vulab@iscas.ac.cn>
+Date: Thu, 11 Jun 2026 13:30:37 +0800
+Subject: scsi: elx: efct: Fix refcount leak in efct_hw_io_abort()
+
+From: WenTao Liang <vulab@iscas.ac.cn>
+
+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 <vulab@iscas.ac.cn>
+Reviewed-by: Daniel Wagner <dwagner@suse.de>
+Link: https://patch.msgid.link/20260611053037.63756-1-vulab@iscas.ac.cn
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1997,6 +1997,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-7.1/scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch b/queue-7.1/scsi-hpsa-fix-dma-mapping-leak-on-ioaccel2-reset-path.patch
new file mode 100644 (file)
index 0000000..47b518d
--- /dev/null
@@ -0,0 +1,39 @@
+From e166bafc483e927150cb9b5f286c9191ea0df84e Mon Sep 17 00:00:00 2001
+From: Haoxiang Li <haoxiang_li2024@163.com>
+Date: Tue, 23 Jun 2026 00:00:28 +0800
+Subject: scsi: hpsa: Fix DMA mapping leak on IOACCEL2 reset path
+
+From: Haoxiang Li <haoxiang_li2024@163.com>
+
+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 <haoxiang_li2024@163.com>
+Acked-by: Don Brace <don.brace@microchip.com>
+Link: https://patch.msgid.link/20260622160028.1240496-1-haoxiang_li2024@163.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/hpsa.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/scsi/hpsa.c
++++ b/drivers/scsi/hpsa.c
+@@ -5017,6 +5017,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-7.1/scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch b/queue-7.1/scsi-lpfc-fix-memory-leak-in-lpfc_sli4_driver_resource_setup.patch
new file mode 100644 (file)
index 0000000..3eb7345
--- /dev/null
@@ -0,0 +1,43 @@
+From 1bd28625e25be549ee7c47532e7c3ef91c682410 Mon Sep 17 00:00:00 2001
+From: Abdun Nihaal <nihaal@cse.iitm.ac.in>
+Date: Tue, 7 Jul 2026 12:23:02 +0530
+Subject: scsi: lpfc: Fix memory leak in lpfc_sli4_driver_resource_setup()
+
+From: Abdun Nihaal <nihaal@cse.iitm.ac.in>
+
+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 <nihaal@cse.iitm.ac.in>
+Reviewed-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://patch.msgid.link/20260707065304.949135-1-nihaal@cse.iitm.ac.in
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -8189,6 +8189,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
+@@ -8311,8 +8312,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-7.1/scsi-sg-report-request-table-problems-when-any-status-is-set.patch b/queue-7.1/scsi-sg-report-request-table-problems-when-any-status-is-set.patch
new file mode 100644 (file)
index 0000000..53d1587
--- /dev/null
@@ -0,0 +1,49 @@
+From 1d3a742afeb761eaead774691bde1ced699e9a5d Mon Sep 17 00:00:00 2001
+From: Xu Rao <raoxu@uniontech.com>
+Date: Tue, 7 Jul 2026 11:08:45 +0800
+Subject: scsi: sg: Report request-table problems when any status is set
+
+From: Xu Rao <raoxu@uniontech.com>
+
+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 <raoxu@uniontech.com>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Link: https://patch.msgid.link/54B60C19F7DB8889+20260707030845.970018-1-raoxu@uniontech.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/sg.c |    7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -863,10 +863,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-7.1/scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch b/queue-7.1/scsi-target-bound-pr-out-transportid-parsing-to-the-received-buffer.patch
new file mode 100644 (file)
index 0000000..4d9a5c8
--- /dev/null
@@ -0,0 +1,250 @@
+From d04a179085c262c9ed577d0a4cbc6482ff1fd9a3 Mon Sep 17 00:00:00 2001
+From: Bryam Vargas <hexlabsecurity@proton.me>
+Date: Thu, 11 Jun 2026 13:42:26 -0500
+Subject: scsi: target: Bound PR-OUT TransportID parsing to the received buffer
+
+From: Bryam Vargas <hexlabsecurity@proton.me>
+
+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 <hexlabsecurity@proton.me>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: David Disseldorp <ddiss@suse.de>
+Link: https://patch.msgid.link/20260611-b4-disp-9f20739e-v6-1-f6630e2aae44@proton.me
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -290,13 +290,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:
+        *
+@@ -316,15 +327,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
+@@ -332,16 +345,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
+@@ -349,7 +378,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
+@@ -367,10 +396,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;
+ }
+@@ -420,8 +461,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:
+               /*
+@@ -440,8 +489,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;
+                       /*
+@@ -3285,7 +3285,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-7.1/scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch b/queue-7.1/scsi-target-core-fix-iscsi-isid-use-after-free-in-register-and-move.patch
new file mode 100644 (file)
index 0000000..ee6e0b7
--- /dev/null
@@ -0,0 +1,69 @@
+From fda6a1f3c3d7047b5ce5654487649c2daa738bfc Mon Sep 17 00:00:00 2001
+From: Bryam Vargas <hexlabsecurity@proton.me>
+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 <hexlabsecurity@proton.me>
+
+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 <hexlabsecurity@proton.me>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: David Disseldorp <ddiss@suse.de>
+Link: https://patch.msgid.link/20260610042245.35473-1-hexlabsecurity@proton.me
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -3293,9 +3293,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) ?
+@@ -3532,6 +3529,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-7.1/scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch b/queue-7.1/scsi-xen-scsiback-free-the-command-tag-on-the-tmr-submit-failure-path.patch
new file mode 100644 (file)
index 0000000..6fd0fdc
--- /dev/null
@@ -0,0 +1,52 @@
+From 66aefc277ebb796ec285d550305535dc3fc0179f Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+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 <michael.bommarito@gmail.com>
+
+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 <michael.bommarito@gmail.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Link: https://patch.msgid.link/20260611123046.2323342-3-michael.bommarito@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -639,7 +639,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-7.1/scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch b/queue-7.1/scsi-xen-scsiback-free-unsubmitted-command-instead-of-double-putting-it.patch
new file mode 100644 (file)
index 0000000..1680fd6
--- /dev/null
@@ -0,0 +1,94 @@
+From ca978f8a93d4d36841839bf2847d29b88c2591d6 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Thu, 11 Jun 2026 08:30:45 -0400
+Subject: scsi: xen: scsiback: Free unsubmitted command instead of double-putting it
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+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 <michael.bommarito@gmail.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Link: https://patch.msgid.link/20260611123046.2323342-2-michael.bommarito@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -611,6 +611,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)
+ {
+@@ -792,9 +811,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);
+                       }
+@@ -808,9 +826,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-7.1/sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch b/queue-7.1/sctp-validate-stale_cookie-cause-length-before-reading-staleness.patch
new file mode 100644 (file)
index 0000000..c1e383a
--- /dev/null
@@ -0,0 +1,103 @@
+From 1cd23ca80784223fa2204e16203f754da4e821f8 Mon Sep 17 00:00:00 2001
+From: Weiming Shi <bestswngs@gmail.com>
+Date: Fri, 3 Jul 2026 20:35:46 -0700
+Subject: sctp: validate STALE_COOKIE cause length before reading staleness
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+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 <xmei5@asu.edu>
+Assisted-by: Claude:claude-opus-4-8
+Cc: stable@vger.kernel.org
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260704033545.2438373-2-bestswngs@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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,
+@@ -2529,9 +2530,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
+@@ -2573,13 +2580,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) {
+@@ -2590,8 +2597,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-7.1/selftests-bpf-cover-negative-buffer-pointer-offsets.patch b/queue-7.1/selftests-bpf-cover-negative-buffer-pointer-offsets.patch
new file mode 100644 (file)
index 0000000..f96e8ba
--- /dev/null
@@ -0,0 +1,216 @@
+From 6f59deb32efa4673fc3b1fef9f3a0da48e9d8494 Mon Sep 17 00:00:00 2001
+From: Sun Jian <sun.jian.kdev@gmail.com>
+Date: Tue, 14 Jul 2026 02:38:46 -0700
+Subject: selftests/bpf: Cover negative buffer pointer offsets
+
+From: Sun Jian <sun.jian.kdev@gmail.com>
+
+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 <sun.jian.kdev@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260714093846.18159-3-sun.jian.kdev@gmail.com
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <test_progs.h>
++#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 <test_progs.h>
+-#include <linux/nbd.h>
+-#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
+@@ -77,6 +77,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"
+@@ -225,6 +226,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 <vmlinux.h>
++#include <bpf/bpf_helpers.h>
++#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";
index 3f63ae530dd2d51e5393b80a27a2d4778b008dae..1b9ec0aa6977f6eeb9b828ce8a2c66cf20c3b80d 100644 (file)
@@ -1765,3 +1765,126 @@ 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
+dmaengine-sh-rz-dmac-fix-incorrect-null-check-for-list_first_entry.patch
+dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch
+dmaengine-sh-rz-dmac-move-interrupt-request-after-everything-is-set-up.patch
+platform-x86-intel-tpmi-use-cleanup-helpers-in-mem_write.patch
+platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch
+platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8d26.patch
+platform-x86-hp-wmi-add-support-for-omen-16-ap0xxx-8e35.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-imx-reconfigure-for-pio-when-dma-cannot-be-started.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
+ovl-use-linked-upper-dentry-in-copy-up-tmpfile.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-locking-when-updating-filter-and-timer-values.patch
+can-bcm-add-missing-rcu-list-annotations-and-operations.patch
+can-bcm-extend-bcm_tx_lock-usage-for-data-and-timer-updates.patch
+can-bcm-fix-can-frame-rx-tx-statistics.patch
+can-bcm-fix-data-race-on-rx_stamp-rx_ifindex-in-bcm_rx_handler.patch
+can-bcm-fix-stale-rx-tx-ops-after-device-removal.patch
+can-bcm-track-a-single-source-interface-for-anydev-timeout-throttle-ops.patch
+can-bcm-validate-frame-length-in-bcm_rx_setup-for-rtr-replies.patch
+can-bcm-add-missing-device-refcount-for-can-filter-removal.patch
+io_uring-bpf-ops-reject-re-registration-of-an-already-bound-ops.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-avoid-leaking-the-caller-s-thread-keyring-via-the-table-device-file.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-fix-buffer-overflow-in-fec-calculation.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
+dma-fence-use-correct-callback-in-dma_fence_timeline_name.patch
+dma-buf-dma-fence-fix-potential-null-pointer-dereference.patch
+accel-amdxdna-fix-use-after-free-in-amdxdna_gem_dmabuf_mmap.patch
+accel-amdxdna-reject-command-submission-on-devices-without-a-submit-op.patch
+accel-amdxdna-reject-user-command-submission-without-a-command-bo.patch
+accel-amdxdna-use-caller-client-for-debug-bo-sync.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-7.1/smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch b/queue-7.1/smb-client-use-kvzalloc-for-megabyte-buffer-in-simple-fallocate.patch
new file mode 100644 (file)
index 0000000..147a25d
--- /dev/null
@@ -0,0 +1,75 @@
+From 806c00c23e3ce8eae397a40ced536ef88ae4e012 Mon Sep 17 00:00:00 2001
+From: Fredric Cover <fredric.cover.lkernel@gmail.com>
+Date: Sat, 11 Jul 2026 19:54:02 -0700
+Subject: smb: client: use kvzalloc() for megabyte buffer in simple fallocate
+
+From: Fredric Cover <fredric.cover.lkernel@gmail.com>
+
+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:
+ <TASK>
+ 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
+ </TASK>
+
+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 <fredric.cover.lkernel@gmail.com>
+Tested-by: Fredric Cover <fredric.cover.lkernel@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -3595,7 +3595,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;
+@@ -3652,7 +3652,7 @@ static int smb3_simple_fallocate_range(u
+  out:
+       kfree(out_data);
+-      kfree(buf);
++      kvfree(buf);
+       return rc;
+ }
diff --git a/queue-7.1/spi-imx-reconfigure-for-pio-when-dma-cannot-be-started.patch b/queue-7.1/spi-imx-reconfigure-for-pio-when-dma-cannot-be-started.patch
new file mode 100644 (file)
index 0000000..46c3a11
--- /dev/null
@@ -0,0 +1,66 @@
+From 245404c26563aafb36aafb01298f148db1851be3 Mon Sep 17 00:00:00 2001
+From: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
+Date: Wed, 24 Jun 2026 17:19:58 +0200
+Subject: spi: imx: reconfigure for PIO when DMA cannot be started
+
+From: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
+
+commit 245404c26563aafb36aafb01298f148db1851be3 upstream.
+
+When spi_imx_can_dma() selects DMA, the ECSPI is configured for DMA:
+spi_imx_setupxfer() sets CTRL.SMC and clears dynamic_burst, and
+spi_imx_dma_transfer() programs the dynamic-burst BURST_LENGTH and the
+SDMA watermarks.
+
+If the DMA descriptor cannot be prepared (dmaengine_prep_slave_single()
+returns NULL), the transfer is failed with SPI_TRANS_FAIL_NO_START and
+falls back to PIO. The dynamic-burst DMA path uses its own bounce
+buffers instead of the SPI core's mapping, so xfer->{tx,rx}_sg_mapped
+are not set and the core's DMA->PIO retry is skipped; the driver falls
+back to PIO internally. But none of the DMA-mode configuration is
+undone, so the PIO transfer runs with CTRL.SMC set, the wrong burst
+length and dynamic_burst cleared, and the transferred data is corrupted.
+
+This is easily hit on i.MX8MP boards that describe ECSPI DMA in the
+device tree but run SDMA on ROM firmware (no external sdma-imx7d.bin):
+every ECSPI DMA prepare fails. An Infineon SLB9670 TPM on ECSPI1 then
+returns shifted TPM2_GetCapability data, is flagged "field failure
+mode", /dev/tpmrm0 is never created.
+
+Set controller->fallback before re-running spi_imx_setupxfer() so the
+ECSPI is reconfigured exactly like a normal PIO transfer. With
+controller->fallback set, spi_imx_setupxfer() sees spi_imx_can_dma()
+return false, so it clears spi_imx->usedma and reprograms the controller
+(clears CTRL.SMC, restores dynamic_burst and the PIO burst length). No
+explicit spi_imx->usedma = false is needed: setupxfer() already updates
+it from the can_dma() result.
+
+Fixes: faa8e404ad8e ("spi: imx: support dynamic burst length for ECSPI DMA mode")
+Cc: stable@vger.kernel.org
+Signed-off-by: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
+Acked-by: Carlos Song <carlos.song@nxp.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Link: https://patch.msgid.link/20260624151958.18626-1-javier.pastrana@linutronix.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-imx.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
+index ae9912905c67..79a6c1a60b0a 100644
+--- a/drivers/spi/spi-imx.c
++++ b/drivers/spi/spi-imx.c
+@@ -2152,7 +2152,8 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
+       if (spi_imx->usedma) {
+               ret = spi_imx_dma_transfer(spi_imx, transfer);
+               if (transfer->error & SPI_TRANS_FAIL_NO_START) {
+-                      spi_imx->usedma = false;
++                      controller->fallback = true;
++                      spi_imx_setupxfer(spi, transfer);
+                       if (spi_imx->target_mode)
+                               return spi_imx_pio_transfer_target(spi, transfer);
+                       else
+-- 
+2.55.0
+
diff --git a/queue-7.1/spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch b/queue-7.1/spi-uniphier-fix-completion-initialization-order-before-devm_request_irq.patch
new file mode 100644 (file)
index 0000000..f183ec6
--- /dev/null
@@ -0,0 +1,52 @@
+From f3ad1c87d8201e54b66bd6072442f0b5d5a308ee Mon Sep 17 00:00:00 2001
+From: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Date: Tue, 16 Jun 2026 10:12:23 +0900
+Subject: spi: uniphier: Fix completion initialization order before devm_request_irq()
+
+From: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+
+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 <sangyun.kim@snu.ac.kr>
+Reported-by: Kyungwook Boo <bookyungwook@gmail.com>
+Fixes: 5ba155a4d4cc ("spi: add SPI controller driver for UniPhier SoC")
+Cc: stable@vger.kernel.org
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Link: https://patch.msgid.link/20260616011223.201357-1-hayashi.kunihiko@socionext.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/sunrpc-fix-uninitialized-xprt_create_args-structure.patch b/queue-7.1/sunrpc-fix-uninitialized-xprt_create_args-structure.patch
new file mode 100644 (file)
index 0000000..7c1120e
--- /dev/null
@@ -0,0 +1,44 @@
+From 17d90b68c3a3d7d7e95b49e1fe9381a723f637a8 Mon Sep 17 00:00:00 2001
+From: Hongling Zeng <zenghongling@kylinos.cn>
+Date: Wed, 3 Jun 2026 09:36:52 +0800
+Subject: sunrpc: fix uninitialized xprt_create_args structure
+
+From: Hongling Zeng <zenghongling@kylinos.cn>
+
+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 <jlayton@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sunrpc/sysfs.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/sunrpc/sysfs.c
++++ b/net/sunrpc/sysfs.c
+@@ -327,7 +327,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-7.1/taskstats-retain-dead-thread-stats-in-tgid-queries.patch b/queue-7.1/taskstats-retain-dead-thread-stats-in-tgid-queries.patch
new file mode 100644 (file)
index 0000000..d998430
--- /dev/null
@@ -0,0 +1,167 @@
+From b3e4fbb04220efc3bc022bcf31b5689d39c6b111 Mon Sep 17 00:00:00 2001
+From: Yiyang Chen <cyyzero16@gmail.com>
+Date: Mon, 13 Apr 2026 23:45:44 +0800
+Subject: taskstats: retain dead thread stats in TGID queries
+
+From: Yiyang Chen <cyyzero16@gmail.com>
+
+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 <cyyzero16@gmail.com>
+Acked-by: Balbir Singh <balbirs@nvidia.com>
+Cc: Dr. Thomas Orgis <thomas.orgis@uni-hamburg.de>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Wang Yaxin <wang.yaxin@zte.com.cn>
+Cc: Yang Yang <yang.yang29@zte.com.cn>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/tcp-decrement-tcp_md5_needed-static-branch.patch b/queue-7.1/tcp-decrement-tcp_md5_needed-static-branch.patch
new file mode 100644 (file)
index 0000000..8650fb5
--- /dev/null
@@ -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 <q.h.hack.winter@gmail.com>
+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 <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -4333,8 +4333,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-7.1/tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch b/queue-7.1/tcp-defer-md5sig_info-kfree-past-rcu-grace-period-in-tcp_connect.patch
new file mode 100644 (file)
index 0000000..38e4c71
--- /dev/null
@@ -0,0 +1,123 @@
+From b74cd55038905d5e74c1de109ab78a30b2ea0e1f Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+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 <michael.bommarito@gmail.com>
+
+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 <edumazet@google.com>
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Reviewed-by: Dmitry Safonov <dima@arista.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+[also credits to Qihang, who found that this races with tcp-diag]
+Reported-by: Qihang <q.h.hack.winter@gmail.com>
+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 <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1467,9 +1467,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
+@@ -4328,9 +4328,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-7.1/time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch b/queue-7.1/time-fix-off-by-one-in-compat-settimeofday-usec-validation.patch
new file mode 100644 (file)
index 0000000..6042d7f
--- /dev/null
@@ -0,0 +1,44 @@
+From 269f2b43fae692d1f3988c9f888a6301aa537b82 Mon Sep 17 00:00:00 2001
+From: Wang Yan <wangyan01@kylinos.cn>
+Date: Mon, 22 Jun 2026 18:33:48 +0800
+Subject: time: Fix off-by-one in compat settimeofday() usec validation
+
+From: Wang Yan <wangyan01@kylinos.cn>
+
+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 <wangyan01@kylinos.cn>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260622103348.120255-1-wangyan01@kylinos.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch b/queue-7.1/tpm-fix-event_size-output-in-tpm1_binary_bios_measurements_show.patch
new file mode 100644 (file)
index 0000000..4af27d6
--- /dev/null
@@ -0,0 +1,51 @@
+From 1a58f6115bfb34eabcc7de8a3a9745b219179781 Mon Sep 17 00:00:00 2001
+From: Thorsten Blum <thorsten.blum@linux.dev>
+Date: Mon, 15 Jun 2026 15:02:05 +0300
+Subject: tpm: fix event_size output in tpm1_binary_bios_measurements_show
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+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 <thorsten.blum@linux.dev>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/tpm-make-the-tpm-character-devices-non-seekable.patch b/queue-7.1/tpm-make-the-tpm-character-devices-non-seekable.patch
new file mode 100644 (file)
index 0000000..c41e831
--- /dev/null
@@ -0,0 +1,75 @@
+From f20d61c22bcaf172d6790b6500e3838e532e71c8 Mon Sep 17 00:00:00 2001
+From: Jaewon Yang <yong010301@gmail.com>
+Date: Mon, 13 Jul 2026 02:11:47 +0900
+Subject: tpm: Make the TPM character devices non-seekable
+
+From: Jaewon Yang <yong010301@gmail.com>
+
+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 <yong010301@gmail.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/tpm-restore-timeout-for-key-creation-commands.patch b/queue-7.1/tpm-restore-timeout-for-key-creation-commands.patch
new file mode 100644 (file)
index 0000000..a654f04
--- /dev/null
@@ -0,0 +1,46 @@
+From de59d78e64039baa5fed455ddb905ba8263e7ede Mon Sep 17 00:00:00 2001
+From: Baoli Zhang <baoli.zhang@linux.intel.com>
+Date: Tue, 21 Apr 2026 08:50:20 +0800
+Subject: tpm: restore timeout for key creation commands
+
+From: Baoli Zhang <baoli.zhang@linux.intel.com>
+
+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 <lili.li@intel.com>
+Signed-off-by: Lili Li <lili.li@intel.com>
+Signed-off-by: Baoli Zhang <baoli.zhang@linux.intel.com>
+Link: https://lore.kernel.org/r/20260421005021.13765-1-baoli.zhang@linux.intel.com
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -71,9 +71,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-7.1/tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch b/queue-7.1/tpm-tpm2-sessions-wait-for-async-kpp-completion-in-tpm_buf_append_salt.patch
new file mode 100644 (file)
index 0000000..e03c8bf
--- /dev/null
@@ -0,0 +1,141 @@
+From 73851a7c43dfa52d2ed9415889b33daf85da0ed9 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+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 <michael.bommarito@gmail.com>
+
+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 <michael.bommarito@gmail.com>
+Assisted-by: Claude:claude-opus-4-7
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -489,15 +489,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);
+@@ -520,14 +522,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 */
+@@ -535,11 +538,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
+@@ -551,8 +560,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
+@@ -562,8 +572,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;
+ }
+ /**
+@@ -1018,7 +1036,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-7.1/tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch b/queue-7.1/tpm-tpm_tis_spi-use-wait_woken-in-wait_for_tmp_stat.patch
new file mode 100644 (file)
index 0000000..be6e7cd
--- /dev/null
@@ -0,0 +1,95 @@
+From c0c9cfb3b75def8bf200a2d4db09015806acfeaf Mon Sep 17 00:00:00 2001
+From: Jarkko Sakkinen <jarkko@kernel.org>
+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 <jarkko@kernel.org>
+
+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 <linusw@kernel.org>
+Reported-by: Stefan Wahren <wahrenst@gmx.net>
+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 <linusw@kernel.org>
+Tested-by: Stefan Wahren <wahrenst@gmx.net>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-7.1/ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch b/queue-7.1/ufs-core-tracing-do-not-dereference-pointers-in-tp_printk.patch
new file mode 100644 (file)
index 0000000..3c1bd7d
--- /dev/null
@@ -0,0 +1,252 @@
+From 535fcf4b8a261fbb8cc4f91e4597343c135a90f2 Mon Sep 17 00:00:00 2001
+From: Steven Rostedt <rostedt@goodmis.org>
+Date: Tue, 30 Jun 2026 18:54:12 -0400
+Subject: ufs: core: tracing: Do not dereference pointers in TP_printk()
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+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 <peter.wang@mediatek.com>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -89,16 +89,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))
+ );
+@@ -111,6 +113,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)
+@@ -119,6 +122,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;
+@@ -126,7 +130,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)
+ );
+@@ -138,16 +142,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,
+@@ -158,6 +164,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)
+@@ -165,13 +172,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)
+ );
+@@ -200,6 +208,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)
+       ),
+@@ -208,13 +217,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),
+@@ -279,6 +289,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)
+@@ -291,6 +302,7 @@ TRACE_EVENT(ufshcd_command,
+       ),
+       TP_fast_assign(
++              __assign_str(dev_name);
+               __entry->sdev = sdev;
+               __entry->hba = hba;
+               __entry->str_t = str_t;
+@@ -307,7 +319,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
+@@ -322,6 +334,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)
+@@ -331,6 +344,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;
+@@ -340,7 +354,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
+       )
+ );
+@@ -353,6 +367,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)
+@@ -361,6 +376,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));
+@@ -369,7 +385,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))
+@@ -384,16 +400,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-7.1/xen-gntdev-fix-error-handling-in-ioctl.patch b/queue-7.1/xen-gntdev-fix-error-handling-in-ioctl.patch
new file mode 100644 (file)
index 0000000..6c63b25
--- /dev/null
@@ -0,0 +1,61 @@
+From 45ca1afe2fd14c04e37227e79d3f8455831d8408 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+Date: Mon, 22 Jun 2026 19:25:41 +0800
+Subject: xen/gntdev: fix error handling in ioctl
+
+From: Wentao Liang <vulab@iscas.ac.cn>
+
+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 <vulab@iscas.ac.cn>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Message-ID: <20260622112541.38194-1-vulab@iscas.ac.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/gntdev.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -670,11 +670,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-7.1/xfrm-nat_keepalive-avoid-double-free-on-send-error.patch b/queue-7.1/xfrm-nat_keepalive-avoid-double-free-on-send-error.patch
new file mode 100644 (file)
index 0000000..d85d9ac
--- /dev/null
@@ -0,0 +1,87 @@
+From 226f4a490d1a938fc838d8f8c46a4eca864c0d78 Mon Sep 17 00:00:00 2001
+From: Qianyu Luo <qianyuluo3@gmail.com>
+Date: Thu, 25 Jun 2026 13:55:08 +0800
+Subject: xfrm: nat_keepalive: avoid double free on send error
+
+From: Qianyu Luo <qianyuluo3@gmail.com>
+
+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 <yuantan098@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Qianyu Luo <qianyuluo3@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eyal Birger <eyal.birger@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 = ip6_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-7.1/xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch b/queue-7.1/xfrm-use-compat-translator-only-for-u64-alignment-mismatch.patch
new file mode 100644 (file)
index 0000000..9681b6d
--- /dev/null
@@ -0,0 +1,88 @@
+From 355fbcbdc2539cca7890b0d0914d4ce0f985ad74 Mon Sep 17 00:00:00 2001
+From: Sanman Pradhan <psanman@juniper.net>
+Date: Sun, 7 Jun 2026 16:47:34 +0000
+Subject: xfrm: use compat translator only for u64 alignment mismatch
+
+From: Sanman Pradhan <psanman@juniper.net>
+
+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 <psanman@juniper.net>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2984,7 +2984,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
+@@ -3472,7 +3472,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-7.1/xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch b/queue-7.1/xfrm-xfrm_interface-require-cap_net_admin-in-the-device-netns-for-changelink.patch
new file mode 100644 (file)
index 0000000..b772f25
--- /dev/null
@@ -0,0 +1,44 @@
+From 095515d89b19b6cc19dfcdc846f97403ed1ebce3 Mon Sep 17 00:00:00 2001
+From: Maoyi Xie <maoyixie.tju@gmail.com>
+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 <maoyixie.tju@gmail.com>
+
+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 <shaw.leon@gmail.com>
+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 <maoyixie.tju@gmail.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20260612085941.3158249-8-maoyixie.tju@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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");