From: Greg Kroah-Hartman Date: Thu, 28 May 2026 12:14:08 +0000 (+0200) Subject: 7.0-stable patches X-Git-Tag: v5.10.258~24 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=45b13753cb299a828df21c4b6d97d82d73f5e943;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: arm64-probes-handle-probes-on-hinted-conditional-branch-instructions.patch asoc-codecs-pcm512x-fix-null-ptr-dereference-in-pcm512x_overclock_xxx_put.patch batman-adv-bla-avoid-double-decrement-of-bla.num_requests.patch batman-adv-bla-avoid-null-ptr-deref-for-claim-via-dropped-interface.patch batman-adv-bla-fix-report_work-leak-on-backbone_gw-purge.patch batman-adv-clear-current-gateway-during-teardown.patch batman-adv-dat-handle-forward-allocation-error.patch batman-adv-fix-fragment-reassembly-length-accounting.patch batman-adv-fix-tp_meter-counter-underflow-during-shutdown.patch batman-adv-frag-disallow-unicast-fragment-in-fragment.patch batman-adv-iv-recover-ogm-scheduling-after-forward-packet-error.patch batman-adv-mcast-fix-use-after-free-in-orig_node-rcu-release.patch batman-adv-tp_meter-avoid-role-confusion-in-tp_list.patch batman-adv-tp_meter-avoid-use-of-uninit-sender-vars.patch batman-adv-tp_meter-directly-shut-down-timer-on-cleanup.patch batman-adv-tp_meter-fix-race-condition-in-send-error-reporting.patch batman-adv-tp_meter-fix-tp_vars-reference-leak-in-receiver-shutdown.patch batman-adv-tt-avoid-empty-vlan-responses.patch batman-adv-tt-fix-negative-last_changeset_len.patch batman-adv-tt-fix-negative-tt_buff_len.patch batman-adv-tt-fix-toctou-race-for-reported-vlans.patch batman-adv-tt-prevent-tvlv-entry-number-overflow.patch batman-adv-tt-reject-oversized-local-tvlv-buffers.patch batman-adv-tvlv-abort-ogm-send-on-tvlv-append-failure.patch batman-adv-tvlv-reject-oversized-tvlv-packets.patch batman-adv-v-stop-ogmv2-on-disabled-interface.patch cifs-fix-busy-dentry-used-after-unmounting.patch cpufreq-intel_pstate-use-correct-scaling-factor-on-raptor-lake-e.patch device-property-set-fwnode-secondary-to-null-in-fwnode_init.patch drm-amd-display-fix-integer-overflow-in-bios_get_image.patch drm-amd-display-validate-gpio-pin-lut-table-size-before-iterating.patch drm-amd-display-validate-payload-length-and-link_index-in-dc_process_dmub_aux_transfer_async.patch drm-amdgpu-vpe-force-collaborate-sync-after-trap.patch drm-bridge-chipone-icn6211-use-devm_drm_bridge_add-in-i2c-probe.patch drm-bridge-it66121-acquire-reset-gpio-in-probe.patch drm-bridge-megachips-remove-bridge-when-irq-request-fails.patch drm-i915-display-copy-color-pipeline-from-plane-in-the-primary-joiner-pipe.patch drm-i915-psr-apply-intel-dpcd-workaround-when-sdp-on-prior-line-used.patch drm-msm-fix-shrinker-deadlock.patch drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-on-error-path.patch drm-v3d-release-indirect-csd-gem-reference-on-cpu-job-free.patch drm-virtio-use-uninterruptible-resv-lock-for-plane-updates.patch drm-xe-multi_queue-fix-secondary-queue-error-case.patch fwctl-pds-validate-rpc-input-size-before-parsing.patch hwmon-pmbus-adm1266-bounce-blackbox-records-through-a-protocol-sized-buffer.patch hwmon-pmbus-adm1266-cap-pdio-scan-in-get_multiple-at-adm1266_pdio_nr.patch hwmon-pmbus-adm1266-don-t-clobber-gpio-bits-before-pdio-read-in-get_multiple.patch hwmon-pmbus-adm1266-include-pec-byte-in-pmbus_block_xfer-read-buffer.patch hwmon-pmbus-adm1266-register-the-gpio_chip-after-pmbus_do_probe.patch hwmon-pmbus-adm1266-register-the-nvmem-device-after-pmbus_do_probe.patch hwmon-pmbus-adm1266-reject-implausible-blackbox-record_count.patch hwmon-pmbus-adm1266-reject-short-block-read-responses-in-the-gpio-accessors.patch hwmon-pmbus-adm1266-seed-timestamp-from-the-real-time-clock.patch hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch i2c-tegra-fix-pm_runtime-leak-on-mutex_lock-failure.patch kvm-arm64-vgic-free-private_irqs-when-init-fails-after-allocation.patch kvm-arm64-vgic-its-reject-restored-dte-with-out-of-range-num_eventid_bits.patch kvm-svm-disable-avic-ipi-virtualization-on-hygon-family-18h-erratum-1235.patch loongarch-kprobes-use-larch_insn_text_copy-to-patch-instructions.patch loongarch-remove-unused-code-to-avoid-build-warning.patch mm-slub-hold-cpus_read_lock-around-flush_rcu_sheaves_on_cache.patch phy-exynos5-usbdrd-fix-usb-2.0-hs-phy-tuning-values-for-exynos7870.patch phy-qcom-edp-add-edp-dp-mode-switch-support.patch phy-qcom-edp-fix-aux_cfg8-programming-for-dp-mode.patch phy-qcom-edp-unify-generic-dp-edp-swing-and-pre-emphasis-tables.patch phy-qcom-qmp-ufs-fix-kaanapali-phy-pll-lock-failure-after-sm8650-g4-fix.patch phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch rdma-siw-reject-mpa-fpdu-length-underflow-before-signed-receive-math.patch riscv-kvm-return-sbi_err_failure-for-pmu_event_info-when-oom.patch riscv-kvm-return-sbi_err_failure-for-pmu_snapshot_set_shmem-when-oom.patch s390-cio-restore-gfp_dma-for-chsc-allocation.patch s390-pai-disable-duplicate-read-of-kernel-pai-counter-value.patch s390-pai-fix-missing-pai-counter-increments-under-heavy-load.patch scsi-isci-fix-use-after-free-in-device-removal-path.patch spi-ep93xx-fix-error-pointer-deref-after-dma-setup-failure.patch spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch spi-sprd-fix-error-pointer-deref-after-dma-setup-failure.patch spi-ti-qspi-fix-use-after-free-after-dma-setup-failure.patch tracing-do-not-call-map-ops-elt_free-if-elt_alloc-fails.patch virt-sev-guest-explicitly-leak-pages-in-unknown-state.patch --- diff --git a/queue-7.0/arm64-probes-handle-probes-on-hinted-conditional-branch-instructions.patch b/queue-7.0/arm64-probes-handle-probes-on-hinted-conditional-branch-instructions.patch new file mode 100644 index 0000000000..dfde592621 --- /dev/null +++ b/queue-7.0/arm64-probes-handle-probes-on-hinted-conditional-branch-instructions.patch @@ -0,0 +1,36 @@ +From 2ccd8ff980b50e842481bae71102fa3883fc4377 Mon Sep 17 00:00:00 2001 +From: Vladimir Murzin +Date: Fri, 15 May 2026 14:37:29 +0100 +Subject: arm64: probes: Handle probes on hinted conditional branch instructions + +From: Vladimir Murzin + +commit 2ccd8ff980b50e842481bae71102fa3883fc4377 upstream. + +BC.cond instructions introduced by FEAT_HBC cannot be executed +out-of-line, like other branch instructions. However, they can be +simulated in the same way as B.cond instructions. + +Extend the B.cond decoder mask to match BC.cond instructions as well, +and handle them using the existing B.cond simulation path. + +Fixes: 7f86d128e437 ("arm64: add HWCAP for FEAT_HBC (hinted conditional branches)") +Cc: +Signed-off-by: Vladimir Murzin +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/include/asm/insn.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/include/asm/insn.h ++++ b/arch/arm64/include/asm/insn.h +@@ -409,7 +409,7 @@ __AARCH64_INSN_FUNCS(cbz, 0x7F000000, 0x + __AARCH64_INSN_FUNCS(cbnz, 0x7F000000, 0x35000000) + __AARCH64_INSN_FUNCS(tbz, 0x7F000000, 0x36000000) + __AARCH64_INSN_FUNCS(tbnz, 0x7F000000, 0x37000000) +-__AARCH64_INSN_FUNCS(bcond, 0xFF000010, 0x54000000) ++__AARCH64_INSN_FUNCS(bcond, 0xFF000000, 0x54000000) + __AARCH64_INSN_FUNCS(svc, 0xFFE0001F, 0xD4000001) + __AARCH64_INSN_FUNCS(hvc, 0xFFE0001F, 0xD4000002) + __AARCH64_INSN_FUNCS(smc, 0xFFE0001F, 0xD4000003) diff --git a/queue-7.0/asoc-codecs-pcm512x-fix-null-ptr-dereference-in-pcm512x_overclock_xxx_put.patch b/queue-7.0/asoc-codecs-pcm512x-fix-null-ptr-dereference-in-pcm512x_overclock_xxx_put.patch new file mode 100644 index 0000000000..8cba1adfcc --- /dev/null +++ b/queue-7.0/asoc-codecs-pcm512x-fix-null-ptr-dereference-in-pcm512x_overclock_xxx_put.patch @@ -0,0 +1,57 @@ +From 09e8f9a9aa19aa8c1b0cc7a0ebc68f6ecf86a660 Mon Sep 17 00:00:00 2001 +From: Jeongjun Park +Date: Thu, 21 May 2026 20:37:12 +0900 +Subject: ASoC: codecs: pcm512x: fix null-ptr dereference in pcm512x_overclock_xxx_put() + +From: Jeongjun Park + +commit 09e8f9a9aa19aa8c1b0cc7a0ebc68f6ecf86a660 upstream. + +In the pcm512x chipset driver, pcm512x_overclock_xxx_put() is defined as +a general mixer kcontrol instead of a DAPM kcontrol, so struct +snd_soc_dapm_context must not be accessed via +snd_soc_dapm_kcontrol_to_dapm(). + +This causes a NULL pointer dereference, so it must be modified to use +snd_soc_component_to_dapm(). + +Cc: stable@kernel.org +Closes: https://github.com/raspberrypi/linux/issues/7242 +Fixes: 02dbbb7e982a ("ASoC: codecs: pcm512x: convert to snd_soc_dapm_xxx()") +Signed-off-by: Jeongjun Park +Link: https://patch.msgid.link/20260521113712.227438-1-aha310510@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/codecs/pcm512x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -235,7 +235,7 @@ static int pcm512x_overclock_pll_put(str + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); ++ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + switch (snd_soc_dapm_get_bias_level(dapm)) { +@@ -264,7 +264,7 @@ static int pcm512x_overclock_dsp_put(str + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); ++ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + switch (snd_soc_dapm_get_bias_level(dapm)) { +@@ -293,7 +293,7 @@ static int pcm512x_overclock_dac_put(str + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); ++ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + switch (snd_soc_dapm_get_bias_level(dapm)) { diff --git a/queue-7.0/batman-adv-bla-avoid-double-decrement-of-bla.num_requests.patch b/queue-7.0/batman-adv-bla-avoid-double-decrement-of-bla.num_requests.patch new file mode 100644 index 0000000000..efefcd4426 --- /dev/null +++ b/queue-7.0/batman-adv-bla-avoid-double-decrement-of-bla.num_requests.patch @@ -0,0 +1,223 @@ +From 83ab69bd12b80f6ea169c8bea6977701b53a043d Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Tue, 12 May 2026 09:13:31 +0200 +Subject: batman-adv: bla: avoid double decrement of bla.num_requests + +From: Sven Eckelmann + +commit 83ab69bd12b80f6ea169c8bea6977701b53a043d upstream. + +The bla.num_requests is increased when no request_sent was in progress. And +it is decremented in various places (announcement was received, backbone is +purged, periodic work). But the check if the request_sent is actually set +to a specific state and the atomic_dec/_inc are not safe because they are +not atomic (TOCTOU) and multiple such code portions can run concurrently. + +At the same time, it is necessary to modify request_sent (state) and +bla.num_requests atomically. Otherwise batadv_bla_send_request() might set +request_sent to 1 and is interrupted. batadv_handle_announce() can then +set request_sent back to 0 and decrement num_requests before +batadv_bla_send_request() incremented it. + +The two operations must therefore be locked. And since state (request_sent) +and wait_periods are only accessed inside this lock, they can be converted +to simpler datatypes. And to avoid that the bla.num_requests is touched by +a parallel running context with a valid backbone_gw reference after +batadv_bla_purge_backbone_gw() ran, a third state "stopped" is required to +correctly signal that a backbone_gw is in the state of being cleaned up. + +Cc: stable@kernel.org +Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bridge_loop_avoidance.c | 51 ++++++++++++++++++++++----------- + net/batman-adv/mesh-interface.c | 1 + net/batman-adv/types.h | 39 ++++++++++++++++++++----- + 3 files changed, 67 insertions(+), 24 deletions(-) + +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -514,8 +514,8 @@ batadv_bla_get_backbone_gw(struct batadv + entry->crc = BATADV_BLA_CRC_INIT; + entry->bat_priv = bat_priv; + spin_lock_init(&entry->crc_lock); +- atomic_set(&entry->request_sent, 0); +- atomic_set(&entry->wait_periods, 0); ++ entry->state = BATADV_BLA_BACKBONE_GW_SYNCED; ++ entry->wait_periods = 0; + ether_addr_copy(entry->orig, orig); + INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report); + kref_init(&entry->refcount); +@@ -544,9 +544,13 @@ batadv_bla_get_backbone_gw(struct batadv + batadv_bla_send_announce(bat_priv, entry); + + /* this will be decreased in the worker thread */ +- atomic_inc(&entry->request_sent); +- atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS); +- atomic_inc(&bat_priv->bla.num_requests); ++ spin_lock_bh(&bat_priv->bla.num_requests_lock); ++ if (entry->state == BATADV_BLA_BACKBONE_GW_SYNCED) { ++ entry->state = BATADV_BLA_BACKBONE_GW_UNSYNCED; ++ entry->wait_periods = BATADV_BLA_WAIT_PERIODS; ++ atomic_inc(&bat_priv->bla.num_requests); ++ } ++ spin_unlock_bh(&bat_priv->bla.num_requests_lock); + } + + return entry; +@@ -649,10 +653,12 @@ static void batadv_bla_send_request(stru + backbone_gw->vid, BATADV_CLAIM_TYPE_REQUEST); + + /* no local broadcasts should be sent or received, for now. */ +- if (!atomic_read(&backbone_gw->request_sent)) { ++ spin_lock_bh(&backbone_gw->bat_priv->bla.num_requests_lock); ++ if (backbone_gw->state == BATADV_BLA_BACKBONE_GW_SYNCED) { ++ backbone_gw->state = BATADV_BLA_BACKBONE_GW_UNSYNCED; + atomic_inc(&backbone_gw->bat_priv->bla.num_requests); +- atomic_set(&backbone_gw->request_sent, 1); + } ++ spin_unlock_bh(&backbone_gw->bat_priv->bla.num_requests_lock); + } + + /** +@@ -873,10 +879,12 @@ static bool batadv_handle_announce(struc + /* if we have sent a request and the crc was OK, + * we can allow traffic again. + */ +- if (atomic_read(&backbone_gw->request_sent)) { ++ spin_lock_bh(&bat_priv->bla.num_requests_lock); ++ if (backbone_gw->state == BATADV_BLA_BACKBONE_GW_UNSYNCED) { ++ backbone_gw->state = BATADV_BLA_BACKBONE_GW_SYNCED; + atomic_dec(&backbone_gw->bat_priv->bla.num_requests); +- atomic_set(&backbone_gw->request_sent, 0); + } ++ spin_unlock_bh(&bat_priv->bla.num_requests_lock); + } + + batadv_backbone_gw_put(backbone_gw); +@@ -1255,9 +1263,13 @@ purge_now: + purged = true; + + /* don't wait for the pending request anymore */ +- if (atomic_read(&backbone_gw->request_sent)) ++ spin_lock_bh(&bat_priv->bla.num_requests_lock); ++ if (backbone_gw->state == BATADV_BLA_BACKBONE_GW_UNSYNCED) + atomic_dec(&bat_priv->bla.num_requests); + ++ backbone_gw->state = BATADV_BLA_BACKBONE_GW_STOPPED; ++ spin_unlock_bh(&bat_priv->bla.num_requests_lock); ++ + batadv_bla_del_backbone_claims(backbone_gw); + + hlist_del_rcu(&backbone_gw->hash_entry); +@@ -1508,7 +1520,7 @@ static void batadv_bla_periodic_work(str + batadv_bla_send_loopdetect(bat_priv, + backbone_gw); + +- /* request_sent is only set after creation to avoid ++ /* state is only set to unsynced after creation to avoid + * problems when we are not yet known as backbone gw + * in the backbone. + * +@@ -1517,14 +1529,21 @@ static void batadv_bla_periodic_work(str + * some grace time. + */ + +- if (atomic_read(&backbone_gw->request_sent) == 0) +- continue; ++ spin_lock_bh(&bat_priv->bla.num_requests_lock); ++ if (backbone_gw->state != BATADV_BLA_BACKBONE_GW_UNSYNCED) ++ goto unlock_next; + +- if (!atomic_dec_and_test(&backbone_gw->wait_periods)) +- continue; ++ if (backbone_gw->wait_periods > 0) ++ backbone_gw->wait_periods--; ++ ++ if (backbone_gw->wait_periods > 0) ++ goto unlock_next; + ++ backbone_gw->state = BATADV_BLA_BACKBONE_GW_SYNCED; + atomic_dec(&backbone_gw->bat_priv->bla.num_requests); +- atomic_set(&backbone_gw->request_sent, 0); ++ ++unlock_next: ++ spin_unlock_bh(&bat_priv->bla.num_requests_lock); + } + rcu_read_unlock(); + } +--- a/net/batman-adv/mesh-interface.c ++++ b/net/batman-adv/mesh-interface.c +@@ -787,6 +787,7 @@ static int batadv_meshif_init_late(struc + atomic_set(&bat_priv->tt.ogm_append_cnt, 0); + #ifdef CONFIG_BATMAN_ADV_BLA + atomic_set(&bat_priv->bla.num_requests, 0); ++ spin_lock_init(&bat_priv->bla.num_requests_lock); + #endif + atomic_set(&bat_priv->tp_num, 0); + +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -1027,6 +1027,12 @@ struct batadv_priv_bla { + atomic_t num_requests; + + /** ++ * @num_requests_lock: locks update num_requests + ++ * batadv_backbone_gw::state + batadv_backbone_gw::wait_periods update ++ */ ++ spinlock_t num_requests_lock; ++ ++ /** + * @claim_hash: hash table containing mesh nodes this host has claimed + */ + struct batadv_hashtable *claim_hash; +@@ -1669,6 +1675,27 @@ struct batadv_priv { + + #ifdef CONFIG_BATMAN_ADV_BLA + ++enum batadv_bla_backbone_gw_state { ++ /** ++ * @BATADV_BLA_BACKBONE_GW_STOPPED: backbone gw is being removed ++ * and it must not longer work on requests ++ */ ++ BATADV_BLA_BACKBONE_GW_STOPPED, ++ ++ /** ++ * @BATADV_BLA_BACKBONE_GW_UNSYNCED: backbone was detected out ++ * of sync and a request was send. No traffic is forwarded until the ++ * situation is resolved ++ */ ++ BATADV_BLA_BACKBONE_GW_UNSYNCED, ++ ++ /** ++ * @BATADV_BLA_BACKBONE_GW_SYNCED: backbone is consider to be in ++ * sync. traffic can be forwarded ++ */ ++ BATADV_BLA_BACKBONE_GW_SYNCED, ++}; ++ + /** + * struct batadv_bla_backbone_gw - batman-adv gateway bridged into the LAN + */ +@@ -1694,16 +1721,12 @@ struct batadv_bla_backbone_gw { + /** + * @wait_periods: grace time for bridge forward delays and bla group + * forming at bootup phase - no bcast traffic is formwared until it has +- * elapsed ++ * elapsed. Must only be access with num_requests_lock. + */ +- atomic_t wait_periods; ++ u8 wait_periods; + +- /** +- * @request_sent: if this bool is set to true we are out of sync with +- * this backbone gateway - no bcast traffic is formwared until the +- * situation was resolved +- */ +- atomic_t request_sent; ++ /** @state: sync state. Must only be access with num_requests_lock. */ ++ enum batadv_bla_backbone_gw_state state; + + /** @crc: crc16 checksum over all claims */ + u16 crc; diff --git a/queue-7.0/batman-adv-bla-avoid-null-ptr-deref-for-claim-via-dropped-interface.patch b/queue-7.0/batman-adv-bla-avoid-null-ptr-deref-for-claim-via-dropped-interface.patch new file mode 100644 index 0000000000..bd416dec44 --- /dev/null +++ b/queue-7.0/batman-adv-bla-avoid-null-ptr-deref-for-claim-via-dropped-interface.patch @@ -0,0 +1,47 @@ +From f80d3d98d2ff78d9e2fe5d68b1f45948c4f7bd24 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Tue, 19 May 2026 09:23:49 +0200 +Subject: batman-adv: bla: avoid NULL-ptr deref for claim via dropped interface + +From: Sven Eckelmann + +commit f80d3d98d2ff78d9e2fe5d68b1f45948c4f7bd24 upstream. + +Without rtnl_lock held, a hardif might be retrieved as primary interface of +a meshif, but then (while operating on this interface) getting decoupled +from the mesh interface. In this case, the meshif still exists but the +pointer from the primary hardif to the meshif is set to NULL. + +The mesh_iface must be checked first to be non-NULL before continuing to +send an ARP request using meshif. + +Cc: stable@kernel.org +Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code") +Reported-by: Ido Schimmel +Reported-by: syzbot+9fdcc9f05a98a540b816@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=9fdcc9f05a98a540b816 +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bridge_loop_avoidance.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -356,12 +356,14 @@ static void batadv_bla_send_claim(struct + sizeof(local_claim_dest)); + local_claim_dest.type = claimtype; + +- mesh_iface = primary_if->mesh_iface; ++ mesh_iface = READ_ONCE(primary_if->mesh_iface); ++ if (!mesh_iface) ++ goto out; + + skb = arp_create(ARPOP_REPLY, ETH_P_ARP, + /* IP DST: 0.0.0.0 */ + zeroip, +- primary_if->mesh_iface, ++ mesh_iface, + /* IP SRC: 0.0.0.0 */ + zeroip, + /* Ethernet DST: Broadcast */ diff --git a/queue-7.0/batman-adv-bla-fix-report_work-leak-on-backbone_gw-purge.patch b/queue-7.0/batman-adv-bla-fix-report_work-leak-on-backbone_gw-purge.patch new file mode 100644 index 0000000000..858c972a91 --- /dev/null +++ b/queue-7.0/batman-adv-bla-fix-report_work-leak-on-backbone_gw-purge.patch @@ -0,0 +1,115 @@ +From 0459430add32ea41f3e2ef9351610e6d33627a6b Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sun, 10 May 2026 11:43:20 +0200 +Subject: batman-adv: bla: fix report_work leak on backbone_gw purge + +From: Sven Eckelmann + +commit 0459430add32ea41f3e2ef9351610e6d33627a6b upstream. + +batadv_bla_purge_backbone_gw() removes stale backbone gateway entries, +but fails to properly handle their associated report_work: + +- If report_work is running, the purge must wait for it to finish before + freeing the backbone_gw, otherwise the worker may access freed memory + (e.g. bat_priv). +- If report_work is pending, the purge must cancel it and release the + reference held for that pending work item. + +The previous implementation called hlist_for_each_entry_safe() inside a +spin_lock_bh() section, but cancel_work_sync() may sleep and therefore +cannot be called from within a spinlock-protected region. + +Restructure the loop to handle one entry per spinlock critical section: +acquire the lock, find the next entry to purge, remove it from the hash +list, then release the lock before calling cancel_work_sync() and +dropping the hash_entry reference. Repeat until no more entries require +purging. + +Cc: stable@kernel.org +Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code") +Reviewed-by: Simon Wunderlich +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bridge_loop_avoidance.c | 60 ++++++++++++++++++++------------- + 1 file changed, 38 insertions(+), 22 deletions(-) + +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -1224,6 +1224,7 @@ static void batadv_bla_purge_backbone_gw + struct hlist_head *head; + struct batadv_hashtable *hash; + spinlock_t *list_lock; /* protects write access to the hash lists */ ++ bool purged; + int i; + + hash = bat_priv->bla.backbone_hash; +@@ -1234,30 +1235,45 @@ static void batadv_bla_purge_backbone_gw + head = &hash->table[i]; + list_lock = &hash->list_locks[i]; + +- spin_lock_bh(list_lock); +- hlist_for_each_entry_safe(backbone_gw, node_tmp, +- head, hash_entry) { +- if (now) +- goto purge_now; +- if (!batadv_has_timed_out(backbone_gw->lasttime, +- BATADV_BLA_BACKBONE_TIMEOUT)) +- continue; +- +- batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv, +- "%s(): backbone gw %pM timed out\n", +- __func__, backbone_gw->orig); ++ do { ++ purged = false; ++ ++ spin_lock_bh(list_lock); ++ hlist_for_each_entry_safe(backbone_gw, node_tmp, ++ head, hash_entry) { ++ if (now) ++ goto purge_now; ++ if (!batadv_has_timed_out(backbone_gw->lasttime, ++ BATADV_BLA_BACKBONE_TIMEOUT)) ++ continue; ++ ++ batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv, ++ "%s(): backbone gw %pM timed out\n", ++ __func__, backbone_gw->orig); + + purge_now: +- /* don't wait for the pending request anymore */ +- if (atomic_read(&backbone_gw->request_sent)) +- atomic_dec(&bat_priv->bla.num_requests); +- +- batadv_bla_del_backbone_claims(backbone_gw); +- +- hlist_del_rcu(&backbone_gw->hash_entry); +- batadv_backbone_gw_put(backbone_gw); +- } +- spin_unlock_bh(list_lock); ++ purged = true; ++ ++ /* don't wait for the pending request anymore */ ++ if (atomic_read(&backbone_gw->request_sent)) ++ atomic_dec(&bat_priv->bla.num_requests); ++ ++ batadv_bla_del_backbone_claims(backbone_gw); ++ ++ hlist_del_rcu(&backbone_gw->hash_entry); ++ break; ++ } ++ spin_unlock_bh(list_lock); ++ ++ if (purged) { ++ /* reference for pending report_work */ ++ if (cancel_work_sync(&backbone_gw->report_work)) ++ batadv_backbone_gw_put(backbone_gw); ++ ++ /* reference for hash_entry */ ++ batadv_backbone_gw_put(backbone_gw); ++ } ++ } while (purged); + } + } + diff --git a/queue-7.0/batman-adv-clear-current-gateway-during-teardown.patch b/queue-7.0/batman-adv-clear-current-gateway-during-teardown.patch new file mode 100644 index 0000000000..5e98694cba --- /dev/null +++ b/queue-7.0/batman-adv-clear-current-gateway-during-teardown.patch @@ -0,0 +1,48 @@ +From a340a51ed801eab7bb454150c226323b865263cc Mon Sep 17 00:00:00 2001 +From: Ruijie Li +Date: Thu, 14 May 2026 16:13:25 +0800 +Subject: batman-adv: clear current gateway during teardown + +From: Ruijie Li + +commit a340a51ed801eab7bb454150c226323b865263cc upstream. + +batadv_gw_node_free() removes the gateway list entries during mesh teardown, +but it does not clear the currently selected gateway. This leaves stale +gateway state behind across cleanup and can break a later mesh recreation. + +Clear bat_priv->gw.curr_gw before walking the gateway list so the selected +gateway reference is dropped as part of teardown. + +Fixes: 2265c1410864 ("batman-adv: gateway election code refactoring") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Ruijie Li +Signed-off-by: Zhanpeng Li +Signed-off-by: Ren Wei +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/gateway_client.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/net/batman-adv/gateway_client.c ++++ b/net/batman-adv/gateway_client.c +@@ -478,10 +478,14 @@ void batadv_gw_node_delete(struct batadv + */ + void batadv_gw_node_free(struct batadv_priv *bat_priv) + { ++ struct batadv_gw_node *curr_gw; + struct batadv_gw_node *gw_node; + struct hlist_node *node_tmp; + + spin_lock_bh(&bat_priv->gw.list_lock); ++ curr_gw = rcu_replace_pointer(bat_priv->gw.curr_gw, NULL, true); ++ batadv_gw_node_put(curr_gw); ++ + hlist_for_each_entry_safe(gw_node, node_tmp, + &bat_priv->gw.gateway_list, list) { + hlist_del_init_rcu(&gw_node->list); diff --git a/queue-7.0/batman-adv-dat-handle-forward-allocation-error.patch b/queue-7.0/batman-adv-dat-handle-forward-allocation-error.patch new file mode 100644 index 0000000000..cf44e3d5a3 --- /dev/null +++ b/queue-7.0/batman-adv-dat-handle-forward-allocation-error.patch @@ -0,0 +1,42 @@ +From 2d8826a2d3657cea66fb0370f9e521575a673871 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Wed, 13 May 2026 09:01:34 +0200 +Subject: batman-adv: dat: handle forward allocation error + +From: Sven Eckelmann + +commit 2d8826a2d3657cea66fb0370f9e521575a673871 upstream. + +batadv_dat_forward_data() calls pskb_copy_for_clone() to duplicate an skb +for each DHT candidate, but does not check the return value before passing +it to batadv_send_skb_prepare_unicast_4addr(). That function dereferences +the skb unconditionally, so a failed allocation triggers a NULL pointer +dereference. + +Skip forwarding to the current DHT candidate on allocation failure. + +Cc: stable@kernel.org +Fixes: 785ea1144182 ("batman-adv: Distributed ARP Table - create DHT helper functions") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Reviewed-by: Yuan Tan +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/distributed-arp-table.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/batman-adv/distributed-arp-table.c ++++ b/net/batman-adv/distributed-arp-table.c +@@ -696,6 +696,9 @@ static bool batadv_dat_forward_data(stru + goto free_orig; + + tmp_skb = pskb_copy_for_clone(skb, GFP_ATOMIC); ++ if (!tmp_skb) ++ goto free_neigh; ++ + if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb, + cand[i].orig_node, + packet_subtype)) { diff --git a/queue-7.0/batman-adv-fix-fragment-reassembly-length-accounting.patch b/queue-7.0/batman-adv-fix-fragment-reassembly-length-accounting.patch new file mode 100644 index 0000000000..af6c40ebb8 --- /dev/null +++ b/queue-7.0/batman-adv-fix-fragment-reassembly-length-accounting.patch @@ -0,0 +1,132 @@ +From 9cd3f16c320bfdadd4509358122368deb56a5741 Mon Sep 17 00:00:00 2001 +From: Ruide Cao +Date: Wed, 13 May 2026 11:58:15 +0800 +Subject: batman-adv: fix fragment reassembly length accounting + +From: Ruide Cao + +commit 9cd3f16c320bfdadd4509358122368deb56a5741 upstream. + +batman-adv keeps a running payload length for queued fragments and uses it +to validate a fragment chain before reassembly. + +That accounting currently allows the accumulated fragment length to be +truncated during updates. As a result, malformed fragment chains can +bypass the intended validation and drive reassembly with inconsistent +length state, leading to a local denial of service. + +Fix the accounting by storing the accumulated length in a length-typed +field and rejecting update overflows before the existing validation logic +runs. + +The fix was verified against the original reproducer and against valid +fragment reassembly paths. + +Fixes: 610bfc6bc99b ("batman-adv: Receive fragmented packets and merge") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Ruide Cao +Tested-by: Ren Wei +Signed-off-by: Ren Wei +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/fragmentation.c | 23 +++++++++++++++++------ + net/batman-adv/types.h | 2 +- + 2 files changed, 18 insertions(+), 7 deletions(-) + +--- a/net/batman-adv/fragmentation.c ++++ b/net/batman-adv/fragmentation.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -80,9 +81,9 @@ void batadv_frag_purge_orig(struct batad + * + * Return: the maximum size of payload that can be fragmented. + */ +-static int batadv_frag_size_limit(void) ++static size_t batadv_frag_size_limit(void) + { +- int limit = BATADV_FRAG_MAX_FRAG_SIZE; ++ size_t limit = BATADV_FRAG_MAX_FRAG_SIZE; + + limit -= sizeof(struct batadv_frag_packet); + limit *= BATADV_FRAG_MAX_FRAGMENTS; +@@ -143,7 +144,9 @@ static bool batadv_frag_insert_packet(st + struct batadv_frag_packet *frag_packet; + u8 bucket; + u16 seqno, hdr_size = sizeof(struct batadv_frag_packet); ++ bool overflow = false; + bool ret = false; ++ size_t data_len; + + /* Linearize packet to avoid linearizing 16 packets in a row when doing + * the later merge. Non-linear merge should be added to remove this +@@ -153,6 +156,7 @@ static bool batadv_frag_insert_packet(st + goto err; + + frag_packet = (struct batadv_frag_packet *)skb->data; ++ data_len = skb->len - hdr_size; + seqno = ntohs(frag_packet->seqno); + bucket = seqno % BATADV_FRAG_BUFFER_COUNT; + +@@ -171,7 +175,7 @@ static bool batadv_frag_insert_packet(st + spin_lock_bh(&chain->lock); + if (batadv_frag_init_chain(chain, seqno)) { + hlist_add_head(&frag_entry_new->list, &chain->fragment_list); +- chain->size = skb->len - hdr_size; ++ chain->size = data_len; + chain->timestamp = jiffies; + chain->total_size = ntohs(frag_packet->total_size); + ret = true; +@@ -188,7 +192,11 @@ static bool batadv_frag_insert_packet(st + if (frag_entry_curr->no < frag_entry_new->no) { + hlist_add_before(&frag_entry_new->list, + &frag_entry_curr->list); +- chain->size += skb->len - hdr_size; ++ ++ if (check_add_overflow(chain->size, data_len, ++ &chain->size)) ++ overflow = true; ++ + chain->timestamp = jiffies; + ret = true; + goto out; +@@ -201,13 +209,16 @@ static bool batadv_frag_insert_packet(st + /* Reached the end of the list, so insert after 'frag_entry_last'. */ + if (likely(frag_entry_last)) { + hlist_add_behind(&frag_entry_new->list, &frag_entry_last->list); +- chain->size += skb->len - hdr_size; ++ ++ if (check_add_overflow(chain->size, data_len, &chain->size)) ++ overflow = true; ++ + chain->timestamp = jiffies; + ret = true; + } + + out: +- if (chain->size > batadv_frag_size_limit() || ++ if (overflow || chain->size > batadv_frag_size_limit() || + chain->total_size != ntohs(frag_packet->total_size) || + chain->total_size > batadv_frag_size_limit()) { + /* Clear chain if total size of either the list or the packet +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -304,7 +304,7 @@ struct batadv_frag_table_entry { + u16 seqno; + + /** @size: accumulated size of packets in list */ +- u16 size; ++ size_t size; + + /** @total_size: expected size of the assembled packet */ + u16 total_size; diff --git a/queue-7.0/batman-adv-fix-tp_meter-counter-underflow-during-shutdown.patch b/queue-7.0/batman-adv-fix-tp_meter-counter-underflow-during-shutdown.patch new file mode 100644 index 0000000000..858323ba5e --- /dev/null +++ b/queue-7.0/batman-adv-fix-tp_meter-counter-underflow-during-shutdown.patch @@ -0,0 +1,56 @@ +From 94f3b133168d1c49895e7cc6afbcf1cc0b354602 Mon Sep 17 00:00:00 2001 +From: Luxiao Xu +Date: Mon, 11 May 2026 18:52:09 +0200 +Subject: batman-adv: fix tp_meter counter underflow during shutdown + +From: Luxiao Xu + +commit 94f3b133168d1c49895e7cc6afbcf1cc0b354602 upstream. + +batadv_tp_sender_shutdown() unconditionally decrements the "sending" +atomic counter. If multiple paths (e.g. timeout, user cancel, and +normal finish) call this function, the counter can underflow to -1. + +Since the sender logic treats any non-zero value as "still sending", +a negative value causes the sender kthread to loop indefinitely. +This leads to a use-after-free when the interface is removed while +the zombie thread is still active. + +Fix this by using atomic_xchg() to ensure the counter only transitions +from 1 to 0 once. + +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +[sven: added missing change in batadv_tp_send] +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -451,7 +451,7 @@ static void batadv_tp_sender_end(struct + static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars, + enum batadv_tp_meter_reason reason) + { +- if (!atomic_dec_and_test(&tp_vars->sending)) ++ if (atomic_xchg(&tp_vars->sending, 0) != 1) + return; + + tp_vars->reason = reason; +@@ -885,7 +885,7 @@ static int batadv_tp_send(void *arg) + "Meter: %s() cannot send packets (%d)\n", + __func__, err); + /* ensure nobody else tries to stop the thread now */ +- if (atomic_dec_and_test(&tp_vars->sending)) ++ if (atomic_xchg(&tp_vars->sending, 0) == 1) + tp_vars->reason = err; + break; + } diff --git a/queue-7.0/batman-adv-frag-disallow-unicast-fragment-in-fragment.patch b/queue-7.0/batman-adv-frag-disallow-unicast-fragment-in-fragment.patch new file mode 100644 index 0000000000..e6ca6a3b94 --- /dev/null +++ b/queue-7.0/batman-adv-frag-disallow-unicast-fragment-in-fragment.patch @@ -0,0 +1,87 @@ +From bc62216dc8e221e3781afa14430f45208bfa9af9 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Wed, 13 May 2026 09:01:36 +0200 +Subject: batman-adv: frag: disallow unicast fragment in fragment + +From: Sven Eckelmann + +commit bc62216dc8e221e3781afa14430f45208bfa9af9 upstream. + +batadv_frag_skb_buffer() is called by batadv_batman_skb_recv() when a +BATADV_UNICAST_FRAG packet is received. Once all fragments are collected +and the packet is reassembled, batadv_recv_frag_packet() calls +batadv_batman_skb_recv() again to process the defragmented payload. + +A malicious sender can craft a BATADV_UNICAST_FRAG packet whose reassembled +payload is itself a BATADV_UNICAST_FRAG packet (matryoshka-style nesting). +Each nesting level recurses through batadv_batman_skb_recv() without bound, +growing the kernel stack until it is exhausted. + +Since refragmentation or fragments in fragments are not actually allowed, +discard all packets which are still BATADV_UNICAST_FRAG packets after the +defragmentation process. + +Cc: stable@kernel.org +Fixes: 610bfc6bc99b ("batman-adv: Receive fragmented packets and merge") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Reviewed-by: Yuan Tan +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/fragmentation.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/net/batman-adv/fragmentation.c ++++ b/net/batman-adv/fragmentation.c +@@ -305,6 +305,31 @@ free: + } + + /** ++ * batadv_skb_is_frag() - check if newly merged skb is gain a unicast packet ++ * @skb: newly merged skb ++ * ++ * Return: if newly skb is of type BATADV_UNICAST_FRAG ++ */ ++static bool batadv_skb_is_frag(struct sk_buff *skb) ++{ ++ struct batadv_ogm_packet *batadv_ogm_packet; ++ ++ /* packet should hold at least type and version */ ++ if (unlikely(!pskb_may_pull(skb, 2))) ++ return false; ++ ++ batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data; ++ ++ if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) ++ return false; ++ ++ if (batadv_ogm_packet->packet_type != BATADV_UNICAST_FRAG) ++ return false; ++ ++ return true; ++} ++ ++/** + * batadv_frag_skb_buffer() - buffer fragment for later merge + * @skb: skb to buffer + * @orig_node_src: originator that the skb is received from +@@ -337,6 +362,16 @@ bool batadv_frag_skb_buffer(struct sk_bu + if (!skb_out) + goto out_err; + ++ /* fragment in fragment is not allowed. otherwise it is possible ++ * to exhaust the stack when receiving a matryoshka-style ++ * "fragments in a fragment packet" ++ */ ++ if (batadv_skb_is_frag(skb_out)) { ++ kfree_skb(skb_out); ++ skb_out = NULL; ++ goto out_err; ++ } ++ + out: + ret = true; + out_err: diff --git a/queue-7.0/batman-adv-iv-recover-ogm-scheduling-after-forward-packet-error.patch b/queue-7.0/batman-adv-iv-recover-ogm-scheduling-after-forward-packet-error.patch new file mode 100644 index 0000000000..2ea60e6cff --- /dev/null +++ b/queue-7.0/batman-adv-iv-recover-ogm-scheduling-after-forward-packet-error.patch @@ -0,0 +1,223 @@ +From aa3153bd139a6c48667dcd02608d3b2c80bff02c Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Fri, 15 May 2026 22:00:40 +0200 +Subject: batman-adv: iv: recover OGM scheduling after forward packet error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sven Eckelmann + +commit aa3153bd139a6c48667dcd02608d3b2c80bff02c upstream. + +When batadv_iv_ogm_schedule_buff() fails to allocate and queue a forward +packet for OGM transmission, the work item that drives periodic OGM +scheduling is never re-armed. This silently halts transmission of the +node's own OGMs on the affected interface — only OGMs from other peers +continue to be aggregated and forwarded. + +Fix this by tracking whether batadv_iv_ogm_queue_add() (and transitively +batadv_iv_ogm_aggregate_new()) successfully scheduled a forward packet. +When scheduling fails, batadv_iv_ogm_schedule_buff() falls back to queuing +a dedicated recovery work item (reschedule_work) that fires after one +originator interval and calls batadv_iv_ogm_schedule() again. + +Cc: stable@kernel.org +Fixes: c6c8fea29769 ("net: Add batman-adv meshing protocol") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bat_iv_ogm.c | 76 +++++++++++++++++++++++++++++++++----------- + net/batman-adv/types.h | 3 + + 2 files changed, 60 insertions(+), 19 deletions(-) + +--- a/net/batman-adv/bat_iv_ogm.c ++++ b/net/batman-adv/bat_iv_ogm.c +@@ -224,6 +224,8 @@ static void batadv_iv_ogm_iface_disable( + hard_iface->bat_iv.ogm_buff = NULL; + + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); ++ ++ cancel_delayed_work_sync(&hard_iface->bat_iv.reschedule_work); + } + + static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) +@@ -536,8 +538,10 @@ out: + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * @own_packet: true if it is a self-generated ogm ++ * ++ * Return: whether forward packet was scheduled + */ +-static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, ++static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, + int packet_len, unsigned long send_time, + bool direct_link, + struct batadv_hard_iface *if_incoming, +@@ -561,13 +565,13 @@ static void batadv_iv_ogm_aggregate_new( + + skb = netdev_alloc_skb_ip_align(NULL, skb_size); + if (!skb) +- return; ++ return false; + + forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing, + queue_left, bat_priv, skb); + if (!forw_packet_aggr) { + kfree_skb(skb); +- return; ++ return false; + } + + forw_packet_aggr->skb->priority = TC_PRIO_CONTROL; +@@ -590,6 +594,8 @@ static void batadv_iv_ogm_aggregate_new( + batadv_iv_send_outstanding_bat_ogm_packet); + + batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time); ++ ++ return true; + } + + /* aggregate a new packet into the existing ogm packet */ +@@ -617,8 +623,10 @@ static void batadv_iv_ogm_aggregate(stru + * @if_outgoing: interface for which the retransmission should be considered + * @own_packet: true if it is a self-generated ogm + * @send_time: timestamp (jiffies) when the packet is to be sent ++ * ++ * Return: whether forward packet was scheduled + */ +-static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, ++static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, + unsigned char *packet_buff, + int packet_len, + struct batadv_hard_iface *if_incoming, +@@ -670,14 +678,16 @@ static void batadv_iv_ogm_queue_add(stru + if (!own_packet && atomic_read(&bat_priv->aggregated_ogms)) + send_time += max_aggregation_jiffies; + +- batadv_iv_ogm_aggregate_new(packet_buff, packet_len, +- send_time, direct_link, +- if_incoming, if_outgoing, +- own_packet); ++ return batadv_iv_ogm_aggregate_new(packet_buff, packet_len, ++ send_time, direct_link, ++ if_incoming, if_outgoing, ++ own_packet); + } else { + batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff, + packet_len, direct_link); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); ++ ++ return true; + } + } + +@@ -790,6 +800,8 @@ static void batadv_iv_ogm_schedule_buff( + u32 seqno; + u16 tvlv_len = 0; + unsigned long send_time; ++ bool reschedule = false; ++ bool scheduled; + int ret; + + lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); +@@ -818,11 +830,8 @@ static void batadv_iv_ogm_schedule_buff( + ogm_buff_len, + BATADV_OGM_HLEN); + if (ret < 0) { +- /* OGMs must be queued even when the buffer allocation for +- * TVLVs failed. just fall back to the non-TVLV version +- */ +- ret = 0; +- *ogm_buff_len = BATADV_OGM_HLEN; ++ reschedule = true; ++ goto out; + } + + tvlv_len = ret; +@@ -844,8 +853,11 @@ static void batadv_iv_ogm_schedule_buff( + /* OGMs from secondary interfaces are only scheduled on their + * respective interfaces. + */ +- batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, +- hard_iface, hard_iface, 1, send_time); ++ scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, ++ hard_iface, hard_iface, 1, send_time); ++ if (!scheduled) ++ reschedule = true; ++ + goto out; + } + +@@ -857,15 +869,28 @@ static void batadv_iv_ogm_schedule_buff( + if (!kref_get_unless_zero(&tmp_hard_iface->refcount)) + continue; + +- batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, +- *ogm_buff_len, hard_iface, +- tmp_hard_iface, 1, send_time); +- ++ scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, ++ *ogm_buff_len, hard_iface, ++ tmp_hard_iface, 1, send_time); + batadv_hardif_put(tmp_hard_iface); ++ ++ if (!scheduled && tmp_hard_iface == hard_iface) ++ reschedule = true; + } + rcu_read_unlock(); + + out: ++ if (reschedule) { ++ /* there was a failure scheduling the own forward packet. ++ * as result, the batadv_iv_send_outstanding_bat_ogm_packet() ++ * work item is no longer scheduled. it is therefore necessary ++ * to reschedule it manually ++ */ ++ queue_delayed_work(batadv_event_workqueue, ++ &hard_iface->bat_iv.reschedule_work, ++ msecs_to_jiffies(atomic_read(&bat_priv->orig_interval))); ++ } ++ + batadv_hardif_put(primary_if); + } + +@@ -880,6 +905,17 @@ static void batadv_iv_ogm_schedule(struc + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); + } + ++static void batadv_iv_ogm_reschedule(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = to_delayed_work(work); ++ struct batadv_hard_iface *hard_iface; ++ ++ hard_iface = container_of(delayed_work, ++ struct batadv_hard_iface, ++ bat_iv.reschedule_work); ++ batadv_iv_ogm_schedule(hard_iface); ++} ++ + /** + * batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over interface + * @orig_node: originator which reproadcasted the OGMs directly +@@ -2272,6 +2308,8 @@ batadv_iv_ogm_neigh_is_sob(struct batadv + + static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface) + { ++ INIT_DELAYED_WORK(&hard_iface->bat_iv.reschedule_work, batadv_iv_ogm_reschedule); ++ + /* begin scheduling originator messages on that interface */ + batadv_iv_ogm_schedule(hard_iface); + } +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -83,6 +83,9 @@ struct batadv_hard_iface_bat_iv { + /** @ogm_seqno: OGM sequence number - used to identify each OGM */ + atomic_t ogm_seqno; + ++ /** @reschedule_work: recover OGM schedule after schedule error */ ++ struct delayed_work reschedule_work; ++ + /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */ + struct mutex ogm_buff_mutex; + }; diff --git a/queue-7.0/batman-adv-mcast-fix-use-after-free-in-orig_node-rcu-release.patch b/queue-7.0/batman-adv-mcast-fix-use-after-free-in-orig_node-rcu-release.patch new file mode 100644 index 0000000000..5849c201aa --- /dev/null +++ b/queue-7.0/batman-adv-mcast-fix-use-after-free-in-orig_node-rcu-release.patch @@ -0,0 +1,51 @@ +From 20c2d6a20ca936f5aaa6dd40f73f262ac45c87cc Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Thu, 14 May 2026 19:22:02 +0200 +Subject: batman-adv: mcast: fix use-after-free in orig_node RCU release +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sven Eckelmann + +commit 20c2d6a20ca936f5aaa6dd40f73f262ac45c87cc upstream. + +batadv_mcast_purge_orig() removes entries from RCU-protected hlists but +does not wait for an RCU grace period before returning. Concurrent RCU +readers may still accesses references to those entries at the point of +removal. RCU-protected readers trying to operate on entries like +orig->mcast_want_all_ipv6_node will then access already freed memory. + +Fix this by moving batadv_mcast_purge_orig() to batadv_orig_node_release(), +just before the call_rcu() invocation. This ensures RCU readers that were +active at purge time have drained before the orig_node memory is reclaimed. + +Cc: stable@kernel.org +Fixes: ab49886e3da7 ("batman-adv: Add IPv4 link-local/IPv6-ll-all-nodes multicast support") +Acked-by: Linus Lüssing +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/originator.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/batman-adv/originator.c ++++ b/net/batman-adv/originator.c +@@ -835,8 +835,6 @@ static void batadv_orig_node_free_rcu(st + + orig_node = container_of(rcu, struct batadv_orig_node, rcu); + +- batadv_mcast_purge_orig(orig_node); +- + batadv_frag_purge_orig(orig_node, NULL); + + kfree(orig_node->tt_buff); +@@ -887,6 +885,8 @@ void batadv_orig_node_release(struct kre + } + spin_unlock_bh(&orig_node->vlan_list_lock); + ++ batadv_mcast_purge_orig(orig_node); ++ + call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu); + } + diff --git a/queue-7.0/batman-adv-tp_meter-avoid-role-confusion-in-tp_list.patch b/queue-7.0/batman-adv-tp_meter-avoid-role-confusion-in-tp_list.patch new file mode 100644 index 0000000000..57d24390d3 --- /dev/null +++ b/queue-7.0/batman-adv-tp_meter-avoid-role-confusion-in-tp_list.patch @@ -0,0 +1,190 @@ +From ff24f2ecfd94c07a2b89bac497433e3b23271cac Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 16 May 2026 12:33:41 +0200 +Subject: batman-adv: tp_meter: avoid role confusion in tp_list + +From: Sven Eckelmann + +commit ff24f2ecfd94c07a2b89bac497433e3b23271cac upstream. + +Session lookups in tp_list matched only on destination address (and +optionally session ID), leaving role validation to the caller. If two +sessions with the same other_end coexisted (one as sender, one as receiver) +a lookup could silently return the wrong one, causing the caller's role to +bail out early, potentially skipping necessary cleanup. + +Move the role check into the lookup functions themselves so the correct +entry is always returned, or none at all. Since batadv_tp_start() +legitimately needs to detect any active session to a destination regardless +of role, introduce a dedicated helper for that case rather than bending the +existing lookup semantics. + +Cc: stable@kernel.org +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 59 ++++++++++++++++++++++++++++------------------ + 1 file changed, 36 insertions(+), 23 deletions(-) + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -255,6 +255,7 @@ static void batadv_tp_batctl_error_notif + * batadv_tp_list_find() - find a tp_vars object in the global list + * @bat_priv: the bat priv with all the mesh interface information + * @dst: the other endpoint MAC address to look for ++ * @role: role of the session + * + * Look for a tp_vars object matching dst as end_point and return it after + * having increment the refcounter. Return NULL is not found +@@ -262,7 +263,8 @@ static void batadv_tp_batctl_error_notif + * Return: matching tp_vars or NULL when no tp_vars with @dst was found + */ + static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv, +- const u8 *dst) ++ const u8 *dst, ++ enum batadv_tp_meter_role role) + { + struct batadv_tp_vars *pos, *tp_vars = NULL; + +@@ -271,6 +273,9 @@ static struct batadv_tp_vars *batadv_tp_ + if (!batadv_compare_eth(pos->other_end, dst)) + continue; + ++ if (pos->role != role) ++ continue; ++ + /* most of the time this function is invoked during the normal + * process..it makes sens to pay more when the session is + * finished and to speed the process up during the measurement +@@ -287,11 +292,32 @@ static struct batadv_tp_vars *batadv_tp_ + } + + /** ++ * batadv_tp_list_active() - check if session from/to destination is ongoing ++ * @bat_priv: the bat priv with all the mesh interface information ++ * @dst: the other endpoint MAC address to look for ++ * ++ * Return: if matching session with @dst was found ++ */ ++static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst) ++ __must_hold(&bat_priv->tp_list_lock) ++{ ++ struct batadv_tp_vars *tp_vars; ++ ++ hlist_for_each_entry_rcu(tp_vars, &bat_priv->tp_list, list) { ++ if (batadv_compare_eth(tp_vars->other_end, dst)) ++ return true; ++ } ++ ++ return false; ++} ++ ++/** + * batadv_tp_list_find_session() - find tp_vars session object in the global + * list + * @bat_priv: the bat priv with all the mesh interface information + * @dst: the other endpoint MAC address to look for + * @session: session identifier ++ * @role: role of the session + * + * Look for a tp_vars object matching dst as end_point, session as tp meter + * session and return it after having increment the refcounter. Return NULL +@@ -301,7 +327,7 @@ static struct batadv_tp_vars *batadv_tp_ + */ + static struct batadv_tp_vars * + batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst, +- const u8 *session) ++ const u8 *session, enum batadv_tp_meter_role role) + { + struct batadv_tp_vars *pos, *tp_vars = NULL; + +@@ -313,6 +339,9 @@ batadv_tp_list_find_session(struct batad + if (memcmp(pos->session, session, sizeof(pos->session)) != 0) + continue; + ++ if (pos->role != role) ++ continue; ++ + /* most of the time this function is invoked during the normal + * process..it makes sense to pay more when the session is + * finished and to speed the process up during the measurement +@@ -665,13 +694,10 @@ static void batadv_tp_recv_ack(struct ba + + /* find the tp_vars */ + tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, +- icmp->session); ++ icmp->session, BATADV_TP_SENDER); + if (unlikely(!tp_vars)) + return; + +- if (unlikely(tp_vars->role != BATADV_TP_SENDER)) +- goto out; +- + if (unlikely(batadv_tp_sender_stopped(tp_vars))) + goto out; + +@@ -980,10 +1006,8 @@ void batadv_tp_start(struct batadv_priv + return; + } + +- tp_vars = batadv_tp_list_find(bat_priv, dst); +- if (tp_vars) { ++ if (batadv_tp_list_active(bat_priv, dst)) { + spin_unlock_bh(&bat_priv->tp_list_lock); +- batadv_tp_vars_put(tp_vars); + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Meter: test to or from the same node already ongoing, aborting\n"); + batadv_tp_batctl_error_notify(BATADV_TP_REASON_ALREADY_ONGOING, +@@ -1104,18 +1128,14 @@ void batadv_tp_stop(struct batadv_priv * + if (!orig_node) + return; + +- tp_vars = batadv_tp_list_find(bat_priv, orig_node->orig); ++ tp_vars = batadv_tp_list_find(bat_priv, orig_node->orig, BATADV_TP_SENDER); + if (!tp_vars) { + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Meter: trying to interrupt an already over connection\n"); + goto out_put_orig_node; + } + +- if (unlikely(tp_vars->role != BATADV_TP_SENDER)) +- goto out_put_tp_vars; +- + batadv_tp_sender_shutdown(tp_vars, return_value); +-out_put_tp_vars: + batadv_tp_vars_put(tp_vars); + out_put_orig_node: + batadv_orig_node_put(orig_node); +@@ -1371,7 +1391,7 @@ batadv_tp_init_recv(struct batadv_priv * + goto out_unlock; + + tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, +- icmp->session); ++ icmp->session, BATADV_TP_RECEIVER); + if (tp_vars) + goto out_unlock; + +@@ -1442,7 +1462,7 @@ static void batadv_tp_recv_msg(struct ba + } + } else { + tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, +- icmp->session); ++ icmp->session, BATADV_TP_RECEIVER); + if (!tp_vars) { + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Unexpected packet from %pM!\n", +@@ -1451,13 +1471,6 @@ static void batadv_tp_recv_msg(struct ba + } + } + +- if (unlikely(tp_vars->role != BATADV_TP_RECEIVER)) { +- batadv_dbg(BATADV_DBG_TP_METER, bat_priv, +- "Meter: dropping packet: not expected (role=%u)\n", +- tp_vars->role); +- goto out; +- } +- + tp_vars->last_recv_time = jiffies; + + /* if the packet is a duplicate, it may be the case that an ACK has been diff --git a/queue-7.0/batman-adv-tp_meter-avoid-use-of-uninit-sender-vars.patch b/queue-7.0/batman-adv-tp_meter-avoid-use-of-uninit-sender-vars.patch new file mode 100644 index 0000000000..e0648b1f31 --- /dev/null +++ b/queue-7.0/batman-adv-tp_meter-avoid-use-of-uninit-sender-vars.patch @@ -0,0 +1,65 @@ +From 6c65cf23d4c6170fcf5714c32aa64689718cb142 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Wed, 13 May 2026 09:01:35 +0200 +Subject: batman-adv: tp_meter: avoid use of uninit sender vars + +From: Sven Eckelmann + +commit 6c65cf23d4c6170fcf5714c32aa64689718cb142 upstream. + +batadv_tp_recv_ack() and batadv_tp_stop() are only valid for tp_vars in the +BATADV_TP_SENDER role. When called with a BATADV_TP_RECEIVER role, it +proceeds to read sender-only members that were never initialized, leading +to undefined behavior. + +This can be triggered when a node that is currently acting as a receiver in +an ongoing tp_meter session receives a malicious ACK packet. + +Guard against this by checking tp_vars->role immediately after the +lookup and bailing out if it is not BATADV_TP_SENDER, before any of +those members are accessed. + +Cc: stable@kernel.org +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Reviewed-by: Yuan Tan +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -663,6 +663,9 @@ static void batadv_tp_recv_ack(struct ba + if (unlikely(!tp_vars)) + return; + ++ if (unlikely(tp_vars->role != BATADV_TP_SENDER)) ++ goto out; ++ + if (unlikely(atomic_read(&tp_vars->sending) == 0)) + goto out; + +@@ -1100,12 +1103,16 @@ void batadv_tp_stop(struct batadv_priv * + if (!tp_vars) { + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Meter: trying to interrupt an already over connection\n"); +- goto out; ++ goto out_put_orig_node; + } + ++ if (unlikely(tp_vars->role != BATADV_TP_SENDER)) ++ goto out_put_tp_vars; ++ + batadv_tp_sender_shutdown(tp_vars, return_value); ++out_put_tp_vars: + batadv_tp_vars_put(tp_vars); +-out: ++out_put_orig_node: + batadv_orig_node_put(orig_node); + } + diff --git a/queue-7.0/batman-adv-tp_meter-directly-shut-down-timer-on-cleanup.patch b/queue-7.0/batman-adv-tp_meter-directly-shut-down-timer-on-cleanup.patch new file mode 100644 index 0000000000..e6e89593b8 --- /dev/null +++ b/queue-7.0/batman-adv-tp_meter-directly-shut-down-timer-on-cleanup.patch @@ -0,0 +1,54 @@ +From d5487249a81ea658717614009c8f46acc5b7101a Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Wed, 13 May 2026 10:43:54 +0200 +Subject: batman-adv: tp_meter: directly shut down timer on cleanup + +From: Sven Eckelmann + +commit d5487249a81ea658717614009c8f46acc5b7101a upstream. + +batadv_tp_sender_cleanup() was calling timer_delete_sync() followed by +timer_delete() to guard against the timer handler re-arming itself between +the two calls. This double-deletion hack relied on the sending status being +set to 0 to suppress re-arming. + +Replace both calls with a single timer_shutdown_sync(). This function both +waits for any running timer callback to complete (like timer_delete_sync()) +and permanently disarms the timer so it cannot be re-armed afterwards, +making re-arming prevention unconditional and self-documenting. + +The re-arming property is also required because otherwise: + +1. context 0 (batadv_tp_recv_ack()) checks in + batadv_tp_reset_sender_timer() if sending is still 1 -> it is +2. context 1 changes in batadv_tp_sender_shutdown() sending to 0 and in + this process forces the kthread to stop timer in + batadv_tp_sender_cleanup() +3. context 0 continues in batadv_tp_reset_sender_timer() and rearms the + timer -> but the reference for it is already gone + +Cc: stable@kernel.org +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -400,13 +400,7 @@ static void batadv_tp_sender_cleanup(str + batadv_tp_list_detach(tp_vars); + + /* kill the timer and remove its reference */ +- timer_delete_sync(&tp_vars->timer); +- /* the worker might have rearmed itself therefore we kill it again. Note +- * that if the worker should run again before invoking the following +- * timer_delete(), it would not re-arm itself once again because the status +- * is OFF now +- */ +- timer_delete(&tp_vars->timer); ++ timer_shutdown_sync(&tp_vars->timer); + batadv_tp_vars_put(tp_vars); + } + diff --git a/queue-7.0/batman-adv-tp_meter-fix-race-condition-in-send-error-reporting.patch b/queue-7.0/batman-adv-tp_meter-fix-race-condition-in-send-error-reporting.patch new file mode 100644 index 0000000000..463c27e8c8 --- /dev/null +++ b/queue-7.0/batman-adv-tp_meter-fix-race-condition-in-send-error-reporting.patch @@ -0,0 +1,182 @@ +From 71dce47f0758537fff78fddb5fb0d4632d29b29f Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Wed, 13 May 2026 23:38:54 +0200 +Subject: batman-adv: tp_meter: fix race condition in send error reporting + +From: Sven Eckelmann + +commit 71dce47f0758537fff78fddb5fb0d4632d29b29f upstream. + +batadv_tp_sender_shutdown() previously used two separate variables to track +session state: sending (an atomic flag indicating whether the session was +active) and reason (a plain enum storing the stop reason). This introduced +a race window between the two writes: after sending was cleared to 0, +batadv_tp_send() could observe the stopped state and call +batadv_tp_sender_end() before reason was written, causing the wrong stop +reason to be reported to the caller. + +Fix this by consolidating both variables into a single atomic send_result, +which holds 0 while the session is running and the stop reason once it +ends. + +Cc: stable@kernel.org +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 40 +++++++++++++++++++++++++--------------- + net/batman-adv/types.h | 10 +++++----- + 2 files changed, 30 insertions(+), 20 deletions(-) + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -413,11 +413,14 @@ static void batadv_tp_sender_cleanup(str + static void batadv_tp_sender_end(struct batadv_priv *bat_priv, + struct batadv_tp_vars *tp_vars) + { ++ enum batadv_tp_meter_reason reason; + u32 session_cookie; + ++ reason = atomic_read(&tp_vars->send_result); ++ + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Test towards %pM finished..shutting down (reason=%d)\n", +- tp_vars->other_end, tp_vars->reason); ++ tp_vars->other_end, reason); + + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Last timing stats: SRTT=%ums RTTVAR=%ums RTO=%ums\n", +@@ -430,7 +433,7 @@ static void batadv_tp_sender_end(struct + session_cookie = batadv_tp_session_cookie(tp_vars->session, + tp_vars->icmp_uid); + +- batadv_tp_batctl_notify(tp_vars->reason, ++ batadv_tp_batctl_notify(reason, + tp_vars->other_end, + bat_priv, + tp_vars->start_time, +@@ -446,10 +449,18 @@ static void batadv_tp_sender_end(struct + static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars, + enum batadv_tp_meter_reason reason) + { +- if (atomic_xchg(&tp_vars->sending, 0) != 1) +- return; ++ atomic_cmpxchg(&tp_vars->send_result, 0, reason); ++} + +- tp_vars->reason = reason; ++/** ++ * batadv_tp_sender_stopped() - check if tp session was stopped with reason ++ * @tp_vars: the private data of the current TP meter session ++ * ++ * Return: whether stop reason was found ++ */ ++static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars) ++{ ++ return atomic_read(&tp_vars->send_result) != 0; + } + + /** +@@ -479,7 +490,7 @@ static void batadv_tp_reset_sender_timer + /* most of the time this function is invoked while normal packet + * reception... + */ +- if (unlikely(atomic_read(&tp_vars->sending) == 0)) ++ if (unlikely(batadv_tp_sender_stopped(tp_vars))) + /* timer ref will be dropped in batadv_tp_sender_cleanup */ + return; + +@@ -499,7 +510,7 @@ static void batadv_tp_sender_timeout(str + struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer); + struct batadv_priv *bat_priv = tp_vars->bat_priv; + +- if (atomic_read(&tp_vars->sending) == 0) ++ if (batadv_tp_sender_stopped(tp_vars)) + return; + + /* if the user waited long enough...shutdown the test */ +@@ -661,7 +672,7 @@ static void batadv_tp_recv_ack(struct ba + if (unlikely(tp_vars->role != BATADV_TP_SENDER)) + goto out; + +- if (unlikely(atomic_read(&tp_vars->sending) == 0)) ++ if (unlikely(batadv_tp_sender_stopped(tp_vars))) + goto out; + + /* old ACK? silently drop it.. */ +@@ -827,21 +838,21 @@ static int batadv_tp_send(void *arg) + + if (unlikely(tp_vars->role != BATADV_TP_SENDER)) { + err = BATADV_TP_REASON_DST_UNREACHABLE; +- tp_vars->reason = err; ++ batadv_tp_sender_shutdown(tp_vars, err); + goto out; + } + + orig_node = batadv_orig_hash_find(bat_priv, tp_vars->other_end); + if (unlikely(!orig_node)) { + err = BATADV_TP_REASON_DST_UNREACHABLE; +- tp_vars->reason = err; ++ batadv_tp_sender_shutdown(tp_vars, err); + goto out; + } + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (unlikely(!primary_if)) { + err = BATADV_TP_REASON_DST_UNREACHABLE; +- tp_vars->reason = err; ++ batadv_tp_sender_shutdown(tp_vars, err); + goto out; + } + +@@ -860,7 +871,7 @@ static int batadv_tp_send(void *arg) + queue_delayed_work(batadv_event_workqueue, &tp_vars->finish_work, + msecs_to_jiffies(tp_vars->test_length)); + +- while (atomic_read(&tp_vars->sending) != 0) { ++ while (!batadv_tp_sender_stopped(tp_vars)) { + if (unlikely(!batadv_tp_avail(tp_vars, payload_len))) { + batadv_tp_wait_available(tp_vars, payload_len); + continue; +@@ -883,8 +894,7 @@ static int batadv_tp_send(void *arg) + "Meter: %s() cannot send packets (%d)\n", + __func__, err); + /* ensure nobody else tries to stop the thread now */ +- if (atomic_xchg(&tp_vars->sending, 0) == 1) +- tp_vars->reason = err; ++ batadv_tp_sender_shutdown(tp_vars, err); + break; + } + +@@ -1006,7 +1016,7 @@ void batadv_tp_start(struct batadv_priv + ether_addr_copy(tp_vars->other_end, dst); + kref_init(&tp_vars->refcount); + tp_vars->role = BATADV_TP_SENDER; +- atomic_set(&tp_vars->sending, 1); ++ atomic_set(&tp_vars->send_result, 0); + memcpy(tp_vars->session, session_id, sizeof(session_id)); + tp_vars->icmp_uid = icmp_uid; + +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -1329,15 +1329,15 @@ struct batadv_tp_vars { + /** @role: receiver/sender modi */ + enum batadv_tp_meter_role role; + +- /** @sending: sending binary semaphore: 1 if sending, 0 is not */ +- atomic_t sending; ++ /** ++ * @send_result: 0 when sending is ongoing and otherwise ++ * enum batadv_tp_meter_reason ++ */ ++ atomic_t send_result; + + /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */ + atomic_t receiving; + +- /** @reason: reason for a stopped session */ +- enum batadv_tp_meter_reason reason; +- + /** @finish_work: work item for the finishing procedure */ + struct delayed_work finish_work; + diff --git a/queue-7.0/batman-adv-tp_meter-fix-tp_vars-reference-leak-in-receiver-shutdown.patch b/queue-7.0/batman-adv-tp_meter-fix-tp_vars-reference-leak-in-receiver-shutdown.patch new file mode 100644 index 0000000000..eb88098c95 --- /dev/null +++ b/queue-7.0/batman-adv-tp_meter-fix-tp_vars-reference-leak-in-receiver-shutdown.patch @@ -0,0 +1,91 @@ +From 77098e4bea37af51d3962efa88a5af2ea5e1ac57 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sun, 10 May 2026 11:31:03 +0200 +Subject: batman-adv: tp_meter: fix tp_vars reference leak in receiver shutdown + +From: Sven Eckelmann + +commit 77098e4bea37af51d3962efa88a5af2ea5e1ac57 upstream. + +The receiver shutdown timer handler, batadv_tp_receiver_shutdown(), is +responsible for releasing the tp_vars reference it holds. However, the +existing logic for coordinating this release with batadv_tp_stop_all() was +flawed. + +timer_shutdown_sync() guarantees the timer will not fire again after it +returns, but it returns non-zero only when the timer was pending at the +time of the call. If the timer had already expired (and +batadv_tp_stop_all() would unsucessfully try to rearm itself), +batadv_tp_stop_all() skips its batadv_tp_vars_put(), and +batadv_tp_receiver_shutdown() fails to put its own reference as well. + +Fix this by introducing a new atomic variable receiving that is set to 1 +when the receiver is initialized and cleared atomically with atomic_xchg() +by whichever side claims it first. Only the side that observes the +transition from 1 to 0 is responsible for releasing the tp_vars timer +reference, eliminating the uncertainty. + +Cc: stable@kernel.org +Fixes: 3d3cf6a7314a ("batman-adv: stop tp_meter sessions during mesh teardown") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 13 +++++++++++-- + net/batman-adv/types.h | 3 +++ + 2 files changed, 14 insertions(+), 2 deletions(-) + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -8,6 +8,7 @@ + #include "main.h" + + #include ++#include + #include + #include + #include +@@ -1157,6 +1158,9 @@ static void batadv_tp_receiver_shutdown( + spin_unlock_bh(&tp_vars->unacked_lock); + + /* drop reference of timer */ ++ if (WARN_ON(atomic_xchg(&tp_vars->receiving, 0) != 1)) ++ return; ++ + batadv_tp_vars_put(tp_vars); + } + +@@ -1375,6 +1379,7 @@ batadv_tp_init_recv(struct batadv_priv * + + ether_addr_copy(tp_vars->other_end, icmp->orig); + tp_vars->role = BATADV_TP_RECEIVER; ++ atomic_set(&tp_vars->receiving, 1); + memcpy(tp_vars->session, icmp->session, sizeof(tp_vars->session)); + tp_vars->last_recv = BATADV_TP_FIRST_SEQ; + tp_vars->bat_priv = bat_priv; +@@ -1547,8 +1552,12 @@ void batadv_tp_stop_all(struct batadv_pr + break; + case BATADV_TP_RECEIVER: + batadv_tp_list_detach(tp_var); +- if (timer_shutdown_sync(&tp_var->timer)) +- batadv_tp_vars_put(tp_var); ++ timer_shutdown_sync(&tp_var->timer); ++ ++ if (atomic_xchg(&tp_var->receiving, 0) != 1) ++ break; ++ ++ batadv_tp_vars_put(tp_var); + break; + } + +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -1332,6 +1332,9 @@ struct batadv_tp_vars { + /** @sending: sending binary semaphore: 1 if sending, 0 is not */ + atomic_t sending; + ++ /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */ ++ atomic_t receiving; ++ + /** @reason: reason for a stopped session */ + enum batadv_tp_meter_reason reason; + diff --git a/queue-7.0/batman-adv-tt-avoid-empty-vlan-responses.patch b/queue-7.0/batman-adv-tt-avoid-empty-vlan-responses.patch new file mode 100644 index 0000000000..e765f4fc01 --- /dev/null +++ b/queue-7.0/batman-adv-tt-avoid-empty-vlan-responses.patch @@ -0,0 +1,83 @@ +From fa1bd704940b5bcbc32c0b28db9167405c8ee5e0 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 2 May 2026 20:47:34 +0200 +Subject: batman-adv: tt: avoid empty VLAN responses + +From: Sven Eckelmann + +commit fa1bd704940b5bcbc32c0b28db9167405c8ee5e0 upstream. + +The commit 16116dac2339 ("batman-adv: prevent TT request storms by not +sending inconsistent TT TLVLs") added checks to the local (direct) TT +response code. But the response can also be done indirectly by another node +using the global TT state. To avoid such inconsistency states reported in +the original fix, also avoid sending empty VLANs for replies from the +global TT state. + +Cc: stable@kernel.org +Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/translation-table.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -797,24 +797,26 @@ batadv_tt_prepare_tvlv_global_data(struc + s32 *tt_len) + { + u16 num_vlan = 0; +- u16 num_entries = 0; + u16 tvlv_len = 0; + unsigned int change_offset; + struct batadv_tvlv_tt_vlan_data *tt_vlan; + struct batadv_orig_node_vlan *vlan; ++ u16 total_entries = 0; + u8 *tt_change_ptr; ++ int vlan_entries; + + spin_lock_bh(&orig_node->vlan_list_lock); + hlist_for_each_entry(vlan, &orig_node->vlan_list, list) { ++ vlan_entries = atomic_read(&vlan->tt.num_entries); ++ total_entries += vlan_entries; + num_vlan++; +- num_entries += atomic_read(&vlan->tt.num_entries); + } + + change_offset = struct_size(*tt_data, vlan_data, num_vlan); + + /* if tt_len is negative, allocate the space needed by the full table */ + if (*tt_len < 0) +- *tt_len = batadv_tt_len(num_entries); ++ *tt_len = batadv_tt_len(total_entries); + + if (change_offset > U16_MAX || *tt_len > U16_MAX - change_offset) { + *tt_len = 0; +@@ -835,14 +837,26 @@ batadv_tt_prepare_tvlv_global_data(struc + (*tt_data)->num_vlan = htons(num_vlan); + + tt_vlan = (*tt_data)->vlan_data; ++ num_vlan = 0; + hlist_for_each_entry(vlan, &orig_node->vlan_list, list) { ++ vlan_entries = atomic_read(&vlan->tt.num_entries); ++ if (vlan_entries < 1) ++ continue; ++ + tt_vlan->vid = htons(vlan->vid); + tt_vlan->crc = htonl(vlan->tt.crc); + tt_vlan->reserved = 0; + + tt_vlan++; ++ num_vlan++; + } + ++ /* recalculate in case number of VLANs reduced */ ++ change_offset = struct_size(*tt_data, vlan_data, num_vlan); ++ tvlv_len = *tt_len + change_offset; ++ ++ (*tt_data)->num_vlan = htons(num_vlan); ++ + tt_change_ptr = (u8 *)*tt_data + change_offset; + *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; + diff --git a/queue-7.0/batman-adv-tt-fix-negative-last_changeset_len.patch b/queue-7.0/batman-adv-tt-fix-negative-last_changeset_len.patch new file mode 100644 index 0000000000..e984e2ee45 --- /dev/null +++ b/queue-7.0/batman-adv-tt-fix-negative-last_changeset_len.patch @@ -0,0 +1,41 @@ +From fc92cdfcb295cefa4344d71a527d61b638b7bfc4 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 2 May 2026 19:53:21 +0200 +Subject: batman-adv: tt: fix negative last_changeset_len + +From: Sven Eckelmann + +commit fc92cdfcb295cefa4344d71a527d61b638b7bfc4 upstream. + +batadv_piv_tt::last_changeset_len len was declared as s16, but the field is +never intended to hold a negative value. When a value greater than 32767 is +assigned, it wraps to a negative signed integer. + +In batadv_send_my_tt_response(), last_changeset_len is temporarily widened +to s32. The incorrectly negative s16 value propagates into the s32, causing +batadv_tt_prepare_tvlv_local_data() to allocate a full sized buffer but +populates only a small portion of it with the collected changeset. All +remaining bits are kept uninitialized. + +Using an u16 avoids this type confusion and ensures that no (negative) sign +extension is performed in batadv_send_my_tt_response(). + +Cc: stable@kernel.org +Fixes: a73105b8d4c7 ("batman-adv: improved client announcement mechanism") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/types.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -996,7 +996,7 @@ struct batadv_priv_tt { + * @last_changeset_len: length of last tt changeset this host has + * generated + */ +- s16 last_changeset_len; ++ u16 last_changeset_len; + + /** + * @last_changeset_lock: lock protecting last_changeset & diff --git a/queue-7.0/batman-adv-tt-fix-negative-tt_buff_len.patch b/queue-7.0/batman-adv-tt-fix-negative-tt_buff_len.patch new file mode 100644 index 0000000000..5725e1d6f3 --- /dev/null +++ b/queue-7.0/batman-adv-tt-fix-negative-tt_buff_len.patch @@ -0,0 +1,41 @@ +From b64963a2ceeb7529310b6cf253a1e540784422f4 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 2 May 2026 19:53:21 +0200 +Subject: batman-adv: tt: fix negative tt_buff_len + +From: Sven Eckelmann + +commit b64963a2ceeb7529310b6cf253a1e540784422f4 upstream. + +batadv_orig_node::tt_buff_len was declared as s16, but the field is never +intended to hold a negative value. When a value greater than 32767 is +assigned, it wraps to a negative signed integer. + +In batadv_send_other_tt_response(), tt_buff_len is temporarily widened to +s32. The incorrectly negative s16 value propagates into the s32, causing +batadv_tt_prepare_tvlv_global_data() to allocate a full sized buffer but +populates only a small portion of it with the collected changeset. All +remaining bits are kept uninitialized. + +Using an u16 avoids this type confusion and ensures that no (negative) sign +extension is performed in batadv_send_other_tt_response(). + +Cc: stable@kernel.org +Fixes: a73105b8d4c7 ("batman-adv: improved client announcement mechanism") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/types.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -455,7 +455,7 @@ struct batadv_orig_node { + * @tt_buff_len: length of the last tt changeset this node received + * from the orig node + */ +- s16 tt_buff_len; ++ u16 tt_buff_len; + + /** @tt_buff_lock: lock that protects tt_buff and tt_buff_len */ + spinlock_t tt_buff_lock; diff --git a/queue-7.0/batman-adv-tt-fix-toctou-race-for-reported-vlans.patch b/queue-7.0/batman-adv-tt-fix-toctou-race-for-reported-vlans.patch new file mode 100644 index 0000000000..aeedcb0733 --- /dev/null +++ b/queue-7.0/batman-adv-tt-fix-toctou-race-for-reported-vlans.patch @@ -0,0 +1,71 @@ +From 94d27005016be15ffc638b2ecbc4d58805ad7b48 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 2 May 2026 19:47:11 +0200 +Subject: batman-adv: tt: fix TOCTOU race for reported vlans + +From: Sven Eckelmann + +commit 94d27005016be15ffc638b2ecbc4d58805ad7b48 upstream. + +The local TT based TVLV is generated by first checking the number of VLANs +which have at least one TT entry. A new buffer with the correct size for +the VLANs is then allocated. Only then, the list of VLANs s used to fill +the VLAN entries in the buffer. During this time, the meshif_vlan_list_lock +is held. But the actual number of TT entries of each VLAN can still +increase during this time - just not the number of VLANs in the list. + +But the prefilter used in the buffer size calculation might still cause an +increase of the number of VLANs which need to be stored. Simply because a +VLAN might now suddenly have at least one entry when it had none in the +pre-alloc check - and then needs to occupy space which was not allocated. + +It is better to overestimate the buffer size at the beginning and then fill +the buffer only with the VLANs which are not empty. + +Cc: stable@kernel.org +Fixes: 16116dac2339 ("batman-adv: prevent TT request storms by not sending inconsistent TT TLVLs") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/translation-table.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -887,11 +887,8 @@ batadv_tt_prepare_tvlv_local_data(struct + spin_lock_bh(&bat_priv->meshif_vlan_list_lock); + hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) { + vlan_entries = atomic_read(&vlan->tt.num_entries); +- if (vlan_entries < 1) +- continue; +- +- num_vlan++; + total_entries += vlan_entries; ++ num_vlan++; + } + + change_offset = struct_size(*tt_data, vlan_data, num_vlan); +@@ -914,6 +911,7 @@ batadv_tt_prepare_tvlv_local_data(struct + (*tt_data)->num_vlan = htons(num_vlan); + + tt_vlan = (*tt_data)->vlan_data; ++ num_vlan = 0; + hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) { + vlan_entries = atomic_read(&vlan->tt.num_entries); + if (vlan_entries < 1) +@@ -924,8 +922,15 @@ batadv_tt_prepare_tvlv_local_data(struct + tt_vlan->reserved = 0; + + tt_vlan++; ++ num_vlan++; + } + ++ /* recalculate in case number of VLANs reduced */ ++ change_offset = struct_size(*tt_data, vlan_data, num_vlan); ++ tvlv_len = *tt_len + change_offset; ++ ++ (*tt_data)->num_vlan = htons(num_vlan); ++ + tt_change_ptr = (u8 *)*tt_data + change_offset; + *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; + diff --git a/queue-7.0/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch b/queue-7.0/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch new file mode 100644 index 0000000000..69492e09e4 --- /dev/null +++ b/queue-7.0/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch @@ -0,0 +1,75 @@ +From 99d9958fa10fb684b2a8e2c48a8d704122721420 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 2 May 2026 21:25:19 +0200 +Subject: batman-adv: tt: prevent TVLV entry number overflow + +From: Sven Eckelmann + +commit 99d9958fa10fb684b2a8e2c48a8d704122721420 upstream. + +The helpers to prepare the buffers for the local and global TT based +replies are trying to sum up all TT entries which can be found for each +VLAN. In theory, this sum can be too big for an u16 and therefore overflow. +A too small buffer would then be allocated for the TVLV. + +The too small buffer will be handled gracefully by +batadv_tt_tvlv_generate() and is not causing a buffer overflow - just a +truncated reply. But this overflow shouldn't have happened in the first and +the too small buffer should never have been allocated when an overflow was +detected. + +Cc: stable@kernel.org +Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/translation-table.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -804,11 +804,18 @@ batadv_tt_prepare_tvlv_global_data(struc + u16 total_entries = 0; + u8 *tt_change_ptr; + int vlan_entries; ++ u16 sum_entries; + + spin_lock_bh(&orig_node->vlan_list_lock); + hlist_for_each_entry(vlan, &orig_node->vlan_list, list) { + vlan_entries = atomic_read(&vlan->tt.num_entries); +- total_entries += vlan_entries; ++ ++ if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) { ++ *tt_len = 0; ++ goto out; ++ } ++ ++ total_entries = sum_entries; + num_vlan++; + } + +@@ -893,15 +900,22 @@ batadv_tt_prepare_tvlv_local_data(struct + struct batadv_meshif_vlan *vlan; + size_t change_offset; + u16 num_vlan = 0; +- u16 vlan_entries = 0; + u16 total_entries = 0; + u16 tvlv_len; + u8 *tt_change_ptr; ++ int vlan_entries; ++ u16 sum_entries; + + spin_lock_bh(&bat_priv->meshif_vlan_list_lock); + hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) { + vlan_entries = atomic_read(&vlan->tt.num_entries); +- total_entries += vlan_entries; ++ ++ if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) { ++ tvlv_len = 0; ++ goto out; ++ } ++ ++ total_entries = sum_entries; + num_vlan++; + } + diff --git a/queue-7.0/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch b/queue-7.0/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch new file mode 100644 index 0000000000..01bf5c9fee --- /dev/null +++ b/queue-7.0/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch @@ -0,0 +1,56 @@ +From 1e9fab756f8395096d5bba7be0c373c4c8f5d165 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 2 May 2026 19:08:37 +0200 +Subject: batman-adv: tt: reject oversized local TVLV buffers + +From: Sven Eckelmann + +commit 1e9fab756f8395096d5bba7be0c373c4c8f5d165 upstream. + +The commit 3a359bf5c61d ("batman-adv: reject oversized global TT response +buffers") added a check to ensure that a global return buffer size can be +stored in an u16. The same buffer handling also exists for the local data +buffer but was not touched. + +A similar check should be also be in place for the local TVLV buffer. It +doesn't have the similar attack surface because it is only generated from +locally discovered MAC addresses but the dynamic nature could still cause +temporarily to large buffers. + +Cc: stable@kernel.org +Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/translation-table.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -877,12 +877,12 @@ batadv_tt_prepare_tvlv_local_data(struct + { + struct batadv_tvlv_tt_vlan_data *tt_vlan; + struct batadv_meshif_vlan *vlan; ++ size_t change_offset; + u16 num_vlan = 0; + u16 vlan_entries = 0; + u16 total_entries = 0; + u16 tvlv_len; + u8 *tt_change_ptr; +- int change_offset; + + spin_lock_bh(&bat_priv->meshif_vlan_list_lock); + hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) { +@@ -897,8 +897,10 @@ batadv_tt_prepare_tvlv_local_data(struct + if (*tt_len < 0) + *tt_len = batadv_tt_len(total_entries); + +- tvlv_len = *tt_len; +- tvlv_len += change_offset; ++ if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) { ++ tvlv_len = 0; ++ goto out; ++ } + + *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); + if (!*tt_data) { diff --git a/queue-7.0/batman-adv-tvlv-abort-ogm-send-on-tvlv-append-failure.patch b/queue-7.0/batman-adv-tvlv-abort-ogm-send-on-tvlv-append-failure.patch new file mode 100644 index 0000000000..b8af1a778f --- /dev/null +++ b/queue-7.0/batman-adv-tvlv-abort-ogm-send-on-tvlv-append-failure.patch @@ -0,0 +1,185 @@ +From 501368506563e151b322c8c3f228b796e615b90d Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Thu, 14 May 2026 16:33:12 +0200 +Subject: batman-adv: tvlv: abort OGM send on tvlv append failure + +From: Sven Eckelmann + +commit 501368506563e151b322c8c3f228b796e615b90d upstream. + +batadv_tvlv_container_ogm_append() could fail in two ways: a memory +allocation failure when resizing the packet buffer, or the tvlv data +exceeding U16_MAX bytes. In both cases the function previously returned the +old (now stale) tvlv_value_len rather than signalling an error, causing the +OGM/OGM2 send path to transmit a packet whose TVLV length field no longer +matched the actual buffer contents. And because it also didn't fill in the +new TVLV data, sending either uninitialized or corrupted data on the wire. + +All errors in batadv_tvlv_container_ogm_append() must be forwarded to the +caller. And the caller must abort the send of the OGM2. For B.A.T.M.A.N. +IV, it is currently not allowed to abort the send. The non-TVLV part of the +OGM must be queued up instead. + +Cc: stable@kernel.org +Fixes: ef26157747d4 ("batman-adv: tvlv - basic infrastructure") +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bat_iv_ogm.c | 16 +++++++++++++--- + net/batman-adv/bat_v_ogm.c | 26 ++++++++++++++------------ + net/batman-adv/tvlv.c | 17 ++++++++++++----- + net/batman-adv/tvlv.h | 2 +- + 4 files changed, 40 insertions(+), 21 deletions(-) + +--- a/net/batman-adv/bat_iv_ogm.c ++++ b/net/batman-adv/bat_iv_ogm.c +@@ -790,6 +790,7 @@ static void batadv_iv_ogm_schedule_buff( + u32 seqno; + u16 tvlv_len = 0; + unsigned long send_time; ++ int ret; + + lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); + +@@ -813,9 +814,18 @@ static void batadv_iv_ogm_schedule_buff( + * appended as it may alter the tt tvlv container + */ + batadv_tt_local_commit_changes(bat_priv); +- tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, +- ogm_buff_len, +- BATADV_OGM_HLEN); ++ ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, ++ ogm_buff_len, ++ BATADV_OGM_HLEN); ++ if (ret < 0) { ++ /* OGMs must be queued even when the buffer allocation for ++ * TVLVs failed. just fall back to the non-TVLV version ++ */ ++ ret = 0; ++ *ogm_buff_len = BATADV_OGM_HLEN; ++ } ++ ++ tvlv_len = ret; + } + + batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); +--- a/net/batman-adv/bat_v_ogm.c ++++ b/net/batman-adv/bat_v_ogm.c +@@ -269,10 +269,10 @@ static void batadv_v_ogm_send_meshif(str + struct batadv_hard_iface *hard_iface; + struct batadv_ogm2_packet *ogm_packet; + struct sk_buff *skb, *skb_tmp; +- unsigned char *ogm_buff; ++ unsigned char **ogm_buff; + struct list_head *iter; +- int ogm_buff_len; +- u16 tvlv_len = 0; ++ int *ogm_buff_len; ++ u16 tvlv_len; + int ret; + + lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex); +@@ -280,25 +280,27 @@ static void batadv_v_ogm_send_meshif(str + if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) + goto out; + +- ogm_buff = bat_priv->bat_v.ogm_buff; +- ogm_buff_len = bat_priv->bat_v.ogm_buff_len; ++ ogm_buff = &bat_priv->bat_v.ogm_buff; ++ ogm_buff_len = &bat_priv->bat_v.ogm_buff_len; ++ + /* tt changes have to be committed before the tvlv data is + * appended as it may alter the tt tvlv container + */ + batadv_tt_local_commit_changes(bat_priv); +- tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff, +- &ogm_buff_len, +- BATADV_OGM2_HLEN); ++ ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, ++ ogm_buff_len, ++ BATADV_OGM2_HLEN); ++ if (ret < 0) ++ goto reschedule; + +- bat_priv->bat_v.ogm_buff = ogm_buff; +- bat_priv->bat_v.ogm_buff_len = ogm_buff_len; ++ tvlv_len = ret; + +- skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len); ++ skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + *ogm_buff_len); + if (!skb) + goto reschedule; + + skb_reserve(skb, ETH_HLEN); +- skb_put_data(skb, ogm_buff, ogm_buff_len); ++ skb_put_data(skb, *ogm_buff, *ogm_buff_len); + + ogm_packet = (struct batadv_ogm2_packet *)skb->data; + ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno)); +--- a/net/batman-adv/tvlv.c ++++ b/net/batman-adv/tvlv.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -306,9 +307,10 @@ static bool batadv_tvlv_realloc_packet_b + * The ogm packet might be enlarged or shrunk depending on the current size + * and the size of the to-be-appended tvlv containers. + * +- * Return: size of all appended tvlv containers in bytes. ++ * Return: size of all appended tvlv containers in bytes (max U16_MAX), negative ++ * if operation failed + */ +-u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, ++int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, int packet_min_len) + { +@@ -316,6 +318,7 @@ u16 batadv_tvlv_container_ogm_append(str + struct batadv_tvlv_hdr *tvlv_hdr; + u16 tvlv_value_len; + void *tvlv_value; ++ int tvlv_len_ret; + bool ret; + + spin_lock_bh(&bat_priv->tvlv.container_list_lock); +@@ -323,9 +326,12 @@ u16 batadv_tvlv_container_ogm_append(str + + ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, + packet_min_len, tvlv_value_len); +- +- if (!ret) ++ if (!ret) { ++ tvlv_len_ret = -ENOMEM; + goto end; ++ } ++ ++ tvlv_len_ret = tvlv_value_len; + + if (!tvlv_value_len) + goto end; +@@ -344,7 +350,8 @@ u16 batadv_tvlv_container_ogm_append(str + + end: + spin_unlock_bh(&bat_priv->tvlv.container_list_lock); +- return tvlv_value_len; ++ ++ return tvlv_len_ret; + } + + /** +--- a/net/batman-adv/tvlv.h ++++ b/net/batman-adv/tvlv.h +@@ -16,7 +16,7 @@ + void batadv_tvlv_container_register(struct batadv_priv *bat_priv, + u8 type, u8 version, + void *tvlv_value, u16 tvlv_value_len); +-u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, ++int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, int packet_min_len); + void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, diff --git a/queue-7.0/batman-adv-tvlv-reject-oversized-tvlv-packets.patch b/queue-7.0/batman-adv-tvlv-reject-oversized-tvlv-packets.patch new file mode 100644 index 0000000000..0803fa2613 --- /dev/null +++ b/queue-7.0/batman-adv-tvlv-reject-oversized-tvlv-packets.patch @@ -0,0 +1,80 @@ +From f50487e3566358b2b982b7801945e858c78ad9ab Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 9 May 2026 21:55:29 +0200 +Subject: batman-adv: tvlv: reject oversized TVLV packets + +From: Sven Eckelmann + +commit f50487e3566358b2b982b7801945e858c78ad9ab upstream. + +batadv_tvlv_container_ogm_append() builds a TVLV packet section from +the tvlv.container_list. The total size of this section is computed by +batadv_tvlv_container_list_size(), which sums the sizes of all registered +containers. + +The return type and accumulator in batadv_tvlv_container_list_size() were +u16. If the accumulated size exceeds U16_MAX, the value wraps around, +causing the subsequent allocation in batadv_tvlv_container_ogm_append() +to be undersized. The memcpy-style copy that follows would then write +beyond the end of the allocated buffer, corrupting kernel memory. + +Fix this by widening the return type of batadv_tvlv_container_list_size() +to size_t. In batadv_tvlv_container_ogm_append(), check the computed length +against U16_MAX before proceeding, and bail out as if the allocation had +failed when the limit is exceeded. + +Cc: stable@kernel.org +Fixes: ef26157747d4 ("batman-adv: tvlv - basic infrastructure") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Reviewed-by: Yuan Tan +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tvlv.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/net/batman-adv/tvlv.c ++++ b/net/batman-adv/tvlv.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -160,10 +161,10 @@ batadv_tvlv_container_get(struct batadv_ + * + * Return: size of all currently registered tvlv containers in bytes. + */ +-static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) ++static size_t batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) + { + struct batadv_tvlv_container *tvlv; +- u16 tvlv_len = 0; ++ size_t tvlv_len = 0; + + lockdep_assert_held(&bat_priv->tvlv.container_list_lock); + +@@ -316,13 +317,17 @@ int batadv_tvlv_container_ogm_append(str + { + struct batadv_tvlv_container *tvlv; + struct batadv_tvlv_hdr *tvlv_hdr; +- u16 tvlv_value_len; ++ size_t tvlv_value_len; + void *tvlv_value; + int tvlv_len_ret; + bool ret; + + spin_lock_bh(&bat_priv->tvlv.container_list_lock); + tvlv_value_len = batadv_tvlv_container_list_size(bat_priv); ++ if (tvlv_value_len > U16_MAX) { ++ tvlv_len_ret = -E2BIG; ++ goto end; ++ } + + ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, + packet_min_len, tvlv_value_len); diff --git a/queue-7.0/batman-adv-v-stop-ogmv2-on-disabled-interface.patch b/queue-7.0/batman-adv-v-stop-ogmv2-on-disabled-interface.patch new file mode 100644 index 0000000000..8b6589a69c --- /dev/null +++ b/queue-7.0/batman-adv-v-stop-ogmv2-on-disabled-interface.patch @@ -0,0 +1,143 @@ +From f8ce8b8331a1bc44ad4905886a482214d428b253 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Sat, 9 May 2026 22:44:12 +0200 +Subject: batman-adv: v: stop OGMv2 on disabled interface + +From: Sven Eckelmann + +commit f8ce8b8331a1bc44ad4905886a482214d428b253 upstream. + +When a batadv_hard_iface is disabled, its mesh_iface pointer is set to +NULL. However, batadv_v_ogm_send_meshif() may still dispatch OGMs via +batadv_v_ogm_queue_on_if() for interfaces that have since lost their +mesh_iface association. This results in a NULL pointer dereference when +batadv_v_ogm_queue_on_if() unconditionally calls netdev_priv() on the +now NULL hard_iface->mesh_iface to retrieve the batadv_priv. + +It is necessary to ensure that the batadv_v_ogm_queue_on_if() checks that +it is using the same mesh_iface for which batadv_v_ogm_send_meshif() was +called. + +Cc: stable@kernel.org +Fixes: 0da0035942d4 ("batman-adv: OGMv2 - add basic infrastructure") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Reviewed-by: Yuan Tan +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bat_v_ogm.c | 33 +++++++++++++++++++++------------ + 1 file changed, 21 insertions(+), 12 deletions(-) + +--- a/net/batman-adv/bat_v_ogm.c ++++ b/net/batman-adv/bat_v_ogm.c +@@ -113,14 +113,14 @@ static void batadv_v_ogm_start_timer(str + + /** + * batadv_v_ogm_send_to_if() - send a batman ogm using a given interface ++ * @bat_priv: the bat priv with all the mesh interface information + * @skb: the OGM to send + * @hard_iface: the interface to use to send the OGM + */ +-static void batadv_v_ogm_send_to_if(struct sk_buff *skb, ++static void batadv_v_ogm_send_to_if(struct batadv_priv *bat_priv, ++ struct sk_buff *skb, + struct batadv_hard_iface *hard_iface) + { +- struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); +- + if (hard_iface->if_status != BATADV_IF_ACTIVE) { + kfree_skb(skb); + return; +@@ -187,6 +187,7 @@ static void batadv_v_ogm_aggr_list_free( + + /** + * batadv_v_ogm_aggr_send() - flush & send aggregation queue ++ * @bat_priv: the bat priv with all the mesh interface information + * @hard_iface: the interface with the aggregation queue to flush + * + * Aggregates all OGMv2 packets currently in the aggregation queue into a +@@ -196,7 +197,8 @@ static void batadv_v_ogm_aggr_list_free( + * + * Caller needs to hold the hard_iface->bat_v.aggr_list.lock. + */ +-static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface) ++static void batadv_v_ogm_aggr_send(struct batadv_priv *bat_priv, ++ struct batadv_hard_iface *hard_iface) + { + unsigned int aggr_len = hard_iface->bat_v.aggr_len; + struct sk_buff *skb_aggr; +@@ -226,27 +228,32 @@ static void batadv_v_ogm_aggr_send(struc + consume_skb(skb); + } + +- batadv_v_ogm_send_to_if(skb_aggr, hard_iface); ++ batadv_v_ogm_send_to_if(bat_priv, skb_aggr, hard_iface); + } + + /** + * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface ++ * @bat_priv: the bat priv with all the mesh interface information + * @skb: the OGM to queue + * @hard_iface: the interface to queue the OGM on + */ +-static void batadv_v_ogm_queue_on_if(struct sk_buff *skb, ++static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv, ++ struct sk_buff *skb, + struct batadv_hard_iface *hard_iface) + { +- struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); ++ if (hard_iface->mesh_iface != bat_priv->mesh_iface) { ++ kfree_skb(skb); ++ return; ++ } + + if (!atomic_read(&bat_priv->aggregated_ogms)) { +- batadv_v_ogm_send_to_if(skb, hard_iface); ++ batadv_v_ogm_send_to_if(bat_priv, skb, hard_iface); + return; + } + + spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); + if (!batadv_v_ogm_queue_left(skb, hard_iface)) +- batadv_v_ogm_aggr_send(hard_iface); ++ batadv_v_ogm_aggr_send(bat_priv, hard_iface); + + hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb); + __skb_queue_tail(&hard_iface->bat_v.aggr_list, skb); +@@ -343,7 +350,7 @@ static void batadv_v_ogm_send_meshif(str + break; + } + +- batadv_v_ogm_queue_on_if(skb_tmp, hard_iface); ++ batadv_v_ogm_queue_on_if(bat_priv, skb_tmp, hard_iface); + batadv_hardif_put(hard_iface); + } + rcu_read_unlock(); +@@ -383,12 +390,14 @@ void batadv_v_ogm_aggr_work(struct work_ + { + struct batadv_hard_iface_bat_v *batv; + struct batadv_hard_iface *hard_iface; ++ struct batadv_priv *bat_priv; + + batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work); + hard_iface = container_of(batv, struct batadv_hard_iface, bat_v); ++ bat_priv = netdev_priv(hard_iface->mesh_iface); + + spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); +- batadv_v_ogm_aggr_send(hard_iface); ++ batadv_v_ogm_aggr_send(bat_priv, hard_iface); + spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); + + batadv_v_ogm_start_queue_timer(hard_iface); +@@ -578,7 +587,7 @@ static void batadv_v_ogm_forward(struct + if_outgoing->net_dev->name, ntohl(ogm_forward->throughput), + ogm_forward->ttl, if_incoming->net_dev->name); + +- batadv_v_ogm_queue_on_if(skb, if_outgoing); ++ batadv_v_ogm_queue_on_if(bat_priv, skb, if_outgoing); + + out: + batadv_orig_ifinfo_put(orig_ifinfo); diff --git a/queue-7.0/cifs-fix-busy-dentry-used-after-unmounting.patch b/queue-7.0/cifs-fix-busy-dentry-used-after-unmounting.patch new file mode 100644 index 0000000000..c4f9037b24 --- /dev/null +++ b/queue-7.0/cifs-fix-busy-dentry-used-after-unmounting.patch @@ -0,0 +1,73 @@ +From c68337442f03953237a94577beb468ab2662a851 Mon Sep 17 00:00:00 2001 +From: Zhihao Cheng +Date: Tue, 19 May 2026 17:18:05 +0800 +Subject: cifs: Fix busy dentry used after unmounting + +From: Zhihao Cheng + +commit c68337442f03953237a94577beb468ab2662a851 upstream. + +Since commit 340cea84f691c ("cifs: open files should not hold ref on +superblock"), cifs file only holds the dentry ref_cnt, the cifs file +close work(cfile->deferred) could be executed after unmounting, which +will trigger a warning in generic_shutdown_super: + BUG: Dentry 00000000a14a6845{i=c,n=file} still in use (1) [unmount of + cifs cifs] + +The detailed processs is: + process A process B kworker + fd = open(PATH) + vfs_open + file->__f_path = *path // dentry->d_lockref.count = 1 + cifs_open + cifs_new_fileinfo + cfile->dentry = dget(dentry) // dentry->d_lockref.count = 2 + close(fd) + __fput + cifs_close + queue_delayed_work(deferredclose_wq, cfile->deferred) + dput(dentry) // dentry->d_lockref.count = 1 + smb2_deferred_work_close + _cifsFileInfo_put + list_del(&cifs_file->flist) + umount + cleanup_mnt + deactivate_super + cifs_kill_sb + cifs_close_all_deferred_files_sb + cifs_close_all_deferred_files + // cannot find cfile, skip _cifsFileInfo_put + kill_anon_super + generic_shutdown_super + shrink_dcache_for_umount + umount_check + WARN ! // dentry->d_lockref.count = 1 + cifsFileInfo_put_final + dput(cifs_file->dentry) + // dentry->d_lockref.count = 0 + +Fix it by flushing 'deferredclose_wq' before calling kill_anon_super. + +Fetch a reproducer in https://bugzilla.kernel.org/show_bug.cgi?id=221548. + +Fixes: 340cea84f691c ("cifs: open files should not hold ref on superblock") +Cc: stable@vger.kernel.org +Reviewed-by: Shyam Prasad N +Signed-off-by: Zhihao Cheng +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/cifsfs.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/smb/client/cifsfs.c ++++ b/fs/smb/client/cifsfs.c +@@ -340,6 +340,8 @@ static void cifs_kill_sb(struct super_bl + + /* Wait for all pending oplock breaks to complete */ + flush_workqueue(cifsoplockd_wq); ++ /* Wait for all opened files to release */ ++ flush_workqueue(deferredclose_wq); + + /* finally release root dentry */ + dput(cifs_sb->root); diff --git a/queue-7.0/cpufreq-intel_pstate-use-correct-scaling-factor-on-raptor-lake-e.patch b/queue-7.0/cpufreq-intel_pstate-use-correct-scaling-factor-on-raptor-lake-e.patch new file mode 100644 index 0000000000..52d2b226ad --- /dev/null +++ b/queue-7.0/cpufreq-intel_pstate-use-correct-scaling-factor-on-raptor-lake-e.patch @@ -0,0 +1,45 @@ +From 0e7c710478b3089cdfe8669347f77b163e836c4f Mon Sep 17 00:00:00 2001 +From: "Rafael J. Wysocki" +Date: Tue, 12 May 2026 21:20:30 +0200 +Subject: cpufreq: intel_pstate: Use correct scaling factor on Raptor Lake-E + +From: Rafael J. Wysocki + +commit 0e7c710478b3089cdfe8669347f77b163e836c4f upstream. + +Raptor Lake-E has the same processor ID as Raptor Lake-S, so there is +an entry in intel_hybrid_scaling_factor[] for it. It does not contain +E-cores though and hybrid_get_cpu_type() returns 0 for its P-cores, so +they get the default "core" scaling factor. However, the original +Raptor Lake scaling factor for P-cores still needs to be used for +mapping the HWP performance levels of the P-cores in Raptor Lake-E to +frequency, as though they were part of a real hybrid system. + +To address this, update hwp_get_cpu_scaling() to return +hybrid_scaling_factor, which is the P-core scaling factor +retrieved from intel_hybrid_scaling_factor[], for all CPUs +that are not enumerated as E-cores. + +Fixes: 9b18d536b124 ("cpufreq: intel_pstate: Use CPPC to get scaling factors") +Link: https://lore.kernel.org/all/20260511235328.2018458-1-srinivas.pandruvada@linux.intel.com/ +Reported-by: Henry Tseng +Closes: https://lore.kernel.org/linux-pm/20260508063032.3248602-1-henrytseng@qnap.com/ +Signed-off-by: Rafael J. Wysocki +Cc: All applicable +Link: https://patch.msgid.link/4523296.ejJDZkT8p0@rafael.j.wysocki +Signed-off-by: Greg Kroah-Hartman +--- + drivers/cpufreq/intel_pstate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -2279,7 +2279,7 @@ static int hwp_get_cpu_scaling(int cpu) + * Return the hybrid scaling factor for P-cores and use the + * default core scaling for E-cores. + */ +- if (hybrid_get_cpu_type(cpu) == INTEL_CPU_TYPE_CORE) ++ if (hybrid_get_cpu_type(cpu) != INTEL_CPU_TYPE_ATOM) + return hybrid_scaling_factor; + + return core_get_scaling(); diff --git a/queue-7.0/device-property-set-fwnode-secondary-to-null-in-fwnode_init.patch b/queue-7.0/device-property-set-fwnode-secondary-to-null-in-fwnode_init.patch new file mode 100644 index 0000000000..9271fba892 --- /dev/null +++ b/queue-7.0/device-property-set-fwnode-secondary-to-null-in-fwnode_init.patch @@ -0,0 +1,40 @@ +From 215c90ee656114f5e8c32408228d97082f8e0eef Mon Sep 17 00:00:00 2001 +From: Bartosz Golaszewski +Date: Wed, 6 May 2026 13:57:00 +0200 +Subject: device property: set fwnode->secondary to NULL in fwnode_init() + +From: Bartosz Golaszewski + +commit 215c90ee656114f5e8c32408228d97082f8e0eef upstream. + +If a firmware node is allocated on the stack (for instance: temporary +software node whose life-time we control) or on the heap - but using a +non-zeroing allocation function - and initialized using fwnode_init(), +its secondary pointer will contain uninitalized memory which likely will +be neither NULL nor IS_ERR() and so may end up being dereferenced (for +example: in dev_to_swnode()). Set fwnode->secondary to NULL on +initialization. + +Cc: stable +Fixes: 01bb86b380a3 ("driver core: Add fwnode_init()") +Signed-off-by: Bartosz Golaszewski +Reviewed-by: Rafael J. Wysocki (Intel) +Reviewed-by: Andy Shevchenko +Reviewed-by: Sakari Ailus +Link: https://patch.msgid.link/20260506115701.23035-1-bartosz.golaszewski@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/fwnode.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/fwnode.h ++++ b/include/linux/fwnode.h +@@ -208,6 +208,7 @@ struct fwnode_operations { + static inline void fwnode_init(struct fwnode_handle *fwnode, + const struct fwnode_operations *ops) + { ++ fwnode->secondary = NULL; + fwnode->ops = ops; + INIT_LIST_HEAD(&fwnode->consumers); + INIT_LIST_HEAD(&fwnode->suppliers); diff --git a/queue-7.0/drm-amd-display-fix-integer-overflow-in-bios_get_image.patch b/queue-7.0/drm-amd-display-fix-integer-overflow-in-bios_get_image.patch new file mode 100644 index 0000000000..a664689894 --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-integer-overflow-in-bios_get_image.patch @@ -0,0 +1,56 @@ +From cd86529ec61474a38c3837fb7823790a7c3f8cce Mon Sep 17 00:00:00 2001 +From: Harry Wentland +Date: Mon, 4 May 2026 11:14:45 -0400 +Subject: drm/amd/display: Fix integer overflow in bios_get_image() + +From: Harry Wentland + +commit cd86529ec61474a38c3837fb7823790a7c3f8cce upstream. + +[Why&How] +The bounds check in bios_get_image() computes 'offset + size' using +unsigned 32-bit arithmetic before comparing against bios_size. If a +VBIOS image contains a near-UINT32_MAX offset the addition wraps to a +small value, the comparison passes, and the function returns a wild +pointer past the VBIOS mapping. + +Additionally, the comparison uses '<' (strict), which incorrectly +rejects the valid exact-fit case where offset + size == bios_size. + +Fix both issues by restructuring the check to avoid the addition +entirely: first reject if offset alone exceeds bios_size, then check +size against the remaining space (bios_size - offset). This eliminates +the overflow and correctly permits exact-fit accesses. + +Assisted-by: GitHub Copilot:claude-opus-4.6 +Reviewed-by: Alex Hung +Signed-off-by: Harry Wentland +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +(cherry picked from commit d40fb392af659c4a02b560319f226842f6ec1a95) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c +@@ -37,10 +37,13 @@ uint8_t *bios_get_image(struct dc_bios * + uint32_t offset, + uint32_t size) + { +- if (bp->bios && offset + size < bp->bios_size) +- return bp->bios + offset; +- else ++ if (!bp->bios) + return NULL; ++ ++ if (offset > bp->bios_size || size > bp->bios_size - offset) ++ return NULL; ++ ++ return bp->bios + offset; + } + + #include "reg_helper.h" diff --git a/queue-7.0/drm-amd-display-validate-gpio-pin-lut-table-size-before-iterating.patch b/queue-7.0/drm-amd-display-validate-gpio-pin-lut-table-size-before-iterating.patch new file mode 100644 index 0000000000..e24b964efe --- /dev/null +++ b/queue-7.0/drm-amd-display-validate-gpio-pin-lut-table-size-before-iterating.patch @@ -0,0 +1,60 @@ +From 86d2b20644b11d21fe52c596e6e922b4590a3e3f Mon Sep 17 00:00:00 2001 +From: Harry Wentland +Date: Mon, 4 May 2026 16:14:11 -0400 +Subject: drm/amd/display: Validate GPIO pin LUT table size before iterating + +From: Harry Wentland + +commit 86d2b20644b11d21fe52c596e6e922b4590a3e3f upstream. + +[Why&How] +The GPIO pin table parsers in get_gpio_i2c_info() and +bios_parser_get_gpio_pin_info() derive an element count from the VBIOS +table_header.structuresize field, then iterate over gpio_pin[] entries. +However, GET_IMAGE() only validates that the table header itself fits +within the BIOS image. If the VBIOS reports a structuresize larger than +the actual mapped data, the loop reads past the end of the BIOS image, +causing an out-of-bounds read. + +Fix this by calling bios_get_image() to validate that the full claimed +structuresize is accessible within the BIOS image before entering the +loop in both functions. + +Assisted-by: GitHub Copilot:claude-opus-4-6 +Reviewed-by: Alex Hung +Signed-off-by: Harry Wentland +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +(cherry picked from commit ba5e95b43b773ae1bf1f66ee6b31eb774e65afe3) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +@@ -492,6 +492,10 @@ static enum bp_result get_gpio_i2c_info( + - sizeof(struct atom_common_table_header)) + / sizeof(struct atom_gpio_pin_assignment); + ++ if (!bios_get_image(&bp->base, DATA_TABLES(gpio_pin_lut), ++ le16_to_cpu(header->table_header.structuresize))) ++ return BP_RESULT_BADBIOSTABLE; ++ + pin = (struct atom_gpio_pin_assignment *) header->gpio_pin; + + for (table_index = 0; table_index < count; table_index++) { +@@ -680,6 +684,11 @@ static enum bp_result bios_parser_get_gp + count = (le16_to_cpu(header->table_header.structuresize) + - sizeof(struct atom_common_table_header)) + / sizeof(struct atom_gpio_pin_assignment); ++ ++ if (!bios_get_image(&bp->base, DATA_TABLES(gpio_pin_lut), ++ le16_to_cpu(header->table_header.structuresize))) ++ return BP_RESULT_BADBIOSTABLE; ++ + for (i = 0; i < count; ++i) { + if (header->gpio_pin[i].gpio_id != gpio_id) + continue; diff --git a/queue-7.0/drm-amd-display-validate-payload-length-and-link_index-in-dc_process_dmub_aux_transfer_async.patch b/queue-7.0/drm-amd-display-validate-payload-length-and-link_index-in-dc_process_dmub_aux_transfer_async.patch new file mode 100644 index 0000000000..69662ec977 --- /dev/null +++ b/queue-7.0/drm-amd-display-validate-payload-length-and-link_index-in-dc_process_dmub_aux_transfer_async.patch @@ -0,0 +1,50 @@ +From 6c92f6d9600efa3ef0d9e560a2b52776d9803c29 Mon Sep 17 00:00:00 2001 +From: Harry Wentland +Date: Thu, 7 May 2026 16:26:31 -0400 +Subject: drm/amd/display: Validate payload length and link_index in dc_process_dmub_aux_transfer_async + +From: Harry Wentland + +commit 6c92f6d9600efa3ef0d9e560a2b52776d9803c29 upstream. + +[Why&How] +dc_process_dmub_aux_transfer_async() copies payload->length bytes into a +16-byte stack buffer (dpaux.data[16]) guarded only by an ASSERT(), which +is a no-op in release builds. If a caller ever passes length > 16 this +results in a stack buffer overflow via memcpy. + +Additionally, link_index is used to dereference dc->links[] without +bounds checking against dc->link_count, risking an out-of-bounds access. + +Replace the ASSERT with a hard runtime check that returns false when +payload->length exceeds the destination buffer size, and add a bounds +check for link_index before it is used. + +Assisted-by: GitHub Copilot:Claude claude-4-opus +Reviewed-by: Alex Hung +Signed-off-by: Harry Wentland +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +(cherry picked from commit ba4caa9fecdf7a38f98c878ad05a8a64148b6881) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -5993,7 +5993,11 @@ bool dc_process_dmub_aux_transfer_async( + uint8_t action; + union dmub_rb_cmd cmd = {0}; + +- ASSERT(payload->length <= 16); ++ if (link_index >= dc->link_count || !dc->links[link_index]) ++ return false; ++ ++ if (payload->length > sizeof(cmd.dp_aux_access.aux_control.dpaux.data)) ++ return false; + + cmd.dp_aux_access.header.type = DMUB_CMD__DP_AUX_ACCESS; + cmd.dp_aux_access.header.payload_bytes = 0; diff --git a/queue-7.0/drm-amdgpu-vpe-force-collaborate-sync-after-trap.patch b/queue-7.0/drm-amdgpu-vpe-force-collaborate-sync-after-trap.patch new file mode 100644 index 0000000000..e322bc9831 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vpe-force-collaborate-sync-after-trap.patch @@ -0,0 +1,47 @@ +From b6074630a461b1322a814988779005cbc43612ea Mon Sep 17 00:00:00 2001 +From: Alan Liu +Date: Fri, 1 May 2026 12:35:48 +0800 +Subject: drm/amdgpu/vpe: Force collaborate sync after TRAP + +From: Alan Liu + +commit b6074630a461b1322a814988779005cbc43612ea upstream. + +VPE1 could possibly hang and fail to power off at the end of commands in +collaboration mode. This workaround adds a COLLAB_SYNC after TRAP to +force instances synchronized to avoid VPE1 fail to power off. + +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Alan liu +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5171 +Signed-off-by: Alex Deucher +(cherry picked from commit a8b749c5c5afb7e5daa2bfb95d958fb3c6b8f055) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c +@@ -562,6 +562,11 @@ static void vpe_ring_emit_fence(struct a + amdgpu_ring_write(ring, 0); + } + ++ /* WA: Force sync after TRAP to avoid VPE1 fail to power off */ ++ if (ring->adev->vpe.collaborate_mode) { ++ amdgpu_ring_write(ring, VPE_CMD_HEADER(VPE_CMD_OPCODE_COLLAB_SYNC, 0)); ++ amdgpu_ring_write(ring, 0xabcd); ++ } + } + + static void vpe_ring_emit_pipeline_sync(struct amdgpu_ring *ring) +@@ -968,7 +973,7 @@ static const struct amdgpu_ring_funcs vp + .emit_frame_size = + 5 + /* vpe_ring_init_cond_exec */ + 6 + /* vpe_ring_emit_pipeline_sync */ +- 10 + 10 + 10 + /* vpe_ring_emit_fence */ ++ 12 + 12 + 12 + /* vpe_ring_emit_fence */ + /* vpe_ring_emit_vm_flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6, diff --git a/queue-7.0/drm-bridge-chipone-icn6211-use-devm_drm_bridge_add-in-i2c-probe.patch b/queue-7.0/drm-bridge-chipone-icn6211-use-devm_drm_bridge_add-in-i2c-probe.patch new file mode 100644 index 0000000000..a77f370daa --- /dev/null +++ b/queue-7.0/drm-bridge-chipone-icn6211-use-devm_drm_bridge_add-in-i2c-probe.patch @@ -0,0 +1,36 @@ +From 73d01051e8040c0b1de7fd26b3b8d0c2ffa6895c Mon Sep 17 00:00:00 2001 +From: Osama Abdelkader +Date: Thu, 30 Apr 2026 21:49:42 +0200 +Subject: drm/bridge: chipone-icn6211: use devm_drm_bridge_add in i2c probe + +From: Osama Abdelkader + +commit 73d01051e8040c0b1de7fd26b3b8d0c2ffa6895c upstream. + +Use devm_drm_bridge_add() so the bridge is released if probe +fails after registration, and drop drm_bridge_remove() in chipone_i2c_probe. + +Signed-off-by: Osama Abdelkader +Fixes: 8dde6f7452a1 ("drm: bridge: icn6211: Add I2C configuration support") +Cc: stable@vger.kernel.org +Reviewed-by: Luca Ceresoli +Link: https://patch.msgid.link/20260430194944.78119-1-osama.abdelkader@gmail.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/bridge/chipone-icn6211.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/bridge/chipone-icn6211.c ++++ b/drivers/gpu/drm/bridge/chipone-icn6211.c +@@ -758,7 +758,9 @@ static int chipone_i2c_probe(struct i2c_ + dev_set_drvdata(dev, icn); + i2c_set_clientdata(client, icn); + +- drm_bridge_add(&icn->bridge); ++ ret = devm_drm_bridge_add(dev, &icn->bridge); ++ if (ret) ++ return ret; + + return chipone_dsi_host_attach(icn); + } diff --git a/queue-7.0/drm-bridge-it66121-acquire-reset-gpio-in-probe.patch b/queue-7.0/drm-bridge-it66121-acquire-reset-gpio-in-probe.patch new file mode 100644 index 0000000000..fe4db670fa --- /dev/null +++ b/queue-7.0/drm-bridge-it66121-acquire-reset-gpio-in-probe.patch @@ -0,0 +1,50 @@ +From e02b5262fd288cc235f14e12233ea54e78c04611 Mon Sep 17 00:00:00 2001 +From: Julien Chauveau +Date: Tue, 24 Mar 2026 20:30:11 +0100 +Subject: drm/bridge: it66121: acquire reset GPIO in probe + +From: Julien Chauveau + +commit e02b5262fd288cc235f14e12233ea54e78c04611 upstream. + +The it66121_ctx structure has a gpio_reset field, and it66121_hw_reset() +calls gpiod_set_value() on it. However, the GPIO descriptor is never +acquired via devm_gpiod_get(), leaving gpio_reset as NULL throughout +the driver lifetime. + +gpiod_set_value() silently returns when passed a NULL descriptor, so +the hardware reset sequence in it66121_hw_reset() is a no-op. This +leaves the chip in an undefined state at probe time, which can prevent +it from responding on the I2C bus. + +The DT binding marks reset-gpios as a required property, so all +compliant device trees provide this GPIO. Add the missing +devm_gpiod_get() call after enabling power supplies and before the +hardware reset, so the chip is properly reset with power applied. + +Fixes: 988156dc2fc9 ("drm: bridge: add it66121 driver") +Cc: stable@vger.kernel.org +Signed-off-by: Julien Chauveau +Reviewed-by: Javier Martinez Canillas +Tested-by: Javier Martinez Canillas +Link: https://patch.msgid.link/20260324193011.16583-1-chauveau.julien@gmail.com +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/bridge/ite-it66121.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -1559,6 +1559,11 @@ static int it66121_probe(struct i2c_clie + return ret; + } + ++ ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(ctx->gpio_reset)) ++ return dev_err_probe(dev, PTR_ERR(ctx->gpio_reset), ++ "Failed to get reset GPIO\n"); ++ + it66121_hw_reset(ctx); + + ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config); diff --git a/queue-7.0/drm-bridge-megachips-remove-bridge-when-irq-request-fails.patch b/queue-7.0/drm-bridge-megachips-remove-bridge-when-irq-request-fails.patch new file mode 100644 index 0000000000..b50eca2877 --- /dev/null +++ b/queue-7.0/drm-bridge-megachips-remove-bridge-when-irq-request-fails.patch @@ -0,0 +1,68 @@ +From d45d5c819f2cd0b6b5d76a194a537a5f4aeefecb Mon Sep 17 00:00:00 2001 +From: Osama Abdelkader +Date: Thu, 30 Apr 2026 21:56:59 +0200 +Subject: drm/bridge: megachips: remove bridge when irq request fails + +From: Osama Abdelkader + +commit d45d5c819f2cd0b6b5d76a194a537a5f4aeefecb upstream. + +If devm_request_threaded_irq() fails after drm_bridge_add(), remove the +bridge before returning. + +Keep drm_bridge_add() rather than devm_drm_bridge_add(): registration is +tied to the STDP4028 device while ge_b850v3_register() may complete from +either I2C probe; devm would not unwind the bridge if the other client's +probe fails. + +Signed-off-by: Osama Abdelkader +Fixes: fcfa0ddc18ed ("drm/bridge: Drivers for megachips-stdpxxxx-ge-b850v3-fw (LVDS-DP++)") +Cc: stable@vger.kernel.org +Reviewed-by: Luca Ceresoli +Tested-by: Ian Ray +Link: https://patch.msgid.link/20260430195700.80317-1-osama.abdelkader@gmail.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 16 +++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c ++++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +@@ -251,7 +251,6 @@ static void ge_b850v3_lvds_remove(void) + goto out; + + drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); +- + ge_b850v3_lvds_ptr = NULL; + out: + mutex_unlock(&ge_b850v3_lvds_dev_mutex); +@@ -261,6 +260,7 @@ static int ge_b850v3_register(void) + { + struct i2c_client *stdp4028_i2c = ge_b850v3_lvds_ptr->stdp4028_i2c; + struct device *dev = &stdp4028_i2c->dev; ++ int ret; + + /* drm bridge initialization */ + ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT | +@@ -277,11 +277,15 @@ static int ge_b850v3_register(void) + if (!stdp4028_i2c->irq) + return 0; + +- return devm_request_threaded_irq(&stdp4028_i2c->dev, +- stdp4028_i2c->irq, NULL, +- ge_b850v3_lvds_irq_handler, +- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, +- "ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr); ++ ret = devm_request_threaded_irq(&stdp4028_i2c->dev, ++ stdp4028_i2c->irq, NULL, ++ ge_b850v3_lvds_irq_handler, ++ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++ "ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr); ++ if (ret) ++ drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); ++ ++ return ret; + } + + static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c) diff --git a/queue-7.0/drm-i915-display-copy-color-pipeline-from-plane-in-the-primary-joiner-pipe.patch b/queue-7.0/drm-i915-display-copy-color-pipeline-from-plane-in-the-primary-joiner-pipe.patch new file mode 100644 index 0000000000..eedabb0115 --- /dev/null +++ b/queue-7.0/drm-i915-display-copy-color-pipeline-from-plane-in-the-primary-joiner-pipe.patch @@ -0,0 +1,46 @@ +From 86ed2d96db1965e9008e919b1936145ae66540e3 Mon Sep 17 00:00:00 2001 +From: Chaitanya Kumar Borah +Date: Mon, 11 May 2026 11:02:10 +0530 +Subject: drm/i915/display: Copy color pipeline from plane in the primary joiner pipe + +From: Chaitanya Kumar Borah + +commit 86ed2d96db1965e9008e919b1936145ae66540e3 upstream. + +When copying plane color state in a joiner configuration, use the plane in +the primary joiner pipe since it carries the pipeline number selected by +the user-space. + +This assumes that all pipes in the joiner are symmetric in their plane +color capabilities. + +Cc: stable@vger.kernel.org # v6.19+ +Fixes: a78f1b6baf4d ("drm/i915/color: Add framework to program CSC") +Tested-by: Vidya Srinivas +Signed-off-by: Chaitanya Kumar Borah +Reviewed-by: Uma Shankar +Signed-off-by: Ankit Nautiyal +Link: https://patch.msgid.link/20260511053213.3122314-2-chaitanya.kumar.borah@intel.com +(cherry picked from commit e8308fb5e05ca08ddfb8b46f6d947a6e3fd80cd7) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_plane.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c +index 5390ceb21ca4..82f445c83158 100644 +--- a/drivers/gpu/drm/i915/display/intel_plane.c ++++ b/drivers/gpu/drm/i915/display/intel_plane.c +@@ -373,7 +373,7 @@ intel_plane_color_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, + bool changed = false; + int i = 0; + +- iter_colorop = plane_state->uapi.color_pipeline; ++ iter_colorop = from_plane_state->uapi.color_pipeline; + + while (iter_colorop) { + for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { +-- +2.54.0 + diff --git a/queue-7.0/drm-i915-psr-apply-intel-dpcd-workaround-when-sdp-on-prior-line-used.patch b/queue-7.0/drm-i915-psr-apply-intel-dpcd-workaround-when-sdp-on-prior-line-used.patch new file mode 100644 index 0000000000..2072237717 --- /dev/null +++ b/queue-7.0/drm-i915-psr-apply-intel-dpcd-workaround-when-sdp-on-prior-line-used.patch @@ -0,0 +1,87 @@ +From 4703049f768fc1c1caac754134118bee1a3af189 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jouni=20H=C3=B6gander?= +Date: Fri, 15 May 2026 12:57:55 +0300 +Subject: drm/i915/psr: Apply Intel DPCD workaround when SDP on prior line used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jouni Högander + +commit 4703049f768fc1c1caac754134118bee1a3af189 upstream. + +There is Intel specific workaround DPCD address containing workaround for +case where SDP is on prior line. Apply this workaround according to values +in the offset. + +Fixes: 61e887329e33 ("drm/i915/xelpd: Handle PSR2 SDP indication in the prior scanline") +Cc: # v5.15+ +Signed-off-by: Jouni Högander +Reviewed-by: Suraj Kandpal +Link: https://patch.msgid.link/20260515095756.2799483-4-jouni.hogander@intel.com +(cherry picked from commit c3fe899fbeac86ea4a5ca9dd845b2cbc0da46249) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_psr.c | 35 +++++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_psr.c ++++ b/drivers/gpu/drm/i915/display/intel_psr.c +@@ -1350,9 +1350,35 @@ static bool psr2_granularity_check(struc + return true; + } + +-static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_dp, +- struct intel_crtc_state *crtc_state) ++static bool apply_scanline_indication_wa(struct intel_crtc_state *crtc_state, ++ struct intel_connector *connector) + { ++ struct intel_dp *intel_dp = intel_attached_dp(connector); ++ u8 early_scanline_support = connector->dp.psr_caps.intel_wa_dpcd & ++ INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_EARLYSCANLINE_SDP_SUPPORT_MASK; ++ ++ if (intel_dp->edp_dpcd[0] >= DP_EDP_15) ++ return true; ++ ++ switch (early_scanline_support) { ++ case INTEL_DPCD_INTEL_WA_REGISTER_CAPS_FALL_BACK_TO_PSR1: ++ crtc_state->req_psr2_sdp_prior_scanline = false; ++ return false; ++ case INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_WITH_EARLY_SCANLINE: ++ return true; ++ case INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_WITHOUT_EARLY_SCANLINE: ++ crtc_state->req_psr2_sdp_prior_scanline = false; ++ return true; ++ default: ++ MISSING_CASE(early_scanline_support); ++ return false; ++ } ++} ++ ++static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_crtc_state *crtc_state, ++ struct intel_connector *connector) ++{ ++ struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_display *display = to_intel_display(intel_dp); + const struct drm_display_mode *adjusted_mode = &crtc_state->uapi.adjusted_mode; + u32 hblank_total, hblank_ns, req_ns; +@@ -1371,7 +1397,8 @@ static bool _compute_psr2_sdp_prior_scan + return false; + + crtc_state->req_psr2_sdp_prior_scanline = true; +- return true; ++ ++ return apply_scanline_indication_wa(crtc_state, connector); + } + + static int intel_psr_entry_setup_frames(struct intel_dp *intel_dp, +@@ -1653,7 +1680,7 @@ static bool intel_sel_update_config_vali + conn_state)) + goto unsupported; + +- if (!_compute_psr2_sdp_prior_scanline_indication(intel_dp, crtc_state)) { ++ if (!_compute_psr2_sdp_prior_scanline_indication(crtc_state, connector)) { + drm_dbg_kms(display->drm, + "Selective update not enabled, SDP indication do not fit in hblank\n"); + goto unsupported; diff --git a/queue-7.0/drm-msm-fix-shrinker-deadlock.patch b/queue-7.0/drm-msm-fix-shrinker-deadlock.patch new file mode 100644 index 0000000000..8803e2cfa5 --- /dev/null +++ b/queue-7.0/drm-msm-fix-shrinker-deadlock.patch @@ -0,0 +1,237 @@ +From 3392291fc509d8ad6e4ad90f15b0a193f721cbc9 Mon Sep 17 00:00:00 2001 +From: Daniel J Blueman +Date: Fri, 8 May 2026 14:57:21 +0800 +Subject: drm/msm: Fix shrinker deadlock + +From: Daniel J Blueman + +commit 3392291fc509d8ad6e4ad90f15b0a193f721cbc9 upstream. + +With PROVE_LOCKING on an Snapdragon X1 and VM reclaim pressure, we see: + + ====================================================== + WARNING: possible circular locking dependency detected + 7.0.0-debug+ #43 Tainted: G W + ------------------------------------------------------ + kswapd0/82 is trying to acquire lock: + ffff800080ec3870 (reservation_ww_class_acquire){+.+.}-{0:0}, at: msm_gem_shrinker_scan+0x17c/0x400 [msm] + + but task is already holding lock: + ffffc31709b263b8 (fs_reclaim){+.+.}-{0:0}, at: balance_pgdat+0x88/0x988 + + which lock already depends on the new lock. + + the existing dependency chain (in reverse order) is: + + -> #2 (fs_reclaim){+.+.}-{0:0}: + __lock_acquire+0x4d0/0xad0 + lock_acquire.part.0+0xc4/0x248 + lock_acquire+0x8c/0x248 + fs_reclaim_acquire+0xd0/0xf0 + dma_resv_lockdep+0x224/0x348 + do_one_initcall+0x84/0x5d0 + do_initcalls+0x194/0x1d8 + kernel_init_freeable+0x128/0x180 + kernel_init+0x2c/0x160 + ret_from_fork+0x10/0x20 + + -> #1 (reservation_ww_class_mutex){+.+.}-{4:4}: + __lock_acquire+0x4d0/0xad0 + lock_acquire.part.0+0xc4/0x248 + lock_acquire+0x8c/0x248 + dma_resv_lockdep+0x1a8/0x348 + do_one_initcall+0x84/0x5d0 + do_initcalls+0x194/0x1d8 + kernel_init_freeable+0x128/0x180 + kernel_init+0x2c/0x160 + ret_from_fork+0x10/0x20 + + -> #0 (reservation_ww_class_acquire){+.+.}-{0:0}: + check_prev_add+0x114/0x790 + validate_chain+0x594/0x6f0 + __lock_acquire+0x4d0/0xad0 + lock_acquire.part.0+0xc4/0x248 + lock_acquire+0x8c/0x248 + drm_gem_lru_scan+0x1ac/0x440 + msm_gem_shrinker_scan+0x17c/0x400 [msm] + do_shrink_slab+0x150/0x4a0 + shrink_slab+0x144/0x460 + shrink_one+0x9c/0x1b0 + shrink_many+0x27c/0x5c0 + shrink_node+0x344/0x550 + balance_pgdat+0x2c0/0x988 + kswapd+0x11c/0x318 + kthread+0x10c/0x128 + ret_from_fork+0x10/0x20 + + other info that might help us debug this: + Chain exists of: + reservation_ww_class_acquire --> reservation_ww_class_mutex --> fs_reclaim + Possible unsafe locking scenario: + CPU0 CPU1 + ---- ---- + lock(fs_reclaim); + lock(reservation_ww_class_mutex); + lock(fs_reclaim); + lock(reservation_ww_class_acquire); + + *** DEADLOCK *** + 1 lock held by kswapd0/82: + #0: ffffc31709b263b8 (fs_reclaim){+.+.}-{0:0}, at: balance_pgdat+0x88/0x988 + + stack backtrace: + CPU: 4 UID: 0 PID: 82 Comm: kswapd0 Tainted: G W 7.0.0-debug+ #43 PREEMPT(full) + Tainted: [W]=WARN + Hardware name: LENOVO 21BX0016US/21BX0016US, BIOS N3HET94W (1.66 ) 09/15/2025 + Call trace: + show_stack+0x20/0x40 (C) + dump_stack_lvl+0x9c/0xd0 + dump_stack+0x18/0x30 + print_circular_bug+0x114/0x120 + check_noncircular+0x178/0x198 + check_prev_add+0x114/0x790 + validate_chain+0x594/0x6f0 + __lock_acquire+0x4d0/0xad0 + lock_acquire.part.0+0xc4/0x248 + lock_acquire+0x8c/0x248 + drm_gem_lru_scan+0x1ac/0x440 + msm_gem_shrinker_scan+0x17c/0x400 [msm] + do_shrink_slab+0x150/0x4a0 + shrink_slab+0x144/0x460 + shrink_one+0x9c/0x1b0 + shrink_many+0x27c/0x5c0 + shrink_node+0x344/0x550 + balance_pgdat+0x2c0/0x988 + kswapd+0x11c/0x318 + kthread+0x10c/0x128 + ret_from_fork+0x10/0x20 + +kswapd0 holding fs_reclaim calls the MSM shrinker, which calls +dma_resv_lock. This in turn acquires fs_reclaim. + +Fix this deadlock by using dma_resv_trylock() instead, dropping the +subsequently unused passed wait-wound lock 'ticket'. + +Cc: stable@vger.kernel.org +Signed-off-by: Daniel J Blueman +Fixes: fe4952b5f27c ("drm/msm: Convert vm locking") +Patchwork: https://patchwork.freedesktop.org/patch/723564/ +Message-ID: <20260508065722.18785-1-daniel@quora.org> +[rob: fixup compile errors, replace lockdep splat with something legible] +Signed-off-by: Rob Clark +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/msm/msm_gem_shrinker.c | 40 +++++++++++++-------------------- + 1 file changed, 16 insertions(+), 24 deletions(-) + +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -43,8 +43,7 @@ msm_gem_shrinker_count(struct shrinker * + } + + static bool +-with_vm_locks(struct ww_acquire_ctx *ticket, +- void (*fn)(struct drm_gem_object *obj), ++with_vm_locks(void (*fn)(struct drm_gem_object *obj), + struct drm_gem_object *obj) + { + /* +@@ -52,7 +51,7 @@ with_vm_locks(struct ww_acquire_ctx *tic + * success paths + */ + struct drm_gpuvm_bo *vm_bo, *last_locked = NULL; +- int ret = 0; ++ bool locked = true; + + drm_gem_for_each_gpuvm_bo (vm_bo, obj) { + struct dma_resv *resv = drm_gpuvm_resv(vm_bo->vm); +@@ -60,23 +59,14 @@ with_vm_locks(struct ww_acquire_ctx *tic + if (resv == obj->resv) + continue; + +- ret = dma_resv_lock(resv, ticket); +- +- /* +- * Since we already skip the case when the VM and obj +- * share a resv (ie. _NO_SHARE objs), we don't expect +- * to hit a double-locking scenario... which the lock +- * unwinding cannot really cope with. +- */ +- WARN_ON(ret == -EALREADY); +- + /* +- * Don't bother with slow-lock / backoff / retry sequence, +- * if we can't get the lock just give up and move on to +- * the next object. ++ * dma_resv_lock can't be used due to acquiring 'ticket' before the ++ * fs_reclaim lock, which is held in shrinker context + */ +- if (ret) ++ if (!dma_resv_trylock(resv)) { ++ locked = false; + goto out_unlock; ++ } + + /* + * Hold a ref to prevent the vm_bo from being freed +@@ -108,11 +98,11 @@ out_unlock: + } + } + +- return ret == 0; ++ return locked; + } + + static bool +-purge(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket) ++purge(struct drm_gem_object *obj, struct ww_acquire_ctx *) + { + if (!is_purgeable(to_msm_bo(obj))) + return false; +@@ -120,11 +110,11 @@ purge(struct drm_gem_object *obj, struct + if (msm_gem_active(obj)) + return false; + +- return with_vm_locks(ticket, msm_gem_purge, obj); ++ return with_vm_locks(msm_gem_purge, obj); + } + + static bool +-evict(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket) ++evict(struct drm_gem_object *obj, struct ww_acquire_ctx *) + { + if (is_unevictable(to_msm_bo(obj))) + return false; +@@ -132,7 +122,7 @@ evict(struct drm_gem_object *obj, struct + if (msm_gem_active(obj)) + return false; + +- return with_vm_locks(ticket, msm_gem_evict, obj); ++ return with_vm_locks(msm_gem_evict, obj); + } + + static bool +@@ -164,7 +154,6 @@ static unsigned long + msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) + { + struct msm_drm_private *priv = shrinker->private_data; +- struct ww_acquire_ctx ticket; + struct { + struct drm_gem_lru *lru; + bool (*shrink)(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket); +@@ -185,11 +174,14 @@ msm_gem_shrinker_scan(struct shrinker *s + for (unsigned i = 0; (nr > 0) && (i < ARRAY_SIZE(stages)); i++) { + if (!stages[i].cond) + continue; ++ /* ++ * 'ticket' not needed on trylock paths ++ */ + stages[i].freed = + drm_gem_lru_scan(stages[i].lru, nr, + &stages[i].remaining, + stages[i].shrink, +- &ticket); ++ NULL); + nr -= stages[i].freed; + freed += stages[i].freed; + remaining += stages[i].remaining; diff --git a/queue-7.0/drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-on-error-path.patch b/queue-7.0/drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-on-error-path.patch new file mode 100644 index 0000000000..cc46a863f6 --- /dev/null +++ b/queue-7.0/drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-on-error-path.patch @@ -0,0 +1,122 @@ +From b0fe80c0b9250b35e2211bf3117e7aca814a21b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Fri, 15 May 2026 12:07:14 -0300 +Subject: drm/v3d: Fix use-after-free of CPU job query arrays on error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +commit b0fe80c0b9250b35e2211bf3117e7aca814a21b0 upstream. + +The CPU job ioctl's fail label calls kvfree() on cpu_job's timestamp and +performance query arrays after v3d_job_cleanup(), which drops the job's +last reference and frees cpu_job. Reading cpu_job at that point is a +use-after-free. Also, on the early v3d_job_init() failure path, it is a +NULL dereference, since v3d_job_deallocate() zeroes the local pointer. + +In the success path, the arrays are released from the scheduler's +.free_job callback, but on the error path, they are freed manually, as +the job was never pushed to the scheduler. While the success path deals +with this correctly, the fail path doesn't. + +On top of that, the manual kvfree() calls only free the array storage; +they don't drm_syncobj_put() the per-query syncobjs that +v3d_timestamp_query_info_free() and v3d_performance_query_info_free() +release on the success path. So the same fail path that triggers the +use-after-free also leaks one syncobj reference per query. + +Unify the CPU job teardown into the CPU job's kref destructor, mirroring +v3d_render_job_free(). The scheduler's .free_job slot reverts to the +generic v3d_sched_job_free() and the fail label drops the manual +kvfree() calls, leaving a single teardown path that is reached from both +the scheduler and the ioctl error path. That removes the use-after-free, +the NULL dereference, and the syncobj leak by construction. + +Cc: stable@vger.kernel.org +Fixes: 9ba0ff3e083f ("drm/v3d: Create a CPU job extension for the timestamp query job") +Assisted-by: Claude:claude-opus-4.7 +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260515-v3d-cpu-job-leaks-v1-1-7f147cbbf935@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/v3d/v3d_sched.c | 16 +--------------- + drivers/gpu/drm/v3d/v3d_submit.c | 19 ++++++++++++++++--- + 2 files changed, 17 insertions(+), 18 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -105,20 +105,6 @@ v3d_performance_query_info_free(struct v + } + + static void +-v3d_cpu_job_free(struct drm_sched_job *sched_job) +-{ +- struct v3d_cpu_job *job = to_cpu_job(sched_job); +- +- v3d_timestamp_query_info_free(&job->timestamp_query, +- job->timestamp_query.count); +- +- v3d_performance_query_info_free(&job->performance_query, +- job->performance_query.count); +- +- v3d_job_cleanup(&job->base); +-} +- +-static void + v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job) + { + struct v3d_perfmon *perfmon = v3d->global_perfmon; +@@ -861,7 +847,7 @@ static const struct drm_sched_backend_op + + static const struct drm_sched_backend_ops v3d_cpu_sched_ops = { + .run_job = v3d_cpu_job_run, +- .free_job = v3d_cpu_job_free ++ .free_job = v3d_sched_job_free + }; + + static int +--- a/drivers/gpu/drm/v3d/v3d_submit.c ++++ b/drivers/gpu/drm/v3d/v3d_submit.c +@@ -120,6 +120,21 @@ v3d_render_job_free(struct kref *ref) + v3d_job_free(ref); + } + ++static void ++v3d_cpu_job_free(struct kref *ref) ++{ ++ struct v3d_cpu_job *job = container_of(ref, struct v3d_cpu_job, ++ base.refcount); ++ ++ v3d_timestamp_query_info_free(&job->timestamp_query, ++ job->timestamp_query.count); ++ ++ v3d_performance_query_info_free(&job->performance_query, ++ job->performance_query.count); ++ ++ v3d_job_free(ref); ++} ++ + void v3d_job_cleanup(struct v3d_job *job) + { + if (!job) +@@ -1296,7 +1311,7 @@ v3d_submit_cpu_ioctl(struct drm_device * + trace_v3d_submit_cpu_ioctl(&v3d->drm, cpu_job->job_type); + + ret = v3d_job_init(v3d, file_priv, &cpu_job->base, +- v3d_job_free, 0, &se, V3D_CPU); ++ v3d_cpu_job_free, 0, &se, V3D_CPU); + if (ret) { + v3d_job_deallocate((void *)&cpu_job); + goto fail; +@@ -1379,8 +1394,6 @@ fail: + v3d_job_cleanup((void *)csd_job); + v3d_job_cleanup(clean_job); + v3d_put_multisync_post_deps(&se); +- kvfree(cpu_job->timestamp_query.queries); +- kvfree(cpu_job->performance_query.queries); + + return ret; + } diff --git a/queue-7.0/drm-v3d-release-indirect-csd-gem-reference-on-cpu-job-free.patch b/queue-7.0/drm-v3d-release-indirect-csd-gem-reference-on-cpu-job-free.patch new file mode 100644 index 0000000000..8bfa334055 --- /dev/null +++ b/queue-7.0/drm-v3d-release-indirect-csd-gem-reference-on-cpu-job-free.patch @@ -0,0 +1,43 @@ +From 6eb6e5acafa46854d4363e6c34981289995f3ace Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Fri, 15 May 2026 12:07:15 -0300 +Subject: drm/v3d: Release indirect CSD GEM reference on CPU job free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +commit 6eb6e5acafa46854d4363e6c34981289995f3ace upstream. + +v3d_get_cpu_indirect_csd_params() takes a reference to the indirect BO via +drm_gem_object_lookup() and stashes it in cpu_job->indirect_csd.indirect, +but nothing on the CPU job teardown path ever drops that reference. + +Drop the extra reference in v3d_cpu_job_free(). The NULL check covers ioctl +errors before the lookup ran and CPU job types other than +V3D_CPU_JOB_TYPE_INDIRECT_CSD, which leave the field zero-initialised. + +Cc: stable@vger.kernel.org +Fixes: 18b8413b25b7 ("drm/v3d: Create a CPU job extension for a indirect CSD job") +Assisted-by: Claude:claude-opus-4.7 +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260515-v3d-cpu-job-leaks-v1-2-7f147cbbf935@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/v3d/v3d_submit.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/v3d/v3d_submit.c ++++ b/drivers/gpu/drm/v3d/v3d_submit.c +@@ -132,6 +132,9 @@ v3d_cpu_job_free(struct kref *ref) + v3d_performance_query_info_free(&job->performance_query, + job->performance_query.count); + ++ if (job->indirect_csd.indirect) ++ drm_gem_object_put(job->indirect_csd.indirect); ++ + v3d_job_free(ref); + } + diff --git a/queue-7.0/drm-virtio-use-uninterruptible-resv-lock-for-plane-updates.patch b/queue-7.0/drm-virtio-use-uninterruptible-resv-lock-for-plane-updates.patch new file mode 100644 index 0000000000..435704caf4 --- /dev/null +++ b/queue-7.0/drm-virtio-use-uninterruptible-resv-lock-for-plane-updates.patch @@ -0,0 +1,145 @@ +From 9af1b6e175c82daf4b423da339a722d8e67a735a Mon Sep 17 00:00:00 2001 +From: Deepanshu Kartikey +Date: Tue, 19 May 2026 13:52:47 +0530 +Subject: drm/virtio: use uninterruptible resv lock for plane updates + +From: Deepanshu Kartikey + +commit 9af1b6e175c82daf4b423da339a722d8e67a735a upstream. + +virtio_gpu_cursor_plane_update() and virtio_gpu_resource_flush() lock +the framebuffer BO's dma_resv via virtio_gpu_array_lock_resv() and +ignore its return value. The function can fail with -EINTR from +dma_resv_lock_interruptible() (signal during lock wait) or with +-ENOMEM from dma_resv_reserve_fences() (fence slot allocation), +leaving the resv lock not held. The queue path then walks the object +array and calls dma_resv_add_fence(), which requires the lock held; +with lockdep enabled this trips dma_resv_assert_held(): + + WARNING: drivers/dma-buf/dma-resv.c:296 at dma_resv_add_fence+0x71e/0x840 + Call Trace: + virtio_gpu_array_add_fence + virtio_gpu_queue_ctrl_sgs + virtio_gpu_queue_fenced_ctrl_buffer + virtio_gpu_cursor_plane_update + drm_atomic_helper_commit_planes + drm_atomic_helper_commit_tail + commit_tail + drm_atomic_helper_commit + drm_atomic_commit + drm_atomic_helper_update_plane + __setplane_atomic + drm_mode_cursor_universal + drm_mode_cursor_common + drm_mode_cursor_ioctl + drm_ioctl + __x64_sys_ioctl + +Beyond the WARN, mutating the dma_resv fence list without the lock +races with concurrent readers/writers and can corrupt the list. + +Both call sites run inside the .atomic_update plane callback, which +DRM atomic helpers do not allow to fail (by the time it runs, the +commit has been signed off to userspace and there is no clean +rollback path). Moving the lock acquisition to .prepare_fb was +rejected because the broader lock scope deadlocks against other BO +locking paths in the same atomic commit. + +Introduce virtio_gpu_lock_one_resv_uninterruptible() that uses +dma_resv_lock() instead of dma_resv_lock_interruptible(). This +eliminates the -EINTR failure mode -- the realistic syzbot trigger +-- without extending the lock hold across the commit. The helper +locks a single BO and rejects nents > 1 with -EINVAL; both fix +sites lock exactly one BO. + +Use it from virtio_gpu_cursor_plane_update() and +virtio_gpu_resource_flush(); check the return value to handle the +remaining -ENOMEM case from dma_resv_reserve_fences() by freeing +the objs and skipping the plane update for that frame. The +framebuffer BOs touched here are not shared with other contexts +and lock contention is expected to be brief, so the loss of +signal-interruptibility is acceptable. + +Other callers of virtio_gpu_array_lock_resv() (the ioctl paths) +continue to use the interruptible variant. + +The bug was reported by syzbot, triggered via fault injection +(fail_nth) on the DRM_IOCTL_MODE_CURSOR path, which forces the +-ENOMEM branch in dma_resv_reserve_fences(). + +Reported-by: syzbot+72bd3dd3a5d5f39a0271@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=72bd3dd3a5d5f39a0271 +Fixes: 5cfd31c5b3a3 ("drm/virtio: fix virtio_gpu_cursor_plane_update().") +Cc: stable@vger.kernel.org +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20260519082247.34470-1-kartikey406@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/virtio/virtgpu_drv.h | 1 + + drivers/gpu/drm/virtio/virtgpu_gem.c | 17 +++++++++++++++++ + drivers/gpu/drm/virtio/virtgpu_plane.c | 10 ++++++++-- + 3 files changed, 26 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/virtio/virtgpu_drv.h ++++ b/drivers/gpu/drm/virtio/virtgpu_drv.h +@@ -317,6 +317,7 @@ virtio_gpu_array_from_handles(struct drm + void virtio_gpu_array_add_obj(struct virtio_gpu_object_array *objs, + struct drm_gem_object *obj); + int virtio_gpu_array_lock_resv(struct virtio_gpu_object_array *objs); ++int virtio_gpu_lock_one_resv_uninterruptible(struct virtio_gpu_object_array *objs); + void virtio_gpu_array_unlock_resv(struct virtio_gpu_object_array *objs); + void virtio_gpu_array_add_fence(struct virtio_gpu_object_array *objs, + struct dma_fence *fence); +--- a/drivers/gpu/drm/virtio/virtgpu_gem.c ++++ b/drivers/gpu/drm/virtio/virtgpu_gem.c +@@ -238,6 +238,23 @@ int virtio_gpu_array_lock_resv(struct vi + return ret; + } + ++int virtio_gpu_lock_one_resv_uninterruptible(struct virtio_gpu_object_array *objs) ++{ ++ int ret; ++ ++ if (objs->nents != 1) ++ return -EINVAL; ++ ++ dma_resv_lock(objs->objs[0]->resv, NULL); ++ ++ ret = dma_resv_reserve_fences(objs->objs[0]->resv, 1); ++ if (ret) { ++ virtio_gpu_array_unlock_resv(objs); ++ return ret; ++ } ++ return 0; ++} ++ + void virtio_gpu_array_unlock_resv(struct virtio_gpu_object_array *objs) + { + if (objs->nents == 1) { +--- a/drivers/gpu/drm/virtio/virtgpu_plane.c ++++ b/drivers/gpu/drm/virtio/virtgpu_plane.c +@@ -215,7 +215,10 @@ static void virtio_gpu_resource_flush(st + if (!objs) + return; + virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]); +- virtio_gpu_array_lock_resv(objs); ++ if (virtio_gpu_lock_one_resv_uninterruptible(objs)) { ++ virtio_gpu_array_put_free(objs); ++ return; ++ } + virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y, + width, height, objs, + vgplane_st->fence); +@@ -459,7 +462,10 @@ static void virtio_gpu_cursor_plane_upda + if (!objs) + return; + virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]); +- virtio_gpu_array_lock_resv(objs); ++ if (virtio_gpu_lock_one_resv_uninterruptible(objs)) { ++ virtio_gpu_array_put_free(objs); ++ return; ++ } + virtio_gpu_cmd_transfer_to_host_2d + (vgdev, 0, + plane->state->crtc_w, diff --git a/queue-7.0/drm-xe-multi_queue-fix-secondary-queue-error-case.patch b/queue-7.0/drm-xe-multi_queue-fix-secondary-queue-error-case.patch new file mode 100644 index 0000000000..10b231a7f3 --- /dev/null +++ b/queue-7.0/drm-xe-multi_queue-fix-secondary-queue-error-case.patch @@ -0,0 +1,64 @@ +From 00907da2126ed785451b2a2f0fef282246dad104 Mon Sep 17 00:00:00 2001 +From: Niranjana Vishwanathapura +Date: Mon, 18 May 2026 12:16:40 -0700 +Subject: drm/xe/multi_queue: Fix secondary queue error case +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Niranjana Vishwanathapura + +commit 00907da2126ed785451b2a2f0fef282246dad104 upstream. + +If xe_lrc_create() fails, the secondary queue added to the +multi-queue group list is not removed before freeing the +queue. Fix error path handling for secondary queues by +removing it from the multi-queue group list at the right +place. + +Reported-by: Sebastian Österlund +Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7979 +Fixes: d716a5088c88 ("drm/xe/multi_queue: Handle tearing down of a multi queue") +Cc: stable@vger.kernel.org # v7.0+ +Signed-off-by: Niranjana Vishwanathapura +Reviewed-by: Matthew Auld +Link: https://patch.msgid.link/20260518191639.320890-2-niranjana.vishwanathapura@intel.com +(cherry picked from commit d2d23c12789cf69eddc35b8d38cd8eaabd0168f1) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/xe/xe_guc_submit.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/xe/xe_guc_submit.c ++++ b/drivers/gpu/drm/xe/xe_guc_submit.c +@@ -1623,6 +1623,14 @@ static void guc_exec_queue_fini(struct x + struct xe_guc_exec_queue *ge = q->guc; + struct xe_guc *guc = exec_queue_to_guc(q); + ++ if (xe_exec_queue_is_multi_queue_secondary(q)) { ++ struct xe_exec_queue_group *group = q->multi_queue.group; ++ ++ mutex_lock(&group->list_lock); ++ list_del(&q->multi_queue.link); ++ mutex_unlock(&group->list_lock); ++ } ++ + release_guc_id(guc, q); + xe_sched_entity_fini(&ge->entity); + xe_sched_fini(&ge->sched); +@@ -1644,14 +1652,6 @@ static void __guc_exec_queue_destroy_asy + guard(xe_pm_runtime)(guc_to_xe(guc)); + trace_xe_exec_queue_destroy(q); + +- if (xe_exec_queue_is_multi_queue_secondary(q)) { +- struct xe_exec_queue_group *group = q->multi_queue.group; +- +- mutex_lock(&group->list_lock); +- list_del(&q->multi_queue.link); +- mutex_unlock(&group->list_lock); +- } +- + /* Confirm no work left behind accessing device structures */ + cancel_delayed_work_sync(&ge->sched.base.work_tdr); + diff --git a/queue-7.0/fwctl-pds-validate-rpc-input-size-before-parsing.patch b/queue-7.0/fwctl-pds-validate-rpc-input-size-before-parsing.patch new file mode 100644 index 0000000000..b948f188de --- /dev/null +++ b/queue-7.0/fwctl-pds-validate-rpc-input-size-before-parsing.patch @@ -0,0 +1,43 @@ +From e7537735028c3ad4b0bfc02ff8fa2a1a28aa04fe Mon Sep 17 00:00:00 2001 +From: Heechan Kang +Date: Sun, 17 May 2026 15:22:32 +0900 +Subject: fwctl: pds: Validate RPC input size before parsing + +From: Heechan Kang + +commit e7537735028c3ad4b0bfc02ff8fa2a1a28aa04fe upstream. + +The fwctl core allocates the device-specific RPC input buffer with +fwctl_rpc.in_len and passes that buffer to the driver callback. + +pdsfc_fw_rpc() casts the buffer to struct fwctl_rpc_pds and then calls +pdsfc_validate_rpc(), which reads fields from that structure before +checking that the input buffer is large enough to contain it. A short +in_len can make pds_fwctl read beyond the allocation. + +Reject pds RPC buffers that are smaller than struct fwctl_rpc_pds before +parsing any pds-specific fields. + +Fixes: 92c66ee829b9 ("pds_fwctl: add rpc and query support") +Link: https://patch.msgid.link/r/20260517062232.1858747-1-gganji11@naver.com +Cc: stable@vger.kernel.org # v6.15+ +Signed-off-by: Heechan Kang +Reviewed-by: Dave Jiang +Signed-off-by: Jason Gunthorpe +Signed-off-by: Greg Kroah-Hartman +--- + drivers/fwctl/pds/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/fwctl/pds/main.c ++++ b/drivers/fwctl/pds/main.c +@@ -362,6 +362,9 @@ static void *pdsfc_fw_rpc(struct fwctl_u + void *out = NULL; + int err; + ++ if (in_len < sizeof(*rpc)) ++ return ERR_PTR(-EINVAL); ++ + err = pdsfc_validate_rpc(pdsfc, rpc, scope); + if (err) + return ERR_PTR(err); diff --git a/queue-7.0/hwmon-pmbus-adm1266-bounce-blackbox-records-through-a-protocol-sized-buffer.patch b/queue-7.0/hwmon-pmbus-adm1266-bounce-blackbox-records-through-a-protocol-sized-buffer.patch new file mode 100644 index 0000000000..259c7bc54b --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-bounce-blackbox-records-through-a-protocol-sized-buffer.patch @@ -0,0 +1,69 @@ +From 43cae21424ff8e33894a0f86c6b80b840c049fd7 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Fri, 15 May 2026 15:11:51 -0700 +Subject: hwmon: (pmbus/adm1266) bounce blackbox records through a protocol-sized buffer + +From: Abdurrahman Hussain + +commit 43cae21424ff8e33894a0f86c6b80b840c049fd7 upstream. + +adm1266_pmbus_block_xfer() copies the device-supplied block payload +into the caller-provided buffer using the device-supplied length: + + memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]); + +The helper does not know how large data_r is and trusts the device to +return at most one record's worth of bytes. adm1266_nvmem_read_blackbox() +violates that contract: it advances read_buff inside data->dev_mem in +ADM1266_BLACKBOX_SIZE (64-byte) strides while the helper is willing to +write up to ADM1266_PMBUS_BLOCK_MAX (255) bytes. A device that returns +more than 64 bytes on the trailing record (read_buff offset 1984 in +the 2048-byte dev_mem allocation) overflows dev_mem by up to 191 bytes +before the post-call + + if (ret != ADM1266_BLACKBOX_SIZE) + return -EIO; + +can reject the response. + +Contain the fix in the caller without changing the helper signature: +read each record into a 255-byte local bounce buffer that matches the +helper's maximum output, validate the returned length, and only then +copy exactly ADM1266_BLACKBOX_SIZE bytes into the dev_mem slot. + +Fixes: 407dc802a9c0 ("hwmon: (pmbus/adm1266) Add Block process call") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260515-adm1266-fixes-v1-5-1c1ea1349cfe@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -348,6 +348,7 @@ static void adm1266_init_debugfs(struct + + static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff) + { ++ u8 record[ADM1266_PMBUS_BLOCK_MAX]; + int record_count; + char index; + u8 buf[I2C_SMBUS_BLOCK_MAX]; +@@ -365,13 +366,14 @@ static int adm1266_nvmem_read_blackbox(s + return -EIO; + + for (index = 0; index < record_count; index++) { +- ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff); ++ ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, record); + if (ret < 0) + return ret; + + if (ret != ADM1266_BLACKBOX_SIZE) + return -EIO; + ++ memcpy(read_buff, record, ADM1266_BLACKBOX_SIZE); + read_buff += ADM1266_BLACKBOX_SIZE; + } + diff --git a/queue-7.0/hwmon-pmbus-adm1266-cap-pdio-scan-in-get_multiple-at-adm1266_pdio_nr.patch b/queue-7.0/hwmon-pmbus-adm1266-cap-pdio-scan-in-get_multiple-at-adm1266_pdio_nr.patch new file mode 100644 index 0000000000..37ec95b11d --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-cap-pdio-scan-in-get_multiple-at-adm1266_pdio_nr.patch @@ -0,0 +1,55 @@ +From d7834d92251baade796812876e95555e2066fa9f Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:25 -0700 +Subject: hwmon: (pmbus/adm1266) cap PDIO scan in get_multiple at ADM1266_PDIO_NR + +From: Abdurrahman Hussain + +commit d7834d92251baade796812876e95555e2066fa9f upstream. + +adm1266_gpio_get_multiple() iterates the PDIO portion of the +caller-supplied mask using + + for_each_set_bit_from(gpio_nr, mask, + ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) { + ... + } + +where ADM1266_PDIO_STATUS is the PMBus command code (0xE9, i.e. 233), +not the number of PDIO pins. The intended upper bound is +ADM1266_GPIO_NR + ADM1266_PDIO_NR = 25. + +gpiolib hands in a mask sized for gc.ngpio (= 25 bits on this chip), +so the iteration walks find_next_bit() up to 242, reading up to 217 +extra bits (a handful of unsigned-long words: four on 64-bit, seven +on 32-bit) of whatever lives past the end of the mask in the +caller's stack. Any incidental set bit in that range then drives a +set_bit(gpio_nr, bits) call that writes past the end of the +caller-supplied bits array too -- both out-of-bounds. + +Substitute ADM1266_PDIO_NR for the constant so the scan stops at the +last real PDIO bit. + +Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Linus Walleij +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-1-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -212,7 +212,7 @@ static int adm1266_gpio_get_multiple(str + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; +- for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) { ++ for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_NR) { + if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status)) + set_bit(gpio_nr, bits); + } diff --git a/queue-7.0/hwmon-pmbus-adm1266-don-t-clobber-gpio-bits-before-pdio-read-in-get_multiple.patch b/queue-7.0/hwmon-pmbus-adm1266-don-t-clobber-gpio-bits-before-pdio-read-in-get_multiple.patch new file mode 100644 index 0000000000..1ff5371e34 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-don-t-clobber-gpio-bits-before-pdio-read-in-get_multiple.patch @@ -0,0 +1,55 @@ +From 3327a12aee9e10ffa903e28b8445dfd1af5307c0 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:26 -0700 +Subject: hwmon: (pmbus/adm1266) don't clobber GPIO bits before PDIO read in get_multiple + +From: Abdurrahman Hussain + +commit 3327a12aee9e10ffa903e28b8445dfd1af5307c0 upstream. + +adm1266_gpio_get_multiple() zeroes *bits before the GPIO_STATUS loop +and then a second time before the PDIO_STATUS loop: + + *bits = 0; + for_each_set_bit(gpio_nr, mask, ADM1266_GPIO_NR) { + ... + set_bit(gpio_nr, bits); + } + + ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, ...); + ... + *bits = 0; + for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_NR) { + ... + set_bit(gpio_nr, bits); + } + +The second *bits = 0 throws away every GPIO bit the first loop just +populated, so callers asking for any combination of GPIO and PDIO +pins always see the GPIO portion of the returned bits as zero. + +Drop the redundant second assignment so both halves of the result +survive. + +Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Linus Walleij +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-2-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -211,7 +211,6 @@ static int adm1266_gpio_get_multiple(str + + status = read_buf[0] + (read_buf[1] << 8); + +- *bits = 0; + for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_NR) { + if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status)) + set_bit(gpio_nr, bits); diff --git a/queue-7.0/hwmon-pmbus-adm1266-include-pec-byte-in-pmbus_block_xfer-read-buffer.patch b/queue-7.0/hwmon-pmbus-adm1266-include-pec-byte-in-pmbus_block_xfer-read-buffer.patch new file mode 100644 index 0000000000..74d4a341f9 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-include-pec-byte-in-pmbus_block_xfer-read-buffer.patch @@ -0,0 +1,52 @@ +From 487566cb1ccdf3756fdd7bf8d875e612ff3169bb Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Fri, 15 May 2026 15:11:50 -0700 +Subject: hwmon: (pmbus/adm1266) include PEC byte in pmbus_block_xfer read buffer + +From: Abdurrahman Hussain + +commit 487566cb1ccdf3756fdd7bf8d875e612ff3169bb upstream. + +adm1266_pmbus_block_xfer() sets up the read transaction with + + .buf = data->read_buf, + .len = ADM1266_PMBUS_BLOCK_MAX + 2, + +but read_buf in struct adm1266_data is declared as + + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + +For a max-length block response (length byte = 255 + up to 1 PEC +byte), the i2c controller is told to write 257 bytes into a 256-byte +buffer, putting one byte past the end of read_buf. The same response +also makes the subsequent PEC compare + + if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) + +read a byte beyond the array. + +Bump the read_buf declaration to ADM1266_PMBUS_BLOCK_MAX + 2 so the +buffer can hold the length byte, up to 255 payload bytes, and the PEC +byte the i2c_msg length already accounts for. + +Fixes: 407dc802a9c0 ("hwmon: (pmbus/adm1266) Add Block process call") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260515-adm1266-fixes-v1-4-1c1ea1349cfe@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -61,7 +61,7 @@ struct adm1266_data { + u8 *dev_mem; + struct mutex buf_mutex; + u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; +- u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; ++ u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 2] ____cacheline_aligned; + }; + + static const struct nvmem_cell_info adm1266_nvmem_cells[] = { diff --git a/queue-7.0/hwmon-pmbus-adm1266-register-the-gpio_chip-after-pmbus_do_probe.patch b/queue-7.0/hwmon-pmbus-adm1266-register-the-gpio_chip-after-pmbus_do_probe.patch new file mode 100644 index 0000000000..8123ef12e5 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-register-the-gpio_chip-after-pmbus_do_probe.patch @@ -0,0 +1,60 @@ +From 491403b9b76cf66abd81301c5901aa4a4549f1e8 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:28 -0700 +Subject: hwmon: (pmbus/adm1266) register the gpio_chip after pmbus_do_probe() + +From: Abdurrahman Hussain + +commit 491403b9b76cf66abd81301c5901aa4a4549f1e8 upstream. + +adm1266_probe() calls adm1266_config_gpio() -- which goes on to +devm_gpiochip_add_data() and exposes the gpio_chip callbacks to +gpiolib -- before pmbus_do_probe() has initialised the per-client +PMBus state (notably the pmbus_lock mutex the core hands out via +pmbus_get_data()). + +That ordering is already a latent hazard: any GPIO access that lands +between adm1266_config_gpio() and the end of pmbus_do_probe() (for +example a sysfs read from a user space agent that opens the gpiochip +the instant gpiolib advertises it) races pmbus_do_probe()'s own +device accesses with no serialisation. + +Move adm1266_config_gpio() down past pmbus_do_probe() so the chip +isn't reachable from userspace until the PMBus state it depends on +is fully initialised. + +Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Bartosz Golaszewski +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-4-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -468,10 +468,6 @@ static int adm1266_probe(struct i2c_clie + crc8_populate_msb(pmbus_crc_table, 0x7); + mutex_init(&data->buf_mutex); + +- ret = adm1266_config_gpio(data); +- if (ret < 0) +- return ret; +- + ret = adm1266_set_rtc(data); + if (ret < 0) + return ret; +@@ -484,6 +480,10 @@ static int adm1266_probe(struct i2c_clie + if (ret) + return ret; + ++ ret = adm1266_config_gpio(data); ++ if (ret < 0) ++ return ret; ++ + adm1266_init_debugfs(data); + + return 0; diff --git a/queue-7.0/hwmon-pmbus-adm1266-register-the-nvmem-device-after-pmbus_do_probe.patch b/queue-7.0/hwmon-pmbus-adm1266-register-the-nvmem-device-after-pmbus_do_probe.patch new file mode 100644 index 0000000000..8611dca479 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-register-the-nvmem-device-after-pmbus_do_probe.patch @@ -0,0 +1,55 @@ +From 6af713af91d5c34ec049eb3cc2c5b3f5eba953b8 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:29 -0700 +Subject: hwmon: (pmbus/adm1266) register the nvmem device after pmbus_do_probe() + +From: Abdurrahman Hussain + +commit 6af713af91d5c34ec049eb3cc2c5b3f5eba953b8 upstream. + +adm1266_probe() calls adm1266_config_nvmem() -- which goes on to +devm_nvmem_register() and exposes adm1266_nvmem_read() to userspace -- +before pmbus_do_probe() has initialised the per-client PMBus state. + +Same latent hazard as the gpio_chip one fixed in the previous patch: +once the nvmem device is registered, gpiolib's nvmem char-dev / sysfs +interface is reachable, and any concurrent read triggers +adm1266_nvmem_read() -> adm1266_nvmem_read_blackbox(), which issues +PMBus traffic that races pmbus_do_probe()'s own device accesses with +no serialisation. + +Move adm1266_config_nvmem() down past pmbus_do_probe() so the nvmem +device isn't reachable from userspace until the PMBus state the +nvmem accessors depend on is fully initialised. + +Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-5-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -472,14 +472,14 @@ static int adm1266_probe(struct i2c_clie + if (ret < 0) + return ret; + +- ret = adm1266_config_nvmem(data); +- if (ret < 0) +- return ret; +- + ret = pmbus_do_probe(client, &data->info); + if (ret) + return ret; + ++ ret = adm1266_config_nvmem(data); ++ if (ret < 0) ++ return ret; ++ + ret = adm1266_config_gpio(data); + if (ret < 0) + return ret; diff --git a/queue-7.0/hwmon-pmbus-adm1266-reject-implausible-blackbox-record_count.patch b/queue-7.0/hwmon-pmbus-adm1266-reject-implausible-blackbox-record_count.patch new file mode 100644 index 0000000000..7d1da45716 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-reject-implausible-blackbox-record_count.patch @@ -0,0 +1,51 @@ +From 4afca954622d672ea65ed961bed01cf91caa034e Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Fri, 15 May 2026 15:11:49 -0700 +Subject: hwmon: (pmbus/adm1266) reject implausible blackbox record_count + +From: Abdurrahman Hussain + +commit 4afca954622d672ea65ed961bed01cf91caa034e upstream. + +adm1266_nvmem_read_blackbox() loops over a record_count that comes +straight from byte 3 of the BLACKBOX_INFO response. The destination +buffer is data->dev_mem, sized for the nvmem cell's declared 2048 +bytes (ADM1266_BLACKBOX_MAX_RECORDS * ADM1266_BLACKBOX_SIZE = 32 * 64). +A device that reports a record_count greater than 32 -- whether due +to firmware bugs, bus corruption, or a non-responsive slave returning +0xff -- would walk read_buff past the end of the dev_mem allocation +on the trailing iterations. + +Cap record_count at ADM1266_BLACKBOX_MAX_RECORDS (introduced here) +before entering the loop and return -EIO on any larger value, so a +malformed BLACKBOX_INFO response cannot drive the loop out of bounds. + +Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260515-adm1266-fixes-v1-3-1c1ea1349cfe@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -46,6 +46,7 @@ + + #define ADM1266_BLACKBOX_OFFSET 0 + #define ADM1266_BLACKBOX_SIZE 64 ++#define ADM1266_BLACKBOX_MAX_RECORDS 32 + + #define ADM1266_PMBUS_BLOCK_MAX 255 + +@@ -360,6 +361,8 @@ static int adm1266_nvmem_read_blackbox(s + return -EIO; + + record_count = buf[3]; ++ if (record_count > ADM1266_BLACKBOX_MAX_RECORDS) ++ return -EIO; + + for (index = 0; index < record_count; index++) { + ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff); diff --git a/queue-7.0/hwmon-pmbus-adm1266-reject-short-block-read-responses-in-the-gpio-accessors.patch b/queue-7.0/hwmon-pmbus-adm1266-reject-short-block-read-responses-in-the-gpio-accessors.patch new file mode 100644 index 0000000000..b3ff5cbdba --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-reject-short-block-read-responses-in-the-gpio-accessors.patch @@ -0,0 +1,71 @@ +From a7232f68c43ca62f545049b7f5fbfc75137b843b Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:27 -0700 +Subject: hwmon: (pmbus/adm1266) reject short block-read responses in the GPIO accessors + +From: Abdurrahman Hussain + +commit a7232f68c43ca62f545049b7f5fbfc75137b843b upstream. + +adm1266_gpio_get() and adm1266_gpio_get_multiple() both compose the +pin-status word as + + pins_status = read_buf[0] + (read_buf[1] << 8); + +right after i2c_smbus_read_block_data(), guarding only against an +error return. A well-behaved device returns 2 bytes for +GPIO_STATUS/PDIO_STATUS, but the helper happily reports a 0- or +1-byte response too. If the device returns 0 bytes, both read_buf +slots are uninitialized stack memory; if it returns 1 byte, read_buf[1] +is. + +The composed value then flows through set_bit() into the caller's +*bits in adm1266_gpio_get_multiple(), or into the return value of +adm1266_gpio_get(), and ends up in userspace via gpiolib (sysfs and +the char-dev ioctls). That leaks a few bits of kernel stack per +request on any device whose firmware glitch, bus error, or hostile +slave produces a short block-read response. + +Add the missing length check to both call sites and surface a short +response as -EIO. + +Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Bartosz Golaszewski +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-3-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -176,6 +176,8 @@ static int adm1266_gpio_get(struct gpio_ + ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); + if (ret < 0) + return ret; ++ if (ret < 2) ++ return -EIO; + + pins_status = read_buf[0] + (read_buf[1] << 8); + if (offset < ADM1266_GPIO_NR) +@@ -196,6 +198,8 @@ static int adm1266_gpio_get_multiple(str + ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); + if (ret < 0) + return ret; ++ if (ret < 2) ++ return -EIO; + + status = read_buf[0] + (read_buf[1] << 8); + +@@ -208,6 +212,8 @@ static int adm1266_gpio_get_multiple(str + ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf); + if (ret < 0) + return ret; ++ if (ret < 2) ++ return -EIO; + + status = read_buf[0] + (read_buf[1] << 8); + diff --git a/queue-7.0/hwmon-pmbus-adm1266-seed-timestamp-from-the-real-time-clock.patch b/queue-7.0/hwmon-pmbus-adm1266-seed-timestamp-from-the-real-time-clock.patch new file mode 100644 index 0000000000..717fc47bc1 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-seed-timestamp-from-the-real-time-clock.patch @@ -0,0 +1,45 @@ +From b86095e3d7dcf2bf80c747349a35912a87a85098 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Fri, 15 May 2026 15:11:47 -0700 +Subject: hwmon: (pmbus/adm1266) seed timestamp from the real-time clock + +From: Abdurrahman Hussain + +commit b86095e3d7dcf2bf80c747349a35912a87a85098 upstream. + +adm1266_set_rtc() seeds the chip's SET_RTC register from +ktime_get_seconds(), which returns CLOCK_MONOTONIC -- i.e. seconds +since the host last booted, not seconds since the Unix epoch. + +The chip stamps that value into every blackbox record it captures. +Userspace reading those timestamps back expects wall-clock seconds: +that's what the SET_RTC frame layout documents (datasheet Rev. D, +Table 84) and what every other consumer of "seconds since epoch" +assumes. Seeding from CLOCK_MONOTONIC gives blackbox records a +timestamp that is only meaningful within a single boot of the host +and silently resets to small values on every reboot. + +Switch to ktime_get_real_seconds() so the seed matches what the +register is documented to hold. + +Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260515-adm1266-fixes-v1-1-1c1ea1349cfe@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -434,7 +434,7 @@ static int adm1266_set_rtc(struct adm126 + char write_buf[6]; + int i; + +- kt = ktime_get_seconds(); ++ kt = ktime_get_real_seconds(); + + memset(write_buf, 0, sizeof(write_buf)); + diff --git a/queue-7.0/hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch b/queue-7.0/hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch new file mode 100644 index 0000000000..2c3e3d7110 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch @@ -0,0 +1,62 @@ +From bab8c6fb5af8df7e753d196c1262cb78e92ca872 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:30 -0700 +Subject: hwmon: (pmbus/adm1266) serialize GPIO PMBus accesses with pmbus_lock + +From: Abdurrahman Hussain + +commit bab8c6fb5af8df7e753d196c1262cb78e92ca872 upstream. + +adm1266_gpio_get(), adm1266_gpio_get_multiple(), and +adm1266_gpio_dbg_show() all issue PMBus reads against the device but +none of them take pmbus_lock. The pmbus_core framework holds +pmbus_lock around its own multi-transaction sequences (notably the +"set PAGE, then read paged register" pattern used by hwmon +attributes), so an unlocked GPIO accessor can land between a PAGE +write and the subsequent paged read in another thread and corrupt +either side's view of the device state machine. + +Take pmbus_lock at the top of each of the three accessors via the +scope-based guard(). The lock is uncontended in the common case and +adds only a single mutex round-trip per call. + +Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Bartosz Golaszewski +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-6-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -173,6 +173,8 @@ static int adm1266_gpio_get(struct gpio_ + else + pmbus_cmd = ADM1266_PDIO_STATUS; + ++ guard(pmbus_lock)(data->client); ++ + ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); + if (ret < 0) + return ret; +@@ -195,6 +197,8 @@ static int adm1266_gpio_get_multiple(str + unsigned int gpio_nr; + int ret; + ++ guard(pmbus_lock)(data->client); ++ + ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); + if (ret < 0) + return ret; +@@ -236,6 +240,8 @@ static void adm1266_gpio_dbg_show(struct + int ret; + int i; + ++ guard(pmbus_lock)(data->client); ++ + for (i = 0; i < ADM1266_GPIO_NR; i++) { + write_cmd = adm1266_gpio_mapping[i][1]; + ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf); diff --git a/queue-7.0/hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch b/queue-7.0/hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch new file mode 100644 index 0000000000..da6d945b6a --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch @@ -0,0 +1,58 @@ +From 9f1dd8f9491eb840cbea7ffdf4cad031e25f8ae0 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:31 -0700 +Subject: hwmon: (pmbus/adm1266) serialize NVMEM blackbox read with pmbus_lock + +From: Abdurrahman Hussain + +commit 9f1dd8f9491eb840cbea7ffdf4cad031e25f8ae0 upstream. + +adm1266_nvmem_read() is the reg_read callback the NVMEM core invokes +when userspace reads /sys/bus/nvmem/devices/.../nvmem on this chip. +On the first byte of every read it does a memset of data->dev_mem, +walks the device blackbox through adm1266_nvmem_read_blackbox() +(which issues a chain of PMBus block transactions), and then memcpys +the refreshed buffer out to userspace. None of that runs under +pmbus_lock today. + +Two consequences: + + - The PMBus traffic the refresh issues is not serialised against + pmbus_core's own multi-step PAGE+register sequences. A paged + hwmon attribute read from another thread can land between a + PAGE write and the paged read in either direction and corrupt + one side's view of the device state machine. + + - The NVMEM core does not serialise concurrent reg_read calls, so + two userspace readers racing at offset 0 can interleave the + memset of data->dev_mem with another reader's + adm1266_nvmem_read_blackbox() refill or memcpy out, returning + torn data to userspace. + +Take pmbus_lock at the top of adm1266_nvmem_read() via the +scope-based guard(). Patch 5 of this series moves +adm1266_config_nvmem() past pmbus_do_probe() so the lock is +guaranteed to be live before the callback is reachable from +userspace. + +Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-7-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -383,6 +383,8 @@ static int adm1266_nvmem_read(void *priv + if (offset + bytes > data->nvmem_config.size) + return -EINVAL; + ++ guard(pmbus_lock)(data->client); ++ + if (offset == 0) { + memset(data->dev_mem, 0, data->nvmem_config.size); + diff --git a/queue-7.0/hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch b/queue-7.0/hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch new file mode 100644 index 0000000000..1c10ea0dcc --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch @@ -0,0 +1,44 @@ +From 4e4af55aaca7f6d7673d5f9889ad0529db86a048 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 18 May 2026 17:52:32 -0700 +Subject: hwmon: (pmbus/adm1266) serialize sequencer_state debugfs read with pmbus_lock + +From: Abdurrahman Hussain + +commit 4e4af55aaca7f6d7673d5f9889ad0529db86a048 upstream. + +adm1266_state_read() backs the sequencer_state debugfs entry and +issues an i2c_smbus_read_word_data(client, ADM1266_READ_STATE) +against the device without taking pmbus_lock. pmbus_core holds +pmbus_lock around its own multi-transaction sequences (notably the +"set PAGE, then read paged register" pattern used by hwmon +attributes), so an unlocked debugfs reader can land between a PAGE +write and the subsequent paged read in another thread. READ_STATE +itself is not paged, so it cannot corrupt PAGE in flight, but the +same defensive serialisation that applies to the GPIO accessors +applies here: any direct device access from outside pmbus_core +should be ordered with respect to pmbus_core's own. + +Take pmbus_lock at the top of adm1266_state_read() via the +scope-based guard(). + +Fixes: ed1ff457e187 ("hwmon: (pmbus/adm1266) add debugfs for states") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-8-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -334,6 +334,7 @@ static int adm1266_state_read(struct seq + struct i2c_client *client = to_i2c_client(dev); + int ret; + ++ guard(pmbus_lock)(client); + ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE); + if (ret < 0) + return ret; diff --git a/queue-7.0/i2c-tegra-fix-pm_runtime-leak-on-mutex_lock-failure.patch b/queue-7.0/i2c-tegra-fix-pm_runtime-leak-on-mutex_lock-failure.patch new file mode 100644 index 0000000000..da2ad121b7 --- /dev/null +++ b/queue-7.0/i2c-tegra-fix-pm_runtime-leak-on-mutex_lock-failure.patch @@ -0,0 +1,42 @@ +From 57cf4e8d6a57dc2ef5810f4852a23ba4c71b74bb Mon Sep 17 00:00:00 2001 +From: Saurav Sachidanand +Date: Thu, 7 May 2026 22:11:44 +0000 +Subject: i2c: tegra: fix pm_runtime leak on mutex_lock failure + +From: Saurav Sachidanand + +commit 57cf4e8d6a57dc2ef5810f4852a23ba4c71b74bb upstream. + +If tegra_i2c_mutex_lock() fails, the function returns without calling +pm_runtime_put(), leaking the runtime PM reference acquired by the +preceding pm_runtime_get_sync(). This prevents the device from ever +entering runtime suspend. + +Add the missing pm_runtime_put() before returning on lock failure. + +Fixes: 6077cfd716fb ("i2c: tegra: Add support for SW mutex register") +Signed-off-by: Saurav Sachidanand +Cc: # v7.0+ +Reviewed-by: Jon Hunter +Acked-by: Thierry Reding +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260507221145.62183-2-sauravsc@amazon.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i2c/busses/i2c-tegra.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/i2c/busses/i2c-tegra.c ++++ b/drivers/i2c/busses/i2c-tegra.c +@@ -1522,8 +1522,10 @@ static int tegra_i2c_xfer(struct i2c_ada + } + + ret = tegra_i2c_mutex_lock(i2c_dev); +- if (ret) ++ if (ret) { ++ pm_runtime_put(i2c_dev->dev); + return ret; ++ } + + for (i = 0; i < num; i++) { + enum msg_end_type end_type = MSG_END_STOP; diff --git a/queue-7.0/kvm-arm64-vgic-free-private_irqs-when-init-fails-after-allocation.patch b/queue-7.0/kvm-arm64-vgic-free-private_irqs-when-init-fails-after-allocation.patch new file mode 100644 index 0000000000..edba5db966 --- /dev/null +++ b/queue-7.0/kvm-arm64-vgic-free-private_irqs-when-init-fails-after-allocation.patch @@ -0,0 +1,46 @@ +From f19c354dbd457759dfcf1195ab4bdba2bb568323 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Tue, 19 May 2026 09:50:42 -0400 +Subject: KVM: arm64: vgic: Free private_irqs when init fails after allocation + +From: Michael Bommarito + +commit f19c354dbd457759dfcf1195ab4bdba2bb568323 upstream. + +Companion to commit 250f25367b58 ("KVM: arm64: Tear down vGIC on +failed vCPU creation"), which added the missing kvm_vgic_vcpu_destroy() +call to the kvm_share_hyp() failure path in kvm_arch_vcpu_create(). The +kvm_vgic_vcpu_init() failure path immediately above it has the same +shape and still needs the same cleanup. + +Call kvm_vgic_vcpu_destroy() when kvm_vgic_vcpu_init() fails so private +IRQs allocated before a redistributor iodev registration failure are +released before the failed vCPU is freed. + +Fixes: 03b3d00a70b5 ("KVM: arm64: vgic: Allocate private interrupts on demand") +Cc: stable@vger.kernel.org +Cc: Will Deacon +Reviewed-by: Yuan Yao +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Link: https://lore.kernel.org/r/20260519135042.2219239-1-michael.bommarito@gmail.com +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kvm/arm.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -540,8 +540,10 @@ int kvm_arch_vcpu_create(struct kvm_vcpu + kvm_destroy_mpidr_data(vcpu->kvm); + + err = kvm_vgic_vcpu_init(vcpu); +- if (err) ++ if (err) { ++ kvm_vgic_vcpu_destroy(vcpu); + return err; ++ } + + err = kvm_share_hyp(vcpu, vcpu + 1); + if (err) diff --git a/queue-7.0/kvm-arm64-vgic-its-reject-restored-dte-with-out-of-range-num_eventid_bits.patch b/queue-7.0/kvm-arm64-vgic-its-reject-restored-dte-with-out-of-range-num_eventid_bits.patch new file mode 100644 index 0000000000..ac80e37381 --- /dev/null +++ b/queue-7.0/kvm-arm64-vgic-its-reject-restored-dte-with-out-of-range-num_eventid_bits.patch @@ -0,0 +1,43 @@ +From 9ce754ed8e7ab4e3999767ce1505f85c449ccb07 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Tue, 19 May 2026 09:25:19 -0400 +Subject: KVM: arm64: vgic-its: Reject restored DTE with out-of-range num_eventid_bits + +From: Michael Bommarito + +commit 9ce754ed8e7ab4e3999767ce1505f85c449ccb07 upstream. + +Userspace can restore an ITS Device Table Entry whose Size field encodes +more EventID bits than the virtual ITS supports. The live MAPD path +rejects that state, but vgic_its_restore_dte() accepts it and stores the +out-of-range value in dev->num_eventid_bits. + +Reject restored DTEs with num_eventid_bits > VITS_TYPER_IDBITS before +allocating the device. This mirrors the MAPD check and prevents the +restored state from reaching vgic_its_restore_itt(), where the unchecked +value can be converted into an oversized scan_its_table() range. + +Fixes: 57a9a117154c ("KVM: arm64: vgic-its: Device table save/restore") +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Link: https://lore.kernel.org/r/20260519132519.2142458-1-michael.bommarito@gmail.com +Signed-off-by: Marc Zyngier +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kvm/vgic/vgic-its.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm64/kvm/vgic/vgic-its.c ++++ b/arch/arm64/kvm/vgic/vgic-its.c +@@ -2307,6 +2307,10 @@ static int vgic_its_restore_dte(struct v + /* dte entry is valid */ + offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT; + ++ /* Mimic the MAPD behaviour and reject invalid EID bits. */ ++ if (num_eventid_bits > VITS_TYPER_IDBITS) ++ return -EINVAL; ++ + if (!vgic_its_check_id(its, baser, id, NULL)) + return -EINVAL; + diff --git a/queue-7.0/kvm-svm-disable-avic-ipi-virtualization-on-hygon-family-18h-erratum-1235.patch b/queue-7.0/kvm-svm-disable-avic-ipi-virtualization-on-hygon-family-18h-erratum-1235.patch new file mode 100644 index 0000000000..94d2f19957 --- /dev/null +++ b/queue-7.0/kvm-svm-disable-avic-ipi-virtualization-on-hygon-family-18h-erratum-1235.patch @@ -0,0 +1,54 @@ +From 9a12fa5213cfc391e0eed63902d3be98f0913765 Mon Sep 17 00:00:00 2001 +From: Tina Zhang +Date: Fri, 22 May 2026 12:00:14 +0800 +Subject: KVM: SVM: Disable AVIC IPI virtualization on Hygon Family 18h (erratum #1235) + +From: Tina Zhang + +commit 9a12fa5213cfc391e0eed63902d3be98f0913765 upstream. + +Hygon Family 18h CPUs are derived from AMD Family 17h (Zen1) silicon and +share the same erratum #1235: hardware may read a stale IsRunning=1 bit +during ICR write emulation and silently fail to generate an +AVIC_IPI_FAILURE_TARGET_NOT_RUNNING VM-Exit on the sending vCPU. + +The absence of the VM-Exit causes KVM to miss the required wakeup of +blocking target vCPUs, leading to hung vCPUs and unbounded delays in +guest execution. + +Extend the existing AMD Family 17h erratum #1235 workaround to also cover +Hygon Family 18h. With IPI virtualization disabled, KVM never sets +IsRunning=1 in the Physical ID table, so every non-self IPI generates a +VM-Exit and is correctly emulated. + +Fixes: 8de4a1c8164e ("KVM: SVM: Disable (x2)AVIC IPI virtualization if CPU has erratum #1235") +Cc: +Signed-off-by: Tina Zhang +Message-ID: <20260522040014.3380201-1-zhang_wei@open-hieco.net> +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/svm/avic.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/arch/x86/kvm/svm/avic.c ++++ b/arch/x86/kvm/svm/avic.c +@@ -1289,12 +1289,14 @@ bool __init avic_hardware_setup(void) + } + + /* +- * Disable IPI virtualization for AMD Family 17h CPUs (Zen1 and Zen2) +- * due to erratum 1235, which results in missed VM-Exits on the sender +- * and thus missed wake events for blocking vCPUs due to the CPU +- * failing to see a software update to clear IsRunning. ++ * Disable IPI virtualization for AMD Family 17h (Zen1 and Zen2) and ++ * Hygon Family 18h (derived from AMD Zen1) CPUs due to erratum 1235, ++ * which results in missed VM-Exits on the sender and thus missed wake ++ * events for blocking vCPUs due to the CPU failing to see a software ++ * update to clear IsRunning. + */ +- enable_ipiv = enable_ipiv && boot_cpu_data.x86 != 0x17; ++ if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) ++ enable_ipiv = false; + + amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier); + diff --git a/queue-7.0/loongarch-kprobes-use-larch_insn_text_copy-to-patch-instructions.patch b/queue-7.0/loongarch-kprobes-use-larch_insn_text_copy-to-patch-instructions.patch new file mode 100644 index 0000000000..303468ca98 --- /dev/null +++ b/queue-7.0/loongarch-kprobes-use-larch_insn_text_copy-to-patch-instructions.patch @@ -0,0 +1,71 @@ +From e3ef9a28f558d1cbf0b42d6dcd16c60da557562b Mon Sep 17 00:00:00 2001 +From: Tiezhu Yang +Date: Fri, 22 May 2026 15:05:07 +0800 +Subject: LoongArch: kprobes: Use larch_insn_text_copy() to patch instructions + +From: Tiezhu Yang + +commit e3ef9a28f558d1cbf0b42d6dcd16c60da557562b upstream. + +On SMP systems, kprobe handlers would occasionally fail to execute on +certain CPU cores. The issue is hard to reproduce and typically occurs +randomly under high system load. + +The root cause is a software-side instruction hazard. According to the +LoongArch Reference Manual, while the cache coherency is maintained by +hardware, software must explicitly use the "IBAR" instruction to ensure +the instruction fetch unit (IFU) observes the effects of recent stores. + +The current arch_arm_kprobe() and arch_disarm_kprobe() only execute the +"IBAR" barrier (via flush_insn_slot -> local_flush_icache_range) on the +local CPU. This leaves a vulnerable window where remote CPU cores may +continue executing stale instructions from their pipelines or prefetch +buffers, as they have not executed an "IBAR" since the code modification. + +Switch to larch_insn_text_copy() to fix this: +1. Synchronization: It uses stop_machine_cpuslocked() to synchronize all + online CPUs, ensuring no CPU is executing the target code area during + modification. +2. Visibility: By passing cpu_online_mask to stop_machine_cpuslocked(), + the callback text_copy_cb() is executed on all online cores. Each CPU + core invokes local_flush_icache_range() to execute "IBAR", clearing + instruction hazards system-wide and ensuring the "break" instruction + is visible to the fetch units of all cores. +3. Robustness: It properly manages memory write permissions (ROX/RW) for + the kernel text segment during patching, ensuring compatibility with + CONFIG_STRICT_KERNEL_RWX. + +Cc: # 6.18+ +Fixes: 6d4cc40fb5f5 ("LoongArch: Add kprobes support") +Signed-off-by: Tiezhu Yang +Signed-off-by: Huacai Chen +Signed-off-by: Greg Kroah-Hartman +--- + arch/loongarch/kernel/kprobes.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/arch/loongarch/kernel/kprobes.c ++++ b/arch/loongarch/kernel/kprobes.c +@@ -60,16 +60,18 @@ NOKPROBE_SYMBOL(arch_prepare_kprobe); + /* Install breakpoint in text */ + void arch_arm_kprobe(struct kprobe *p) + { +- *p->addr = KPROBE_BP_INSN; +- flush_insn_slot(p); ++ u32 insn = KPROBE_BP_INSN; ++ ++ larch_insn_text_copy(p->addr, &insn, LOONGARCH_INSN_SIZE); + } + NOKPROBE_SYMBOL(arch_arm_kprobe); + + /* Remove breakpoint from text */ + void arch_disarm_kprobe(struct kprobe *p) + { +- *p->addr = p->opcode; +- flush_insn_slot(p); ++ u32 insn = p->opcode; ++ ++ larch_insn_text_copy(p->addr, &insn, LOONGARCH_INSN_SIZE); + } + NOKPROBE_SYMBOL(arch_disarm_kprobe); + diff --git a/queue-7.0/loongarch-remove-unused-code-to-avoid-build-warning.patch b/queue-7.0/loongarch-remove-unused-code-to-avoid-build-warning.patch new file mode 100644 index 0000000000..85e65ccf40 --- /dev/null +++ b/queue-7.0/loongarch-remove-unused-code-to-avoid-build-warning.patch @@ -0,0 +1,40 @@ +From 0ccc9d47cf020994097ff51827cebd04aa2b0bf4 Mon Sep 17 00:00:00 2001 +From: Huacai Chen +Date: Thu, 21 May 2026 20:58:40 +0800 +Subject: LoongArch: Remove unused code to avoid build warning + +From: Huacai Chen + +commit 0ccc9d47cf020994097ff51827cebd04aa2b0bf4 upstream. + +After commit feee6b2989165631b1 ("mm/memory_hotplug: shrink zones when +offlining memory"), __remove_pages() doesn't need the "zone" parameter +so the "page" variable is also unused. Remove the unused code to avoid +such build warning: + +arch/loongarch/mm/init.c: In function 'arch_remove_memory': +arch/loongarch/mm/init.c:134:22: warning: variable 'page' set but not used [-Wunused-but-set-variable=] + 134 | struct page *page = pfn_to_page(start_pfn); + +Cc: +Reviewed-by: Guo Ren +Signed-off-by: Huacai Chen +Signed-off-by: Greg Kroah-Hartman +--- + arch/loongarch/mm/init.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/arch/loongarch/mm/init.c ++++ b/arch/loongarch/mm/init.c +@@ -93,11 +93,7 @@ void arch_remove_memory(u64 start, u64 s + { + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; +- struct page *page = pfn_to_page(start_pfn); + +- /* With altmap the first mapped page is offset from @start */ +- if (altmap) +- page += vmem_altmap_offset(altmap); + __remove_pages(start_pfn, nr_pages, altmap); + } + #endif diff --git a/queue-7.0/mm-slub-hold-cpus_read_lock-around-flush_rcu_sheaves_on_cache.patch b/queue-7.0/mm-slub-hold-cpus_read_lock-around-flush_rcu_sheaves_on_cache.patch new file mode 100644 index 0000000000..6400fe8ceb --- /dev/null +++ b/queue-7.0/mm-slub-hold-cpus_read_lock-around-flush_rcu_sheaves_on_cache.patch @@ -0,0 +1,72 @@ +From 67ea9d353d0ba12bdbc9183ff568dead9e949b80 Mon Sep 17 00:00:00 2001 +From: Qing Wang +Date: Tue, 12 May 2026 11:50:35 +0800 +Subject: mm/slub: hold cpus_read_lock around flush_rcu_sheaves_on_cache() + +From: Qing Wang + +commit 67ea9d353d0ba12bdbc9183ff568dead9e949b80 upstream. + +flush_rcu_sheaves_on_cache() calls queue_work_on() in a +for_each_online_cpu() loop, which requires the cpu to stay online. +But cpus_read_lock() is not held in kvfree_rcu_barrier_on_cache() and the +set of "online cpus" is subject to change. + +There are two paths that call flush_rcu_sheaves_on_cache(): + + // has cpus_read_lock() + flush_all_rcu_sheaves() + -> flush_rcu_sheaves_on_cache() + + // no cpus_read_lock() + kvfree_rcu_barrier_on_cache() + -> flush_rcu_sheaves_on_cache() + +Fix this by holding cpus_read_lock() in kvfree_rcu_barrier_on_cache(). + +Why not move cpus_read_lock() from flush_all_rcu_sheaves() into +flush_rcu_sheaves_on_cache()? The reason is it would introduce a new lock +order (slab_mutex -> cpu_hotplug_lock). The reverse order +(cpu_hotplug_lock -> slab_mutex) is established by + +- cpuhp_setup_state_nocalls(..., slub_cpu_setup, ...) +- kmem_cache_destroy() + +The two orders together would form an AB-BA deadlock. + +Finally, add lockdep_assert_cpus_held() in flush_rcu_sheaves_on_cache() +to catch the same problem in the future. + +Fixes: 0f35040de593 ("mm/slab: introduce kvfree_rcu_barrier_on_cache() for cache destruction") +Cc: +Signed-off-by: Qing Wang +Link: https://patch.msgid.link/20260512035035.762317-1-wangqing7171@gmail.com +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Greg Kroah-Hartman +--- + mm/slab_common.c | 2 ++ + mm/slub.c | 1 + + 2 files changed, 3 insertions(+) + +--- a/mm/slab_common.c ++++ b/mm/slab_common.c +@@ -2110,7 +2110,9 @@ EXPORT_SYMBOL_GPL(kvfree_rcu_barrier); + void kvfree_rcu_barrier_on_cache(struct kmem_cache *s) + { + if (cache_has_sheaves(s)) { ++ cpus_read_lock(); + flush_rcu_sheaves_on_cache(s); ++ cpus_read_unlock(); + rcu_barrier(); + } + +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -4038,6 +4038,7 @@ void flush_rcu_sheaves_on_cache(struct k + struct slub_flush_work *sfw; + unsigned int cpu; + ++ lockdep_assert_cpus_held(); + mutex_lock(&flush_lock); + + for_each_online_cpu(cpu) { diff --git a/queue-7.0/phy-exynos5-usbdrd-fix-usb-2.0-hs-phy-tuning-values-for-exynos7870.patch b/queue-7.0/phy-exynos5-usbdrd-fix-usb-2.0-hs-phy-tuning-values-for-exynos7870.patch new file mode 100644 index 0000000000..7ece510dbe --- /dev/null +++ b/queue-7.0/phy-exynos5-usbdrd-fix-usb-2.0-hs-phy-tuning-values-for-exynos7870.patch @@ -0,0 +1,59 @@ +From 5a759b120e31aa3ed914d98b51eb1755235250f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C5=81ukasz=20Lebiedzi=C5=84ski?= +Date: Mon, 6 Apr 2026 15:56:27 +0200 +Subject: phy: exynos5-usbdrd: fix USB 2.0 HS PHY tuning values for Exynos7870 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Łukasz Lebiedziński + +commit 5a759b120e31aa3ed914d98b51eb1755235250f2 upstream. + +The existing PHYPARAM0 tuning values for Exynos7870 are incorrect, +causing the USB 2.0 PHY to fail high-speed negotiation and fall back +to full-speed (12Mbps) operation. + +Fix TXVREFTUNE (transmitter voltage reference) from 14 to 3, +TXRESTUNE (transmitter impedance) from 3 to 2, and SQRXTUNE +(squelch threshold) from 6 to 5. Also explicitly set +TXPREEMPPULSETUNE to 0, which was previously missing from the +tuning table despite being included in the register mask. + +All values are derived from the vendor kernel for the Samsung +Galaxy A6 (SM-A600FN), as no public hardware documentation is +available for the Exynos7870 USB DRD PHY. With these corrections, +the PHY successfully negotiates high-speed (480Mbps) operation. + +Fixes: 588d5d20ca8d ("phy: exynos5-usbdrd: add exynos7870 USBDRD support") +Cc: stable@vger.kernel.org +Tested-by: Kaustabh Chakraborty +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Łukasz Lebiedziński +Link: https://patch.msgid.link/20260406135627.234835-1-kernel@lvkasz.us +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/samsung/phy-exynos5-usbdrd.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c ++++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c +@@ -1958,13 +1958,14 @@ const struct exynos5_usbdrd_phy_tuning e + PHYPARAM0_TXPREEMPAMPTUNE | PHYPARAM0_TXHSXVTUNE | + PHYPARAM0_TXFSLSTUNE | PHYPARAM0_SQRXTUNE | + PHYPARAM0_OTGTUNE | PHYPARAM0_COMPDISTUNE), +- (FIELD_PREP_CONST(PHYPARAM0_TXVREFTUNE, 14) | ++ (FIELD_PREP_CONST(PHYPARAM0_TXVREFTUNE, 3) | + FIELD_PREP_CONST(PHYPARAM0_TXRISETUNE, 1) | +- FIELD_PREP_CONST(PHYPARAM0_TXRESTUNE, 3) | ++ FIELD_PREP_CONST(PHYPARAM0_TXRESTUNE, 2) | ++ FIELD_PREP_CONST(PHYPARAM0_TXPREEMPPULSETUNE, 0) | + FIELD_PREP_CONST(PHYPARAM0_TXPREEMPAMPTUNE, 0) | + FIELD_PREP_CONST(PHYPARAM0_TXHSXVTUNE, 0) | + FIELD_PREP_CONST(PHYPARAM0_TXFSLSTUNE, 3) | +- FIELD_PREP_CONST(PHYPARAM0_SQRXTUNE, 6) | ++ FIELD_PREP_CONST(PHYPARAM0_SQRXTUNE, 5) | + FIELD_PREP_CONST(PHYPARAM0_OTGTUNE, 2) | + FIELD_PREP_CONST(PHYPARAM0_COMPDISTUNE, 3))), + PHY_TUNING_ENTRY_LAST diff --git a/queue-7.0/phy-qcom-edp-add-edp-dp-mode-switch-support.patch b/queue-7.0/phy-qcom-edp-add-edp-dp-mode-switch-support.patch new file mode 100644 index 0000000000..89f0705166 --- /dev/null +++ b/queue-7.0/phy-qcom-edp-add-edp-dp-mode-switch-support.patch @@ -0,0 +1,160 @@ +From 3011c365a329cf2db6d55e8d684550dc88350436 Mon Sep 17 00:00:00 2001 +From: Yongxing Mou +Date: Mon, 27 Apr 2026 14:35:20 +0800 +Subject: phy: qcom: edp: Add eDP/DP mode switch support + +From: Yongxing Mou + +commit 3011c365a329cf2db6d55e8d684550dc88350436 upstream. + +The eDP PHY supports both eDP/DP modes, each requiring a different +swing/pre-emphasis table. However, the driver currently uses a fixed +static table for eDP programming rather than selecting the appropriate +table based on the current mode. Add separate tables for eDP and DP +modes, and select the appropriate table dynamically based on the +current mode. + +Glymur's DP mode table differs from the other platforms, add a +dedicated table for it. + +This also fixes the table mismatch for X1E80100 (eDP) and SA8775P (DP). + +Cc: stable@vger.kernel.org +Fixes: 3f12bf16213c ("phy: qcom: edp: Add support for eDP PHY on SA8775P") +Reviewed-by: Konrad Dybcio +Signed-off-by: Yongxing Mou +Link: https://patch.msgid.link/20260427-edp_phy-v5-2-3bb876824475@oss.qualcomm.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/qualcomm/phy-qcom-edp.c | 46 ++++++++++++++++++++++++++---------- + 1 file changed, 34 insertions(+), 12 deletions(-) + +--- a/drivers/phy/qualcomm/phy-qcom-edp.c ++++ b/drivers/phy/qualcomm/phy-qcom-edp.c +@@ -87,7 +87,8 @@ struct qcom_edp_phy_cfg { + bool is_edp; + const u8 *aux_cfg; + const u8 *vco_div_cfg; +- const struct qcom_edp_swing_pre_emph_cfg *swing_pre_emph_cfg; ++ const struct qcom_edp_swing_pre_emph_cfg *dp_swing_pre_emph_cfg; ++ const struct qcom_edp_swing_pre_emph_cfg *edp_swing_pre_emph_cfg; + const struct phy_ver_ops *ver_ops; + }; + +@@ -150,6 +151,20 @@ static const struct qcom_edp_swing_pre_e + .pre_emphasis_hbr3_hbr2 = &dp_pre_emp_hbr2_hbr3, + }; + ++static const u8 dp_pre_emp_hbr_rbr_v8[4][4] = { ++ { 0x00, 0x0e, 0x15, 0x1a }, ++ { 0x00, 0x0e, 0x15, 0xff }, ++ { 0x00, 0x0e, 0xff, 0xff }, ++ { 0x00, 0xff, 0xff, 0xff } ++}; ++ ++static const struct qcom_edp_swing_pre_emph_cfg dp_phy_swing_pre_emph_cfg_v8 = { ++ .swing_hbr_rbr = &dp_swing_hbr_rbr, ++ .swing_hbr3_hbr2 = &dp_swing_hbr2_hbr3, ++ .pre_emphasis_hbr_rbr = &dp_pre_emp_hbr_rbr_v8, ++ .pre_emphasis_hbr3_hbr2 = &dp_pre_emp_hbr2_hbr3, ++}; ++ + static const u8 edp_swing_hbr_rbr[4][4] = { + { 0x07, 0x0f, 0x16, 0x1f }, + { 0x0d, 0x16, 0x1e, 0xff }, +@@ -246,7 +261,7 @@ static int qcom_edp_phy_init(struct phy + * when more information becomes available about why this is + * even needed. + */ +- if (edp->cfg->swing_pre_emph_cfg && !edp->is_edp) ++ if (edp->cfg->dp_swing_pre_emph_cfg && !edp->is_edp) + aux_cfg[8] = 0xb7; + + writel(0xfc, edp->edp + DP_PHY_MODE); +@@ -270,7 +285,7 @@ out_disable_supplies: + + static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts) + { +- const struct qcom_edp_swing_pre_emph_cfg *cfg = edp->cfg->swing_pre_emph_cfg; ++ const struct qcom_edp_swing_pre_emph_cfg *cfg; + unsigned int v_level = 0; + unsigned int p_level = 0; + u8 ldo_config; +@@ -278,12 +293,14 @@ static int qcom_edp_set_voltages(struct + u8 emph; + int i; + ++ if (edp->is_edp) ++ cfg = edp->cfg->edp_swing_pre_emph_cfg; ++ else ++ cfg = edp->cfg->dp_swing_pre_emph_cfg; ++ + if (!cfg) + return 0; + +- if (edp->is_edp) +- cfg = &edp_phy_swing_pre_emph_cfg; +- + for (i = 0; i < dp_opts->lanes; i++) { + v_level = max(v_level, dp_opts->voltage[i]); + p_level = max(p_level, dp_opts->pre[i]); +@@ -543,7 +560,8 @@ static const struct qcom_edp_phy_cfg sa8 + .is_edp = false, + .aux_cfg = edp_phy_aux_cfg_v5, + .vco_div_cfg = edp_phy_vco_div_cfg_v4, +- .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, ++ .dp_swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, ++ .edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, + }; + +@@ -556,7 +574,8 @@ static const struct qcom_edp_phy_cfg sc7 + static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, + .vco_div_cfg = edp_phy_vco_div_cfg_v4, +- .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, ++ .dp_swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, ++ .edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, + }; + +@@ -564,7 +583,8 @@ static const struct qcom_edp_phy_cfg sc8 + .is_edp = true, + .aux_cfg = edp_phy_aux_cfg_v4, + .vco_div_cfg = edp_phy_vco_div_cfg_v4, +- .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, ++ .dp_swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, ++ .edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, + }; + +@@ -745,7 +765,8 @@ static const struct phy_ver_ops qcom_edp + static struct qcom_edp_phy_cfg x1e80100_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, + .vco_div_cfg = edp_phy_vco_div_cfg_v4, +- .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, ++ .dp_swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, ++ .edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v6, + }; + +@@ -924,7 +945,8 @@ static const struct phy_ver_ops qcom_edp + static struct qcom_edp_phy_cfg glymur_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v8, + .vco_div_cfg = edp_phy_vco_div_cfg_v8, +- .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, ++ .dp_swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg_v8, ++ .edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v8, + }; + +@@ -942,7 +964,7 @@ static int qcom_edp_phy_power_on(struct + if (ret) + return ret; + +- if (edp->cfg->swing_pre_emph_cfg && !edp->is_edp) ++ if (edp->cfg->edp_swing_pre_emph_cfg && !edp->is_edp) + ldo_config = 0x1; + + writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); diff --git a/queue-7.0/phy-qcom-edp-fix-aux_cfg8-programming-for-dp-mode.patch b/queue-7.0/phy-qcom-edp-fix-aux_cfg8-programming-for-dp-mode.patch new file mode 100644 index 0000000000..5d69d64fb5 --- /dev/null +++ b/queue-7.0/phy-qcom-edp-fix-aux_cfg8-programming-for-dp-mode.patch @@ -0,0 +1,41 @@ +From bf237a9fcbbf9d658522f7315ffc04bf2d49be42 Mon Sep 17 00:00:00 2001 +From: Yongxing Mou +Date: Mon, 27 Apr 2026 14:35:22 +0800 +Subject: phy: qcom: edp: Fix AUX_CFG8 programming for DP mode + +From: Yongxing Mou + +commit bf237a9fcbbf9d658522f7315ffc04bf2d49be42 upstream. + +AUX_CFG8 depends on whether the PHY is operating in eDP or DP mode, not +the selected swing/pre-emphasis table. All supported platforms already +have the proper tables, so remove the unnecessary check. + +Cc: stable@vger.kernel.org +Fixes: 6078b8ce070c ("phy: qcom: edp: Add set_mode op for configuring eDP/DP submode") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Yongxing Mou +Link: https://patch.msgid.link/20260427-edp_phy-v5-4-3bb876824475@oss.qualcomm.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/qualcomm/phy-qcom-edp.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +--- a/drivers/phy/qualcomm/phy-qcom-edp.c ++++ b/drivers/phy/qualcomm/phy-qcom-edp.c +@@ -256,12 +256,7 @@ static int qcom_edp_phy_init(struct phy + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + edp->edp + DP_PHY_PD_CTL); + +- /* +- * TODO: Re-work the conditions around setting the cfg8 value +- * when more information becomes available about why this is +- * even needed. +- */ +- if (edp->cfg->dp_swing_pre_emph_cfg && !edp->is_edp) ++ if (!edp->is_edp) + aux_cfg[8] = 0xb7; + + writel(0xfc, edp->edp + DP_PHY_MODE); diff --git a/queue-7.0/phy-qcom-edp-unify-generic-dp-edp-swing-and-pre-emphasis-tables.patch b/queue-7.0/phy-qcom-edp-unify-generic-dp-edp-swing-and-pre-emphasis-tables.patch new file mode 100644 index 0000000000..7d618f6ea5 --- /dev/null +++ b/queue-7.0/phy-qcom-edp-unify-generic-dp-edp-swing-and-pre-emphasis-tables.patch @@ -0,0 +1,134 @@ +From fd672888cccd6b855154efe0ac78e7ce3e8ab088 Mon Sep 17 00:00:00 2001 +From: Yongxing Mou +Date: Mon, 27 Apr 2026 14:35:19 +0800 +Subject: phy: qcom: edp: Unify generic DP/eDP swing and pre-emphasis tables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yongxing Mou + +commit fd672888cccd6b855154efe0ac78e7ce3e8ab088 upstream. + +The current eDP and DP swing/pre-emphasis tables do not match the HPG +requirements for the supported platforms, correct the table accordingly. + +The generic tables which can be shared as follows: + +DP mode: + -sa8775p/sc7280/sc8280xp/x1e80100 + -glymur + -sc8180x +eDP mode(low vdiff): + -glymur/sa8775p/sc8280xp/x1e80100 + -sc7280 + -sc8180x + +The proper tables for SC8180X and SC7280 will be added in a later patch, +since they need separate table. + +Cc: stable@vger.kernel.org +Fixes: f199223cb490 ("phy: qcom: Introduce new eDP PHY driver") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Yongxing Mou +Link: https://patch.msgid.link/20260427-edp_phy-v5-1-3bb876824475@oss.qualcomm.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/qualcomm/phy-qcom-edp.c | 41 ++++++++---------------------------- + 1 file changed, 10 insertions(+), 31 deletions(-) + +--- a/drivers/phy/qualcomm/phy-qcom-edp.c ++++ b/drivers/phy/qualcomm/phy-qcom-edp.c +@@ -116,17 +116,17 @@ struct qcom_edp { + }; + + static const u8 dp_swing_hbr_rbr[4][4] = { +- { 0x08, 0x0f, 0x16, 0x1f }, ++ { 0x07, 0x0f, 0x16, 0x1f }, + { 0x11, 0x1e, 0x1f, 0xff }, + { 0x16, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } + }; + + static const u8 dp_pre_emp_hbr_rbr[4][4] = { +- { 0x00, 0x0d, 0x14, 0x1a }, ++ { 0x00, 0x0e, 0x15, 0x1a }, + { 0x00, 0x0e, 0x15, 0xff }, + { 0x00, 0x0e, 0xff, 0xff }, +- { 0x03, 0xff, 0xff, 0xff } ++ { 0x04, 0xff, 0xff, 0xff } + }; + + static const u8 dp_swing_hbr2_hbr3[4][4] = { +@@ -158,7 +158,7 @@ static const u8 edp_swing_hbr_rbr[4][4] + }; + + static const u8 edp_pre_emp_hbr_rbr[4][4] = { +- { 0x05, 0x12, 0x17, 0x1d }, ++ { 0x05, 0x11, 0x17, 0x1d }, + { 0x05, 0x11, 0x18, 0xff }, + { 0x06, 0x11, 0xff, 0xff }, + { 0x00, 0xff, 0xff, 0xff } +@@ -172,10 +172,10 @@ static const u8 edp_swing_hbr2_hbr3[4][4 + }; + + static const u8 edp_pre_emp_hbr2_hbr3[4][4] = { +- { 0x08, 0x11, 0x17, 0x1b }, +- { 0x00, 0x0c, 0x13, 0xff }, +- { 0x05, 0x10, 0xff, 0xff }, +- { 0x00, 0xff, 0xff, 0xff } ++ { 0x0c, 0x15, 0x19, 0x1e }, ++ { 0x0b, 0x15, 0x19, 0xff }, ++ { 0x0e, 0x14, 0xff, 0xff }, ++ { 0x0d, 0xff, 0xff, 0xff } + }; + + static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = { +@@ -193,27 +193,6 @@ static const u8 edp_phy_vco_div_cfg_v4[4 + 0x01, 0x01, 0x02, 0x00, + }; + +-static const u8 edp_pre_emp_hbr_rbr_v5[4][4] = { +- { 0x05, 0x11, 0x17, 0x1d }, +- { 0x05, 0x11, 0x18, 0xff }, +- { 0x06, 0x11, 0xff, 0xff }, +- { 0x00, 0xff, 0xff, 0xff } +-}; +- +-static const u8 edp_pre_emp_hbr2_hbr3_v5[4][4] = { +- { 0x0c, 0x15, 0x19, 0x1e }, +- { 0x0b, 0x15, 0x19, 0xff }, +- { 0x0e, 0x14, 0xff, 0xff }, +- { 0x0d, 0xff, 0xff, 0xff } +-}; +- +-static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg_v5 = { +- .swing_hbr_rbr = &edp_swing_hbr_rbr, +- .swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3, +- .pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr_v5, +- .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3_v5, +-}; +- + static const u8 edp_phy_aux_cfg_v5[DP_AUX_CFG_SIZE] = { + 0x00, 0x13, 0xa4, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x00, + }; +@@ -564,7 +543,7 @@ static const struct qcom_edp_phy_cfg sa8 + .is_edp = false, + .aux_cfg = edp_phy_aux_cfg_v5, + .vco_div_cfg = edp_phy_vco_div_cfg_v4, +- .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v5, ++ .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, + }; + +@@ -945,7 +924,7 @@ static const struct phy_ver_ops qcom_edp + static struct qcom_edp_phy_cfg glymur_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v8, + .vco_div_cfg = edp_phy_vco_div_cfg_v8, +- .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v5, ++ .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v8, + }; + diff --git a/queue-7.0/phy-qcom-qmp-ufs-fix-kaanapali-phy-pll-lock-failure-after-sm8650-g4-fix.patch b/queue-7.0/phy-qcom-qmp-ufs-fix-kaanapali-phy-pll-lock-failure-after-sm8650-g4-fix.patch new file mode 100644 index 0000000000..1764c57160 --- /dev/null +++ b/queue-7.0/phy-qcom-qmp-ufs-fix-kaanapali-phy-pll-lock-failure-after-sm8650-g4-fix.patch @@ -0,0 +1,48 @@ +From 80305760d7a55b884fb9023c490b75568d1ea0b1 Mon Sep 17 00:00:00 2001 +From: Nitin Rawat +Date: Wed, 15 Apr 2026 16:18:51 +0530 +Subject: phy: qcom-qmp-ufs: Fix kaanapali PHY PLL lock failure after SM8650 G4 fix + +From: Nitin Rawat + +commit 80305760d7a55b884fb9023c490b75568d1ea0b1 upstream. + +Commit 81af9e40e2e4 ("phy: qcom: qmp-ufs: Fix SM8650 PCS table for Gear 4") +moved QPHY_V6_PCS_UFS_PLL_CNTL register configuration from the shared +sm8650_ufsphy_g5_pcs table to the SM8650-specific sm8650_ufsphy_pcs base +table to fix Gear 4 operation on SM8650. + +However, this change inadvertently broke kaanapali and SM8750 SoCs +which also rely on the shared sm8650_ufsphy_g5_pcs table for Gear 5 +configuration but use their own sm8750_ufsphy_pcs base table. After the +change, kaanapali PHYs are left without the required PLL_CNTL = 0x33 +setting, causing the PHY PLL to remain at its hardware reset default +value, preventing PLL lock and resulting in DME_LINKSTARTUP timeouts. + +Fix this by adding the missing QPHY_V6_PCS_UFS_PLL_CNTL = 0x33 entry +to the sm8750_ufsphy_pcs table, mirroring what the original commit +already did for sm8650_ufsphy_pcs. + +Cc: stable@vger.kernel.org # v6.19.12 +Fixes: 81af9e40e2e4 ("phy: qcom: qmp-ufs: Fix SM8650 PCS table for Gear 4") +Signed-off-by: Nitin Rawat +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260415104851.2763238-1-nitin.rawat@oss.qualcomm.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c ++++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +@@ -1112,6 +1112,7 @@ static const struct qmp_phy_init_tbl sm8 + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0x40), ++ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e), diff --git a/queue-7.0/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch b/queue-7.0/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch new file mode 100644 index 0000000000..cbe9decb4f --- /dev/null +++ b/queue-7.0/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch @@ -0,0 +1,148 @@ +From da110228b54f2e2143d97ea7151e0dc22e539d67 Mon Sep 17 00:00:00 2001 +From: Wayne Chang +Date: Mon, 4 May 2026 11:33:05 +0800 +Subject: phy: tegra: xusb: Fix per-pad high-speed termination calibration + +From: Wayne Chang + +commit da110228b54f2e2143d97ea7151e0dc22e539d67 upstream. + +The existing code reads a single hs_term_range_adj value from bit field +[10:7] of FUSE_SKU_CALIB_0 and applies it to all USB2 pads uniformly. +However, on SoCs that support per-pad termination, each pad has its own +hs_term_range_adj field: pad 0 in FUSE_SKU_CALIB_0[10:7], and pads 1-3 +in FUSE_USB_CALIB_EXT_0 at bit offsets [8:5], [12:9], and [16:13] +respectively. + +Fix the calibration by reading per-pad values from the appropriate fuse +registers. For SoCs that do not support per-pad termination, replicate +pad 0's value to all pads to maintain existing behavior. + +Add a has_per_pad_term flag to the SoC data to indicate whether per-pad +termination values are available in FUSE_USB_CALIB_EXT_0. + +Fixes: 1ef535c6ba8e ("phy: tegra: xusb: Add Tegra194 support") +Cc: stable@vger.kernel.org +Signed-off-by: Wayne Chang +Signed-off-by: Wei-Cheng Chen +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260504033305.2283145-1-weichengc@nvidia.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/tegra/xusb-tegra186.c | 33 ++++++++++++++++++++++++++------- + drivers/phy/tegra/xusb.h | 1 + + 2 files changed, 27 insertions(+), 7 deletions(-) + +--- a/drivers/phy/tegra/xusb-tegra186.c ++++ b/drivers/phy/tegra/xusb-tegra186.c +@@ -20,8 +20,8 @@ + /* FUSE USB_CALIB registers */ + #define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0) + #define HS_CURR_LEVEL_PAD_MASK 0x3f +-#define HS_TERM_RANGE_ADJ_SHIFT 7 +-#define HS_TERM_RANGE_ADJ_MASK 0xf ++#define HS_TERM_RANGE_ADJ_PADX_SHIFT(x) ((x) ? (5 + (x - 1) * 4) : 7) ++#define HS_TERM_RANGE_ADJ_PAD_MASK 0xf + #define HS_SQUELCH_SHIFT 29 + #define HS_SQUELCH_MASK 0x7 + +@@ -253,7 +253,7 @@ + struct tegra_xusb_fuse_calibration { + u32 *hs_curr_level; + u32 hs_squelch; +- u32 hs_term_range_adj; ++ u32 *hs_term_range_adj; + u32 rpd_ctrl; + }; + +@@ -930,7 +930,7 @@ static int tegra186_utmi_phy_power_on(st + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + value &= ~TERM_RANGE_ADJ(~0); +- value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj); ++ value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj[index]); + value &= ~RPD_CTRL(~0); + value |= RPD_CTRL(priv->calib.rpd_ctrl); + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); +@@ -1464,17 +1464,23 @@ static const char * const tegra186_usb3_ + static int + tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl) + { ++ const struct tegra_xusb_padctl_soc *soc = padctl->base.soc; + struct device *dev = padctl->base.dev; + unsigned int i, count; + u32 value, *level; ++ u32 *hs_term_range_adj; + int err; + +- count = padctl->base.soc->ports.usb2.count; ++ count = soc->ports.usb2.count; + + level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL); + if (!level) + return -ENOMEM; + ++ hs_term_range_adj = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL); ++ if (!hs_term_range_adj) ++ return -ENOMEM; ++ + err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); + if (err) + return dev_err_probe(dev, err, +@@ -1490,8 +1496,8 @@ tegra186_xusb_read_fuse_calibration(stru + + padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) & + HS_SQUELCH_MASK; +- padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) & +- HS_TERM_RANGE_ADJ_MASK; ++ hs_term_range_adj[0] = (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(0)) & ++ HS_TERM_RANGE_ADJ_PAD_MASK; + + err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); + if (err) { +@@ -1503,6 +1509,17 @@ tegra186_xusb_read_fuse_calibration(stru + + padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK; + ++ for (i = 1; i < count; i++) { ++ if (soc->has_per_pad_term) ++ hs_term_range_adj[i] = ++ (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(i)) & ++ HS_TERM_RANGE_ADJ_PAD_MASK; ++ else ++ hs_term_range_adj[i] = hs_term_range_adj[0]; ++ } ++ ++ padctl->calib.hs_term_range_adj = hs_term_range_adj; ++ + return 0; + } + +@@ -1708,6 +1725,7 @@ const struct tegra_xusb_padctl_soc tegra + .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names), + .supports_gen2 = true, + .poll_trk_completed = true, ++ .has_per_pad_term = true, + }; + EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc); + +@@ -1732,6 +1750,7 @@ const struct tegra_xusb_padctl_soc tegra + .trk_hw_mode = false, + .trk_update_on_idle = true, + .supports_lp_cfg_en = true, ++ .has_per_pad_term = true, + }; + EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc); + #endif +--- a/drivers/phy/tegra/xusb.h ++++ b/drivers/phy/tegra/xusb.h +@@ -435,6 +435,7 @@ struct tegra_xusb_padctl_soc { + bool trk_hw_mode; + bool trk_update_on_idle; + bool supports_lp_cfg_en; ++ bool has_per_pad_term; + }; + + struct tegra_xusb_padctl { diff --git a/queue-7.0/rdma-siw-reject-mpa-fpdu-length-underflow-before-signed-receive-math.patch b/queue-7.0/rdma-siw-reject-mpa-fpdu-length-underflow-before-signed-receive-math.patch new file mode 100644 index 0000000000..0d5c819982 --- /dev/null +++ b/queue-7.0/rdma-siw-reject-mpa-fpdu-length-underflow-before-signed-receive-math.patch @@ -0,0 +1,101 @@ +From 0ce1bc9e46ecabe84772bb561e373c0d9876d6f2 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 13 May 2026 13:53:24 -0400 +Subject: RDMA/siw: Reject MPA FPDU length underflow before signed receive math + +From: Michael Bommarito + +commit 0ce1bc9e46ecabe84772bb561e373c0d9876d6f2 upstream. + +A malicious connected siw peer can send an iWARP FPDU whose MPA length +field (c_hdr->mpa_len, 16 bit big-endian, peer-controlled) is smaller +than the fixed DDP/RDMAP header for the announced opcode. Soft-iWARP +parses the full header in siw_get_hdr() based on iwarp_pktinfo[opcode] +.hdr_len, but never compares mpa_len against that header length. + +siw_tcp_rx_data() then derives + + srx->fpdu_part_rem = be16_to_cpu(mpa_len) - fpdu_part_rcvd + + MPA_HDR_SIZE; + +where fpdu_part_rcvd equals iwarp_pktinfo[opcode].hdr_len at this +point. For a tagged WRITE (hdr_len 16, MPA_HDR_SIZE 2) the smallest +on-wire mpa_len of 0 yields fpdu_part_rem = -14, and any mpa_len below +hdr_len - MPA_HDR_SIZE underflows to a negative int. + +The signed value then flows into siw_proc_write()/siw_proc_rresp() as + + bytes = min(srx->fpdu_part_rem, srx->skb_new); + +is handed to siw_check_mem() as an int len (whose interval check +addr + len > mem->va + mem->len is satisfied for a valid base when +len is negative), and reaches siw_rx_data() -> siw_rx_kva() / +siw_rx_umem() -> skb_copy_bits() as a signed copy length. The header +copy branch in skb_copy_bits() promotes that to size_t, producing a +multi-gigabyte read. + +KASAN under a KUnit harness that drives the real kernel TCP receive +path -- a loopback AF_INET socketpair, the malformed FPDU written via +kernel_sendmsg, sk_data_ready firing in softirq, tcp_read_sock +dispatching to siw_tcp_rx_data -- reports: + + BUG: KASAN: use-after-free in skb_copy_bits+0x284/0x480 + Read of size 4294967295 at addr ffff888... + Call Trace: + skb_copy_bits + siw_rx_kva + siw_rx_data + siw_check_mem + siw_proc_write + siw_tcp_rx_data + __tcp_read_sock + siw_qp_llp_data_ready + tcp_data_ready + tcp_data_queue + +Add the missing invariant at the earliest point where the peer header +is fully assembled. iwarp_pktinfo[*].hdr_len - MPA_HDR_SIZE is exactly +the value the siw transmitter uses as the minimum mpa_len for each +opcode (drivers/infiniband/sw/siw/siw_qp.c:33), so this matches the +protocol contract. Out-of-range FPDUs terminate the connection with +TERM_ERROR_LAYER_LLP / LLP_ETYPE_MPA / LLP_ECODE_FPDU_START -- which +is RFC 5044 Section 8 error code 3 ("Marker and ULPDU Length fields +do not agree on the start of an FPDU"), the correct framing-error +class for this inconsistency. + +Fixes: 8b6a361b8c48 ("rdma/siw: receive path") +Link: https://patch.msgid.link/r/20260513175325.2042630-2-michael.bommarito@gmail.com +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Acked-by: Bernard Metzler +Signed-off-by: Jason Gunthorpe +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/sw/siw/siw_qp_rx.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/infiniband/sw/siw/siw_qp_rx.c ++++ b/drivers/infiniband/sw/siw/siw_qp_rx.c +@@ -1082,6 +1082,21 @@ static int siw_get_hdr(struct siw_rx_str + } + + /* ++ * Peer-controlled mpa_len must not underflow srx->fpdu_part_rem ++ * in siw_tcp_rx_data(); a negative value flows as a signed copy ++ * length into siw_check_mem() and skb_copy_bits(). ++ */ ++ if (unlikely(be16_to_cpu(c_hdr->mpa_len) + MPA_HDR_SIZE < ++ iwarp_pktinfo[opcode].hdr_len)) { ++ pr_warn_ratelimited("siw: short mpa_len %u for opcode %u (hdr_len %u)\n", ++ be16_to_cpu(c_hdr->mpa_len), opcode, ++ iwarp_pktinfo[opcode].hdr_len); ++ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_LLP, ++ LLP_ETYPE_MPA, LLP_ECODE_FPDU_START, 0); ++ return -EINVAL; ++ } ++ ++ /* + * DDP/RDMAP header receive completed. Check if the current + * DDP segment starts a new RDMAP message or continues a previously + * started RDMAP message. diff --git a/queue-7.0/riscv-kvm-return-sbi_err_failure-for-pmu_event_info-when-oom.patch b/queue-7.0/riscv-kvm-return-sbi_err_failure-for-pmu_event_info-when-oom.patch new file mode 100644 index 0000000000..f870f8734e --- /dev/null +++ b/queue-7.0/riscv-kvm-return-sbi_err_failure-for-pmu_event_info-when-oom.patch @@ -0,0 +1,42 @@ +From 0e9d0e7a7c78db7aa1c13796c65cfe0aefa54a5b Mon Sep 17 00:00:00 2001 +From: Osama Abdelkader +Date: Thu, 14 May 2026 19:36:41 +0200 +Subject: riscv: kvm: return SBI_ERR_FAILURE for pmu_event_info() when OOM + +From: Osama Abdelkader + +commit 0e9d0e7a7c78db7aa1c13796c65cfe0aefa54a5b upstream. + +kvm_riscv_vcpu_pmu_event_info() returned -ENOMEM from the +SBI extension handler, which caused kvm_riscv_vcpu_sbi_ecall() +to abort KVM_RUN and surface the error to userspace instead of +completing the ECALL with a negative SBI error in a0. +Use SBI_ERR_FAILURE and the normal retdata path, matching other PMU +handlers and kvm_sbi_ext_pmu_handler comment. + +Fixes: e309fd113b9f ("RISC-V: KVM: Implement get event info function") +Cc: stable@vger.kernel.org +Signed-off-by: Osama Abdelkader +Reviewed-by: Anup Patel +Link: https://lore.kernel.org/r/20260514173642.41448-2-osama.abdelkader@gmail.com +Signed-off-by: Anup Patel +Signed-off-by: Greg Kroah-Hartman +--- + arch/riscv/kvm/vcpu_pmu.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/arch/riscv/kvm/vcpu_pmu.c ++++ b/arch/riscv/kvm/vcpu_pmu.c +@@ -482,8 +482,10 @@ int kvm_riscv_vcpu_pmu_event_info(struct + } + + einfo = kzalloc(shmem_size, GFP_KERNEL); +- if (!einfo) +- return -ENOMEM; ++ if (!einfo) { ++ ret = SBI_ERR_FAILURE; ++ goto out; ++ } + + ret = kvm_vcpu_read_guest(vcpu, shmem, einfo, shmem_size); + if (ret) { diff --git a/queue-7.0/riscv-kvm-return-sbi_err_failure-for-pmu_snapshot_set_shmem-when-oom.patch b/queue-7.0/riscv-kvm-return-sbi_err_failure-for-pmu_snapshot_set_shmem-when-oom.patch new file mode 100644 index 0000000000..530d8b1158 --- /dev/null +++ b/queue-7.0/riscv-kvm-return-sbi_err_failure-for-pmu_snapshot_set_shmem-when-oom.patch @@ -0,0 +1,42 @@ +From 0835ee26938e15eccd70f7d33da386b6490f9449 Mon Sep 17 00:00:00 2001 +From: Osama Abdelkader +Date: Thu, 14 May 2026 19:36:40 +0200 +Subject: riscv: kvm: return SBI_ERR_FAILURE for pmu_snapshot_set_shmem() when OOM + +From: Osama Abdelkader + +commit 0835ee26938e15eccd70f7d33da386b6490f9449 upstream. + +kvm_riscv_vcpu_pmu_snapshot_set_shmem() returned -ENOMEM from the +SBI extension handler, which caused kvm_riscv_vcpu_sbi_ecall() to +abort KVM_RUN and surface the error to userspace instead of +ompleting the ECALL with a negative SBI error in a0. +Use SBI_ERR_FAILURE and the normal retdata path, matching other PMU +handlers and kvm_sbi_ext_pmu_handler comment. + +Fixes: c2f41ddbcdd7 ("RISC-V: KVM: Implement SBI PMU Snapshot feature") +Cc: stable@vger.kernel.org +Signed-off-by: Osama Abdelkader +Reviewed-by: Anup Patel +Link: https://lore.kernel.org/r/20260514173642.41448-1-osama.abdelkader@gmail.com +Signed-off-by: Anup Patel +Signed-off-by: Greg Kroah-Hartman +--- + arch/riscv/kvm/vcpu_pmu.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/arch/riscv/kvm/vcpu_pmu.c ++++ b/arch/riscv/kvm/vcpu_pmu.c +@@ -435,8 +435,10 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shme + } + + kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC); +- if (!kvpmu->sdata) +- return -ENOMEM; ++ if (!kvpmu->sdata) { ++ sbiret = SBI_ERR_FAILURE; ++ goto out; ++ } + + /* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */ + if (kvm_vcpu_write_guest(vcpu, saddr, kvpmu->sdata, snapshot_area_size)) { diff --git a/queue-7.0/s390-cio-restore-gfp_dma-for-chsc-allocation.patch b/queue-7.0/s390-cio-restore-gfp_dma-for-chsc-allocation.patch new file mode 100644 index 0000000000..fbd9403662 --- /dev/null +++ b/queue-7.0/s390-cio-restore-gfp_dma-for-chsc-allocation.patch @@ -0,0 +1,141 @@ +From ea34567db0a6b3a7ce78ba421592344315c8f90e Mon Sep 17 00:00:00 2001 +From: Peter Oberparleiter +Date: Thu, 7 May 2026 16:27:08 +0200 +Subject: s390/cio: Restore GFP_DMA for CHSC allocation + +From: Peter Oberparleiter + +commit ea34567db0a6b3a7ce78ba421592344315c8f90e upstream. + +Re-add GFP_DMA when allocating memory for CHSC control blocks. +On some supported machines, CHSC cannot access memory outside +the DMA zone, causing CHSC command failures. + +Cc: stable@vger.kernel.org +Fixes: a3a64a4def8d ("s390/cio: remove unneeded DMA zone allocation") +Signed-off-by: Peter Oberparleiter +Reviewed-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/cio/chsc.c | 4 ++-- + drivers/s390/cio/chsc_sch.c | 20 ++++++++++---------- + drivers/s390/cio/scm.c | 2 +- + 3 files changed, 13 insertions(+), 13 deletions(-) + +--- a/drivers/s390/cio/chsc.c ++++ b/drivers/s390/cio/chsc.c +@@ -1142,8 +1142,8 @@ int __init chsc_init(void) + { + int ret; + +- sei_page = (void *)get_zeroed_page(GFP_KERNEL); +- chsc_page = (void *)get_zeroed_page(GFP_KERNEL); ++ sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); ++ chsc_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sei_page || !chsc_page) { + ret = -ENOMEM; + goto out_err; +--- a/drivers/s390/cio/chsc_sch.c ++++ b/drivers/s390/cio/chsc_sch.c +@@ -292,7 +292,7 @@ static int chsc_ioctl_start(void __user + if (!css_general_characteristics.dynio) + /* It makes no sense to try. */ + return -EOPNOTSUPP; +- chsc_area = (void *)get_zeroed_page(GFP_KERNEL); ++ chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); + if (!chsc_area) + return -ENOMEM; + request = kzalloc_obj(*request); +@@ -340,7 +340,7 @@ static int chsc_ioctl_on_close_set(void + ret = -ENOMEM; + goto out_unlock; + } +- on_close_chsc_area = (void *)get_zeroed_page(GFP_KERNEL); ++ on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); + if (!on_close_chsc_area) { + ret = -ENOMEM; + goto out_free_request; +@@ -392,7 +392,7 @@ static int chsc_ioctl_start_sync(void __ + struct chsc_sync_area *chsc_area; + int ret, ccode; + +- chsc_area = (void *)get_zeroed_page(GFP_KERNEL); ++ chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!chsc_area) + return -ENOMEM; + if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { +@@ -438,7 +438,7 @@ static int chsc_ioctl_info_channel_path( + u8 data[PAGE_SIZE - 20]; + } __attribute__ ((packed)) *scpcd_area; + +- scpcd_area = (void *)get_zeroed_page(GFP_KERNEL); ++ scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!scpcd_area) + return -ENOMEM; + cd = kzalloc_obj(*cd); +@@ -500,7 +500,7 @@ static int chsc_ioctl_info_cu(void __use + u8 data[PAGE_SIZE - 20]; + } __attribute__ ((packed)) *scucd_area; + +- scucd_area = (void *)get_zeroed_page(GFP_KERNEL); ++ scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!scucd_area) + return -ENOMEM; + cd = kzalloc_obj(*cd); +@@ -563,7 +563,7 @@ static int chsc_ioctl_info_sch_cu(void _ + u8 data[PAGE_SIZE - 20]; + } __attribute__ ((packed)) *sscud_area; + +- sscud_area = (void *)get_zeroed_page(GFP_KERNEL); ++ sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sscud_area) + return -ENOMEM; + cud = kzalloc_obj(*cud); +@@ -625,7 +625,7 @@ static int chsc_ioctl_conf_info(void __u + u8 data[PAGE_SIZE - 20]; + } __attribute__ ((packed)) *sci_area; + +- sci_area = (void *)get_zeroed_page(GFP_KERNEL); ++ sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sci_area) + return -ENOMEM; + ci = kzalloc_obj(*ci); +@@ -696,7 +696,7 @@ static int chsc_ioctl_conf_comp_list(voi + u32 res; + } __attribute__ ((packed)) *cssids_parm; + +- sccl_area = (void *)get_zeroed_page(GFP_KERNEL); ++ sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccl_area) + return -ENOMEM; + ccl = kzalloc_obj(*ccl); +@@ -756,7 +756,7 @@ static int chsc_ioctl_chpd(void __user * + int ret; + + chpd = kzalloc_obj(*chpd); +- scpd_area = (void *)get_zeroed_page(GFP_KERNEL); ++ scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!scpd_area || !chpd) { + ret = -ENOMEM; + goto out_free; +@@ -796,7 +796,7 @@ static int chsc_ioctl_dcal(void __user * + u8 data[PAGE_SIZE - 36]; + } __attribute__ ((packed)) *sdcal_area; + +- sdcal_area = (void *)get_zeroed_page(GFP_KERNEL); ++ sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sdcal_area) + return -ENOMEM; + dcal = kzalloc_obj(*dcal); +--- a/drivers/s390/cio/scm.c ++++ b/drivers/s390/cio/scm.c +@@ -229,7 +229,7 @@ int scm_update_information(void) + size_t num; + int ret; + +- scm_info = (void *)__get_free_page(GFP_KERNEL); ++ scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + if (!scm_info) + return -ENOMEM; + diff --git a/queue-7.0/s390-pai-disable-duplicate-read-of-kernel-pai-counter-value.patch b/queue-7.0/s390-pai-disable-duplicate-read-of-kernel-pai-counter-value.patch new file mode 100644 index 0000000000..ef6368ef28 --- /dev/null +++ b/queue-7.0/s390-pai-disable-duplicate-read-of-kernel-pai-counter-value.patch @@ -0,0 +1,75 @@ +From 3fe7ecab1a0856aafe1026a35af1621a5c18d53f Mon Sep 17 00:00:00 2001 +From: Thomas Richter +Date: Mon, 27 Apr 2026 07:17:19 +0200 +Subject: s390/pai: Disable duplicate read of kernel PAI counter value + +From: Thomas Richter + +commit 3fe7ecab1a0856aafe1026a35af1621a5c18d53f upstream. + +The PAI crypto counter design allows for user space and kernel space +PAI counter increment recording. This is achieved by splitting the +recording page in half. The upper part of the 4KB page records user +space increments of PAI crypto counter and the lower half records +kernel space increments. The page itself looks like: + + lowcore ptr ---> ++++++++++++++++++++++++ + |user space area | + +----------------------+ + |kernel space area | + ++++++++++++++++++++++++ + +User space and kernel space entries are handled via a kernel_offset +value when wrting. For PAI crypto counters this offset is 2048 or +half of a page size. + +For PAI NNPA counter design this distinction was not needed. There is +no user and kernel space part for the page pointed to by lowcore. +The set up is: + + lowcore ptr ---> ++++++++++++++++++++++++ + |user + kernel space | + |area | + | | + ++++++++++++++++++++++++ + +There is always only one counter value recorded and saved. + +Depending on number of CPUs and machine load, the number of PAI NNPA +counter increment differs between counting (perf stat) and recording +(perf record). The number reported by sampling was double the number +shown by counting. + +This was caused by a double read of the PAI NNPA values in function +pai_copy(). The first part of that function reads the kernel space part. +The offset into the kernel page part must be larger than zero. +The second part of that function reads the user space part, which +begins of offset zero. This works fine for PAI crypto counters. + +It fails for PAI NNPA counters because the PMU device driver does +not support that feature and has a kernel_offset value of 0x0. +Executing both user and kernel space read out might end up reading +user space value twice. +For the PAI NNPA PMU prohibit the kernel space part read out. + +Cc: stable@vger.kernel.org +Fixes: f12473541356 ("s390/pai_crypto: Rename paicrypt_copy() to pai_copy()") +Signed-off-by: Thomas Richter +Reviewed-by: Sumanth Korikkar +Signed-off-by: Alexander Gordeev +Signed-off-by: Greg Kroah-Hartman +--- + arch/s390/kernel/perf_pai.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/s390/kernel/perf_pai.c ++++ b/arch/s390/kernel/perf_pai.c +@@ -651,7 +651,7 @@ static void pai_have_sample(struct perf_ + rawsize = pai_copy(cpump->save, cpump->area, pp, + (unsigned long *)PAI_SAVE_AREA(event), + event->attr.exclude_user, +- event->attr.exclude_kernel); ++ !pp->kernel_offset ? true : event->attr.exclude_kernel); + if (rawsize) /* No incremented counters */ + pai_push_sample(rawsize, cpump, event); + } diff --git a/queue-7.0/s390-pai-fix-missing-pai-counter-increments-under-heavy-load.patch b/queue-7.0/s390-pai-fix-missing-pai-counter-increments-under-heavy-load.patch new file mode 100644 index 0000000000..d3ec85c4b9 --- /dev/null +++ b/queue-7.0/s390-pai-fix-missing-pai-counter-increments-under-heavy-load.patch @@ -0,0 +1,138 @@ +From 99269799bf2448aebccee164df56c22a7b85b02c Mon Sep 17 00:00:00 2001 +From: Thomas Richter +Date: Tue, 5 May 2026 12:34:33 +0200 +Subject: s390/pai: Fix missing PAI counter increments under heavy load +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Richter + +commit 99269799bf2448aebccee164df56c22a7b85b02c upstream. + +Machines with a larger number of CPUs and under heavy load sometimes +loose PAI counter increments during recording using events +-e CRYPTO_ÂLL or -e NNPA_ALL. Counting is not affected. +This happens when several PAI crypto counters are incremented during +the same cryptographic operation. + +During schedule out the functions + +paiXXX_sched_task() (with XXX either crypt or ext) ++--> pai_have_samples() + +--> pai_have_sample() + +--> pai_copy() + +--> pai_push_sample() + +are called to read out PAI counter values. +In pai_copy() the current values of PAI counters are read from the +PMU memory mapped page and compared to the values read during last +schedule out operation, which have been saved in a backup page +named PAI_SAVE_AREA(event). For each PAI counter a delta is calculated +and when the delta is positive, that PAI counter was incremented by +hardware. This positve delta is reported as raw data record attached +to a sample. +After all deltas have been calculated, the new PAI counter values +are saved in the backup page PAI_SAVE_AREA(event). However this is +done in pai_push_sample(), leaving a small window for missing hardware +triggered updates. Here is one scenario: + + PAI counter idx: 0 1 2 3 4 5 6 7 .... N + +---+---+---+---+---+---+---+---+ +---+ + PAI counter page:| | | X | | | | | |....| Y | + +---+---+---+---+---+---+---+---+ +---+ + +In pai_copy() each PAI counter value is read and compared +to its old value. This is done in a loop. When PAI counter indexed +N is read, the hardware might increment PAI counter indexed 2 again, +updating its value from X to X+1. +Later pai_push_sample() simply mem-copies the complete PAI counter +page to a backup page and the increment of X+1 is lost, because the +backup page now contains the new value. + +Read each PAI counter and save this value in the backup page when +there is a positive delta. This omits any time window between read +and store. This also reduced the work load as only modified PAI +counters are saved. + +Cc: stable@vger.kernel.org +Fixes: fe861b0c8d06 ("s390/pai: save PAI counter value page in event structure") +Signed-off-by: Thomas Richter +Reviewed-by: Sumanth Korikkar +Signed-off-by: Alexander Gordeev +Signed-off-by: Greg Kroah-Hartman +--- + arch/s390/kernel/perf_pai.c | 29 ++++++++++++++++++++--------- + 1 file changed, 20 insertions(+), 9 deletions(-) + +--- a/arch/s390/kernel/perf_pai.c ++++ b/arch/s390/kernel/perf_pai.c +@@ -186,6 +186,13 @@ static u64 pai_getctr(unsigned long *pag + return page[nr]; + } + ++static void pai_setctr(unsigned long *page, int nr, unsigned long offset, u64 v) ++{ ++ if (offset) ++ nr += offset / sizeof(*page); ++ page[nr] = v; ++} ++ + /* Read the counter values. Return value from location in CMP. For base + * event xxx_ALL sum up all events. Returns counter value. + */ +@@ -551,6 +558,8 @@ static void paicrypt_del(struct perf_eve + /* Create raw data and save it in buffer. Calculate the delta for each + * counter between this invocation and the last invocation. + * Returns number of bytes copied. ++ * After reading from PAI counter page, save the read value to the old ++ * page to calculate PAI counter deltas. + * Saves only entries with positive counter difference of the form + * 2 bytes: Number of counter + * 8 bytes: Value of counter +@@ -562,16 +571,22 @@ static size_t pai_copy(struct pai_userda + int i, outidx = 0; + + for (i = 1; i <= pp->num_avail; i++) { +- u64 val = 0, val_old = 0; ++ u64 val = 0, val_old = 0, val_k = 0, val_old_k = 0; + + if (!exclude_kernel) { +- val += pai_getctr(page, i, pp->kernel_offset); +- val_old += pai_getctr(page_old, i, pp->kernel_offset); ++ val_k = pai_getctr(page, i, pp->kernel_offset); ++ val_old_k = pai_getctr(page_old, i, pp->kernel_offset); ++ if (val_k != val_old_k) ++ pai_setctr(page_old, i, pp->kernel_offset, val_k); + } + if (!exclude_user) { +- val += pai_getctr(page, i, 0); +- val_old += pai_getctr(page_old, i, 0); ++ val = pai_getctr(page, i, 0); ++ val_old = pai_getctr(page_old, i, 0); ++ if (val != val_old) ++ pai_setctr(page_old, i, 0, val); + } ++ val += val_k; ++ val_old += val_old_k; + if (val >= val_old) + val -= val_old; + else +@@ -602,8 +617,6 @@ static size_t pai_copy(struct pai_userda + static int pai_push_sample(size_t rawsize, struct pai_map *cpump, + struct perf_event *event) + { +- int idx = PAI_PMU_IDX(event); +- struct pai_pmu *pp = &pai_pmu[idx]; + struct perf_sample_data data; + struct perf_raw_record raw; + struct pt_regs regs; +@@ -634,8 +647,6 @@ static int pai_push_sample(size_t rawsiz + + overflow = perf_event_overflow(event, &data, ®s); + perf_event_update_userpage(event); +- /* Save crypto counter lowcore page after reading event data. */ +- memcpy((void *)PAI_SAVE_AREA(event), cpump->area, pp->area_size); + return overflow; + } + diff --git a/queue-7.0/scsi-isci-fix-use-after-free-in-device-removal-path.patch b/queue-7.0/scsi-isci-fix-use-after-free-in-device-removal-path.patch new file mode 100644 index 0000000000..669a9ecfdb --- /dev/null +++ b/queue-7.0/scsi-isci-fix-use-after-free-in-device-removal-path.patch @@ -0,0 +1,60 @@ +From b52a8d52c3125ec9a93106ed816582368de34426 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 19 Apr 2026 17:04:20 -0400 +Subject: scsi: isci: Fix use-after-free in device removal path + +From: Michael Bommarito + +commit b52a8d52c3125ec9a93106ed816582368de34426 upstream. + +The ISCI completion tasklet is initialized in isci_host_alloc() +(drivers/scsi/isci/init.c:496) and scheduled from both MSI-X and legacy +interrupt handlers (drivers/scsi/isci/host.c:223,613). + +isci_host_deinit() stops the controller and waits for stop completion, +but it never kills completion_tasklet before teardown continues. A +top-of-function tasklet_kill() is not sufficient here: interrupts are +only disabled when isci_host_stop_complete() runs, so until +wait_for_stop() returns the IRQ handlers can still requeue the +tasklet. The tasklet callback also re-enables interrupts after draining +completions, so killing the tasklet before the source is quiesced leaves +the same race open. + +Once wait_for_stop() returns, no further IRQ-driven scheduling can +occur. Kill completion_tasklet there so teardown cannot race a queued +tasklet running on a dead ihost. On remove or unload, the stale callback +can otherwise dereference ihost and touch ihost->smu_registers after the +host lifetime ends. + +A UML + KASAN analogue reproduced the failure class both with no +tasklet_kill() and with tasklet_kill() placed before source quiesce, and +stayed clean once the kill happened after quiescing the scheduling +source. + +This mirrors commit f6ab594672d4 ("scsi: aic94xx: fix use-after-free in +device removal path"), but ISCI needs the kill after wait_for_stop(). + +Fixes: 6f231dda6808 ("isci: Intel(R) C600 Series Chipset Storage Control Unit Driver") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260419210420.2134639-1-michael.bommarito@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/isci/host.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/scsi/isci/host.c ++++ b/drivers/scsi/isci/host.c +@@ -1252,6 +1252,9 @@ void isci_host_deinit(struct isci_host * + + wait_for_stop(ihost); + ++ /* No further IRQ-driven scheduling can happen past wait_for_stop(). */ ++ tasklet_kill(&ihost->completion_tasklet); ++ + /* phy stop is after controller stop to allow port and device to + * go idle before shutting down the phys, but the expectation is + * that i/o has been shut off well before we reach this diff --git a/queue-7.0/series b/queue-7.0/series index 57af450de6..e482f99285 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -93,3 +93,85 @@ wifi-cfg80211-advance-loop-vars-in-cfg80211_merge_profile.patch af_unix-fix-uaf-read-of-tail-len-in-unix_stream_data_wait.patch wifi-mac80211-consume-only-present-negotiated-ttlm-maps.patch octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch +cifs-fix-busy-dentry-used-after-unmounting.patch +tracing-do-not-call-map-ops-elt_free-if-elt_alloc-fails.patch +asoc-codecs-pcm512x-fix-null-ptr-dereference-in-pcm512x_overclock_xxx_put.patch +arm64-probes-handle-probes-on-hinted-conditional-branch-instructions.patch +kvm-arm64-vgic-its-reject-restored-dte-with-out-of-range-num_eventid_bits.patch +kvm-arm64-vgic-free-private_irqs-when-init-fails-after-allocation.patch +kvm-svm-disable-avic-ipi-virtualization-on-hygon-family-18h-erratum-1235.patch +riscv-kvm-return-sbi_err_failure-for-pmu_snapshot_set_shmem-when-oom.patch +riscv-kvm-return-sbi_err_failure-for-pmu_event_info-when-oom.patch +virt-sev-guest-explicitly-leak-pages-in-unknown-state.patch +i2c-tegra-fix-pm_runtime-leak-on-mutex_lock-failure.patch +hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch +drm-bridge-chipone-icn6211-use-devm_drm_bridge_add-in-i2c-probe.patch +spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch +phy-exynos5-usbdrd-fix-usb-2.0-hs-phy-tuning-values-for-exynos7870.patch +phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch +phy-qcom-qmp-ufs-fix-kaanapali-phy-pll-lock-failure-after-sm8650-g4-fix.patch +phy-qcom-edp-unify-generic-dp-edp-swing-and-pre-emphasis-tables.patch +phy-qcom-edp-add-edp-dp-mode-switch-support.patch +phy-qcom-edp-fix-aux_cfg8-programming-for-dp-mode.patch +scsi-isci-fix-use-after-free-in-device-removal-path.patch +spi-ep93xx-fix-error-pointer-deref-after-dma-setup-failure.patch +spi-sprd-fix-error-pointer-deref-after-dma-setup-failure.patch +spi-ti-qspi-fix-use-after-free-after-dma-setup-failure.patch +mm-slub-hold-cpus_read_lock-around-flush_rcu_sheaves_on_cache.patch +rdma-siw-reject-mpa-fpdu-length-underflow-before-signed-receive-math.patch +s390-cio-restore-gfp_dma-for-chsc-allocation.patch +s390-pai-disable-duplicate-read-of-kernel-pai-counter-value.patch +s390-pai-fix-missing-pai-counter-increments-under-heavy-load.patch +fwctl-pds-validate-rpc-input-size-before-parsing.patch +loongarch-kprobes-use-larch_insn_text_copy-to-patch-instructions.patch +loongarch-remove-unused-code-to-avoid-build-warning.patch +cpufreq-intel_pstate-use-correct-scaling-factor-on-raptor-lake-e.patch +device-property-set-fwnode-secondary-to-null-in-fwnode_init.patch +drm-i915-display-copy-color-pipeline-from-plane-in-the-primary-joiner-pipe.patch +drm-i915-psr-apply-intel-dpcd-workaround-when-sdp-on-prior-line-used.patch +drm-msm-fix-shrinker-deadlock.patch +drm-v3d-fix-use-after-free-of-cpu-job-query-arrays-on-error-path.patch +drm-v3d-release-indirect-csd-gem-reference-on-cpu-job-free.patch +drm-virtio-use-uninterruptible-resv-lock-for-plane-updates.patch +drm-xe-multi_queue-fix-secondary-queue-error-case.patch +drm-amdgpu-vpe-force-collaborate-sync-after-trap.patch +drm-bridge-it66121-acquire-reset-gpio-in-probe.patch +drm-bridge-megachips-remove-bridge-when-irq-request-fails.patch +drm-amd-display-fix-integer-overflow-in-bios_get_image.patch +drm-amd-display-validate-gpio-pin-lut-table-size-before-iterating.patch +drm-amd-display-validate-payload-length-and-link_index-in-dc_process_dmub_aux_transfer_async.patch +batman-adv-v-stop-ogmv2-on-disabled-interface.patch +batman-adv-tvlv-abort-ogm-send-on-tvlv-append-failure.patch +batman-adv-tvlv-reject-oversized-tvlv-packets.patch +batman-adv-iv-recover-ogm-scheduling-after-forward-packet-error.patch +batman-adv-mcast-fix-use-after-free-in-orig_node-rcu-release.patch +batman-adv-clear-current-gateway-during-teardown.patch +batman-adv-dat-handle-forward-allocation-error.patch +batman-adv-fix-fragment-reassembly-length-accounting.patch +batman-adv-fix-tp_meter-counter-underflow-during-shutdown.patch +batman-adv-frag-disallow-unicast-fragment-in-fragment.patch +batman-adv-bla-fix-report_work-leak-on-backbone_gw-purge.patch +batman-adv-bla-avoid-double-decrement-of-bla.num_requests.patch +batman-adv-bla-avoid-null-ptr-deref-for-claim-via-dropped-interface.patch +batman-adv-tp_meter-avoid-use-of-uninit-sender-vars.patch +batman-adv-tp_meter-directly-shut-down-timer-on-cleanup.patch +batman-adv-tp_meter-fix-tp_vars-reference-leak-in-receiver-shutdown.patch +batman-adv-tp_meter-fix-race-condition-in-send-error-reporting.patch +batman-adv-tp_meter-avoid-role-confusion-in-tp_list.patch +batman-adv-tt-fix-toctou-race-for-reported-vlans.patch +batman-adv-tt-reject-oversized-local-tvlv-buffers.patch +batman-adv-tt-avoid-empty-vlan-responses.patch +batman-adv-tt-fix-negative-last_changeset_len.patch +batman-adv-tt-fix-negative-tt_buff_len.patch +batman-adv-tt-prevent-tvlv-entry-number-overflow.patch +hwmon-pmbus-adm1266-seed-timestamp-from-the-real-time-clock.patch +hwmon-pmbus-adm1266-reject-implausible-blackbox-record_count.patch +hwmon-pmbus-adm1266-include-pec-byte-in-pmbus_block_xfer-read-buffer.patch +hwmon-pmbus-adm1266-bounce-blackbox-records-through-a-protocol-sized-buffer.patch +hwmon-pmbus-adm1266-cap-pdio-scan-in-get_multiple-at-adm1266_pdio_nr.patch +hwmon-pmbus-adm1266-don-t-clobber-gpio-bits-before-pdio-read-in-get_multiple.patch +hwmon-pmbus-adm1266-register-the-gpio_chip-after-pmbus_do_probe.patch +hwmon-pmbus-adm1266-register-the-nvmem-device-after-pmbus_do_probe.patch +hwmon-pmbus-adm1266-reject-short-block-read-responses-in-the-gpio-accessors.patch +hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch +hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch diff --git a/queue-7.0/spi-ep93xx-fix-error-pointer-deref-after-dma-setup-failure.patch b/queue-7.0/spi-ep93xx-fix-error-pointer-deref-after-dma-setup-failure.patch new file mode 100644 index 0000000000..7248474e1a --- /dev/null +++ b/queue-7.0/spi-ep93xx-fix-error-pointer-deref-after-dma-setup-failure.patch @@ -0,0 +1,48 @@ +From 5e121a81667a83e9a01d62b429e340f5a4a84abc Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 12 May 2026 09:48:49 +0200 +Subject: spi: ep93xx: fix error pointer deref after DMA setup failure + +From: Johan Hovold + +commit 5e121a81667a83e9a01d62b429e340f5a4a84abc upstream. + +The driver falls back to PIO mode if DMA setup fails during probe. + +Make sure to the clear the DMA channel pointers on setup failure to +avoid dereferencing an error pointer on later probe errors or driver +unbind. + +This issue was flagged by Sashiko when reviewing a devres allocation +conversion patch. + +Fixes: e79e7c2df627 ("spi: ep93xx: add DT support for Cirrus EP93xx") +Link: https://sashiko.dev/#/patchset/20260429091333.165363-1-johan%40kernel.org?part=10 +Cc: stable@vger.kernel.org # 6.12 +Cc: Nikita Shubin +Signed-off-by: Johan Hovold +Acked-by: Nikita Shubin +Link: https://patch.msgid.link/20260512074849.915143-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ep93xx.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/spi/spi-ep93xx.c ++++ b/drivers/spi/spi-ep93xx.c +@@ -582,12 +582,14 @@ static int ep93xx_spi_setup_dma(struct d + espi->dma_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(espi->dma_rx)) { + ret = dev_err_probe(dev, PTR_ERR(espi->dma_rx), "rx DMA setup failed"); ++ espi->dma_rx = NULL; + goto fail_free_page; + } + + espi->dma_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(espi->dma_tx)) { + ret = dev_err_probe(dev, PTR_ERR(espi->dma_tx), "tx DMA setup failed"); ++ espi->dma_tx = NULL; + goto fail_release_rx; + } + diff --git a/queue-7.0/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch b/queue-7.0/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch new file mode 100644 index 0000000000..0cd9a71dde --- /dev/null +++ b/queue-7.0/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch @@ -0,0 +1,43 @@ +From a7e8f3efd50a165ba0189f6dc57f7e51a7d149db Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 12 May 2026 09:43:34 +0200 +Subject: spi: qup: fix error pointer deref after DMA setup failure + +From: Johan Hovold + +commit a7e8f3efd50a165ba0189f6dc57f7e51a7d149db upstream. + +The driver falls back to PIO mode if DMA setup fails during probe. + +Make sure to the clear the DMA channel pointers on setup failure to +avoid dereferencing an error pointer (or attempting to release a channel +a second time) on later probe errors or driver unbind. + +This issue was flagged by Sashiko when reviewing a devres allocation +conversion patch. + +Fixes: 612762e82ae6 ("spi: qup: Add DMA capabilities") +Link: https://sashiko.dev/#/patchset/20260505072909.618363-1-johan%40kernel.org?part=4 +Cc: stable@vger.kernel.org # 4.1 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260512074334.914735-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-qup.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/spi/spi-qup.c ++++ b/drivers/spi/spi-qup.c +@@ -996,8 +996,11 @@ static int spi_qup_init_dma(struct spi_c + + err: + dma_release_channel(host->dma_tx); ++ host->dma_tx = NULL; + err_tx: + dma_release_channel(host->dma_rx); ++ host->dma_rx = NULL; ++ + return ret; + } + diff --git a/queue-7.0/spi-sprd-fix-error-pointer-deref-after-dma-setup-failure.patch b/queue-7.0/spi-sprd-fix-error-pointer-deref-after-dma-setup-failure.patch new file mode 100644 index 0000000000..7336e56593 --- /dev/null +++ b/queue-7.0/spi-sprd-fix-error-pointer-deref-after-dma-setup-failure.patch @@ -0,0 +1,42 @@ +From 3d67fffb74267772d461c02c67f1eff893ad547d Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 12 May 2026 09:47:33 +0200 +Subject: spi: sprd: fix error pointer deref after DMA setup failure + +From: Johan Hovold + +commit 3d67fffb74267772d461c02c67f1eff893ad547d upstream. + +The driver falls back to PIO mode if DMA setup fails during probe. + +Make sure to check the dma.enabled flag before trying to release the DMA +channels also on late probe errors to avoid dereferencing an error +pointer (or attempting to release a channel a second time). + +This issue was flagged by Sashiko when reviewing a devres allocation +conversion patch. + +Fixes: 386119bc7be9 ("spi: sprd: spi: sprd: Add DMA mode support") +Link: https://sashiko.dev/#/patchset/20260505072909.618363-1-johan%40kernel.org?part=10 +Cc: stable@vger.kernel.org # 5.1 +Cc: Lanqing Liu +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260512074733.915029-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sprd.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-sprd.c ++++ b/drivers/spi/spi-sprd.c +@@ -991,7 +991,8 @@ err_rpm_put: + disable_clk: + clk_disable_unprepare(ss->clk); + release_dma: +- sprd_spi_dma_release(ss); ++ if (ss->dma.enable) ++ sprd_spi_dma_release(ss); + free_controller: + spi_controller_put(sctlr); + diff --git a/queue-7.0/spi-ti-qspi-fix-use-after-free-after-dma-setup-failure.patch b/queue-7.0/spi-ti-qspi-fix-use-after-free-after-dma-setup-failure.patch new file mode 100644 index 0000000000..9b16b16773 --- /dev/null +++ b/queue-7.0/spi-ti-qspi-fix-use-after-free-after-dma-setup-failure.patch @@ -0,0 +1,41 @@ +From ea6ec3343e05f7937a53eb6d7617b3abdb4abc19 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 12 May 2026 09:48:09 +0200 +Subject: spi: ti-qspi: fix use-after-free after DMA setup failure + +From: Johan Hovold + +commit ea6ec3343e05f7937a53eb6d7617b3abdb4abc19 upstream. + +The driver falls back to PIO mode if DMA setup fails during probe. + +Make sure to clear the DMA channel pointer also if buffer allocation +fails to avoid passing a pointer to the released channel to the DMA +engine (or trying to free the channel a second time on late probe errors +or driver unbind). + +This issue was flagged by Sashiko when reviewing a devres allocation +conversion patch. + +Fixes: c687c46e9e45 ("spi: spi-ti-qspi: Use bounce buffer if read buffer is not DMA'ble") +Link: https://sashiko.dev/#/patchset/20260505072909.618363-1-johan%40kernel.org?part=17 +Cc: stable@vger.kernel.org # 4.12 +Cc: Vignesh R +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260512074809.915084-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -867,6 +867,7 @@ static int ti_qspi_probe(struct platform + dev_err(qspi->dev, + "dma_alloc_coherent failed, using PIO mode\n"); + dma_release_channel(qspi->rx_chan); ++ qspi->rx_chan = NULL; + goto no_dma; + } + host->dma_rx = qspi->rx_chan; diff --git a/queue-7.0/tracing-do-not-call-map-ops-elt_free-if-elt_alloc-fails.patch b/queue-7.0/tracing-do-not-call-map-ops-elt_free-if-elt_alloc-fails.patch new file mode 100644 index 0000000000..a967cb85c7 --- /dev/null +++ b/queue-7.0/tracing-do-not-call-map-ops-elt_free-if-elt_alloc-fails.patch @@ -0,0 +1,73 @@ +From 8f0f5c4fb9df0e19a341e0c6ed8dc4fda9124f03 Mon Sep 17 00:00:00 2001 +From: "Masami Hiramatsu (Google)" +Date: Thu, 21 May 2026 13:49:14 +0900 +Subject: tracing: Do not call map->ops->elt_free() if elt_alloc() fails + +From: Masami Hiramatsu (Google) + +commit 8f0f5c4fb9df0e19a341e0c6ed8dc4fda9124f03 upstream. + +In paths where tracing_map_elt_alloc() failed to allocate objects, +the map->ops->elt_alloc() call was never successful. In this case, +map->ops->elt_free() should not be called. + +Link: https://sashiko.dev/#/patchset/20260520223101.34710-1-rosenp%40gmail.com + +Cc: stable@vger.kernel.org +Cc: Tom Zanussi +Cc: Mathieu Desnoyers +Cc: Rosen Penev +Reported-by: Sashiko +Fixes: 2734b629525a ("tracing: Add per-element variable support to tracing_map") +Link: https://patch.msgid.link/177933895460.108746.5396070821443932634.stgit@devnote2 +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/tracing_map.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +--- a/kernel/trace/tracing_map.c ++++ b/kernel/trace/tracing_map.c +@@ -386,13 +386,11 @@ static void tracing_map_elt_init_fields( + } + } + +-static void tracing_map_elt_free(struct tracing_map_elt *elt) ++static void __tracing_map_elt_free(struct tracing_map_elt *elt) + { + if (!elt) + return; + +- if (elt->map->ops && elt->map->ops->elt_free) +- elt->map->ops->elt_free(elt); + kfree(elt->fields); + kfree(elt->vars); + kfree(elt->var_set); +@@ -400,6 +398,17 @@ static void tracing_map_elt_free(struct + kfree(elt); + } + ++static void tracing_map_elt_free(struct tracing_map_elt *elt) ++{ ++ if (!elt) ++ return; ++ ++ /* Only objects initialized with alloc_elt() should be passed to free_elt().*/ ++ if (elt->map->ops && elt->map->ops->elt_free) ++ elt->map->ops->elt_free(elt); ++ __tracing_map_elt_free(elt); ++} ++ + static struct tracing_map_elt *tracing_map_elt_alloc(struct tracing_map *map) + { + struct tracing_map_elt *elt; +@@ -444,7 +453,7 @@ static struct tracing_map_elt *tracing_m + } + return elt; + free: +- tracing_map_elt_free(elt); ++ __tracing_map_elt_free(elt); + + return ERR_PTR(err); + } diff --git a/queue-7.0/virt-sev-guest-explicitly-leak-pages-in-unknown-state.patch b/queue-7.0/virt-sev-guest-explicitly-leak-pages-in-unknown-state.patch new file mode 100644 index 0000000000..ae5da47899 --- /dev/null +++ b/queue-7.0/virt-sev-guest-explicitly-leak-pages-in-unknown-state.patch @@ -0,0 +1,68 @@ +From fd948c3f96b18ff9ba7d3e8eae13d196593e1aaf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Carlos=20L=C3=B3pez?= +Date: Tue, 12 May 2026 12:00:42 +0200 +Subject: virt: sev-guest: Explicitly leak pages in unknown state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Carlos López + +commit fd948c3f96b18ff9ba7d3e8eae13d196593e1aaf upstream. + +When set_memory_{encrypted,decrypted}() fail, the user cannot know at which +point the function failed, meaning that the pages are left in an unknown state +from the point of view of the caller. + +Since the pages may be left in an unencrypted state, they are not suitable for +general use, and cannot be returned safely to the buddy allocator. Avoid the +issue by never freeing the pages, and then do the proper accounting by calling +snp_leak_pages(). + +Fixes: 3e385c0d6ce8 ("virt: sev-guest: Move SNP Guest Request data pages handling under snp_cmd_mutex") +Signed-off-by: Carlos López +Signed-off-by: Borislav Petkov (AMD) +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/virt/coco/sev-guest/sev-guest.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/virt/coco/sev-guest/sev-guest.c ++++ b/drivers/virt/coco/sev-guest/sev-guest.c +@@ -176,6 +176,7 @@ static int get_ext_report(struct snp_gue + struct snp_guest_req req = {}; + int ret, npages = 0, resp_len; + sockptr_t certs_address; ++ u64 pfn; + + if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data)) + return -EINVAL; +@@ -215,10 +216,11 @@ static int get_ext_report(struct snp_gue + if (!req.certs_data) + return -ENOMEM; + ++ pfn = PHYS_PFN(virt_to_phys(req.certs_data)); + ret = set_memory_decrypted((unsigned long)req.certs_data, npages); + if (ret) { + pr_err("failed to mark page shared, ret=%d\n", ret); +- free_pages_exact(req.certs_data, npages << PAGE_SHIFT); ++ snp_leak_pages(pfn, npages); + return -EFAULT; + } + +@@ -272,10 +274,12 @@ e_free: + kfree(report_resp); + e_free_data: + if (npages) { +- if (set_memory_encrypted((unsigned long)req.certs_data, npages)) ++ if (set_memory_encrypted((unsigned long)req.certs_data, npages)) { + WARN_ONCE(ret, "failed to restore encryption mask (leak it)\n"); +- else ++ snp_leak_pages(pfn, npages); ++ } else { + free_pages_exact(req.certs_data, npages << PAGE_SHIFT); ++ } + } + return ret; + }