From: Greg Kroah-Hartman Date: Tue, 16 Jun 2026 05:06:08 +0000 (+0530) Subject: 6.6-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3172bf92ad8fbfef68d7d684c34fd4b90d1b6bd3;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch memfd-deny-writeable-mappings-when-implying-seal_write.patch mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch rdma-during-rereg_mr-ensure-that-rereg_access-is-compatible.patch rdma-move-dma-block-iterator-logic-into-dedicated-files.patch rdma-umem-fix-kernel-doc-warnings.patch rdma-umem-fix-truncation-for-block-sizes-4g.patch scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch serial-samsung_tty-use-port-lock-wrappers.patch thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch tty-serial-samsung-use-u32-for-register-interactions.patch usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch --- diff --git a/queue-6.6/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch b/queue-6.6/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch new file mode 100644 index 0000000000..d6367a2879 --- /dev/null +++ b/queue-6.6/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch @@ -0,0 +1,74 @@ +From stable+bounces-260602-greg=kroah.com@vger.kernel.org Fri Jun 5 07:15:41 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 21:31:06 -0400 +Subject: ALSA: firewire-motu: Protect register DSP event queue positions +To: stable@vger.kernel.org +Cc: "Cássio Gabriel" , "Takashi Sakamoto" , "Takashi Iwai" , "Sasha Levin" +Message-ID: <20260605013107.2963134-1-sashal@kernel.org> + +From: Cássio Gabriel + +[ Upstream commit 98fb1c1bb11e29eb609b7200a25e136e05aa4498 ] + +The register DSP event queue is updated under parser->lock, but +snd_motu_register_dsp_message_parser_count_event() reads pull_pos and +push_pos without the lock. +snd_motu_register_dsp_message_parser_copy_event() also reads both queue +positions before taking the lock. + +Protect these accesses with parser->lock as well. This keeps the hwdep +poll/read path consistent with the producer side and with the cached +meter/parameter accessors. + +Fixes: 634ec0b2906e ("ALSA: firewire-motu: notify event for parameter change in register DSP model") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Reviewed-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260521-alsa-firewire-motu-event-locking-v1-1-708e1c2b5e56@gmail.com +[ converted copy_event() from manual spin_lock_irqsave/spin_unlock_irqrestore to guard(spinlock_irqsave) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/firewire/motu/motu-register-dsp-message-parser.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/sound/firewire/motu/motu-register-dsp-message-parser.c ++++ b/sound/firewire/motu/motu-register-dsp-message-parser.c +@@ -393,6 +393,8 @@ unsigned int snd_motu_register_dsp_messa + { + struct msg_parser *parser = motu->message_parser; + ++ guard(spinlock_irqsave)(&parser->lock); ++ + if (parser->pull_pos > parser->push_pos) + return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos; + else +@@ -402,14 +404,14 @@ unsigned int snd_motu_register_dsp_messa + bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event) + { + struct msg_parser *parser = motu->message_parser; +- unsigned int pos = parser->pull_pos; +- unsigned long flags; ++ unsigned int pos; + +- if (pos == parser->push_pos) +- return false; ++ guard(spinlock_irqsave)(&parser->lock); + +- spin_lock_irqsave(&parser->lock, flags); ++ if (parser->pull_pos == parser->push_pos) ++ return false; + ++ pos = parser->pull_pos; + *event = parser->event_queue[pos]; + + ++pos; +@@ -417,7 +419,5 @@ bool snd_motu_register_dsp_message_parse + pos = 0; + parser->pull_pos = pos; + +- spin_unlock_irqrestore(&parser->lock, flags); +- + return true; + } diff --git a/queue-6.6/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch b/queue-6.6/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch new file mode 100644 index 0000000000..038577e87d --- /dev/null +++ b/queue-6.6/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch @@ -0,0 +1,92 @@ +From stable+bounces-263425-greg=kroah.com@vger.kernel.org Mon Jun 15 23:38:10 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 14:08:00 -0400 +Subject: hv_netvsc: use kmap_local_page in netvsc_copy_to_send_buf +To: stable@vger.kernel.org +Cc: Anton Leontev , Paolo Abeni , Sasha Levin +Message-ID: <20260615180800.2317919-1-sashal@kernel.org> + +From: Anton Leontev + +[ Upstream commit 004e9ecfe6c5384f9e0b2f6f6389d42ec22789af ] + +netvsc_copy_to_send_buf() copies page buffer entries into the VMBus +send buffer using phys_to_virt() on the entry PFN. Entries for the +RNDIS header and the skb linear data come from kmalloc'd memory and +are always in the kernel direct map, but entries for skb fragments +reference page cache or user pages, which on 32-bit x86 with +CONFIG_HIGHMEM=y can live above the LOWMEM boundary. For such a page +phys_to_virt() returns an address outside the direct map and the +subsequent memcpy() faults on the transmit softirq path, which is +fatal. + +Map the pages with kmap_local_page() instead, handling two properties +of the page buffer entries: + + - pb[i].pfn is a Hyper-V PFN at HV_HYP_PAGE_SIZE (4K) granularity, + not a native PFN. Reconstruct the physical address first and derive + the native page from it, so the mapping stays correct where + PAGE_SIZE > HV_HYP_PAGE_SIZE (e.g. arm64 with 64K pages). + + - Since commit 41a6328b2c55 ("hv_netvsc: Preserve contiguous PFN + grouping in the page buffer array"), an entry describes a full + physically contiguous fragment and pb[i].len can exceed PAGE_SIZE, + while kmap_local_page() maps a single page. Copy page by page, + splitting at native page boundaries. + +The copy path only handles packets smaller than the send section size +(6144 bytes by default); larger packets take the cp_partial path where +only the RNDIS header is copied. So entries here are bounded by the +section size and a copy is split at most once on 4K-page systems. On +!CONFIG_HIGHMEM configs kmap_local_page() folds to page_address() and +no mapping work is added. + +Fixes: c25aaf814a63 ("hyperv: Enable sendbuf mechanism on the send path") +Cc: stable@vger.kernel.org +Signed-off-by: Anton Leontev +Link: https://patch.msgid.link/20260604165938.32033-1-leontyevantony@gmail.com +Signed-off-by: Paolo Abeni +[ adapted `phys_to_page(paddr)` to `pfn_to_page(PHYS_PFN(paddr))` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/hyperv/netvsc.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -957,12 +958,22 @@ static void netvsc_copy_to_send_buf(stru + } + + for (i = 0; i < page_count; i++) { +- char *src = phys_to_virt(pb[i].pfn << HV_HYP_PAGE_SHIFT); +- u32 offset = pb[i].offset; ++ phys_addr_t paddr = (pb[i].pfn << HV_HYP_PAGE_SHIFT) + ++ pb[i].offset; + u32 len = pb[i].len; + +- memcpy(dest, (src + offset), len); +- dest += len; ++ while (len) { ++ struct page *page = pfn_to_page(PHYS_PFN(paddr)); ++ u32 off = offset_in_page(paddr); ++ u32 chunk = min_t(u32, len, PAGE_SIZE - off); ++ char *src = kmap_local_page(page); ++ ++ memcpy(dest, src + off, chunk); ++ kunmap_local(src); ++ dest += chunk; ++ paddr += chunk; ++ len -= chunk; ++ } + } + + if (padding) diff --git a/queue-6.6/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch b/queue-6.6/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch new file mode 100644 index 0000000000..c17e7034a1 --- /dev/null +++ b/queue-6.6/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch @@ -0,0 +1,38 @@ +From stable+bounces-260560-greg=kroah.com@vger.kernel.org Fri Jun 5 00:33:19 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:57:11 -0400 +Subject: iio: chemical: scd30: fix division by zero in write_raw +To: stable@vger.kernel.org +Cc: Antoniu Miclaus , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260604185711.605210-2-sashal@kernel.org> + +From: Antoniu Miclaus + +[ Upstream commit 5aba4f94b225617a55fed442a70329b2ee19c0a5 ] + +Add a zero check for val2 before using it as a divisor when setting the +sampling frequency. A user writing a zero fractional part to the +sampling_frequency sysfs attribute triggers a division by zero in the +kernel. + +Fixes: 64b3d8b1b0f5 ("iio: chemical: scd30: add core driver") +Signed-off-by: Antoniu Miclaus +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/chemical/scd30_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/iio/chemical/scd30_core.c ++++ b/drivers/iio/chemical/scd30_core.c +@@ -257,7 +257,7 @@ static int scd30_write_raw(struct iio_de + guard(mutex)(&state->lock); + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: +- if (val) ++ if (val || !val2) + return -EINVAL; + + val = 1000000000 / val2; diff --git a/queue-6.6/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch b/queue-6.6/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch new file mode 100644 index 0000000000..3488535f67 --- /dev/null +++ b/queue-6.6/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch @@ -0,0 +1,178 @@ +From stable+bounces-260559-greg=kroah.com@vger.kernel.org Fri Jun 5 00:32:46 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:57:10 -0400 +Subject: iio: chemical: scd30: Use guard(mutex) to allow early returns +To: stable@vger.kernel.org +Cc: Jonathan Cameron , David Lechner , Tomasz Duszynski , Sasha Levin +Message-ID: <20260604185711.605210-1-sashal@kernel.org> + +From: Jonathan Cameron + +[ Upstream commit 5feb5532870fbced5d6f450b8061a33f461b88ca ] + +Auto cleanup based release of the lock allows for simpler code flow in a +few functions with large multiplexing style switch statements and no +common operations following the switch. + +Suggested-by: David Lechner +Cc: Tomasz Duszynski +Reviewed-by: David Lechner +Link: https://patch.msgid.link/20250209180624.701140-3-jic23@kernel.org +Signed-off-by: Jonathan Cameron +Stable-dep-of: 5aba4f94b225 ("iio: chemical: scd30: fix division by zero in write_raw") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/chemical/scd30_core.c | 63 ++++++++++++++++---------------------- + 1 file changed, 28 insertions(+), 35 deletions(-) + +--- a/drivers/iio/chemical/scd30_core.c ++++ b/drivers/iio/chemical/scd30_core.c +@@ -5,6 +5,7 @@ + * Copyright (c) 2020 Tomasz Duszynski + */ + #include ++#include + #include + #include + #include +@@ -198,112 +199,104 @@ static int scd30_read_raw(struct iio_dev + int *val, int *val2, long mask) + { + struct scd30_state *state = iio_priv(indio_dev); +- int ret = -EINVAL; ++ int ret; + u16 tmp; + +- mutex_lock(&state->lock); ++ guard(mutex)(&state->lock); + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + if (chan->output) { + *val = state->pressure_comp; +- ret = IIO_VAL_INT; +- break; ++ return IIO_VAL_INT; + } + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) +- break; ++ return ret; + + ret = scd30_read(state); + if (ret) { + iio_device_release_direct_mode(indio_dev); +- break; ++ return ret; + } + + *val = state->meas[chan->address]; + iio_device_release_direct_mode(indio_dev); +- ret = IIO_VAL_INT; +- break; ++ return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 1; +- ret = IIO_VAL_INT_PLUS_MICRO; +- break; ++ return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = scd30_command_read(state, CMD_MEAS_INTERVAL, &tmp); + if (ret) +- break; ++ return ret; + + *val = 0; + *val2 = 1000000000 / tmp; +- ret = IIO_VAL_INT_PLUS_NANO; +- break; ++ return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_CALIBBIAS: + ret = scd30_command_read(state, CMD_TEMP_OFFSET, &tmp); + if (ret) +- break; ++ return ret; + + *val = tmp; +- ret = IIO_VAL_INT; +- break; ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; + } +- mutex_unlock(&state->lock); +- +- return ret; + } + + static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int val, int val2, long mask) + { + struct scd30_state *state = iio_priv(indio_dev); +- int ret = -EINVAL; ++ int ret; + +- mutex_lock(&state->lock); ++ guard(mutex)(&state->lock); + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val) +- break; ++ return -EINVAL; + + val = 1000000000 / val2; + if (val < SCD30_MEAS_INTERVAL_MIN_S || val > SCD30_MEAS_INTERVAL_MAX_S) +- break; ++ return -EINVAL; + + ret = scd30_command_write(state, CMD_MEAS_INTERVAL, val); + if (ret) +- break; ++ return ret; + + state->meas_interval = val; +- break; ++ return 0; + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_PRESSURE: + if (val < SCD30_PRESSURE_COMP_MIN_MBAR || + val > SCD30_PRESSURE_COMP_MAX_MBAR) +- break; ++ return -EINVAL; + + ret = scd30_command_write(state, CMD_START_MEAS, val); + if (ret) +- break; ++ return ret; + + state->pressure_comp = val; +- break; ++ return 0; + default: +- break; ++ return -EINVAL; + } +- break; + case IIO_CHAN_INFO_CALIBBIAS: + if (val < 0 || val > SCD30_TEMP_OFFSET_MAX) +- break; ++ return -EINVAL; + /* + * Manufacturer does not explicitly specify min/max sensible + * values hence check is omitted for simplicity. + */ +- ret = scd30_command_write(state, CMD_TEMP_OFFSET / 10, val); ++ return scd30_command_write(state, CMD_TEMP_OFFSET / 10, val); ++ default: ++ return -EINVAL; + } +- mutex_unlock(&state->lock); +- +- return ret; + } + + static int scd30_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, diff --git a/queue-6.6/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch b/queue-6.6/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch new file mode 100644 index 0000000000..7fda7f3606 --- /dev/null +++ b/queue-6.6/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch @@ -0,0 +1,65 @@ +From stable+bounces-260592-greg=kroah.com@vger.kernel.org Fri Jun 5 06:04:46 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 20:34:32 -0400 +Subject: iio: dac: ad5686: fix ref bit initialization for single-channel parts +To: stable@vger.kernel.org +Cc: Rodrigo Alencar , Andy Shevchenko , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260605003432.2705436-1-sashal@kernel.org> + +From: Rodrigo Alencar + +[ Upstream commit ecae2ae606d493cf11457946436335bd0e726663 ] + +The reference bit position was ignored when writing the register at the +probe() function (!!val was used). When such bit is 1, internal voltage +reference is disabled so that an external one can be used. For +multi-channel devices, bit 0 of the Internal Reference Setup command +behaves the same way, so AD5686_REF_BIT_MSK is created. The issue exists +since support for single-channel devices were first introduced. + +Fixes: be1b24d24541 ("iio:dac:ad5686: Add AD5691R/AD5692R/AD5693/AD5693R support") +Reviewed-by: Andy Shevchenko +Signed-off-by: Rodrigo Alencar +Cc: +Signed-off-by: Jonathan Cameron +[ adapted `has_external_vref` to the in-tree equivalent `voltage_uv` variable in the `val =` computation ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/dac/ad5686.c | 6 +++--- + drivers/iio/dac/ad5686.h | 1 + + 2 files changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/iio/dac/ad5686.c ++++ b/drivers/iio/dac/ad5686.c +@@ -528,7 +528,7 @@ int ad5686_probe(struct device *dev, + break; + case AD5686_REGMAP: + cmd = AD5686_CMD_INTERNAL_REFER_SETUP; +- ref_bit_msk = 0; ++ ref_bit_msk = AD5686_REF_BIT_MSK; + break; + case AD5693_REGMAP: + cmd = AD5686_CMD_CONTROL_REG; +@@ -540,9 +540,9 @@ int ad5686_probe(struct device *dev, + goto error_disable_reg; + } + +- val = (voltage_uv | ref_bit_msk); ++ val = voltage_uv ? ref_bit_msk : 0; + +- ret = st->write(st, cmd, 0, !!val); ++ ret = st->write(st, cmd, 0, val); + if (ret) + goto error_disable_reg; + +--- a/drivers/iio/dac/ad5686.h ++++ b/drivers/iio/dac/ad5686.h +@@ -46,6 +46,7 @@ + + #define AD5310_REF_BIT_MSK BIT(8) + #define AD5683_REF_BIT_MSK BIT(12) ++#define AD5686_REF_BIT_MSK BIT(0) + #define AD5693_REF_BIT_MSK BIT(12) + + /** diff --git a/queue-6.6/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch b/queue-6.6/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch new file mode 100644 index 0000000000..67c623cb76 --- /dev/null +++ b/queue-6.6/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch @@ -0,0 +1,39 @@ +From stable+bounces-260547-greg=kroah.com@vger.kernel.org Thu Jun 4 23:08:08 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 13:37:58 -0400 +Subject: iio: gyro: adis16260: fix division by zero in write_raw +To: stable@vger.kernel.org +Cc: "Antoniu Miclaus" , "Nuno Sá" , Stable@vger.kernel.org, "Jonathan Cameron" , "Sasha Levin" +Message-ID: <20260604173758.25903-1-sashal@kernel.org> + +From: Antoniu Miclaus + +[ Upstream commit 761e8b489e6cf166c574034b70637f8a7eadd0ee ] + +Add a validation check for the sampling frequency value before using it +as a divisor. A user writing zero to the sampling_frequency sysfs +attribute triggers a division by zero in the kernel. + +Fixes: 089a41985c6c ("staging: iio: adis16260 digital gyro driver") +Signed-off-by: Antoniu Miclaus +Reviewed-by: Nuno Sá +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/gyro/adis16260.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/iio/gyro/adis16260.c ++++ b/drivers/iio/gyro/adis16260.c +@@ -288,6 +288,9 @@ static int adis16260_write_raw(struct ii + addr = adis16260_addresses[chan->scan_index][1]; + return adis_write_reg_16(adis, addr, val); + case IIO_CHAN_INFO_SAMP_FREQ: ++ if (val <= 0) ++ return -EINVAL; ++ + adis_dev_lock(adis); + if (spi_get_device_id(adis->spi)->driver_data) + t = 256 / val; diff --git a/queue-6.6/memfd-deny-writeable-mappings-when-implying-seal_write.patch b/queue-6.6/memfd-deny-writeable-mappings-when-implying-seal_write.patch new file mode 100644 index 0000000000..790c1d729f --- /dev/null +++ b/queue-6.6/memfd-deny-writeable-mappings-when-implying-seal_write.patch @@ -0,0 +1,71 @@ +From stable+bounces-260593-greg=kroah.com@vger.kernel.org Fri Jun 5 06:04:59 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 20:34:51 -0400 +Subject: memfd: deny writeable mappings when implying SEAL_WRITE +To: stable@vger.kernel.org +Cc: "Pratyush Yadav (Google)" , Pasha Tatashin , Jeff Xu , Baolin Wang , Brendan Jackman , Greg Thelen , Hugh Dickins , Kees Cook , "David Hildenbrand (Arm)" , Andrew Morton , Sasha Levin +Message-ID: <20260605003451.2707256-1-sashal@kernel.org> + +From: "Pratyush Yadav (Google)" + +[ Upstream commit 3b041514cb6eae45869b020f743c14d983363222 ] + +When SEAL_EXEC is added, SEAL_WRITE is implied to make W^X. But the +implied seal is set after the check that makes sure the memfd can not have +any writable mappings. This means one can use SEAL_EXEC to apply +SEAL_WRITE while having writeable mappings. + +This breaks the contract that SEAL_WRITE provides and can be used by an +attacker to pass a memfd that appears to be write sealed but can still be +modified arbitrarily. + +Fix this by adding the implied seals before the call for +mapping_deny_writable() is done. + +Link: https://lore.kernel.org/20260505133922.797635-1-pratyush@kernel.org +Fixes: c4f75bc8bd6b ("mm/memfd: add write seals when apply SEAL_EXEC to executable memfd") +Signed-off-by: Pratyush Yadav (Google) +Reviewed-by: Pasha Tatashin +Acked-by: Jeff Xu +Cc: Baolin Wang +Cc: Brendan Jackman +Cc: Greg Thelen +Cc: Hugh Dickins +Cc: Kees Cook +Cc: "David Hildenbrand (Arm)" +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/memfd.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/mm/memfd.c ++++ b/mm/memfd.c +@@ -210,6 +210,12 @@ static int memfd_add_seals(struct file * + goto unlock; + } + ++ /* ++ * SEAL_EXEC implies SEAL_WRITE, making W^X from the start. ++ */ ++ if (seals & F_SEAL_EXEC && inode->i_mode & 0111) ++ seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; ++ + if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) { + error = mapping_deny_writable(file->f_mapping); + if (error) +@@ -222,12 +228,6 @@ static int memfd_add_seals(struct file * + } + } + +- /* +- * SEAL_EXEC implys SEAL_WRITE, making W^X from the start. +- */ +- if (seals & F_SEAL_EXEC && inode->i_mode & 0111) +- seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; +- + *file_seals |= seals; + error = 0; + diff --git a/queue-6.6/mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch b/queue-6.6/mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch new file mode 100644 index 0000000000..7337d1a4fc --- /dev/null +++ b/queue-6.6/mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch @@ -0,0 +1,114 @@ +From stable+bounces-263330-greg=kroah.com@vger.kernel.org Mon Jun 15 21:12:52 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 11:39:01 -0400 +Subject: mm/hugetlb: rename folio_putback_active_hugetlb() to folio_putback_hugetlb() +To: stable@vger.kernel.org +Cc: David Hildenbrand , Baolin Wang , "Matthew Wilcox (Oracle)" , Muchun Song , Sidhartha Kumar , Andrew Morton , Sasha Levin +Message-ID: <20260615153903.2214102-3-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit b235448e8cab7eea17d164efc7bf55505985ba65 ] + +Now that folio_putback_hugetlb() is only called on folios that were +previously isolated through folio_isolate_hugetlb(), let's rename it to +match folio_putback_lru(). + +Add some kernel doc to clarify how this function is supposed to be used. + +Link: https://lkml.kernel.org/r/20250113131611.2554758-5-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Baolin Wang +Cc: Matthew Wilcox (Oracle) +Cc: Muchun Song +Cc: Sidhartha Kumar +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 4 ++-- + mm/hugetlb.c | 15 +++++++++++++-- + mm/migrate.c | 6 +++--- + 3 files changed, 18 insertions(+), 7 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -166,7 +166,7 @@ bool folio_isolate_hugetlb(struct folio + int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison); + int get_huge_page_for_hwpoison(unsigned long pfn, int flags, + bool *migratable_cleared); +-void folio_putback_active_hugetlb(struct folio *folio); ++void folio_putback_hugetlb(struct folio *folio); + void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int reason); + void hugetlb_fix_reserve_counts(struct inode *inode); + extern struct mutex *hugetlb_fault_mutex_table; +@@ -462,7 +462,7 @@ static inline int get_huge_page_for_hwpo + return 0; + } + +-static inline void folio_putback_active_hugetlb(struct folio *folio) ++static inline void folio_putback_hugetlb(struct folio *folio) + { + } + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7259,7 +7259,7 @@ __weak unsigned long hugetlb_mask_last_p + * it is already isolated/non-migratable. + * + * On success, an additional folio reference is taken that must be dropped +- * using folio_putback_active_hugetlb() to undo the isolation. ++ * using folio_putback_hugetlb() to undo the isolation. + * + * Return: True if isolation worked, otherwise False. + */ +@@ -7311,7 +7311,18 @@ int get_huge_page_for_hwpoison(unsigned + return ret; + } + +-void folio_putback_active_hugetlb(struct folio *folio) ++/** ++ * folio_putback_hugetlb - unisolate a hugetlb folio ++ * @folio: the isolated hugetlb folio ++ * ++ * Putback/un-isolate the hugetlb folio that was previous isolated using ++ * folio_isolate_hugetlb(): marking it non-isolated/migratable and putting it ++ * back onto the active list. ++ * ++ * Will drop the additional folio reference obtained through ++ * folio_isolate_hugetlb(). ++ */ ++void folio_putback_hugetlb(struct folio *folio) + { + spin_lock_irq(&hugetlb_lock); + folio_set_hugetlb_migratable(folio); +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -151,7 +151,7 @@ void putback_movable_pages(struct list_h + + list_for_each_entry_safe(folio, folio2, l, lru) { + if (unlikely(folio_test_hugetlb(folio))) { +- folio_putback_active_hugetlb(folio); ++ folio_putback_hugetlb(folio); + continue; + } + list_del(&folio->lru); +@@ -1373,7 +1373,7 @@ static int unmap_and_move_huge_page(new_ + + if (folio_ref_count(src) == 1) { + /* page was freed from under us. So we are done. */ +- folio_putback_active_hugetlb(src); ++ folio_putback_hugetlb(src); + return MIGRATEPAGE_SUCCESS; + } + +@@ -1456,7 +1456,7 @@ out_unlock: + folio_unlock(src); + out: + if (rc == MIGRATEPAGE_SUCCESS) +- folio_putback_active_hugetlb(src); ++ folio_putback_hugetlb(src); + else if (rc != -EAGAIN) + list_move_tail(&src->lru, ret); + diff --git a/queue-6.6/mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch b/queue-6.6/mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch new file mode 100644 index 0000000000..c96b53c832 --- /dev/null +++ b/queue-6.6/mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch @@ -0,0 +1,168 @@ +From stable+bounces-263328-greg=kroah.com@vger.kernel.org Mon Jun 15 21:12:40 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 11:38:59 -0400 +Subject: mm/hugetlb: rename isolate_hugetlb() to folio_isolate_hugetlb() +To: stable@vger.kernel.org +Cc: David Hildenbrand , "Matthew Wilcox (Oracle)" , Baolin Wang , Muchun Song , Sidhartha Kumar , Andrew Morton , Sasha Levin +Message-ID: <20260615153903.2214102-1-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 4c640f128074e0d4459ecf072595a44df5c2ae18 ] + +Let's make the function name match "folio_isolate_lru()", and add some +kernel doc. + +Link: https://lkml.kernel.org/r/20250113131611.2554758-3-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Matthew Wilcox (Oracle) +Reviewed-by: Baolin Wang +Cc: Muchun Song +Cc: Sidhartha Kumar +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 4 ++-- + mm/gup.c | 2 +- + mm/hugetlb.c | 25 +++++++++++++++++++------ + mm/memory-failure.c | 2 +- + mm/memory_hotplug.c | 2 +- + mm/mempolicy.c | 2 +- + mm/migrate.c | 4 ++-- + 7 files changed, 27 insertions(+), 14 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -162,7 +162,7 @@ bool hugetlb_reserve_pages(struct inode + vm_flags_t vm_flags); + long hugetlb_unreserve_pages(struct inode *inode, long start, long end, + long freed); +-bool isolate_hugetlb(struct folio *folio, struct list_head *list); ++bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list); + int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison); + int get_huge_page_for_hwpoison(unsigned long pfn, int flags, + bool *migratable_cleared); +@@ -446,7 +446,7 @@ static inline pte_t *huge_pte_offset(str + return NULL; + } + +-static inline bool isolate_hugetlb(struct folio *folio, struct list_head *list) ++static inline bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list) + { + return false; + } +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -1971,7 +1971,7 @@ static unsigned long collect_longterm_un + continue; + + if (folio_test_hugetlb(folio)) { +- isolate_hugetlb(folio, movable_page_list); ++ folio_isolate_hugetlb(folio, movable_page_list); + continue; + } + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -2969,7 +2969,7 @@ retry: + * Fail with -EBUSY if not possible. + */ + spin_unlock_irq(&hugetlb_lock); +- isolated = isolate_hugetlb(old_folio, list); ++ isolated = folio_isolate_hugetlb(old_folio, list); + ret = isolated ? 0 : -EBUSY; + spin_lock_irq(&hugetlb_lock); + goto free_new; +@@ -3045,7 +3045,7 @@ int isolate_or_dissolve_huge_page(struct + if (hstate_is_gigantic(h)) + return -ENOMEM; + +- if (folio_ref_count(folio) && isolate_hugetlb(folio, list)) ++ if (folio_ref_count(folio) && folio_isolate_hugetlb(folio, list)) + ret = 0; + else if (!folio_ref_count(folio)) + ret = alloc_and_dissolve_hugetlb_folio(h, folio, list); +@@ -7246,11 +7246,24 @@ __weak unsigned long hugetlb_mask_last_p + + #endif /* CONFIG_ARCH_WANT_GENERAL_HUGETLB */ + +-/* +- * These functions are overwritable if your architecture needs its own +- * behavior. ++/** ++ * folio_isolate_hugetlb - try to isolate an allocated hugetlb folio ++ * @folio: the folio to isolate ++ * @list: the list to add the folio to on success ++ * ++ * Isolate an allocated (refcount > 0) hugetlb folio, marking it as ++ * isolated/non-migratable, and moving it from the active list to the ++ * given list. ++ * ++ * Isolation will fail if @folio is not an allocated hugetlb folio, or if ++ * it is already isolated/non-migratable. ++ * ++ * On success, an additional folio reference is taken that must be dropped ++ * using folio_putback_active_hugetlb() to undo the isolation. ++ * ++ * Return: True if isolation worked, otherwise False. + */ +-bool isolate_hugetlb(struct folio *folio, struct list_head *list) ++bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list) + { + bool ret = true; + +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -2639,7 +2639,7 @@ static bool isolate_page(struct page *pa + bool isolated = false; + + if (PageHuge(page)) { +- isolated = isolate_hugetlb(page_folio(page), pagelist); ++ isolated = folio_isolate_hugetlb(page_folio(page), pagelist); + } else { + bool lru = !__PageMovable(page); + +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -1720,7 +1720,7 @@ static void do_migrate_range(unsigned lo + + if (PageHuge(page)) { + pfn = page_to_pfn(head) + compound_nr(head) - 1; +- isolate_hugetlb(folio, &source); ++ folio_isolate_hugetlb(folio, &source); + continue; + } else if (PageTransHuge(page)) + pfn = page_to_pfn(head) + thp_nr_pages(page) - 1; +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -608,7 +608,7 @@ static int queue_folios_hugetlb(pte_t *p + */ + if ((flags & MPOL_MF_MOVE_ALL) || + (folio_estimated_sharers(folio) == 1 && !hugetlb_pmd_shared(pte))) +- if (!isolate_hugetlb(folio, qp->pagelist)) ++ if (!folio_isolate_hugetlb(folio, qp->pagelist)) + qp->nr_failed++; + unlock: + spin_unlock(ptl); +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -142,7 +142,7 @@ static void putback_movable_folio(struct + * + * This function shall be used whenever the isolated pageset has been + * built from lru, balloon, hugetlbfs page. See isolate_migratepages_range() +- * and isolate_hugetlb(). ++ * and folio_isolate_hugetlb(). + */ + void putback_movable_pages(struct list_head *l) + { +@@ -2113,7 +2113,7 @@ static int add_page_for_migration(struct + + if (PageHuge(page)) { + if (PageHead(page)) { +- isolated = isolate_hugetlb(page_folio(page), pagelist); ++ isolated = folio_isolate_hugetlb(page_folio(page), pagelist); + err = isolated ? 1 : -EBUSY; + } + } else { diff --git a/queue-6.6/mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch b/queue-6.6/mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch new file mode 100644 index 0000000000..19977ff71c --- /dev/null +++ b/queue-6.6/mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch @@ -0,0 +1,199 @@ +From stable+bounces-263332-greg=kroah.com@vger.kernel.org Mon Jun 15 21:13:02 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 11:39:03 -0400 +Subject: mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison +To: stable@vger.kernel.org +Cc: Wupeng Ma , "Oscar Salvador (SUSE)" , Muchun Song , Kefeng Wang , Miaohe Lin , David Hildenbrand , Liam Howlett , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Naoya Horiguchi , Suren Baghdasaryan , Vlastimil Babka , Andrew Morton , Sasha Levin +Message-ID: <20260615153903.2214102-5-sashal@kernel.org> + +From: Wupeng Ma + +[ Upstream commit 3c2d42b8ee345b17a4ba56b0f6492d1ff4c1178e ] + +Two concurrent madvise(MADV_HWPOISON) calls on the same hugetlb page can +trigger a recursive spinlock self-deadlock (AA deadlock) on hugetlb_lock +when racing with a concurrent unmap: + + thread#0 thread#1 + -------- -------- + madvise(folio, MADV_HWPOISON) + -> poisons the folio successfully + madvise(folio, MADV_HWPOISON) unmap(folio) + try_memory_failure_hugetlb + get_huge_page_for_hwpoison + spin_lock_irq(&hugetlb_lock) <- held + __get_huge_page_for_hwpoison + hugetlb_update_hwpoison() + -> MF_HUGETLB_FOLIO_PRE_POISONED + goto out: + folio_put() + refcount: 1 -> 0 + free_huge_folio() + spin_lock_irqsave(&hugetlb_lock) + -> AA DEADLOCK! + +The out: path in __get_huge_page_for_hwpoison() calls folio_put() to drop +the GUP reference while the hugetlb_lock is still held by the hugetlb.c +wrapper get_huge_page_for_hwpoison(). If concurrent unmap has released +the page table mapping reference, folio_put() drops the folio refcount to +zero, triggering free_huge_folio() which attempts to re-acquire the +non-recursive hugetlb_lock. + +Fix this by moving hugetlb_lock acquisition from the hugetlb.c wrapper +into get_huge_page_for_hwpoison(). Place spin_unlock_irq() before the +folio_put() at the out: label so the folio is always released outside the +lock. + +[akpm@linux-foundation.org: fix race, rename label per Miaohe] + Link: https://sashiko.dev/#/patchset/20260522010305.4099834-1-mawupeng1@huawei.com + Link: https://lore.kernel.org/f39f405e-4b4b-8f79-70fe-a2b5b62114eb@huawei.com +Link: https://lore.kernel.org/20260522010305.4099834-1-mawupeng1@huawei.com +Fixes: 405ce051236c ("mm/hwpoison: fix race between hugetlb free/demotion and memory_failure_hugetlb()") +Signed-off-by: Wupeng Ma +Acked-by: Oscar Salvador (SUSE) +Acked-by: Muchun Song +Reviewed-by: Kefeng Wang +Acked-by: Miaohe Lin +Cc: David Hildenbrand +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Naoya Horiguchi +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 8 -------- + include/linux/mm.h | 8 -------- + mm/hugetlb.c | 11 ----------- + mm/memory-failure.c | 19 ++++++++++--------- + 4 files changed, 10 insertions(+), 36 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -164,8 +164,6 @@ long hugetlb_unreserve_pages(struct inod + long freed); + bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list); + int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison); +-int get_huge_page_for_hwpoison(unsigned long pfn, int flags, +- bool *migratable_cleared); + void folio_putback_hugetlb(struct folio *folio); + void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int reason); + void hugetlb_fix_reserve_counts(struct inode *inode); +@@ -455,12 +453,6 @@ static inline int get_hwpoison_hugetlb_f + { + return 0; + } +- +-static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags, +- bool *migratable_cleared) +-{ +- return 0; +-} + + static inline void folio_putback_hugetlb(struct folio *folio) + { +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -3924,8 +3924,6 @@ extern int soft_offline_page(unsigned lo + */ + extern const struct attribute_group memory_failure_attr_group; + extern void memory_failure_queue(unsigned long pfn, int flags); +-extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, +- bool *migratable_cleared); + void num_poisoned_pages_inc(unsigned long pfn); + void num_poisoned_pages_sub(unsigned long pfn, long i); + struct task_struct *task_early_kill(struct task_struct *tsk, int force_early); +@@ -3934,12 +3932,6 @@ static inline void memory_failure_queue( + { + } + +-static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, +- bool *migratable_cleared) +-{ +- return 0; +-} +- + static inline void num_poisoned_pages_inc(unsigned long pfn) + { + } +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7300,17 +7300,6 @@ int get_hwpoison_hugetlb_folio(struct fo + return ret; + } + +-int get_huge_page_for_hwpoison(unsigned long pfn, int flags, +- bool *migratable_cleared) +-{ +- int ret; +- +- spin_lock_irq(&hugetlb_lock); +- ret = __get_huge_page_for_hwpoison(pfn, flags, migratable_cleared); +- spin_unlock_irq(&hugetlb_lock); +- return ret; +-} +- + /** + * folio_putback_hugetlb - unisolate a hugetlb folio + * @folio: the isolated hugetlb folio +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1994,20 +1994,19 @@ void folio_clear_hugetlb_hwpoison(struct + folio_free_raw_hwp(folio, true); + } + +-/* +- * Called from hugetlb code with hugetlb_lock held. +- */ +-int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, ++static int get_huge_page_for_hwpoison(unsigned long pfn, int flags, + bool *migratable_cleared) + { + struct page *page = pfn_to_page(pfn); +- struct folio *folio = page_folio(page); ++ struct folio *folio; + bool count_increased = false; + int ret, rc; + ++ spin_lock_irq(&hugetlb_lock); ++ folio = page_folio(page); + if (!folio_test_hugetlb(folio)) { + ret = MF_HUGETLB_NON_HUGEPAGE; +- goto out; ++ goto out_unlock; + } else if (flags & MF_COUNT_INCREASED) { + ret = MF_HUGETLB_IN_USED; + count_increased = true; +@@ -2023,13 +2022,13 @@ int __get_huge_page_for_hwpoison(unsigne + } else { + ret = MF_HUGETLB_RETRY; + if (!(flags & MF_NO_RETRY)) +- goto out; ++ goto out_unlock; + } + + rc = hugetlb_update_hwpoison(folio, page); + if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) { + ret = rc; +- goto out; ++ goto out_unlock; + } + + /* +@@ -2041,8 +2040,10 @@ int __get_huge_page_for_hwpoison(unsigne + *migratable_cleared = true; + } + ++ spin_unlock_irq(&hugetlb_lock); + return ret; +-out: ++out_unlock: ++ spin_unlock_irq(&hugetlb_lock); + if (count_increased) + folio_put(folio); + return ret; diff --git a/queue-6.6/mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch b/queue-6.6/mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch new file mode 100644 index 0000000000..2656f0cba3 --- /dev/null +++ b/queue-6.6/mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch @@ -0,0 +1,212 @@ +From stable+bounces-263331-greg=kroah.com@vger.kernel.org Mon Jun 15 21:12:57 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 11:39:02 -0400 +Subject: mm/memory-failure: fix missing ->mf_stats count in hugetlb poison +To: stable@vger.kernel.org +Cc: Jane Chu , Miaohe Lin , Chris Mason , David Hildenbrand , David Rientjes , Jiaqi Yan , "Liam R. Howlett" , Lorenzo Stoakes , "Matthew Wilcox (Oracle)" , Michal Hocko , Mike Rapoport , Muchun Song , Naoya Horiguchi , Oscar Salvador , Suren Baghdasaryan , William Roche , Andrew Morton , Sasha Levin +Message-ID: <20260615153903.2214102-4-sashal@kernel.org> + +From: Jane Chu + +[ Upstream commit a148a2040191b12b45b82cb29c281cb3036baf90 ] + +When a newly poisoned subpage ends up in an already poisoned hugetlb +folio, 'num_poisoned_pages' is incremented, but the per node ->mf_stats is +not. Fix the inconsistency by designating action_result() to update them +both. + +While at it, define __get_huge_page_for_hwpoison() return values in terms +of symbol names for better readibility. Also rename +folio_set_hugetlb_hwpoison() to hugetlb_update_hwpoison() since the +function does more than the conventional bit setting and the fact three +possible return values are expected. + +Link: https://lkml.kernel.org/r/20260120232234.3462258-1-jane.chu@oracle.com +Fixes: 18f41fa616ee ("mm: memory-failure: bump memory failure stats to pglist_data") +Signed-off-by: Jane Chu +Acked-by: Miaohe Lin +Cc: Chris Mason +Cc: David Hildenbrand +Cc: David Rientjes +Cc: Jiaqi Yan +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Matthew Wilcox (Oracle) +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Naoya Horiguchi +Cc: Oscar Salvador +Cc: Suren Baghdasaryan +Cc: William Roche +Cc: +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory-failure.c | 73 ++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 46 insertions(+), 27 deletions(-) + +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1912,12 +1912,22 @@ static unsigned long __folio_free_raw_hw + return count; + } + +-static int folio_set_hugetlb_hwpoison(struct folio *folio, struct page *page) ++#define MF_HUGETLB_FREED 0 /* freed hugepage */ ++#define MF_HUGETLB_IN_USED 1 /* in-use hugepage */ ++#define MF_HUGETLB_NON_HUGEPAGE 2 /* not a hugepage */ ++#define MF_HUGETLB_FOLIO_PRE_POISONED 3 /* folio already poisoned */ ++#define MF_HUGETLB_PAGE_PRE_POISONED 4 /* exact page already poisoned */ ++#define MF_HUGETLB_RETRY 5 /* hugepage is busy, retry */ ++/* ++ * Set hugetlb folio as hwpoisoned, update folio private raw hwpoison list ++ * to keep track of the poisoned pages. ++ */ ++static int hugetlb_update_hwpoison(struct folio *folio, struct page *page) + { + struct llist_head *head; + struct raw_hwp_page *raw_hwp; + struct raw_hwp_page *p, *next; +- int ret = folio_test_set_hwpoison(folio) ? -EHWPOISON : 0; ++ int ret = folio_test_set_hwpoison(folio) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0; + + /* + * Once the hwpoison hugepage has lost reliable raw error info, +@@ -1925,11 +1935,11 @@ static int folio_set_hugetlb_hwpoison(st + * so skip to add additional raw error info. + */ + if (folio_test_hugetlb_raw_hwp_unreliable(folio)) +- return -EHWPOISON; ++ return MF_HUGETLB_FOLIO_PRE_POISONED; + head = raw_hwp_list_head(folio); + llist_for_each_entry_safe(p, next, head->first, node) { + if (p->page == page) +- return -EHWPOISON; ++ return MF_HUGETLB_PAGE_PRE_POISONED; + } + + raw_hwp = kmalloc(sizeof(struct raw_hwp_page), GFP_ATOMIC); +@@ -1986,42 +1996,39 @@ void folio_clear_hugetlb_hwpoison(struct + + /* + * Called from hugetlb code with hugetlb_lock held. +- * +- * Return values: +- * 0 - free hugepage +- * 1 - in-use hugepage +- * 2 - not a hugepage +- * -EBUSY - the hugepage is busy (try to retry) +- * -EHWPOISON - the hugepage is already hwpoisoned + */ + int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, + bool *migratable_cleared) + { + struct page *page = pfn_to_page(pfn); + struct folio *folio = page_folio(page); +- int ret = 2; /* fallback to normal page handling */ + bool count_increased = false; ++ int ret, rc; + +- if (!folio_test_hugetlb(folio)) ++ if (!folio_test_hugetlb(folio)) { ++ ret = MF_HUGETLB_NON_HUGEPAGE; + goto out; +- +- if (flags & MF_COUNT_INCREASED) { +- ret = 1; ++ } else if (flags & MF_COUNT_INCREASED) { ++ ret = MF_HUGETLB_IN_USED; + count_increased = true; + } else if (folio_test_hugetlb_freed(folio)) { +- ret = 0; ++ ret = MF_HUGETLB_FREED; + } else if (folio_test_hugetlb_migratable(folio)) { +- ret = folio_try_get(folio); +- if (ret) ++ if (folio_try_get(folio)) { ++ ret = MF_HUGETLB_IN_USED; + count_increased = true; ++ } else { ++ ret = MF_HUGETLB_FREED; ++ } + } else { +- ret = -EBUSY; ++ ret = MF_HUGETLB_RETRY; + if (!(flags & MF_NO_RETRY)) + goto out; + } + +- if (folio_set_hugetlb_hwpoison(folio, page)) { +- ret = -EHWPOISON; ++ rc = hugetlb_update_hwpoison(folio, page); ++ if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) { ++ ret = rc; + goto out; + } + +@@ -2046,6 +2053,12 @@ out: + * with basic operations like hugepage allocation/free/demotion. + * So some of prechecks for hwpoison (pinning, and testing/setting + * PageHWPoison) should be done in single hugetlb_lock range. ++ * Returns: ++ * 0 - not hugetlb, or recovered ++ * -EBUSY - not recovered ++ * -EOPNOTSUPP - hwpoison_filter'ed ++ * -EHWPOISON - folio or exact page already poisoned ++ * -EFAULT - kill_accessing_process finds current->mm null + */ + static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb) + { +@@ -2058,22 +2071,28 @@ static int try_memory_failure_hugetlb(un + *hugetlb = 1; + retry: + res = get_huge_page_for_hwpoison(pfn, flags, &migratable_cleared); +- if (res == 2) { /* fallback to normal page handling */ ++ switch (res) { ++ case MF_HUGETLB_NON_HUGEPAGE: /* fallback to normal page handling */ + *hugetlb = 0; + return 0; +- } else if (res == -EHWPOISON) { ++ case MF_HUGETLB_FOLIO_PRE_POISONED: ++ case MF_HUGETLB_PAGE_PRE_POISONED: + pr_err("%#lx: already hardware poisoned\n", pfn); ++ res = -EHWPOISON; + if (flags & MF_ACTION_REQUIRED) { + folio = page_folio(p); + res = kill_accessing_process(current, folio_pfn(folio), flags); + } + return res; +- } else if (res == -EBUSY) { ++ case MF_HUGETLB_RETRY: + if (!(flags & MF_NO_RETRY)) { + flags |= MF_NO_RETRY; + goto retry; + } + return action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED); ++ default: ++ WARN_ON((res != MF_HUGETLB_FREED) && (res != MF_HUGETLB_IN_USED)); ++ break; + } + + folio = page_folio(p); +@@ -2084,7 +2103,7 @@ retry: + if (migratable_cleared) + folio_set_hugetlb_migratable(folio); + folio_unlock(folio); +- if (res == 1) ++ if (res == MF_HUGETLB_IN_USED) + folio_put(folio); + return -EOPNOTSUPP; + } +@@ -2093,7 +2112,7 @@ retry: + * Handling free hugepage. The possible race with hugepage allocation + * or demotion can be prevented by PageHWPoison flag. + */ +- if (res == 0) { ++ if (res == MF_HUGETLB_FREED) { + folio_unlock(folio); + if (__page_handle_poison(p) > 0) { + page_ref_inc(p); diff --git a/queue-6.6/mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch b/queue-6.6/mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch new file mode 100644 index 0000000000..93f9bf3f35 --- /dev/null +++ b/queue-6.6/mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch @@ -0,0 +1,83 @@ +From stable+bounces-263329-greg=kroah.com@vger.kernel.org Mon Jun 15 21:12:46 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 11:39:00 -0400 +Subject: mm/migrate: don't call folio_putback_active_hugetlb() on dst hugetlb folio +To: stable@vger.kernel.org +Cc: David Hildenbrand , Baolin Wang , "Matthew Wilcox (Oracle)" , Muchun Song , Sidhartha Kumar , Andrew Morton , Sasha Levin +Message-ID: <20260615153903.2214102-2-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit ba23f58de896842028b4b33b95530f08288396fe ] + +We replaced a simple put_page() by a putback_active_hugepage() call in +commit 3aaa76e125c1 ("mm: migrate: hugetlb: putback destination hugepage +to active list"), to set the "active" flag on the dst hugetlb folio. + +Nowadays, we decoupled the "active" list from the flag, by calling the +flag "migratable". + +Calling "putback" on something that wasn't allocated is weird and not +future proof, especially if we might reach that path when migration failed +and we just want to free the freshly allocated hugetlb folio. + +Let's simply handle the migratable flag and the active list flag in +move_hugetlb_state(), where we know that allocation succeeded and already +handle the temporary flag; use a simple folio_put() to return our +reference. + +Link: https://lkml.kernel.org/r/20250113131611.2554758-4-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Baolin Wang +Cc: Matthew Wilcox (Oracle) +Cc: Muchun Song +Cc: Sidhartha Kumar +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/hugetlb.c | 10 ++++++++++ + mm/migrate.c | 8 ++++---- + 2 files changed, 14 insertions(+), 4 deletions(-) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7358,6 +7358,16 @@ void move_hugetlb_state(struct folio *ol + } + spin_unlock_irq(&hugetlb_lock); + } ++ ++ /* ++ * Our old folio is isolated and has "migratable" cleared until it ++ * is putback. As migration succeeded, set the new folio "migratable" ++ * and add it to the active list. ++ */ ++ spin_lock_irq(&hugetlb_lock); ++ folio_set_hugetlb_migratable(new_folio); ++ list_move_tail(&new_folio->lru, &(folio_hstate(new_folio))->hugepage_activelist); ++ spin_unlock_irq(&hugetlb_lock); + } + + /* +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -1461,14 +1461,14 @@ out: + list_move_tail(&src->lru, ret); + + /* +- * If migration was not successful and there's a freeing callback, use +- * it. Otherwise, put_page() will drop the reference grabbed during +- * isolation. ++ * If migration was not successful and there's a freeing callback, ++ * return the folio to that special allocator. Otherwise, simply drop ++ * our additional reference. + */ + if (put_new_folio) + put_new_folio(dst, private); + else +- folio_putback_active_hugetlb(dst); ++ folio_put(dst); + + return rc; + } diff --git a/queue-6.6/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch b/queue-6.6/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch new file mode 100644 index 0000000000..13fc12d7f3 --- /dev/null +++ b/queue-6.6/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch @@ -0,0 +1,86 @@ +From stable+bounces-263293-greg=kroah.com@vger.kernel.org Mon Jun 15 20:52:22 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 11:16:35 -0400 +Subject: netfilter: nft_fib: fix stale stack leak via the OIFNAME register +To: stable@vger.kernel.org +Cc: Davide Ornaghi , Florian Westphal , Pablo Neira Ayuso , Sasha Levin +Message-ID: <20260615151635.2204309-1-sashal@kernel.org> + +From: Davide Ornaghi + +[ Upstream commit ab185e0c4fb82dfba6fb86f8271e06f931d9c64c ] + +For NFT_FIB_RESULT_OIFNAME the destination register is declared with +len = IFNAMSIZ (four 32-bit registers), but on the lookup-fail, +RTN_LOCAL and oif-mismatch paths nft_fib{4,6}_eval() only writes one +register via "*dest = 0". The remaining three registers are left as +whatever was on the stack in nft_do_chain()'s struct nft_regs, and a +downstream expression that loads the register span can leak that +uninitialised kernel stack to userspace. + +The NFTA_FIB_F_PRESENT existence check has the same shape: it is only +meaningful for NFT_FIB_RESULT_OIF, yet it was accepted for any result type +while the eval stores a single byte via nft_reg_store8(), leaving the rest +of the declared span stale. + +Fix both: + + - replace the bare "*dest = 0" in the eval with nft_fib_store_result(), + which strscpy_pad()s the whole IFNAMSIZ for OIFNAME (and is already + used on the other early-return path), and + + - restrict NFTA_FIB_F_PRESENT to NFT_FIB_RESULT_OIF and declare its + destination as a single u8, so the marked span matches the one byte + the eval writes. + +Fixes: f6d0cbcf09c5 ("netfilter: nf_tables: add fib expression") +Suggested-by: Florian Westphal +Cc: stable@vger.kernel.org +Signed-off-by: Davide Ornaghi +Signed-off-by: Pablo Neira Ayuso +[ kept the tree's existing `ip6_route_lookup`/`rt6_info` machinery (missing `fib6_lookup` refactor) and changed only `*dest = 0;` to `nft_fib_store_result(dest, priv, NULL)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/netfilter/nft_fib_ipv4.c | 2 +- + net/ipv6/netfilter/nft_fib_ipv6.c | 2 +- + net/netfilter/nft_fib.c | 6 ++++++ + 3 files changed, 8 insertions(+), 2 deletions(-) + +--- a/net/ipv4/netfilter/nft_fib_ipv4.c ++++ b/net/ipv4/netfilter/nft_fib_ipv4.c +@@ -122,7 +122,7 @@ void nft_fib4_eval(const struct nft_expr + fl4.saddr = get_saddr(iph->daddr); + } + +- *dest = 0; ++ nft_fib_store_result(dest, priv, NULL); + + if (fib_lookup(nft_net(pkt), &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE)) + return; +--- a/net/ipv6/netfilter/nft_fib_ipv6.c ++++ b/net/ipv6/netfilter/nft_fib_ipv6.c +@@ -193,7 +193,7 @@ void nft_fib6_eval(const struct nft_expr + } + } + +- *dest = 0; ++ nft_fib_store_result(dest, priv, NULL); + rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb, + lookup_flags); + if (rt->dst.error) +--- a/net/netfilter/nft_fib.c ++++ b/net/netfilter/nft_fib.c +@@ -107,6 +107,12 @@ int nft_fib_init(const struct nft_ctx *c + return -EINVAL; + } + ++ if (priv->flags & NFTA_FIB_F_PRESENT) { ++ if (priv->result != NFT_FIB_RESULT_OIF) ++ return -EINVAL; ++ len = sizeof(u8); ++ } ++ + err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg, + NULL, NFT_DATA_VALUE, len); + if (err < 0) diff --git a/queue-6.6/rdma-during-rereg_mr-ensure-that-rereg_access-is-compatible.patch b/queue-6.6/rdma-during-rereg_mr-ensure-that-rereg_access-is-compatible.patch new file mode 100644 index 0000000000..dad16c0677 --- /dev/null +++ b/queue-6.6/rdma-during-rereg_mr-ensure-that-rereg_access-is-compatible.patch @@ -0,0 +1,157 @@ +From stable+bounces-263480-greg=kroah.com@vger.kernel.org Tue Jun 16 04:24:12 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 18:52:07 -0400 +Subject: RDMA: During rereg_mr ensure that REREG_ACCESS is compatible +To: stable@vger.kernel.org +Cc: Jason Gunthorpe , Philip Tsukerman , Sasha Levin +Message-ID: <20260615225207.2520056-1-sashal@kernel.org> + +From: Jason Gunthorpe + +[ Upstream commit badad6fad60def1b9805559dd81dbab3d97b82aa ] + +If IB_MR_REREG_ACCESS changes from RO to RW then the umem has to be +re-evaluated to ensure it is properly pinned as RW. Since the umem is +hidden inside each driver's mr struct add a ib_umem_check_rereg() function +that each driver has to call before processing IB_MR_REREG_ACCESS. + +mlx4 has to retain its duplicate ib_access_writable check because it +implements IB_MR_REREG_ACCESS | IB_MR_REREG_TRANS by changing both items +in place sequentially while the MR is live, so it will continue to not +support this combination. + +Cc: stable@vger.kernel.org +Fixes: b40656aa7d55 ("RDMA/umem: remove FOLL_FORCE usage") +Link: https://patch.msgid.link/r/0-v1-06fb1a2d6cf5+107-rereg_access_jgg@nvidia.com +Reported-by: Philip Tsukerman +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/umem.c | 16 ++++++++++++++++ + drivers/infiniband/hw/hns/hns_roce_mr.c | 4 ++++ + drivers/infiniband/hw/irdma/verbs.c | 4 ++++ + drivers/infiniband/hw/mlx4/mr.c | 4 ++++ + drivers/infiniband/hw/mlx5/mr.c | 4 ++++ + drivers/infiniband/sw/rxe/rxe_verbs.c | 5 +++++ + include/rdma/ib_umem.h | 8 ++++++++ + 7 files changed, 45 insertions(+) + +--- a/drivers/infiniband/core/umem.c ++++ b/drivers/infiniband/core/umem.c +@@ -326,3 +326,19 @@ int ib_umem_copy_from(void *dst, struct + return 0; + } + EXPORT_SYMBOL(ib_umem_copy_from); ++ ++/* ++ * Called during rereg mr if the driver is able to re-use a umem for ++ * IB_MR_REREG_ACCESS. ++ */ ++int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags) ++{ ++ if (!umem) ++ return 0; ++ ++ if ((flags & IB_MR_REREG_ACCESS) && !(flags & IB_MR_REREG_TRANS)) ++ if (ib_access_writable(new_access_flags) && !umem->writable) ++ return -EACCES; ++ return 0; ++} ++EXPORT_SYMBOL(ib_umem_check_rereg); +--- a/drivers/infiniband/hw/hns/hns_roce_mr.c ++++ b/drivers/infiniband/hw/hns/hns_roce_mr.c +@@ -277,6 +277,10 @@ struct ib_mr *hns_roce_rereg_user_mr(str + if (!mr->enabled) + return ERR_PTR(-EINVAL); + ++ ret = ib_umem_check_rereg(mr->pbl_mtr.umem, flags, mr_access_flags); ++ if (ret) ++ return ERR_PTR(ret); ++ + mailbox = hns_roce_alloc_cmd_mailbox(hr_dev); + if (IS_ERR(mailbox)) + return ERR_CAST(mailbox); +--- a/drivers/infiniband/hw/irdma/verbs.c ++++ b/drivers/infiniband/hw/irdma/verbs.c +@@ -3244,6 +3244,10 @@ static struct ib_mr *irdma_rereg_user_mr + if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) + return ERR_PTR(-EOPNOTSUPP); + ++ ret = ib_umem_check_rereg(iwmr->region, flags, new_access); ++ if (ret) ++ return ERR_PTR(ret); ++ + ret = irdma_hwdereg_mr(ib_mr); + if (ret) + return ERR_PTR(ret); +--- a/drivers/infiniband/hw/mlx4/mr.c ++++ b/drivers/infiniband/hw/mlx4/mr.c +@@ -466,6 +466,10 @@ struct ib_mr *mlx4_ib_rereg_user_mr(stru + struct mlx4_mpt_entry **pmpt_entry = &mpt_entry; + int err; + ++ err = ib_umem_check_rereg(mmr->umem, flags, mr_access_flags); ++ if (err) ++ return ERR_PTR(err); ++ + /* Since we synchronize this call and mlx4_ib_dereg_mr via uverbs, + * we assume that the calls can't run concurrently. Otherwise, a + * race exists. +--- a/drivers/infiniband/hw/mlx5/mr.c ++++ b/drivers/infiniband/hw/mlx5/mr.c +@@ -1698,6 +1698,10 @@ struct ib_mr *mlx5_ib_rereg_user_mr(stru + if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) + return ERR_PTR(-EOPNOTSUPP); + ++ err = ib_umem_check_rereg(mr->umem, flags, new_access_flags); ++ if (err) ++ return ERR_PTR(err); ++ + if (!(flags & IB_MR_REREG_ACCESS)) + new_access_flags = mr->access_flags; + if (!(flags & IB_MR_REREG_PD)) +--- a/drivers/infiniband/sw/rxe/rxe_verbs.c ++++ b/drivers/infiniband/sw/rxe/rxe_verbs.c +@@ -1316,6 +1316,7 @@ static struct ib_mr *rxe_rereg_user_mr(s + struct rxe_mr *mr = to_rmr(ibmr); + struct rxe_pd *old_pd = to_rpd(ibmr->pd); + struct rxe_pd *pd = to_rpd(ibpd); ++ int err; + + /* for now only support the two easy cases: + * rereg_pd and rereg_access +@@ -1325,6 +1326,10 @@ static struct ib_mr *rxe_rereg_user_mr(s + return ERR_PTR(-EOPNOTSUPP); + } + ++ err = ib_umem_check_rereg(mr->umem, flags, access); ++ if (err) ++ return ERR_PTR(err); ++ + if (flags & IB_MR_REREG_PD) { + rxe_put(old_pd); + rxe_get(pd); +--- a/include/rdma/ib_umem.h ++++ b/include/rdma/ib_umem.h +@@ -154,6 +154,8 @@ int ib_umem_dmabuf_map_pages(struct ib_u + void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf); + void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf); + ++int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags); ++ + #else /* CONFIG_INFINIBAND_USER_MEM */ + + #include +@@ -203,5 +205,11 @@ static inline int ib_umem_dmabuf_map_pag + static inline void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf) { } + static inline void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf) { } + ++static inline int ib_umem_check_rereg(struct ib_umem *umem, int flags, ++ int new_access_flags) ++{ ++ return -EOPNOTSUPP; ++} ++ + #endif /* CONFIG_INFINIBAND_USER_MEM */ + #endif /* IB_UMEM_H */ diff --git a/queue-6.6/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch b/queue-6.6/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch new file mode 100644 index 0000000000..80545b92e1 --- /dev/null +++ b/queue-6.6/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch @@ -0,0 +1,509 @@ +From stable+bounces-263489-greg=kroah.com@vger.kernel.org Tue Jun 16 05:29:08 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 19:58:47 -0400 +Subject: RDMA: Move DMA block iterator logic into dedicated files +To: stable@vger.kernel.org +Cc: Leon Romanovsky , Sasha Levin +Message-ID: <20260615235848.2562462-2-sashal@kernel.org> + +From: Leon Romanovsky + +[ Upstream commit 6094ea64c69520ed1e770e7c79c43412de202bfa ] + +The DMA iterator logic was mixed into verbs and umem-specific code, +forcing all users to include rdma/ib_umem.h. Move the block iterator +logic into iter.c and rdma/iter.h so that rdma/ib_umem.h and +rdma/ib_verbs.h can be separated in a follow-up patch. + +Link: https://patch.msgid.link/20260213-refactor-umem-v1-1-f3be85847922@nvidia.com +Signed-off-by: Leon Romanovsky +Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/Makefile | 2 + drivers/infiniband/core/iter.c | 43 +++++++++++++ + drivers/infiniband/core/verbs.c | 38 ----------- + drivers/infiniband/hw/bnxt_re/qplib_res.c | 2 + drivers/infiniband/hw/cxgb4/mem.c | 2 + drivers/infiniband/hw/efa/efa_verbs.c | 2 + drivers/infiniband/hw/erdma/erdma_verbs.c | 2 + drivers/infiniband/hw/hns/hns_roce_alloc.c | 2 + drivers/infiniband/hw/irdma/main.h | 2 + drivers/infiniband/hw/mana/mana_ib.h | 2 + drivers/infiniband/hw/mlx4/mr.c | 1 + drivers/infiniband/hw/mlx5/mem.c | 1 + drivers/infiniband/hw/mlx5/umr.c | 1 + drivers/infiniband/hw/mthca/mthca_provider.c | 2 + drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 + drivers/infiniband/hw/qedr/verbs.c | 2 + drivers/infiniband/hw/vmw_pvrdma/pvrdma.h | 2 + include/rdma/ib_umem.h | 32 --------- + include/rdma/ib_verbs.h | 48 -------------- + include/rdma/iter.h | 88 +++++++++++++++++++++++++++ + 20 files changed, 146 insertions(+), 130 deletions(-) + create mode 100644 drivers/infiniband/core/iter.c + create mode 100644 include/rdma/iter.h + +--- a/drivers/infiniband/core/Makefile ++++ b/drivers/infiniband/core/Makefile +@@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verb + roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \ + multicast.o mad.o smi.o agent.o mad_rmpp.o \ + nldev.o restrack.o counters.o ib_core_uverbs.o \ +- trace.o lag.o ++ trace.o lag.o iter.o + + ib_core-$(CONFIG_SECURITY_INFINIBAND) += security.o + ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o +--- /dev/null ++++ b/drivers/infiniband/core/iter.c +@@ -0,0 +1,43 @@ ++// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB ++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */ ++ ++#include ++#include ++ ++void __rdma_block_iter_start(struct ib_block_iter *biter, ++ struct scatterlist *sglist, unsigned int nents, ++ unsigned long pgsz) ++{ ++ memset(biter, 0, sizeof(struct ib_block_iter)); ++ biter->__sg = sglist; ++ biter->__sg_nents = nents; ++ ++ /* Driver provides best block size to use */ ++ biter->__pg_bit = __fls(pgsz); ++} ++EXPORT_SYMBOL(__rdma_block_iter_start); ++ ++bool __rdma_block_iter_next(struct ib_block_iter *biter) ++{ ++ unsigned int block_offset; ++ unsigned int delta; ++ ++ if (!biter->__sg_nents || !biter->__sg) ++ return false; ++ ++ biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; ++ block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); ++ delta = BIT_ULL(biter->__pg_bit) - block_offset; ++ ++ while (biter->__sg_nents && biter->__sg && ++ sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) { ++ delta -= sg_dma_len(biter->__sg) - biter->__sg_advance; ++ biter->__sg_advance = 0; ++ biter->__sg = sg_next(biter->__sg); ++ biter->__sg_nents--; ++ } ++ biter->__sg_advance += delta; ++ ++ return true; ++} ++EXPORT_SYMBOL(__rdma_block_iter_next); +--- a/drivers/infiniband/core/verbs.c ++++ b/drivers/infiniband/core/verbs.c +@@ -3013,44 +3013,6 @@ int rdma_init_netdev(struct ib_device *d + } + EXPORT_SYMBOL(rdma_init_netdev); + +-void __rdma_block_iter_start(struct ib_block_iter *biter, +- struct scatterlist *sglist, unsigned int nents, +- unsigned long pgsz) +-{ +- memset(biter, 0, sizeof(struct ib_block_iter)); +- biter->__sg = sglist; +- biter->__sg_nents = nents; +- +- /* Driver provides best block size to use */ +- biter->__pg_bit = __fls(pgsz); +-} +-EXPORT_SYMBOL(__rdma_block_iter_start); +- +-bool __rdma_block_iter_next(struct ib_block_iter *biter) +-{ +- unsigned int block_offset; +- unsigned int delta; +- +- if (!biter->__sg_nents || !biter->__sg) +- return false; +- +- biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; +- block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); +- delta = BIT_ULL(biter->__pg_bit) - block_offset; +- +- while (biter->__sg_nents && biter->__sg && +- sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) { +- delta -= sg_dma_len(biter->__sg) - biter->__sg_advance; +- biter->__sg_advance = 0; +- biter->__sg = sg_next(biter->__sg); +- biter->__sg_nents--; +- } +- biter->__sg_advance += delta; +- +- return true; +-} +-EXPORT_SYMBOL(__rdma_block_iter_next); +- + /** + * rdma_alloc_hw_stats_struct - Helper function to allocate dynamic struct + * for the drivers. +--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c +@@ -46,7 +46,7 @@ + #include + #include + #include +-#include ++#include + + #include "roce_hsi.h" + #include "qplib_res.h" +--- a/drivers/infiniband/hw/cxgb4/mem.c ++++ b/drivers/infiniband/hw/cxgb4/mem.c +@@ -32,9 +32,9 @@ + + #include + #include +-#include + #include + #include ++#include + + #include "iw_cxgb4.h" + +--- a/drivers/infiniband/hw/efa/efa_verbs.c ++++ b/drivers/infiniband/hw/efa/efa_verbs.c +@@ -9,9 +9,9 @@ + #include + + #include +-#include + #include + #include ++#include + #include + + #include "efa.h" +--- a/drivers/infiniband/hw/erdma/erdma_verbs.c ++++ b/drivers/infiniband/hw/erdma/erdma_verbs.c +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + #include + + #include "erdma.h" +--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c ++++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c +@@ -32,7 +32,7 @@ + */ + + #include +-#include ++#include + #include "hns_roce_device.h" + + void hns_roce_buf_free(struct hns_roce_dev *hr_dev, struct hns_roce_buf *buf) +--- a/drivers/infiniband/hw/irdma/main.h ++++ b/drivers/infiniband/hw/irdma/main.h +@@ -37,8 +37,8 @@ + #include + #include + #include +-#include + #include ++#include + #include + #include "osdep.h" + #include "defs.h" +--- a/drivers/infiniband/hw/mana/mana_ib.h ++++ b/drivers/infiniband/hw/mana/mana_ib.h +@@ -8,7 +8,7 @@ + + #include + #include +-#include ++#include + #include + #include + +--- a/drivers/infiniband/hw/mlx4/mr.c ++++ b/drivers/infiniband/hw/mlx4/mr.c +@@ -33,6 +33,7 @@ + + #include + #include ++#include + + #include "mlx4_ib.h" + +--- a/drivers/infiniband/hw/mlx5/mem.c ++++ b/drivers/infiniband/hw/mlx5/mem.c +@@ -32,6 +32,7 @@ + + #include + #include ++#include + #include "mlx5_ib.h" + #include + +--- a/drivers/infiniband/hw/mlx5/umr.c ++++ b/drivers/infiniband/hw/mlx5/umr.c +@@ -2,6 +2,7 @@ + /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */ + + #include ++#include + #include "mlx5_ib.h" + #include "umr.h" + #include "wr.h" +--- a/drivers/infiniband/hw/mthca/mthca_provider.c ++++ b/drivers/infiniband/hw/mthca/mthca_provider.c +@@ -35,8 +35,8 @@ + */ + + #include +-#include + #include ++#include + #include + + #include +--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c ++++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +@@ -45,9 +45,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + #include "ocrdma.h" +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -39,9 +39,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + #include +--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h ++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h +@@ -53,8 +53,8 @@ + #include + #include + #include +-#include + #include ++#include + #include + + #include "pvrdma_ring.h" +--- a/include/rdma/ib_umem.h ++++ b/include/rdma/ib_umem.h +@@ -70,38 +70,6 @@ static inline size_t ib_umem_num_pages(s + { + return ib_umem_num_dma_blocks(umem, PAGE_SIZE); + } +- +-static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter, +- struct ib_umem *umem, +- unsigned long pgsz) +-{ +- __rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl, +- umem->sgt_append.sgt.nents, pgsz); +- biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1); +- biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz); +-} +- +-static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter) +-{ +- return __rdma_block_iter_next(biter) && biter->__sg_numblocks--; +-} +- +-/** +- * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem +- * @umem: umem to iterate over +- * @biter: block iterator variable +- * @pgsz: Page size to split the list into +- * +- * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The +- * returned DMA blocks will be aligned to pgsz and span the range: +- * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz) +- * +- * Performs exactly ib_umem_num_dma_blocks() iterations. +- */ +-#define rdma_umem_for_each_dma_block(umem, biter, pgsz) \ +- for (__rdma_umem_block_iter_start(biter, umem, pgsz); \ +- __rdma_umem_block_iter_next(biter);) +- + #ifdef CONFIG_INFINIBAND_USER_MEM + + struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr, +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -2839,22 +2839,6 @@ struct ib_client { + u8 no_kverbs_req:1; + }; + +-/* +- * IB block DMA iterator +- * +- * Iterates the DMA-mapped SGL in contiguous memory blocks aligned +- * to a HW supported page size. +- */ +-struct ib_block_iter { +- /* internal states */ +- struct scatterlist *__sg; /* sg holding the current aligned block */ +- dma_addr_t __dma_addr; /* unaligned DMA address of this block */ +- size_t __sg_numblocks; /* ib_umem_num_dma_blocks() */ +- unsigned int __sg_nents; /* number of SG entries */ +- unsigned int __sg_advance; /* number of bytes to advance in sg in next step */ +- unsigned int __pg_bit; /* alignment of current block */ +-}; +- + struct ib_device *_ib_alloc_device(size_t size); + #define ib_alloc_device(drv_struct, member) \ + container_of(_ib_alloc_device(sizeof(struct drv_struct) + \ +@@ -2876,38 +2860,6 @@ void ib_unregister_device_queued(struct + int ib_register_client (struct ib_client *client); + void ib_unregister_client(struct ib_client *client); + +-void __rdma_block_iter_start(struct ib_block_iter *biter, +- struct scatterlist *sglist, +- unsigned int nents, +- unsigned long pgsz); +-bool __rdma_block_iter_next(struct ib_block_iter *biter); +- +-/** +- * rdma_block_iter_dma_address - get the aligned dma address of the current +- * block held by the block iterator. +- * @biter: block iterator holding the memory block +- */ +-static inline dma_addr_t +-rdma_block_iter_dma_address(struct ib_block_iter *biter) +-{ +- return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1); +-} +- +-/** +- * rdma_for_each_block - iterate over contiguous memory blocks of the sg list +- * @sglist: sglist to iterate over +- * @biter: block iterator holding the memory block +- * @nents: maximum number of sg entries to iterate over +- * @pgsz: best HW supported page size to use +- * +- * Callers may use rdma_block_iter_dma_address() to get each +- * blocks aligned DMA address. +- */ +-#define rdma_for_each_block(sglist, biter, nents, pgsz) \ +- for (__rdma_block_iter_start(biter, sglist, nents, \ +- pgsz); \ +- __rdma_block_iter_next(biter);) +- + /** + * ib_get_client_data - Get IB client context + * @device:Device to get context for +--- /dev/null ++++ b/include/rdma/iter.h +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ ++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */ ++ ++#ifndef _RDMA_ITER_H_ ++#define _RDMA_ITER_H_ ++ ++#include ++#include ++ ++/** ++ * IB block DMA iterator ++ * ++ * Iterates the DMA-mapped SGL in contiguous memory blocks aligned ++ * to a HW supported page size. ++ */ ++struct ib_block_iter { ++ /* internal states */ ++ struct scatterlist *__sg; /* sg holding the current aligned block */ ++ dma_addr_t __dma_addr; /* unaligned DMA address of this block */ ++ size_t __sg_numblocks; /* ib_umem_num_dma_blocks() */ ++ unsigned int __sg_nents; /* number of SG entries */ ++ unsigned int __sg_advance; /* number of bytes to advance in sg in next step */ ++ unsigned int __pg_bit; /* alignment of current block */ ++}; ++ ++void __rdma_block_iter_start(struct ib_block_iter *biter, ++ struct scatterlist *sglist, ++ unsigned int nents, ++ unsigned long pgsz); ++bool __rdma_block_iter_next(struct ib_block_iter *biter); ++ ++/** ++ * rdma_block_iter_dma_address - get the aligned dma address of the current ++ * block held by the block iterator. ++ * @biter: block iterator holding the memory block ++ */ ++static inline dma_addr_t ++rdma_block_iter_dma_address(struct ib_block_iter *biter) ++{ ++ return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1); ++} ++ ++/** ++ * rdma_for_each_block - iterate over contiguous memory blocks of the sg list ++ * @sglist: sglist to iterate over ++ * @biter: block iterator holding the memory block ++ * @nents: maximum number of sg entries to iterate over ++ * @pgsz: best HW supported page size to use ++ * ++ * Callers may use rdma_block_iter_dma_address() to get each ++ * blocks aligned DMA address. ++ */ ++#define rdma_for_each_block(sglist, biter, nents, pgsz) \ ++ for (__rdma_block_iter_start(biter, sglist, nents, \ ++ pgsz); \ ++ __rdma_block_iter_next(biter);) ++ ++static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter, ++ struct ib_umem *umem, ++ unsigned long pgsz) ++{ ++ __rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl, ++ umem->sgt_append.sgt.nents, pgsz); ++ biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1); ++ biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz); ++} ++ ++static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter) ++{ ++ return __rdma_block_iter_next(biter) && biter->__sg_numblocks--; ++} ++ ++/** ++ * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem ++ * @umem: umem to iterate over ++ * @pgsz: Page size to split the list into ++ * ++ * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The ++ * returned DMA blocks will be aligned to pgsz and span the range: ++ * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz) ++ * ++ * Performs exactly ib_umem_num_dma_blocks() iterations. ++ */ ++#define rdma_umem_for_each_dma_block(umem, biter, pgsz) \ ++ for (__rdma_umem_block_iter_start(biter, umem, pgsz); \ ++ __rdma_umem_block_iter_next(biter);) ++ ++#endif /* _RDMA_ITER_H_ */ diff --git a/queue-6.6/rdma-umem-fix-kernel-doc-warnings.patch b/queue-6.6/rdma-umem-fix-kernel-doc-warnings.patch new file mode 100644 index 0000000000..0156ae6cde --- /dev/null +++ b/queue-6.6/rdma-umem-fix-kernel-doc-warnings.patch @@ -0,0 +1,60 @@ +From stable+bounces-263488-greg=kroah.com@vger.kernel.org Tue Jun 16 05:30:22 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 19:58:46 -0400 +Subject: RDMA/umem: fix kernel-doc warnings +To: stable@vger.kernel.org +Cc: Randy Dunlap , Leon Romanovsky , Sasha Levin +Message-ID: <20260615235848.2562462-1-sashal@kernel.org> + +From: Randy Dunlap + +[ Upstream commit ff46d1392750444fab5ae5a0194764ffdc4ac0d2 ] + +Add or correct kernel-doc comments to eliminate warnings: + +Warning: include/rdma/ib_umem.h:104 function parameter 'biter' not + described in 'rdma_umem_for_each_dma_block' +Warning: include/rdma/ib_umem.h:140 function parameter 'pgsz_bitmap' not + described in 'ib_umem_find_best_pgoff' +Warning: include/rdma/ib_umem.h:141 No description found for return + value of 'ib_umem_find_best_pgoff' + +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260224003120.3173892-1-rdunlap@infradead.org +Signed-off-by: Leon Romanovsky +Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/rdma/ib_umem.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/include/rdma/ib_umem.h ++++ b/include/rdma/ib_umem.h +@@ -89,6 +89,7 @@ static inline bool __rdma_umem_block_ite + /** + * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem + * @umem: umem to iterate over ++ * @biter: block iterator variable + * @pgsz: Page size to split the list into + * + * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The +@@ -116,7 +117,7 @@ unsigned long ib_umem_find_best_pgsz(str + * ib_umem_find_best_pgoff - Find best HW page size + * + * @umem: umem struct +- * @pgsz_bitmap bitmap of HW supported page sizes ++ * @pgsz_bitmap: bitmap of HW supported page sizes + * @pgoff_bitmask: Mask of bits that can be represented with an offset + * + * This is very similar to ib_umem_find_best_pgsz() except instead of accepting +@@ -129,6 +130,9 @@ unsigned long ib_umem_find_best_pgsz(str + * + * If the pgoff_bitmask requires either alignment in the low bit or an + * unavailable page size for the high bits, this function returns 0. ++ * ++ * Returns: best HW page size for the parameters or 0 if none available ++ * for the given parameters. + */ + static inline unsigned long ib_umem_find_best_pgoff(struct ib_umem *umem, + unsigned long pgsz_bitmap, diff --git a/queue-6.6/rdma-umem-fix-truncation-for-block-sizes-4g.patch b/queue-6.6/rdma-umem-fix-truncation-for-block-sizes-4g.patch new file mode 100644 index 0000000000..ddc8e41204 --- /dev/null +++ b/queue-6.6/rdma-umem-fix-truncation-for-block-sizes-4g.patch @@ -0,0 +1,44 @@ +From stable+bounces-263490-greg=kroah.com@vger.kernel.org Tue Jun 16 05:29:08 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 19:58:48 -0400 +Subject: RDMA/umem: Fix truncation for block sizes >= 4G +To: stable@vger.kernel.org +Cc: Jason Gunthorpe , Sasha Levin +Message-ID: <20260615235848.2562462-3-sashal@kernel.org> + +From: Jason Gunthorpe + +[ Upstream commit 15fe76e23615f502d051ef0768f86babaf08746c ] + +When the iommu is used the linearization of the mapping can give a single +block that is very large split across multiple SG entries. + +When __rdma_block_iter_next() reassembles the split SG entries it is +overflowing the 32 bit stack values and computed the wrong DMA addresses +for blocks after the truncation. + +Use the right types to hold DMA addresses. + +Link: https://patch.msgid.link/r/1-v1-88303e9e509f+f7-ib_umem_types_jgg@nvidia.com +Cc: stable@vger.kernel.org +Fixes: a808273a495c ("RDMA/verbs: Add a DMA iterator to return aligned contiguous memory blocks") +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/iter.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/infiniband/core/iter.c ++++ b/drivers/infiniband/core/iter.c +@@ -19,8 +19,8 @@ EXPORT_SYMBOL(__rdma_block_iter_start); + + bool __rdma_block_iter_next(struct ib_block_iter *biter) + { +- unsigned int block_offset; +- unsigned int delta; ++ dma_addr_t block_offset; ++ dma_addr_t delta; + + if (!biter->__sg_nents || !biter->__sg) + return false; diff --git a/queue-6.6/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch b/queue-6.6/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch new file mode 100644 index 0000000000..d77d8e1d5c --- /dev/null +++ b/queue-6.6/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch @@ -0,0 +1,124 @@ +From stable+bounces-260871-greg=kroah.com@vger.kernel.org Sat Jun 6 17:50:24 2026 +From: Sasha Levin +Date: Sat, 6 Jun 2026 08:19:09 -0400 +Subject: scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd() +To: stable@vger.kernel.org +Cc: Michael Bommarito , John Garry , "Martin K. Petersen" , Sasha Levin +Message-ID: <20260606121909.2851630-1-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit 778c2ab142c625a8a8afa570e0f9b7873f445d99 ] + +Two latent bugs in the Text-phase handler, both present since the +original LIO integration in commit e48354ce078c ("iscsi-target: Add +iSCSI fabric support for target v4.1"): + +1) DataDigest CRC buffer overread (4 bytes past text_in). + + text_in is kzalloc()'d at ALIGN(payload_length, 4). rx_size is then + incremented by ISCSI_CRC_LEN to make room for the received DataDigest + in the iovec, but the same (now-bumped) rx_size is passed as the + buffer length to iscsit_crc_buf(): + + if (conn->conn_ops->DataDigest) { + ... + rx_size += ISCSI_CRC_LEN; + } + ... + if (conn->conn_ops->DataDigest) { + data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL); + + iscsit_crc_buf() walks rx_size bytes of text_in with crc32c(), so + when DataDigest is negotiated it reads 4 bytes past the end of the + text_in allocation. KASAN reproduces this directly on the unpatched + mainline tree as slab-out-of-bounds in crc32c() called from the Text + PDU path. The OOB bytes feed crc32c() and are then compared against + the initiator-supplied checksum, so the value does not flow back to + the attacker, but the kernel does read past the buffer on every Text + PDU with DataDigest=CRC32C. + + Fix by passing the actual padded payload length + (ALIGN(payload_length, 4)) that was used for the kzalloc(). + +2) Stale cmd->text_in_ptr re-free (double-free) on ERL>0 bad DataDigest + drop. + + On DataDigest mismatch with ErrorRecoveryLevel > 0 the handler + silently drops the PDU and lets the initiator plug the CmdSN gap: + + kfree(text_in); + return 0; + + cmd->text_in_ptr still points at the freed buffer. The next Text + Request on the same ITT re-enters iscsit_setup_text_cmd(), which + unconditionally does + + kfree(cmd->text_in_ptr); + cmd->text_in_ptr = NULL; + + freeing the same pointer a second time. Session teardown via + iscsit_release_cmd() has the same shape and hits the same double-free + if the connection is dropped before a second Text Request arrives. + + On an unmodified mainline tree the bug-1 CRC overread fires first on + the initial valid Text Request and perturbs the subsequent state, so + #4 was isolated by building a kernel with only the bug-1 hunk of this + patch applied plus temporary printk() observability around the three + relevant kfree() sites. The observability prints are not part of + this patch. On that build, a three-PDU Text Request sequence after + login produces two back-to-back splats: + + BUG: KASAN: double-free in iscsit_setup_text_cmd+0x?? + BUG: KASAN: double-free in iscsit_release_cmd+0x?? + + showing the same pointer freed in the ERL>0 drop path and again in + iscsit_setup_text_cmd() (next Text Request on the same ITT) and once + more in iscsit_release_cmd() (session teardown). On distro kernels + with CONFIG_SLAB_FREELIST_HARDENED=y (default) the double-free + becomes a remote kernel BUG(); on non-hardened kernels it corrupts + the slab freelist. + + Fix by clearing cmd->text_in_ptr after the kfree() in the ERL>0 drop + path. With both hunks applied #4 is directly observable on the stock + tree without observability printks; fixing bug-1 alone would mask #4 + less, not more, so the hunks are submitted together. + +Both fixes are one-liners. The Text PDU state machine is unchanged and +the wire protocol is unaffected. + +Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/target/iscsi/iscsi_target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -2335,8 +2335,9 @@ iscsit_handle_text_cmd(struct iscsit_con + + if (conn->conn_ops->DataDigest) { + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, +- text_in, rx_size, 0, NULL, +- &data_crc); ++ text_in, ++ ALIGN(payload_length, 4), ++ 0, NULL, &data_crc); + + if (checksum != data_crc) { + pr_err("Text data CRC32C DataDigest" +@@ -2356,6 +2357,7 @@ iscsit_handle_text_cmd(struct iscsit_con + " Command CmdSN: 0x%08x due to" + " DataCRC error.\n", hdr->cmdsn); + kfree(text_in); ++ cmd->text_in_ptr = NULL; + return 0; + } + } else { diff --git a/queue-6.6/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch b/queue-6.6/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch new file mode 100644 index 0000000000..1f54171c2f --- /dev/null +++ b/queue-6.6/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch @@ -0,0 +1,69 @@ +From stable+bounces-260880-greg=kroah.com@vger.kernel.org Sat Jun 6 18:19:51 2026 +From: Sasha Levin +Date: Sat, 6 Jun 2026 08:49:44 -0400 +Subject: serial: qcom_geni: fix kfifo underflow when flush precedes DMA completion IRQ +To: stable@vger.kernel.org +Cc: Viken Dadhaniya , stable , Bartosz Golaszewski , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606124944.2878832-1-sashal@kernel.org> + +From: Viken Dadhaniya + +[ Upstream commit 452d6fa37ae9b021f4f6d397dbae077f7296f6f4 ] + +When uart_flush_buffer() runs before the DMA completion IRQ is delivered, +the following race can occur (all steps serialized by uart_port_lock): + + 1. DMA starts: tx_remaining = N, kfifo contains N bytes + 2. DMA completes in hardware; IRQ is pending but not yet delivered + 3. uart_flush_buffer() acquires the port lock and calls kfifo_reset(), + making kfifo_len() = 0 while tx_remaining remains N + 4. uart_flush_buffer() releases the port lock + 5. DMA IRQ fires; handle_tx_dma() acquires the port lock and calls + uart_xmit_advance(uport, tx_remaining) on an empty kfifo + +uart_xmit_advance() increments kfifo->out by tx_remaining. Since +kfifo_reset() already set both in and out to 0, out wraps past in, +causing kfifo_len() to return UART_XMIT_SIZE - tx_remaining. The next +start_tx_dma() call then submits a DMA transfer of stale buffer data. + +Fix this by snapshotting kfifo_len() at the start of handle_tx_dma() +and skipping uart_xmit_advance() when fifo_len < tx_remaining, which +indicates the kfifo was reset by a preceding flush. + +Fixes: 2aaa43c70778 ("tty: serial: qcom-geni-serial: add support for serial engine DMA") +Cc: stable +Signed-off-by: Viken Dadhaniya +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/20260506-serial-dma-stale-tx-buf-v1-1-e3ccb360d719@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/qcom_geni_serial.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -962,8 +962,21 @@ static void qcom_geni_serial_handle_tx_d + { + struct qcom_geni_serial_port *port = to_dev_port(uport); + struct circ_buf *xmit = &uport->state->xmit; ++ unsigned int chars_pending = uart_circ_chars_pending(xmit); ++ ++ /* ++ * Only advance the buffer if it still contains the bytes that were ++ * transferred. uart_flush_buffer() may have run before this IRQ ++ * fired: it clears the circular buffer under the port lock, making ++ * chars_pending = 0 while tx_remaining remains non-zero. Calling ++ * uart_xmit_advance() in that case would advance xmit->tail past ++ * xmit->head, making uart_circ_chars_pending() wrap to ++ * UART_XMIT_SIZE - tx_remaining and triggering a spurious large DMA ++ * transfer of stale data. ++ */ ++ if (chars_pending >= port->tx_remaining) ++ uart_xmit_advance(uport, port->tx_remaining); + +- uart_xmit_advance(uport, port->tx_remaining); + geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining); + port->tx_dma_addr = 0; + port->tx_remaining = 0; diff --git a/queue-6.6/serial-samsung_tty-use-port-lock-wrappers.patch b/queue-6.6/serial-samsung_tty-use-port-lock-wrappers.patch new file mode 100644 index 0000000000..160d769d1b --- /dev/null +++ b/queue-6.6/serial-samsung_tty-use-port-lock-wrappers.patch @@ -0,0 +1,254 @@ +From stable+bounces-260700-greg=kroah.com@vger.kernel.org Fri Jun 5 19:23:32 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 09:53:22 -0400 +Subject: serial: samsung_tty: Use port lock wrappers +To: stable@vger.kernel.org +Cc: Thomas Gleixner , John Ogness , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605135324.928676-1-sashal@kernel.org> + +From: Thomas Gleixner + +[ Upstream commit 97d7a9aeba1d424c2359f1686d02c75d798ad184 ] + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-54-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/samsung_tty.c | 50 +++++++++++++++++++-------------------- + 1 file changed, 25 insertions(+), 25 deletions(-) + +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -248,7 +248,7 @@ static void s3c24xx_serial_rx_enable(str + unsigned int ucon, ufcon; + int count = 10000; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (--count && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); +@@ -262,7 +262,7 @@ static void s3c24xx_serial_rx_enable(str + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 1; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_rx_disable(struct uart_port *port) +@@ -271,14 +271,14 @@ static void s3c24xx_serial_rx_disable(st + unsigned long flags; + unsigned int ucon; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 0; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_stop_tx(struct uart_port *port) +@@ -344,7 +344,7 @@ static void s3c24xx_serial_tx_dma_comple + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_xmit_advance(port, count); + ourport->tx_in_progress = 0; +@@ -353,7 +353,7 @@ static void s3c24xx_serial_tx_dma_comple + uart_write_wakeup(port); + + s3c24xx_serial_start_next_tx(ourport); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void enable_tx_dma(struct s3c24xx_uart_port *ourport) +@@ -619,7 +619,7 @@ static void s3c24xx_serial_rx_dma_comple + received = dma->rx_bytes_requested - state.residue; + async_tx_ack(dma->rx_desc); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (received) + s3c24xx_uart_copy_rx_to_tty(ourport, t, received); +@@ -631,7 +631,7 @@ static void s3c24xx_serial_rx_dma_comple + + s3c64xx_start_rx_dma(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) +@@ -722,7 +722,7 @@ static irqreturn_t s3c24xx_serial_rx_cha + utrstat = rd_regl(port, S3C2410_UTRSTAT); + rd_regl(port, S3C2410_UFSTAT); + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) { + s3c64xx_start_rx_dma(ourport); +@@ -751,7 +751,7 @@ static irqreturn_t s3c24xx_serial_rx_cha + wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT); + + finish: +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -849,9 +849,9 @@ static irqreturn_t s3c24xx_serial_rx_cha + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + s3c24xx_serial_rx_drain_fifo(ourport); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -932,11 +932,11 @@ static irqreturn_t s3c24xx_serial_tx_irq + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + s3c24xx_serial_tx_chars(ourport); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return IRQ_HANDLED; + } + +@@ -1032,7 +1032,7 @@ static void s3c24xx_serial_break_ctl(str + unsigned long flags; + unsigned int ucon; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ucon = rd_regl(port, S3C2410_UCON); + +@@ -1043,7 +1043,7 @@ static void s3c24xx_serial_break_ctl(str + + wr_regl(port, S3C2410_UCON, ucon); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) +@@ -1302,7 +1302,7 @@ static int s3c64xx_serial_startup(struct + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; +@@ -1312,7 +1312,7 @@ static int s3c64xx_serial_startup(struct + + enable_rx_pio(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); +@@ -1340,7 +1340,7 @@ static int apple_s5l_serial_startup(stru + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; +@@ -1350,7 +1350,7 @@ static int apple_s5l_serial_startup(stru + + enable_rx_pio(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); +@@ -1625,7 +1625,7 @@ static void s3c24xx_serial_set_termios(s + ulcon |= S3C2410_LCON_PNONE; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + dev_dbg(port->dev, + "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", +@@ -1683,7 +1683,7 @@ static void s3c24xx_serial_set_termios(s + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *s3c24xx_serial_type(struct uart_port *port) +@@ -2375,14 +2375,14 @@ s3c24xx_serial_console_write(struct cons + if (cons_uart->sysrq) + locked = false; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&cons_uart->lock, flags); ++ locked = uart_port_trylock_irqsave(cons_uart, &flags); + else +- spin_lock_irqsave(&cons_uart->lock, flags); ++ uart_port_lock_irqsave(cons_uart, &flags); + + uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); + + if (locked) +- spin_unlock_irqrestore(&cons_uart->lock, flags); ++ uart_port_unlock_irqrestore(cons_uart, flags); + } + + /* Shouldn't be __init, as it can be instantiated from other module */ diff --git a/queue-6.6/series b/queue-6.6/series index df6775514d..906a643345 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -406,3 +406,32 @@ serdev-provide-a-bustype-shutdown-function.patch bluetooth-hci_qca-migrate-to-serdev-specific-shutdown-function.patch bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch mptcp-handle-first-subflow-closing-consistently.patch +iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch +iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch +iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch +usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch +iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch +memfd-deny-writeable-mappings-when-implying-seal_write.patch +alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch +serial-samsung_tty-use-port-lock-wrappers.patch +tty-serial-samsung-use-u32-for-register-interactions.patch +tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch +usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch +usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch +usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch +usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch +thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch +scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch +serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch +usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch +netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch +mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch +mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch +mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch +mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch +mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch +hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch +rdma-during-rereg_mr-ensure-that-rereg_access-is-compatible.patch +rdma-umem-fix-kernel-doc-warnings.patch +rdma-move-dma-block-iterator-logic-into-dedicated-files.patch +rdma-umem-fix-truncation-for-block-sizes-4g.patch diff --git a/queue-6.6/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch b/queue-6.6/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch new file mode 100644 index 0000000000..7b70303343 --- /dev/null +++ b/queue-6.6/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch @@ -0,0 +1,112 @@ +From stable+bounces-260811-greg=kroah.com@vger.kernel.org Sat Jun 6 01:17:55 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 15:42:47 -0400 +Subject: thunderbolt: property: Cap recursion depth in __tb_property_parse_dir() +To: stable@vger.kernel.org +Cc: Michael Bommarito , Mika Westerberg , Sasha Levin +Message-ID: <20260605194247.2177334-1-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit 928abe19fbf0127003abcb1ea69cabc1c897d0ab ] + +A DIRECTORY entry's value field is used as the dir_offset for a +recursive call into __tb_property_parse_dir() with no depth counter. +A crafted peer that chains DIRECTORY entries into a back-reference +loop drives the parser until the kernel stack is exhausted and the +guard page fires. Any untrusted XDomain peer (cable, dock, in-line +inspector, adjacent host) that reaches the PROPERTIES_REQUEST +control-plane exchange can trigger this without authentication. + +Thread a depth counter through tb_property_parse() and +__tb_property_parse_dir(), and reject blocks that exceed +TB_PROPERTY_MAX_DEPTH = 8. That is comfortably larger than any +observed legitimate XDomain layout. + +Operators who do not need XDomain host-to-host discovery can disable +the path entirely with thunderbolt.xdomain=0 on the kernel command +line. + +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/thunderbolt/property.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/thunderbolt/property.c ++++ b/drivers/thunderbolt/property.c +@@ -35,10 +35,11 @@ struct tb_property_dir_entry { + }; + + #define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401 ++#define TB_PROPERTY_MAX_DEPTH 8 + + static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, + size_t block_len, unsigned int dir_offset, size_t dir_len, +- bool is_root); ++ bool is_root, unsigned int depth); + + static inline void parse_dwdata(void *dst, const void *src, size_t dwords) + { +@@ -99,7 +100,8 @@ tb_property_alloc(const char *key, enum + } + + static struct tb_property *tb_property_parse(const u32 *block, size_t block_len, +- const struct tb_property_entry *entry) ++ const struct tb_property_entry *entry, ++ unsigned int depth) + { + char key[TB_PROPERTY_KEY_SIZE + 1]; + struct tb_property *property; +@@ -120,7 +122,7 @@ static struct tb_property *tb_property_p + switch (property->type) { + case TB_PROPERTY_TYPE_DIRECTORY: + dir = __tb_property_parse_dir(block, block_len, entry->value, +- entry->length, false); ++ entry->length, false, depth + 1); + if (!dir) { + kfree(property); + return NULL; +@@ -165,13 +167,17 @@ static struct tb_property *tb_property_p + } + + static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, +- size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root) ++ size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root, ++ unsigned int depth) + { + const struct tb_property_entry *entries; + size_t i, content_len, nentries; + unsigned int content_offset; + struct tb_property_dir *dir; + ++ if (depth > TB_PROPERTY_MAX_DEPTH) ++ return NULL; ++ + dir = kzalloc(sizeof(*dir), GFP_KERNEL); + if (!dir) + return NULL; +@@ -206,7 +212,7 @@ static struct tb_property_dir *__tb_prop + for (i = 0; i < nentries; i++) { + struct tb_property *property; + +- property = tb_property_parse(block, block_len, &entries[i]); ++ property = tb_property_parse(block, block_len, &entries[i], depth); + if (!property) { + tb_property_free_dir(dir); + return NULL; +@@ -243,7 +249,7 @@ struct tb_property_dir *tb_property_pars + return NULL; + + return __tb_property_parse_dir(block, block_len, 0, rootdir->length, +- true); ++ true, 0); + } + + /** diff --git a/queue-6.6/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch b/queue-6.6/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch new file mode 100644 index 0000000000..b0a98b4db1 --- /dev/null +++ b/queue-6.6/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch @@ -0,0 +1,85 @@ +From sashal@kernel.org Fri Jun 5 19:23:29 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 09:53:24 -0400 +Subject: tty: serial: samsung: Remove redundant port lock acquisition in rx helpers +To: stable@vger.kernel.org +Cc: Tudor Ambarus , stable , John Ogness , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605135324.928676-3-sashal@kernel.org> + +From: Tudor Ambarus + +[ Upstream commit a3bb136bff5e6a5e48cdd813246c9c4686feaaa9 ] + +Sashiko identified a deadlock when the console flow is engaged [1]. + +When console flow control is enabled (UPF_CONS_FLOW), +s3c24xx_serial_stop_tx() calls s3c24xx_serial_rx_enable() and +s3c24xx_serial_start_tx() calls s3c24xx_serial_rx_disable(). + +The serial core framework invokes the .stop_tx() and .start_tx() +callbacks with the port->lock spinlock already held. Furthermore, all +internal driver paths that invoke stop_tx (such as the DMA TX +completion handler s3c24xx_serial_tx_dma_complete() or the PIO TX IRQ +handler s3c24xx_serial_tx_irq()) also acquire port->lock prior to +calling it. (Note that s3c24xx_serial_start_tx() is only invoked by the +serial core). + +However, s3c24xx_serial_rx_enable() and s3c24xx_serial_rx_disable() +unconditionally attempt to acquire port->lock again using +uart_port_lock_irqsave(). Since spinlocks are not recursive, this +causes a deadlock on the same CPU when console flow control is engaged. + +Remove the redundant lock acquisition from both rx helper functions. + +Cc: stable +Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers") +Reported-by: John Ogness +Closes: https://sashiko.dev/#/patchset/20260506121606.5805-1-john.ogness%40linutronix.de [1] +Signed-off-by: Tudor Ambarus +Link: https://patch.msgid.link/20260515-samsung-tty-flow-control-deadlock-v1-1-93255edbc9bc@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/samsung_tty.c | 8 -------- + 1 file changed, 8 deletions(-) + +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -244,12 +244,9 @@ static int s3c24xx_serial_txempty_nofifo + static void s3c24xx_serial_rx_enable(struct uart_port *port) + { + struct s3c24xx_uart_port *ourport = to_ourport(port); +- unsigned long flags; + int count = 10000; + u32 ucon, ufcon; + +- uart_port_lock_irqsave(port, &flags); +- + while (--count && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); + +@@ -262,23 +259,18 @@ static void s3c24xx_serial_rx_enable(str + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 1; +- uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_rx_disable(struct uart_port *port) + { + struct s3c24xx_uart_port *ourport = to_ourport(port); +- unsigned long flags; + u32 ucon; + +- uart_port_lock_irqsave(port, &flags); +- + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 0; +- uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_stop_tx(struct uart_port *port) diff --git a/queue-6.6/tty-serial-samsung-use-u32-for-register-interactions.patch b/queue-6.6/tty-serial-samsung-use-u32-for-register-interactions.patch new file mode 100644 index 0000000000..5b489dc894 --- /dev/null +++ b/queue-6.6/tty-serial-samsung-use-u32-for-register-interactions.patch @@ -0,0 +1,353 @@ +From sashal@kernel.org Fri Jun 5 19:23:29 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 09:53:23 -0400 +Subject: tty: serial: samsung: use u32 for register interactions +To: stable@vger.kernel.org +Cc: Tudor Ambarus , Sam Protsenko , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605135324.928676-2-sashal@kernel.org> + +From: Tudor Ambarus + +[ Upstream commit 032a725c16add79332d774348d7ad7d0d4b86479 ] + +All registers of the IP have 32 bits. Use u32 variables when reading +or writing from/to the registers. The purpose of those variables becomes +clearer. + +Reviewed-by: Sam Protsenko +Signed-off-by: Tudor Ambarus +Link: https://lore.kernel.org/r/20240119104526.1221243-9-tudor.ambarus@linaro.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/samsung_tty.c | 79 +++++++++++++++++++-------------------- + 1 file changed, 39 insertions(+), 40 deletions(-) + +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -199,7 +199,7 @@ static void wr_reg(const struct uart_por + /* Byte-order aware bit setting/clearing functions. */ + + static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, +- unsigned int reg) ++ u32 reg) + { + unsigned long flags; + u32 val; +@@ -212,7 +212,7 @@ static inline void s3c24xx_set_bit(const + } + + static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx, +- unsigned int reg) ++ u32 reg) + { + unsigned long flags; + u32 val; +@@ -245,8 +245,8 @@ static void s3c24xx_serial_rx_enable(str + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ucon, ufcon; + int count = 10000; ++ u32 ucon, ufcon; + + uart_port_lock_irqsave(port, &flags); + +@@ -269,7 +269,7 @@ static void s3c24xx_serial_rx_disable(st + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ucon; ++ u32 ucon; + + uart_port_lock_irqsave(port, &flags); + +@@ -591,7 +591,7 @@ static inline const struct s3c2410_uartc + } + + static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, +- unsigned long ufstat) ++ u32 ufstat) + { + const struct s3c24xx_uart_info *info = ourport->info; + +@@ -663,7 +663,7 @@ static void s3c64xx_start_rx_dma(struct + static void enable_rx_dma(struct s3c24xx_uart_port *ourport) + { + struct uart_port *port = &ourport->port; +- unsigned int ucon; ++ u32 ucon; + + /* set Rx mode to DMA mode */ + ucon = rd_regl(port, S3C2410_UCON); +@@ -686,7 +686,7 @@ static void enable_rx_dma(struct s3c24xx + static void enable_rx_pio(struct s3c24xx_uart_port *ourport) + { + struct uart_port *port = &ourport->port; +- unsigned int ucon; ++ u32 ucon; + + /* set Rx mode to DMA mode */ + ucon = rd_regl(port, S3C2410_UCON); +@@ -711,13 +711,14 @@ static void s3c24xx_serial_rx_drain_fifo + + static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) + { +- unsigned int utrstat, received; + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + struct s3c24xx_uart_dma *dma = ourport->dma; + struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port); + struct tty_port *t = &port->state->port; + struct dma_tx_state state; ++ unsigned int received; ++ u32 utrstat; + + utrstat = rd_regl(port, S3C2410_UTRSTAT); + rd_regl(port, S3C2410_UFSTAT); +@@ -759,9 +760,9 @@ finish: + static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) + { + struct uart_port *port = &ourport->port; +- unsigned int ufcon, ufstat, uerstat; + unsigned int fifocnt = 0; + int max_count = port->fifosize; ++ u32 ufcon, ufstat, uerstat; + u8 ch, flag; + + while (max_count-- > 0) { +@@ -945,7 +946,7 @@ static irqreturn_t s3c64xx_serial_handle + { + const struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; +- unsigned int pend = rd_regl(port, S3C64XX_UINTP); ++ u32 pend = rd_regl(port, S3C64XX_UINTP); + irqreturn_t ret = IRQ_HANDLED; + + if (pend & S3C64XX_UINTM_RXD_MSK) { +@@ -964,7 +965,7 @@ static irqreturn_t apple_serial_handle_i + { + const struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; +- unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); ++ u32 pend = rd_regl(port, S3C2410_UTRSTAT); + irqreturn_t ret = IRQ_NONE; + + if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) { +@@ -983,8 +984,8 @@ static irqreturn_t apple_serial_handle_i + static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); +- unsigned long ufcon = rd_regl(port, S3C2410_UFCON); ++ u32 ufstat = rd_regl(port, S3C2410_UFSTAT); ++ u32 ufcon = rd_regl(port, S3C2410_UFCON); + + if (ufcon & S3C2410_UFCON_FIFOMODE) { + if ((ufstat & info->tx_fifomask) != 0 || +@@ -999,7 +1000,7 @@ static unsigned int s3c24xx_serial_tx_em + /* no modem control lines */ + static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) + { +- unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); ++ u32 umstat = rd_reg(port, S3C2410_UMSTAT); + + if (umstat & S3C2410_UMSTAT_CTS) + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +@@ -1009,8 +1010,8 @@ static unsigned int s3c24xx_serial_get_m + + static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) + { +- unsigned int umcon = rd_regl(port, S3C2410_UMCON); +- unsigned int ucon = rd_regl(port, S3C2410_UCON); ++ u32 umcon = rd_regl(port, S3C2410_UMCON); ++ u32 ucon = rd_regl(port, S3C2410_UCON); + + if (mctrl & TIOCM_RTS) + umcon |= S3C2410_UMCOM_RTS_LOW; +@@ -1030,7 +1031,7 @@ static void s3c24xx_serial_set_mctrl(str + static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) + { + unsigned long flags; +- unsigned int ucon; ++ u32 ucon; + + uart_port_lock_irqsave(port, &flags); + +@@ -1211,7 +1212,7 @@ static void apple_s5l_serial_shutdown(st + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + +- unsigned int ucon; ++ u32 ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | +@@ -1279,7 +1280,7 @@ static int s3c64xx_serial_startup(struct + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ufcon; ++ u32 ufcon; + int ret; + + wr_regl(port, S3C64XX_UINTM, 0xf); +@@ -1324,7 +1325,7 @@ static int apple_s5l_serial_startup(stru + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ufcon; ++ u32 ufcon; + int ret; + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); +@@ -1409,7 +1410,7 @@ static void s3c24xx_serial_pm(struct uar + static inline int s3c24xx_serial_getsource(struct uart_port *port) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned int ucon; ++ u32 ucon; + + if (info->num_clks == 1) + return 0; +@@ -1423,7 +1424,7 @@ static void s3c24xx_serial_setsource(str + unsigned int clk_sel) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned int ucon; ++ u32 ucon; + + if (info->num_clks == 1) + return; +@@ -1540,9 +1541,8 @@ static void s3c24xx_serial_set_termios(s + struct clk *clk = ERR_PTR(-EINVAL); + unsigned long flags; + unsigned int baud, quot, clk_sel = 0; +- unsigned int ulcon; +- unsigned int umcon; + unsigned int udivslot = 0; ++ u32 ulcon, umcon; + + /* + * We don't support modem control lines. +@@ -1849,7 +1849,7 @@ static void s3c24xx_serial_resetport(str + const struct s3c2410_uartcfg *cfg) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned long ucon = rd_regl(port, S3C2410_UCON); ++ u32 ucon = rd_regl(port, S3C2410_UCON); + + ucon &= (info->clksel_mask | info->ucon_mask); + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); +@@ -2005,7 +2005,7 @@ static int s3c24xx_serial_init_port(stru + wr_regl(port, S3C64XX_UINTSP, 0xf); + break; + case TYPE_APPLE_S5L: { +- unsigned int ucon; ++ u32 ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | +@@ -2212,7 +2212,7 @@ static int s3c24xx_serial_resume_noirq(s + /* restore IRQ mask */ + switch (ourport->info->type) { + case TYPE_S3C6400: { +- unsigned int uintm = 0xf; ++ u32 uintm = 0xf; + + if (ourport->tx_enabled) + uintm &= ~S3C64XX_UINTM_TXD_MSK; +@@ -2228,7 +2228,7 @@ static int s3c24xx_serial_resume_noirq(s + break; + } + case TYPE_APPLE_S5L: { +- unsigned int ucon; ++ u32 ucon; + int ret; + + ret = clk_prepare_enable(ourport->clk); +@@ -2290,10 +2290,10 @@ static const struct dev_pm_ops s3c24xx_s + static struct uart_port *cons_uart; + + static int +-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) ++s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned long ufstat, utrstat; ++ u32 ufstat, utrstat; + + if (ufcon & S3C2410_UFCON_FIFOMODE) { + /* fifo mode - check amount of data in fifo registers... */ +@@ -2309,7 +2309,7 @@ s3c24xx_serial_console_txrdy(struct uart + } + + static bool +-s3c24xx_port_configured(unsigned int ucon) ++s3c24xx_port_configured(u32 ucon) + { + /* consider the serial port configured if the tx/rx mode set */ + return (ucon & 0xf) != 0; +@@ -2324,7 +2324,7 @@ s3c24xx_port_configured(unsigned int uco + static int s3c24xx_serial_get_poll_char(struct uart_port *port) + { + const struct s3c24xx_uart_port *ourport = to_ourport(port); +- unsigned int ufstat; ++ u32 ufstat; + + ufstat = rd_regl(port, S3C2410_UFSTAT); + if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) +@@ -2336,8 +2336,8 @@ static int s3c24xx_serial_get_poll_char( + static void s3c24xx_serial_put_poll_char(struct uart_port *port, + unsigned char c) + { +- unsigned int ufcon = rd_regl(port, S3C2410_UFCON); +- unsigned int ucon = rd_regl(port, S3C2410_UCON); ++ u32 ufcon = rd_regl(port, S3C2410_UFCON); ++ u32 ucon = rd_regl(port, S3C2410_UCON); + + /* not possible to xmit on unconfigured port */ + if (!s3c24xx_port_configured(ucon)) +@@ -2353,7 +2353,7 @@ static void s3c24xx_serial_put_poll_char + static void + s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch) + { +- unsigned int ufcon = rd_regl(port, S3C2410_UFCON); ++ u32 ufcon = rd_regl(port, S3C2410_UFCON); + + while (!s3c24xx_serial_console_txrdy(port, ufcon)) + cpu_relax(); +@@ -2364,7 +2364,7 @@ static void + s3c24xx_serial_console_write(struct console *co, const char *s, + unsigned int count) + { +- unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); ++ u32 ucon = rd_regl(cons_uart, S3C2410_UCON); + unsigned long flags; + bool locked = true; + +@@ -2391,11 +2391,9 @@ s3c24xx_serial_get_options(struct uart_p + int *parity, int *bits) + { + struct clk *clk; +- unsigned int ulcon; +- unsigned int ucon; +- unsigned int ubrdiv; + unsigned long rate; + unsigned int clk_sel; ++ u32 ulcon, ucon, ubrdiv; + char clk_name[MAX_CLK_NAME_LENGTH]; + + ulcon = rd_regl(port, S3C2410_ULCON); +@@ -2806,7 +2804,8 @@ static int samsung_early_read(struct con + { + struct earlycon_device *dev = con->data; + const struct samsung_early_console_data *data = dev->port.private_data; +- int ch, ufstat, num_read = 0; ++ int num_read = 0; ++ u32 ch, ufstat; + + while (num_read < n) { + ufstat = rd_regl(&dev->port, S3C2410_UFSTAT); diff --git a/queue-6.6/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch b/queue-6.6/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch new file mode 100644 index 0000000000..7dbcf4cffc --- /dev/null +++ b/queue-6.6/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch @@ -0,0 +1,48 @@ +From stable+bounces-260588-greg=kroah.com@vger.kernel.org Fri Jun 5 05:19:24 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 19:49:13 -0400 +Subject: usb: cdns3: plat: fix leaked usb2_phy initialization on usb3_phy acquisition failure +To: stable@vger.kernel.org +Cc: Peter Chen , stable , sashiko-bot , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260604234913.2468901-1-sashal@kernel.org> + +From: Peter Chen + +[ Upstream commit e6970cda63fd4b4546aeed9d0e2f53a7c95cd09c ] + +Move usb2_phy initialization after usb3_phy acquisition. + +Fixes: f738957277ba ("usb: cdns3: Split core.c into cdns3-plat and core.c file") +Cc: stable +Reported-by: sashiko-bot +Closes: https://lore.kernel.org/linux-devicetree/agKaEePSFknhDBg2@nchen-desktop/T/#m21e1d9c1574eb127ce03c0c2a1a49002ce435b52 +Signed-off-by: Peter Chen +Link: https://patch.msgid.link/20260513085310.2217547-2-peter.chen@cixtech.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/cdns3/cdns3-plat.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/usb/cdns3/cdns3-plat.c ++++ b/drivers/usb/cdns3/cdns3-plat.c +@@ -121,14 +121,14 @@ static int cdns3_plat_probe(struct platf + if (IS_ERR(cdns->usb2_phy)) + return PTR_ERR(cdns->usb2_phy); + +- ret = phy_init(cdns->usb2_phy); +- if (ret) +- return ret; +- + cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy"); + if (IS_ERR(cdns->usb3_phy)) + return PTR_ERR(cdns->usb3_phy); + ++ ret = phy_init(cdns->usb2_phy); ++ if (ret) ++ return ret; ++ + ret = phy_init(cdns->usb3_phy); + if (ret) + goto err_phy3_init; diff --git a/queue-6.6/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch b/queue-6.6/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch new file mode 100644 index 0000000000..cdf0d27610 --- /dev/null +++ b/queue-6.6/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch @@ -0,0 +1,95 @@ +From sashal@kernel.org Fri Jun 5 21:01:14 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:31:11 -0400 +Subject: usb: dwc3: xilinx: fix error handling in zynqmp init error paths +To: stable@vger.kernel.org +Cc: Radhey Shyam Pandey , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605153111.1929312-1-sashal@kernel.org> + +From: Radhey Shyam Pandey + +[ Upstream commit c1a0ecbf32c4b397353204e2ec94c5bb9f3300ed ] + +Fix error handling and resource cleanup i.e remove invalid +phy_exit() after failed phy_init(), route failures through +proper cleanup paths and return 0 explicitly on success. + +Fixes: 84770f028fab ("usb: dwc3: Add driver for Xilinx platforms") +Cc: stable@vger.kernel.org +Acked-by: Thinh Nguyen +Signed-off-by: Radhey Shyam Pandey +Link: https://patch.msgid.link/20260519115529.2980421-1-radhey.shyam.pandey@amd.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/dwc3-xilinx.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -170,15 +170,13 @@ static int dwc3_xlnx_init_zynqmp(struct + } + + ret = phy_init(priv_data->usb3_phy); +- if (ret < 0) { +- phy_exit(priv_data->usb3_phy); ++ if (ret < 0) + goto err; +- } + + ret = reset_control_deassert(apbrst); + if (ret < 0) { + dev_err(dev, "Failed to release APB reset\n"); +- goto err; ++ goto err_phy_exit; + } + + /* Set PIPE Power Present signal in FPD Power Present Register*/ +@@ -190,27 +188,25 @@ static int dwc3_xlnx_init_zynqmp(struct + ret = reset_control_deassert(crst); + if (ret < 0) { + dev_err(dev, "Failed to release core reset\n"); +- goto err; ++ goto err_phy_exit; + } + + ret = reset_control_deassert(hibrst); + if (ret < 0) { + dev_err(dev, "Failed to release hibernation reset\n"); +- goto err; ++ goto err_phy_exit; + } + + ret = phy_power_on(priv_data->usb3_phy); +- if (ret < 0) { +- phy_exit(priv_data->usb3_phy); +- goto err; +- } ++ if (ret < 0) ++ goto err_phy_exit; + + skip_usb3_phy: + /* ulpi reset via gpio-modepin or gpio-framework driver */ + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) { +- return dev_err_probe(dev, PTR_ERR(reset_gpio), +- "Failed to request reset GPIO\n"); ++ ret = PTR_ERR(reset_gpio); ++ goto err_phy_power_off; + } + + if (reset_gpio) { +@@ -230,6 +226,12 @@ skip_usb3_phy: + writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG); + } + ++ return 0; ++ ++err_phy_power_off: ++ phy_power_off(priv_data->usb3_phy); ++err_phy_exit: ++ phy_exit(priv_data->usb3_phy); + err: + return ret; + } diff --git a/queue-6.6/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch b/queue-6.6/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch new file mode 100644 index 0000000000..82f946cbb3 --- /dev/null +++ b/queue-6.6/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch @@ -0,0 +1,133 @@ +From sashal@kernel.org Sat Jun 6 00:01:30 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 14:31:27 -0400 +Subject: usb: gadget: uvc: hold opts->lock across XU walks in uvc_function_bind +To: stable@vger.kernel.org +Cc: Kai Aizen , stable , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605183127.2055332-1-sashal@kernel.org> + +From: Kai Aizen + +[ Upstream commit 68aa70648b625fa684bc0b71bbfd905f4943ca20 ] + +uvc_function_bind() walks &opts->extension_units twice without holding +opts->lock: + + - directly, for the iExtension string-descriptor fixup loop; + - indirectly, four times via uvc_copy_descriptors() (once per speed), + where the helper iterates uvc->desc.extension_units (which aliases + &opts->extension_units) to size and emit XU descriptors. + +The configfs side (uvcg_extension_make / uvcg_extension_drop, in +drivers/usb/gadget/function/uvc_configfs.c) takes opts->lock around its +list_add_tail / list_del operations. A privileged userspace process +that holds the configfs subtree open and writes the gadget UDC name +to bind the function while concurrently rmdir()'ing an extensions +subdir can race uvcg_extension_drop() against the bind-time list walks +and dereference a freed struct uvcg_extension. + +Hold opts->lock from the start of the XU string-descriptor fixup +through the last uvc_copy_descriptors() call, releasing on the +descriptor-error path via a new error_unlock label that drops the +lock before falling through to the existing error label. This +matches the locking discipline of the configfs callbacks and removes +the only remaining unsynchronised reader of the XU list during bind. + +Reachability: only privileged processes that can mount configfs and +write to gadget UDC files can trigger the race, so this is a +correctness fix rather than a security boundary. + +Fixes: 0525210c9840 ("usb: gadget: uvc: Allow definition of XUs in configfs") +Cc: stable +Signed-off-by: Kai Aizen +Link: https://patch.msgid.link/20260430175643.67120-1-kai.aizen.dev@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_uvc.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +--- a/drivers/usb/gadget/function/f_uvc.c ++++ b/drivers/usb/gadget/function/f_uvc.c +@@ -763,6 +763,16 @@ uvc_function_bind(struct usb_configurati + uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; + + /* ++ * Hold opts->lock across both the XU string-descriptor fixup below and ++ * the descriptor-copy block further down. Without this, configfs ++ * uvcg_extension_drop() (which takes opts->lock) can race with the ++ * list_for_each_entry() walks here and inside uvc_copy_descriptors(), ++ * leading to a UAF on a freed struct uvcg_extension. See ++ * drivers/usb/gadget/function/uvc_configfs.c::uvcg_extension_drop(). ++ */ ++ mutex_lock(&opts->lock); ++ ++ /* + * XUs can have an arbitrary string descriptor describing them. If they + * have one pick up the ID. + */ +@@ -779,7 +789,7 @@ uvc_function_bind(struct usb_configurati + ARRAY_SIZE(uvc_en_us_strings)); + if (IS_ERR(us)) { + ret = PTR_ERR(us); +- goto error; ++ goto error_unlock; + } + + uvc_iad.iFunction = opts->iad_index ? cdev->usb_strings[opts->iad_index].id : +@@ -793,14 +803,14 @@ uvc_function_bind(struct usb_configurati + + /* Allocate interface IDs. */ + if ((ret = usb_interface_id(c, f)) < 0) +- goto error; ++ goto error_unlock; + uvc_iad.bFirstInterface = ret; + uvc_control_intf.bInterfaceNumber = ret; + uvc->control_intf = ret; + opts->control_interface = ret; + + if ((ret = usb_interface_id(c, f)) < 0) +- goto error; ++ goto error_unlock; + uvc_streaming_intf_alt0.bInterfaceNumber = ret; + uvc_streaming_intf_alt1.bInterfaceNumber = ret; + uvc->streaming_intf = ret; +@@ -811,23 +821,25 @@ uvc_function_bind(struct usb_configurati + if (IS_ERR(f->fs_descriptors)) { + ret = PTR_ERR(f->fs_descriptors); + f->fs_descriptors = NULL; +- goto error; ++ goto error_unlock; + } + + f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); + if (IS_ERR(f->hs_descriptors)) { + ret = PTR_ERR(f->hs_descriptors); + f->hs_descriptors = NULL; +- goto error; ++ goto error_unlock; + } + + f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); + if (IS_ERR(f->ss_descriptors)) { + ret = PTR_ERR(f->ss_descriptors); + f->ss_descriptors = NULL; +- goto error; ++ goto error_unlock; + } + ++ mutex_unlock(&opts->lock); ++ + /* Preallocate control endpoint request. */ + uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); + uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL); +@@ -859,6 +871,8 @@ uvc_function_bind(struct usb_configurati + + return 0; + ++error_unlock: ++ mutex_unlock(&opts->lock); + v4l2_error: + v4l2_device_unregister(&uvc->v4l2_dev); + error: diff --git a/queue-6.6/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch b/queue-6.6/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch new file mode 100644 index 0000000000..b0d0f647fc --- /dev/null +++ b/queue-6.6/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch @@ -0,0 +1,54 @@ +From sashal@kernel.org Fri Jun 5 21:01:10 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:31:07 -0400 +Subject: usb: musb: omap2430: Fix use-after-free in omap2430_probe() +To: stable@vger.kernel.org +Cc: Wentao Liang , stable , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605153108.1929169-1-sashal@kernel.org> + +From: Wentao Liang + +[ Upstream commit e194ce048f5a6c549b3a23a8c568c6470f40f772 ] + +In omap2430_probe(), of_node_put(np) is called prematurely before the +last access to np, leading to a use-after-free if the node's reference +count drops to zero. Move the of_node_put() calls after the last use of +np in both the success and error paths. + +Fixes: ffbe2feac59b ("usb: musb: omap2430: Fix probe regression for missing resources") +Cc: stable +Signed-off-by: Wentao Liang +Link: https://patch.msgid.link/20260409101104.480623-1-vulab@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/musb/omap2430.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/musb/omap2430.c ++++ b/drivers/usb/musb/omap2430.c +@@ -340,7 +340,6 @@ static int omap2430_probe(struct platfor + } else { + device_set_of_node_from_dev(&musb->dev, &pdev->dev); + } +- of_node_put(np); + + glue->dev = &pdev->dev; + glue->musb = musb; +@@ -458,6 +457,7 @@ static int omap2430_probe(struct platfor + dev_err(&pdev->dev, "failed to register musb device\n"); + goto err3; + } ++ of_node_put(np); + + return 0; + +@@ -467,6 +467,7 @@ err_put_control_otghs: + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); + err2: ++ of_node_put(np); + platform_device_put(musb); + + err0: diff --git a/queue-6.6/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch b/queue-6.6/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch new file mode 100644 index 0000000000..583fb9b303 --- /dev/null +++ b/queue-6.6/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch @@ -0,0 +1,68 @@ +From sashal@kernel.org Sat Jun 6 00:47:19 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 15:17:16 -0400 +Subject: usb: typec: ucsi: Check if power role change actually happened before handling +To: stable@vger.kernel.org +Cc: Myrrh Periwinkle , stable , Sergey Senozhatsky , Heikki Krogerus , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605191716.2134705-1-sashal@kernel.org> + +From: Myrrh Periwinkle + +[ Upstream commit b80e7d34c7ea6a564525119d6138fbb577a23dba ] + +The CrOS EC may send a connector status change event with the power +direction changed flag set even if the power direction hasn't actually +changed after initiating a SET_PDR command internally [1]. In practice +this happens on every system suspend due to other changes performed by +the EC [2][3][4], causing suspend to fail. + +Fix this by checking if the power role change actually happened before +handling it. + +[1]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=1689;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 +[2]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=3923;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 +[3]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=5094;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 +[4]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=2229;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 + +Cc: stable +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -884,7 +884,7 @@ static void ucsi_handle_connector_change + struct ucsi_connector *con = container_of(work, struct ucsi_connector, + work); + struct ucsi *ucsi = con->ucsi; +- enum typec_role role; ++ enum typec_role role, prev_role; + u64 command; + int ret; + +@@ -892,6 +892,8 @@ static void ucsi_handle_connector_change + + command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); + ++ prev_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); ++ + ret = ucsi_send_command_common(ucsi, command, &con->status, + sizeof(con->status), true); + if (ret < 0) { +@@ -908,7 +910,7 @@ static void ucsi_handle_connector_change + + role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); + +- if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { ++ if ((con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) && role != prev_role) { + typec_set_pwr_role(con->port, role); + ucsi_port_psy_changed(con); + diff --git a/queue-6.6/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch b/queue-6.6/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch new file mode 100644 index 0000000000..2ad337830d --- /dev/null +++ b/queue-6.6/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch @@ -0,0 +1,45 @@ +From stable+bounces-260881-greg=kroah.com@vger.kernel.org Sat Jun 6 18:37:00 2026 +From: Sasha Levin +Date: Sat, 6 Jun 2026 09:05:38 -0400 +Subject: usb: typec: ucsi: Don't update power_supply on power role change if not connected +To: stable@vger.kernel.org +Cc: Myrrh Periwinkle , stable , Sergey Senozhatsky , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606130538.2924564-1-sashal@kernel.org> + +From: Myrrh Periwinkle + +[ Upstream commit d98d413ca65d0790a8f3695d0a5845538958ab84 ] + +We only need to update the power_supply on power role change if the port +is connected, because otherwise the online status should be the same for +both cases. + +Cc: stable +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-2-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +[ changed `UCSI_CONSTAT(con, CONNECTED)` accessor macro to `con->status.flags & UCSI_CONSTAT_CONNECTED` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -912,7 +912,12 @@ static void ucsi_handle_connector_change + + if ((con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) && role != prev_role) { + typec_set_pwr_role(con->port, role); +- ucsi_port_psy_changed(con); ++ ++ /* Some power_supply properties vary depending on the power direction when ++ * connected ++ */ ++ if (con->status.flags & UCSI_CONSTAT_CONNECTED) ++ ucsi_port_psy_changed(con); + + /* Complete pending power role swap */ + if (!completion_done(&con->complete))