]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Apr 2026 07:05:45 +0000 (09:05 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Apr 2026 07:05:45 +0000 (09:05 +0200)
added patches:
counter-rz-mtu3-cnt-do-not-use-struct-rz_mtu3_channel-s-dev-member.patch
counter-rz-mtu3-cnt-prevent-counter-from-being-toggled-multiple-times.patch
cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch
crypto-tegra-add-missing-crypto_alg_async.patch
gpio-mxc-map-both-edge-pad-wakeup-to-rising-edge.patch
misc-fastrpc-possible-double-free-of-cctx-remote_heap.patch
net-ethernet-mtk_ppe-avoid-null-deref-when-gmac0-is-disabled.patch
net-ftgmac100-fix-ring-allocation-unwind-on-open-failure.patch
thermal-core-fix-thermal-zone-device-registration-error-path.patch
thunderbolt-fix-property-read-in-nhi_wake_supported.patch
usb-dummy-hcd-fix-interrupt-synchronization-error.patch
usb-dummy-hcd-fix-locking-synchronization-error.patch
usb-gadget-dummy_hcd-fix-premature-urb-completion-when-zlp-follows-partial-transfer.patch
usb-typec-ucsi-validate-connector-number-in-ucsi_notify_common.patch
vxlan-validate-nd-option-lengths-in-vxlan_na_create.patch

16 files changed:
queue-6.12/counter-rz-mtu3-cnt-do-not-use-struct-rz_mtu3_channel-s-dev-member.patch [new file with mode: 0644]
queue-6.12/counter-rz-mtu3-cnt-prevent-counter-from-being-toggled-multiple-times.patch [new file with mode: 0644]
queue-6.12/cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch [new file with mode: 0644]
queue-6.12/crypto-tegra-add-missing-crypto_alg_async.patch [new file with mode: 0644]
queue-6.12/gpio-mxc-map-both-edge-pad-wakeup-to-rising-edge.patch [new file with mode: 0644]
queue-6.12/misc-fastrpc-possible-double-free-of-cctx-remote_heap.patch [new file with mode: 0644]
queue-6.12/net-ethernet-mtk_ppe-avoid-null-deref-when-gmac0-is-disabled.patch [new file with mode: 0644]
queue-6.12/net-ftgmac100-fix-ring-allocation-unwind-on-open-failure.patch [new file with mode: 0644]
queue-6.12/series
queue-6.12/thermal-core-fix-thermal-zone-device-registration-error-path.patch [new file with mode: 0644]
queue-6.12/thunderbolt-fix-property-read-in-nhi_wake_supported.patch [new file with mode: 0644]
queue-6.12/usb-dummy-hcd-fix-interrupt-synchronization-error.patch [new file with mode: 0644]
queue-6.12/usb-dummy-hcd-fix-locking-synchronization-error.patch [new file with mode: 0644]
queue-6.12/usb-gadget-dummy_hcd-fix-premature-urb-completion-when-zlp-follows-partial-transfer.patch [new file with mode: 0644]
queue-6.12/usb-typec-ucsi-validate-connector-number-in-ucsi_notify_common.patch [new file with mode: 0644]
queue-6.12/vxlan-validate-nd-option-lengths-in-vxlan_na_create.patch [new file with mode: 0644]

diff --git a/queue-6.12/counter-rz-mtu3-cnt-do-not-use-struct-rz_mtu3_channel-s-dev-member.patch b/queue-6.12/counter-rz-mtu3-cnt-do-not-use-struct-rz_mtu3_channel-s-dev-member.patch
new file mode 100644 (file)
index 0000000..0a9508f
--- /dev/null
@@ -0,0 +1,236 @@
+From 2932095c114b98cbb40ccf34fc00d613cb17cead Mon Sep 17 00:00:00 2001
+From: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
+Date: Fri, 30 Jan 2026 14:23:53 +0200
+Subject: counter: rz-mtu3-cnt: do not use struct rz_mtu3_channel's dev member
+
+From: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
+
+commit 2932095c114b98cbb40ccf34fc00d613cb17cead upstream.
+
+The counter driver can use HW channels 1 and 2, while the PWM driver can
+use HW channels 0, 1, 2, 3, 4, 6, 7.
+
+The dev member is assigned both by the counter driver and the PWM driver
+for channels 1 and 2, to their own struct device instance, overwriting
+the previous value.
+
+The sub-drivers race to assign their own struct device pointer to the
+same struct rz_mtu3_channel's dev member.
+
+The dev member of struct rz_mtu3_channel is used by the counter
+sub-driver for runtime PM.
+
+Depending on the probe order of the counter and PWM sub-drivers, the
+dev member may point to the wrong struct device instance, causing the
+counter sub-driver to do runtime PM actions on the wrong device.
+
+To fix this, use the parent pointer of the counter, which is assigned
+during probe to the correct struct device, not the struct device pointer
+inside the shared struct rz_mtu3_channel.
+
+Cc: stable@vger.kernel.org
+Fixes: 0be8907359df ("counter: Add Renesas RZ/G2L MTU3a counter driver")
+Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
+Link: https://lore.kernel.org/r/20260130122353.2263273-6-cosmin-gabriel.tanislav.xa@renesas.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/counter/rz-mtu3-cnt.c |   55 ++++++++++++++++++++----------------------
+ 1 file changed, 27 insertions(+), 28 deletions(-)
+
+--- a/drivers/counter/rz-mtu3-cnt.c
++++ b/drivers/counter/rz-mtu3-cnt.c
+@@ -107,9 +107,9 @@ static bool rz_mtu3_is_counter_invalid(s
+       struct rz_mtu3_cnt *const priv = counter_priv(counter);
+       unsigned long tmdr;
+-      pm_runtime_get_sync(priv->ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
+-      pm_runtime_put(priv->ch->dev);
++      pm_runtime_put(counter->parent);
+       if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr))
+               return false;
+@@ -165,12 +165,12 @@ static int rz_mtu3_count_read(struct cou
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       if (count->id == RZ_MTU3_32_BIT_CH)
+               *val = rz_mtu3_32bit_ch_read(ch, RZ_MTU3_TCNTLW);
+       else
+               *val = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TCNT);
+-      pm_runtime_put(ch->dev);
++      pm_runtime_put(counter->parent);
+       mutex_unlock(&priv->lock);
+       return 0;
+@@ -187,26 +187,26 @@ static int rz_mtu3_count_write(struct co
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       if (count->id == RZ_MTU3_32_BIT_CH)
+               rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TCNTLW, val);
+       else
+               rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TCNT, val);
+-      pm_runtime_put(ch->dev);
++      pm_runtime_put(counter->parent);
+       mutex_unlock(&priv->lock);
+       return 0;
+ }
+ static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch,
+-                                            struct rz_mtu3_cnt *const priv,
++                                            struct counter_device *const counter,
+                                             enum counter_function *function)
+ {
+       u8 timer_mode;
+-      pm_runtime_get_sync(ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1);
+-      pm_runtime_put(ch->dev);
++      pm_runtime_put(counter->parent);
+       switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) {
+       case RZ_MTU3_TMDR1_PH_CNT_MODE_1:
+@@ -240,7 +240,7 @@ static int rz_mtu3_count_function_read(s
+       if (ret)
+               return ret;
+-      ret = rz_mtu3_count_function_read_helper(ch, priv, function);
++      ret = rz_mtu3_count_function_read_helper(ch, counter, function);
+       mutex_unlock(&priv->lock);
+       return ret;
+@@ -279,9 +279,9 @@ static int rz_mtu3_count_function_write(
+               return -EINVAL;
+       }
+-      pm_runtime_get_sync(ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode);
+-      pm_runtime_put(ch->dev);
++      pm_runtime_put(counter->parent);
+       mutex_unlock(&priv->lock);
+       return 0;
+@@ -300,9 +300,9 @@ static int rz_mtu3_count_direction_read(
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       tsr = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TSR);
+-      pm_runtime_put(ch->dev);
++      pm_runtime_put(counter->parent);
+       *direction = (tsr & RZ_MTU3_TSR_TCFD) ?
+               COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD;
+@@ -377,14 +377,14 @@ static int rz_mtu3_count_ceiling_write(s
+               return -EINVAL;
+       }
+-      pm_runtime_get_sync(ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       if (count->id == RZ_MTU3_32_BIT_CH)
+               rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TGRALW, ceiling);
+       else
+               rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, ceiling);
+       rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA);
+-      pm_runtime_put(ch->dev);
++      pm_runtime_put(counter->parent);
+       mutex_unlock(&priv->lock);
+       return 0;
+@@ -495,7 +495,6 @@ static int rz_mtu3_count_enable_read(str
+ static int rz_mtu3_count_enable_write(struct counter_device *counter,
+                                     struct counter_count *count, u8 enable)
+ {
+-      struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id);
+       struct rz_mtu3_cnt *const priv = counter_priv(counter);
+       int ret = 0;
+@@ -505,14 +504,14 @@ static int rz_mtu3_count_enable_write(st
+               goto exit;
+       if (enable) {
+-              pm_runtime_get_sync(ch->dev);
++              pm_runtime_get_sync(counter->parent);
+               ret = rz_mtu3_initialize_counter(counter, count->id);
+               if (ret == 0)
+                       priv->count_is_enabled[count->id] = true;
+       } else {
+               rz_mtu3_terminate_counter(counter, count->id);
+               priv->count_is_enabled[count->id] = false;
+-              pm_runtime_put(ch->dev);
++              pm_runtime_put(counter->parent);
+       }
+ exit:
+@@ -544,9 +543,9 @@ static int rz_mtu3_cascade_counts_enable
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(priv->ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
+-      pm_runtime_put(priv->ch->dev);
++      pm_runtime_put(counter->parent);
+       *cascade_enable = test_bit(RZ_MTU3_TMDR3_LWA, &tmdr);
+       mutex_unlock(&priv->lock);
+@@ -563,10 +562,10 @@ static int rz_mtu3_cascade_counts_enable
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(priv->ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3,
+                                     RZ_MTU3_TMDR3_LWA, cascade_enable);
+-      pm_runtime_put(priv->ch->dev);
++      pm_runtime_put(counter->parent);
+       mutex_unlock(&priv->lock);
+       return 0;
+@@ -583,9 +582,9 @@ static int rz_mtu3_ext_input_phase_clock
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(priv->ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
+-      pm_runtime_put(priv->ch->dev);
++      pm_runtime_put(counter->parent);
+       *ext_input_phase_clock_select = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr);
+       mutex_unlock(&priv->lock);
+@@ -602,11 +601,11 @@ static int rz_mtu3_ext_input_phase_clock
+       if (ret)
+               return ret;
+-      pm_runtime_get_sync(priv->ch->dev);
++      pm_runtime_get_sync(counter->parent);
+       rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3,
+                                     RZ_MTU3_TMDR3_PHCKSEL,
+                                     ext_input_phase_clock_select);
+-      pm_runtime_put(priv->ch->dev);
++      pm_runtime_put(counter->parent);
+       mutex_unlock(&priv->lock);
+       return 0;
+@@ -644,7 +643,7 @@ static int rz_mtu3_action_read(struct co
+       if (ret)
+               return ret;
+-      ret = rz_mtu3_count_function_read_helper(ch, priv, &function);
++      ret = rz_mtu3_count_function_read_helper(ch, counter, &function);
+       if (ret) {
+               mutex_unlock(&priv->lock);
+               return ret;
diff --git a/queue-6.12/counter-rz-mtu3-cnt-prevent-counter-from-being-toggled-multiple-times.patch b/queue-6.12/counter-rz-mtu3-cnt-prevent-counter-from-being-toggled-multiple-times.patch
new file mode 100644 (file)
index 0000000..2842f60
--- /dev/null
@@ -0,0 +1,74 @@
+From 67c3f99bed6f422ba343d2b70a2eeeccdfd91bef Mon Sep 17 00:00:00 2001
+From: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
+Date: Fri, 30 Jan 2026 14:23:52 +0200
+Subject: counter: rz-mtu3-cnt: prevent counter from being toggled multiple times
+
+From: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
+
+commit 67c3f99bed6f422ba343d2b70a2eeeccdfd91bef upstream.
+
+Runtime PM counter is incremented / decremented each time the sysfs
+enable file is written to.
+
+If user writes 0 to the sysfs enable file multiple times, runtime PM
+usage count underflows, generating the following message.
+
+rz-mtu3-counter rz-mtu3-counter.0: Runtime PM usage count underflow!
+
+At the same time, hardware registers end up being accessed with clocks
+off in rz_mtu3_terminate_counter() to disable an already disabled
+channel.
+
+If user writes 1 to the sysfs enable file multiple times, runtime PM
+usage count will be incremented each time, requiring the same number of
+0 writes to get it back to 0.
+
+If user writes 0 to the sysfs enable file while PWM is in progress, PWM
+is stopped without counter being the owner of the underlying MTU3
+channel.
+
+Check against the cached count_is_enabled value and exit if the user
+is trying to set the same enable value.
+
+Cc: stable@vger.kernel.org
+Fixes: 0be8907359df ("counter: Add Renesas RZ/G2L MTU3a counter driver")
+Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
+Link: https://lore.kernel.org/r/20260130122353.2263273-5-cosmin-gabriel.tanislav.xa@renesas.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/counter/rz-mtu3-cnt.c |   12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/counter/rz-mtu3-cnt.c
++++ b/drivers/counter/rz-mtu3-cnt.c
+@@ -499,21 +499,25 @@ static int rz_mtu3_count_enable_write(st
+       struct rz_mtu3_cnt *const priv = counter_priv(counter);
+       int ret = 0;
++      mutex_lock(&priv->lock);
++
++      if (priv->count_is_enabled[count->id] == enable)
++              goto exit;
++
+       if (enable) {
+-              mutex_lock(&priv->lock);
+               pm_runtime_get_sync(ch->dev);
+               ret = rz_mtu3_initialize_counter(counter, count->id);
+               if (ret == 0)
+                       priv->count_is_enabled[count->id] = true;
+-              mutex_unlock(&priv->lock);
+       } else {
+-              mutex_lock(&priv->lock);
+               rz_mtu3_terminate_counter(counter, count->id);
+               priv->count_is_enabled[count->id] = false;
+               pm_runtime_put(ch->dev);
+-              mutex_unlock(&priv->lock);
+       }
++exit:
++      mutex_unlock(&priv->lock);
++
+       return ret;
+ }
diff --git a/queue-6.12/cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch b/queue-6.12/cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch
new file mode 100644 (file)
index 0000000..dc95929
--- /dev/null
@@ -0,0 +1,52 @@
+From 6dcf9d0064ce2f3e3dfe5755f98b93abe6a98e1e Mon Sep 17 00:00:00 2001
+From: Guangshuo Li <lgs201920130244@gmail.com>
+Date: Wed, 1 Apr 2026 10:45:35 +0800
+Subject: cpufreq: governor: fix double free in cpufreq_dbs_governor_init() error path
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+commit 6dcf9d0064ce2f3e3dfe5755f98b93abe6a98e1e upstream.
+
+When kobject_init_and_add() fails, cpufreq_dbs_governor_init() calls
+kobject_put(&dbs_data->attr_set.kobj).
+
+The kobject release callback cpufreq_dbs_data_release() calls
+gov->exit(dbs_data) and kfree(dbs_data), but the current error path
+then calls gov->exit(dbs_data) and kfree(dbs_data) again, causing a
+double free.
+
+Keep the direct kfree(dbs_data) for the gov->init() failure path, but
+after kobject_init_and_add() has been called, let kobject_put() handle
+the cleanup through cpufreq_dbs_data_release().
+
+Fixes: 4ebe36c94aed ("cpufreq: Fix kobject memleak")
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
+Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
+Cc: All applicable <stable@vger.kernel.org>
+Link: https://patch.msgid.link/20260401024535.1395801-1-lgs201920130244@gmail.com
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/cpufreq/cpufreq_governor.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/cpufreq/cpufreq_governor.c
++++ b/drivers/cpufreq/cpufreq_governor.c
+@@ -468,13 +468,13 @@ int cpufreq_dbs_governor_init(struct cpu
+       /* Failure, so roll back. */
+       pr_err("initialization failed (dbs_data kobject init error %d)\n", ret);
+-      kobject_put(&dbs_data->attr_set.kobj);
+-
+       policy->governor_data = NULL;
+       if (!have_governor_per_policy())
+               gov->gdbs_data = NULL;
+-      gov->exit(dbs_data);
++
++      kobject_put(&dbs_data->attr_set.kobj);
++      goto free_policy_dbs_info;
+ free_dbs_data:
+       kfree(dbs_data);
diff --git a/queue-6.12/crypto-tegra-add-missing-crypto_alg_async.patch b/queue-6.12/crypto-tegra-add-missing-crypto_alg_async.patch
new file mode 100644 (file)
index 0000000..0c5e22f
--- /dev/null
@@ -0,0 +1,214 @@
+From 4b56770d345524fc2acc143a2b85539cf7d74bc1 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Mon, 16 Mar 2026 13:21:19 -0700
+Subject: crypto: tegra - Add missing CRYPTO_ALG_ASYNC
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 4b56770d345524fc2acc143a2b85539cf7d74bc1 upstream.
+
+The tegra crypto driver failed to set the CRYPTO_ALG_ASYNC on its
+asynchronous algorithms, causing the crypto API to select them for users
+that request only synchronous algorithms.  This causes crashes (at
+least).  Fix this by adding the flag like what the other drivers do.
+Also remove the unnecessary CRYPTO_ALG_TYPE_* flags, since those just
+get ignored and overridden by the registration function anyway.
+
+Reported-by: Zorro Lang <zlang@redhat.com>
+Closes: https://lore.kernel.org/r/20260314080937.pghb4aa7d4je3mhh@dell-per750-06-vm-08.rhts.eng.pek2.redhat.com
+Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver")
+Cc: stable@vger.kernel.org
+Cc: Akhil R <akhilrajeev@nvidia.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/tegra/tegra-se-aes.c  |   11 +++++++----
+ drivers/crypto/tegra/tegra-se-hash.c |   30 +++++++++++++++++-------------
+ 2 files changed, 24 insertions(+), 17 deletions(-)
+
+--- a/drivers/crypto/tegra/tegra-se-aes.c
++++ b/drivers/crypto/tegra/tegra-se-aes.c
+@@ -480,7 +480,7 @@ static struct tegra_se_alg tegra_aes_alg
+                               .cra_name = "cbc(aes)",
+                               .cra_driver_name = "cbc-aes-tegra",
+                               .cra_priority = 500,
+-                              .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = AES_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_aes_ctx),
+                               .cra_alignmask = 0xf,
+@@ -501,7 +501,7 @@ static struct tegra_se_alg tegra_aes_alg
+                               .cra_name = "ecb(aes)",
+                               .cra_driver_name = "ecb-aes-tegra",
+                               .cra_priority = 500,
+-                              .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = AES_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_aes_ctx),
+                               .cra_alignmask = 0xf,
+@@ -523,7 +523,7 @@ static struct tegra_se_alg tegra_aes_alg
+                               .cra_name = "ctr(aes)",
+                               .cra_driver_name = "ctr-aes-tegra",
+                               .cra_priority = 500,
+-                              .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = 1,
+                               .cra_ctxsize = sizeof(struct tegra_aes_ctx),
+                               .cra_alignmask = 0xf,
+@@ -545,6 +545,7 @@ static struct tegra_se_alg tegra_aes_alg
+                               .cra_name = "xts(aes)",
+                               .cra_driver_name = "xts-aes-tegra",
+                               .cra_priority = 500,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = AES_BLOCK_SIZE,
+                               .cra_ctxsize       = sizeof(struct tegra_aes_ctx),
+                               .cra_alignmask     = (__alignof__(u64) - 1),
+@@ -1804,6 +1805,7 @@ static struct tegra_se_alg tegra_aead_al
+                               .cra_name = "gcm(aes)",
+                               .cra_driver_name = "gcm-aes-tegra",
+                               .cra_priority = 500,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = 1,
+                               .cra_ctxsize = sizeof(struct tegra_aead_ctx),
+                               .cra_alignmask = 0xf,
+@@ -1826,6 +1828,7 @@ static struct tegra_se_alg tegra_aead_al
+                               .cra_name = "ccm(aes)",
+                               .cra_driver_name = "ccm-aes-tegra",
+                               .cra_priority = 500,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = 1,
+                               .cra_ctxsize = sizeof(struct tegra_aead_ctx),
+                               .cra_alignmask = 0xf,
+@@ -1853,7 +1856,7 @@ static struct tegra_se_alg tegra_cmac_al
+                               .cra_name = "cmac(aes)",
+                               .cra_driver_name = "tegra-se-cmac",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = AES_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_cmac_ctx),
+                               .cra_alignmask = 0,
+--- a/drivers/crypto/tegra/tegra-se-hash.c
++++ b/drivers/crypto/tegra/tegra-se-hash.c
+@@ -698,7 +698,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha1",
+                               .cra_driver_name = "tegra-se-sha1",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -723,7 +723,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha224",
+                               .cra_driver_name = "tegra-se-sha224",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA224_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -748,7 +748,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha256",
+                               .cra_driver_name = "tegra-se-sha256",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -773,7 +773,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha384",
+                               .cra_driver_name = "tegra-se-sha384",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA384_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -798,7 +798,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha512",
+                               .cra_driver_name = "tegra-se-sha512",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA512_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -823,7 +823,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha3-224",
+                               .cra_driver_name = "tegra-se-sha3-224",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA3_224_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -848,7 +848,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha3-256",
+                               .cra_driver_name = "tegra-se-sha3-256",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA3_256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -873,7 +873,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha3-384",
+                               .cra_driver_name = "tegra-se-sha3-384",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA3_384_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -898,7 +898,7 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "sha3-512",
+                               .cra_driver_name = "tegra-se-sha3-512",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH,
++                              .cra_flags = CRYPTO_ALG_ASYNC,
+                               .cra_blocksize = SHA3_512_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -925,7 +925,8 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "hmac(sha224)",
+                               .cra_driver_name = "tegra-se-hmac-sha224",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA224_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -952,7 +953,8 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "hmac(sha256)",
+                               .cra_driver_name = "tegra-se-hmac-sha256",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -979,7 +981,8 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "hmac(sha384)",
+                               .cra_driver_name = "tegra-se-hmac-sha384",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA384_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
+@@ -1006,7 +1009,8 @@ static struct tegra_se_alg tegra_hash_al
+                               .cra_name = "hmac(sha512)",
+                               .cra_driver_name = "tegra-se-hmac-sha512",
+                               .cra_priority = 300,
+-                              .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA512_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct tegra_sha_ctx),
+                               .cra_alignmask = 0,
diff --git a/queue-6.12/gpio-mxc-map-both-edge-pad-wakeup-to-rising-edge.patch b/queue-6.12/gpio-mxc-map-both-edge-pad-wakeup-to-rising-edge.patch
new file mode 100644 (file)
index 0000000..917c6ef
--- /dev/null
@@ -0,0 +1,58 @@
+From c720fb57d56274213d027b3c5ab99080cf62a306 Mon Sep 17 00:00:00 2001
+From: Shenwei Wang <shenwei.wang@nxp.com>
+Date: Tue, 24 Mar 2026 14:21:29 -0500
+Subject: gpio: mxc: map Both Edge pad wakeup to Rising Edge
+
+From: Shenwei Wang <shenwei.wang@nxp.com>
+
+commit c720fb57d56274213d027b3c5ab99080cf62a306 upstream.
+
+Suspend may fail on i.MX8QM when Falling Edge is used as a pad wakeup
+trigger due to a hardware bug in the detection logic. Since the hardware
+does not support Both Edge wakeup, remap requests for Both Edge to Rising
+Edge by default to avoid hitting this issue.
+
+A warning is emitted when Falling Edge is selected on i.MX8QM.
+
+Fixes: f60c9eac54af ("gpio: mxc: enable pad wakeup on i.MX8x platforms")
+cc: stable@vger.kernel.org
+Reviewed-by: Peng Fan <peng.fan@nxp.com>
+Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
+Link: https://patch.msgid.link/20260324192129.2797237-1-shenwei.wang@nxp.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-mxc.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpio-mxc.c
++++ b/drivers/gpio/gpio-mxc.c
+@@ -576,12 +576,13 @@ static bool mxc_gpio_set_pad_wakeup(stru
+       unsigned long config;
+       bool ret = false;
+       int i, type;
++      bool is_imx8qm = of_device_is_compatible(port->dev->of_node, "fsl,imx8qm-gpio");
+       static const u32 pad_type_map[] = {
+               IMX_SCU_WAKEUP_OFF,             /* 0 */
+               IMX_SCU_WAKEUP_RISE_EDGE,       /* IRQ_TYPE_EDGE_RISING */
+               IMX_SCU_WAKEUP_FALL_EDGE,       /* IRQ_TYPE_EDGE_FALLING */
+-              IMX_SCU_WAKEUP_FALL_EDGE,       /* IRQ_TYPE_EDGE_BOTH */
++              IMX_SCU_WAKEUP_RISE_EDGE,       /* IRQ_TYPE_EDGE_BOTH */
+               IMX_SCU_WAKEUP_HIGH_LVL,        /* IRQ_TYPE_LEVEL_HIGH */
+               IMX_SCU_WAKEUP_OFF,             /* 5 */
+               IMX_SCU_WAKEUP_OFF,             /* 6 */
+@@ -596,6 +597,13 @@ static bool mxc_gpio_set_pad_wakeup(stru
+                               config = pad_type_map[type];
+                       else
+                               config = IMX_SCU_WAKEUP_OFF;
++
++                      if (is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) {
++                              dev_warn_once(port->dev,
++                                            "No falling-edge support for wakeup on i.MX8QM\n");
++                              config = IMX_SCU_WAKEUP_OFF;
++                      }
++
+                       ret |= mxc_gpio_generic_config(port, i, config);
+               }
+       }
diff --git a/queue-6.12/misc-fastrpc-possible-double-free-of-cctx-remote_heap.patch b/queue-6.12/misc-fastrpc-possible-double-free-of-cctx-remote_heap.patch
new file mode 100644 (file)
index 0000000..aa9e6f0
--- /dev/null
@@ -0,0 +1,42 @@
+From ba2c83167b215da30fa2aae56b140198cf8d8408 Mon Sep 17 00:00:00 2001
+From: Xingjing Deng <micro6947@gmail.com>
+Date: Fri, 30 Jan 2026 07:41:40 +0800
+Subject: misc: fastrpc: possible double-free of cctx->remote_heap
+
+From: Xingjing Deng <micro6947@gmail.com>
+
+commit ba2c83167b215da30fa2aae56b140198cf8d8408 upstream.
+
+fastrpc_init_create_static_process() may free cctx->remote_heap on the
+err_map path but does not clear the pointer. Later, fastrpc_rpmsg_remove()
+frees cctx->remote_heap again if it is non-NULL, which can lead to a
+double-free if the INIT_CREATE_STATIC ioctl hits the error path and the rpmsg
+device is subsequently removed/unbound.
+Clear cctx->remote_heap after freeing it in the error path to prevent the
+later cleanup from freeing it again.
+
+This issue was found by an in-house analysis workflow that extracts AST-based
+information and runs static checks, with LLM assistance for triage, and was
+confirmed by manual code review.
+No hardware testing was performed.
+
+Fixes: 0871561055e66 ("misc: fastrpc: Add support for audiopd")
+Cc: stable@vger.kernel.org # 6.2+
+Signed-off-by: Xingjing Deng <xjdeng@buaa.edu.cn>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260129234140.410983-1-xjdeng@buaa.edu.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/misc/fastrpc.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/misc/fastrpc.c
++++ b/drivers/misc/fastrpc.c
+@@ -1373,6 +1373,7 @@ err_invoke:
+       }
+ err_map:
+       fastrpc_buf_free(fl->cctx->remote_heap);
++      fl->cctx->remote_heap = NULL;
+ err_name:
+       kfree(name);
+ err:
diff --git a/queue-6.12/net-ethernet-mtk_ppe-avoid-null-deref-when-gmac0-is-disabled.patch b/queue-6.12/net-ethernet-mtk_ppe-avoid-null-deref-when-gmac0-is-disabled.patch
new file mode 100644 (file)
index 0000000..1c368e7
--- /dev/null
@@ -0,0 +1,66 @@
+From 976ff48c2ac6e6b25b01428c9d7997bcd0fb2949 Mon Sep 17 00:00:00 2001
+From: "Sven Eckelmann (Plasma Cloud)" <se@simonwunderlich.de>
+Date: Tue, 24 Mar 2026 09:36:01 +0100
+Subject: net: ethernet: mtk_ppe: avoid NULL deref when gmac0 is disabled
+
+From: Sven Eckelmann (Plasma Cloud) <se@simonwunderlich.de>
+
+commit 976ff48c2ac6e6b25b01428c9d7997bcd0fb2949 upstream.
+
+If the gmac0 is disabled, the precheck for a valid ingress device will
+cause a NULL pointer deref and crash the system. This happens because
+eth->netdev[0] will be NULL but the code will directly try to access
+netdev_ops.
+
+Instead of just checking for the first net_device, it must be checked if
+any of the mtk_eth net_devices is matching the netdev_ops of the ingress
+device.
+
+Cc: stable@vger.kernel.org
+Fixes: 73cfd947dbdb ("net: ethernet: mtk_eth_soc: ppe: prevent ppe update for non-mtk devices")
+Signed-off-by: Sven Eckelmann (Plasma Cloud) <se@simonwunderlich.de>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324-wed-crash-gmac0-disabled-v1-1-3bc388aee565@simonwunderlich.de
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/mediatek/mtk_ppe_offload.c |   21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -244,6 +244,25 @@ out:
+       return 0;
+ }
++static bool
++mtk_flow_is_valid_idev(const struct mtk_eth *eth, const struct net_device *idev)
++{
++      size_t i;
++
++      if (!idev)
++              return false;
++
++      for (i = 0; i < ARRAY_SIZE(eth->netdev); i++) {
++              if (!eth->netdev[i])
++                      continue;
++
++              if (idev->netdev_ops == eth->netdev[i]->netdev_ops)
++                      return true;
++      }
++
++      return false;
++}
++
+ static int
+ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
+                        int ppe_index)
+@@ -270,7 +289,7 @@ mtk_flow_offload_replace(struct mtk_eth
+               flow_rule_match_meta(rule, &match);
+               if (mtk_is_netsys_v2_or_greater(eth)) {
+                       idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
+-                      if (idev && idev->netdev_ops == eth->netdev[0]->netdev_ops) {
++                      if (mtk_flow_is_valid_idev(eth, idev)) {
+                               struct mtk_mac *mac = netdev_priv(idev);
+                               if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
diff --git a/queue-6.12/net-ftgmac100-fix-ring-allocation-unwind-on-open-failure.patch b/queue-6.12/net-ftgmac100-fix-ring-allocation-unwind-on-open-failure.patch
new file mode 100644 (file)
index 0000000..8ef185f
--- /dev/null
@@ -0,0 +1,83 @@
+From c0fd0fe745f5e8c568d898cd1513d0083e46204a Mon Sep 17 00:00:00 2001
+From: Yufan Chen <yufan.chen@linux.dev>
+Date: Sun, 29 Mar 2026 00:32:57 +0800
+Subject: net: ftgmac100: fix ring allocation unwind on open failure
+
+From: Yufan Chen <yufan.chen@linux.dev>
+
+commit c0fd0fe745f5e8c568d898cd1513d0083e46204a upstream.
+
+ftgmac100_alloc_rings() allocates rx_skbs, tx_skbs, rxdes, txdes, and
+rx_scratch in stages. On intermediate failures it returned -ENOMEM
+directly, leaking resources allocated earlier in the function.
+
+Rework the failure path to use staged local unwind labels and free
+allocated resources in reverse order before returning -ENOMEM. This
+matches common netdev allocation cleanup style.
+
+Fixes: d72e01a0430f ("ftgmac100: Use a scratch buffer for failed RX allocations")
+Cc: stable@vger.kernel.org
+Signed-off-by: Yufan Chen <yufan.chen@linux.dev>
+Link: https://patch.msgid.link/20260328163257.60836-1-yufan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/faraday/ftgmac100.c |   28 ++++++++++++++++++++++++----
+ 1 file changed, 24 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/faraday/ftgmac100.c
++++ b/drivers/net/ethernet/faraday/ftgmac100.c
+@@ -944,19 +944,19 @@ static int ftgmac100_alloc_rings(struct
+       priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
+                               GFP_KERNEL);
+       if (!priv->tx_skbs)
+-              return -ENOMEM;
++              goto err_free_rx_skbs;
+       /* Allocate descriptors */
+       priv->rxdes = dma_alloc_coherent(priv->dev,
+                                        MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes),
+                                        &priv->rxdes_dma, GFP_KERNEL);
+       if (!priv->rxdes)
+-              return -ENOMEM;
++              goto err_free_tx_skbs;
+       priv->txdes = dma_alloc_coherent(priv->dev,
+                                        MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes),
+                                        &priv->txdes_dma, GFP_KERNEL);
+       if (!priv->txdes)
+-              return -ENOMEM;
++              goto err_free_rxdes;
+       /* Allocate scratch packet buffer */
+       priv->rx_scratch = dma_alloc_coherent(priv->dev,
+@@ -964,9 +964,29 @@ static int ftgmac100_alloc_rings(struct
+                                             &priv->rx_scratch_dma,
+                                             GFP_KERNEL);
+       if (!priv->rx_scratch)
+-              return -ENOMEM;
++              goto err_free_txdes;
+       return 0;
++
++err_free_txdes:
++      dma_free_coherent(priv->dev,
++                        MAX_TX_QUEUE_ENTRIES *
++                        sizeof(struct ftgmac100_txdes),
++                        priv->txdes, priv->txdes_dma);
++      priv->txdes = NULL;
++err_free_rxdes:
++      dma_free_coherent(priv->dev,
++                        MAX_RX_QUEUE_ENTRIES *
++                        sizeof(struct ftgmac100_rxdes),
++                        priv->rxdes, priv->rxdes_dma);
++      priv->rxdes = NULL;
++err_free_tx_skbs:
++      kfree(priv->tx_skbs);
++      priv->tx_skbs = NULL;
++err_free_rx_skbs:
++      kfree(priv->rx_skbs);
++      priv->rx_skbs = NULL;
++      return -ENOMEM;
+ }
+ static void ftgmac100_init_rings(struct ftgmac100 *priv)
index 052b01da0eb37b35612f87d483c935d73bcc9ef3..7ab4077409d2fe6aa1cca91abfd2cacd5503aeac 100644 (file)
@@ -186,3 +186,18 @@ dt-bindings-connector-add-pd-disable-dependency.patch
 nvmem-imx-assign-nvmem_cell_info-raw_len.patch
 nvmem-zynqmp_nvmem-fix-buffer-size-in-dma-and-memcpy.patch
 netfilter-ipset-drop-logically-empty-buckets-in-mtype_del.patch
+counter-rz-mtu3-cnt-prevent-counter-from-being-toggled-multiple-times.patch
+counter-rz-mtu3-cnt-do-not-use-struct-rz_mtu3_channel-s-dev-member.patch
+crypto-tegra-add-missing-crypto_alg_async.patch
+vxlan-validate-nd-option-lengths-in-vxlan_na_create.patch
+net-ftgmac100-fix-ring-allocation-unwind-on-open-failure.patch
+net-ethernet-mtk_ppe-avoid-null-deref-when-gmac0-is-disabled.patch
+cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch
+gpio-mxc-map-both-edge-pad-wakeup-to-rising-edge.patch
+thermal-core-fix-thermal-zone-device-registration-error-path.patch
+misc-fastrpc-possible-double-free-of-cctx-remote_heap.patch
+thunderbolt-fix-property-read-in-nhi_wake_supported.patch
+usb-dummy-hcd-fix-locking-synchronization-error.patch
+usb-dummy-hcd-fix-interrupt-synchronization-error.patch
+usb-gadget-dummy_hcd-fix-premature-urb-completion-when-zlp-follows-partial-transfer.patch
+usb-typec-ucsi-validate-connector-number-in-ucsi_notify_common.patch
diff --git a/queue-6.12/thermal-core-fix-thermal-zone-device-registration-error-path.patch b/queue-6.12/thermal-core-fix-thermal-zone-device-registration-error-path.patch
new file mode 100644 (file)
index 0000000..72a16cb
--- /dev/null
@@ -0,0 +1,40 @@
+From 9e07e3b81807edd356e1f794cffa00a428eff443 Mon Sep 17 00:00:00 2001
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+Date: Wed, 1 Apr 2026 16:33:53 +0200
+Subject: thermal: core: Fix thermal zone device registration error path
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit 9e07e3b81807edd356e1f794cffa00a428eff443 upstream.
+
+If thermal_zone_device_register_with_trips() fails after registering
+a thermal zone device, it needs to wait for the tz->removal completion
+like thermal_zone_device_unregister(), in case user space has managed
+to take a reference to the thermal zone device's kobject, in which case
+thermal_release() may not be called by the error path itself and tz may
+be freed prematurely.
+
+Add the missing wait_for_completion() call to the thermal zone device
+registration error path.
+
+Fixes: 04e6ccfc93c5 ("thermal: core: Fix NULL pointer dereference in zone registration error path")
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Cc: All applicable <stable@vger.kernel.org>
+Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
+Tested-by: Lukasz Luba <lukasz.luba@arm.com>
+Link: https://patch.msgid.link/2849815.mvXUDI8C0e@rafael.j.wysocki
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thermal/thermal_core.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1543,6 +1543,7 @@ unregister:
+       device_del(&tz->device);
+ release_device:
+       put_device(&tz->device);
++      wait_for_completion(&tz->removal);
+ remove_id:
+       ida_free(&thermal_tz_ida, id);
+ free_tzp:
diff --git a/queue-6.12/thunderbolt-fix-property-read-in-nhi_wake_supported.patch b/queue-6.12/thunderbolt-fix-property-read-in-nhi_wake_supported.patch
new file mode 100644 (file)
index 0000000..0c113f6
--- /dev/null
@@ -0,0 +1,37 @@
+From 73a505dc48144ec72e25874e2b2a72487b02d3bc Mon Sep 17 00:00:00 2001
+From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Date: Mon, 9 Mar 2026 10:39:49 +0100
+Subject: thunderbolt: Fix property read in nhi_wake_supported()
+
+From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+
+commit 73a505dc48144ec72e25874e2b2a72487b02d3bc upstream.
+
+device_property_read_foo() returns 0 on success and only then modifies
+'val'. Currently, val is left uninitialized if the aforementioned
+function returns non-zero, making nhi_wake_supported() return true
+almost always (random != 0) if the property is not present in device
+firmware.
+
+Invert the check to make it make sense.
+
+Fixes: 3cdb9446a117 ("thunderbolt: Add support for Intel Ice Lake")
+Cc: stable@vger.kernel.org
+Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/nhi.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thunderbolt/nhi.c
++++ b/drivers/thunderbolt/nhi.c
+@@ -1010,7 +1010,7 @@ static bool nhi_wake_supported(struct pc
+        * If power rails are sustainable for wakeup from S4 this
+        * property is set by the BIOS.
+        */
+-      if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
++      if (!device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
+               return !!val;
+       return true;
diff --git a/queue-6.12/usb-dummy-hcd-fix-interrupt-synchronization-error.patch b/queue-6.12/usb-dummy-hcd-fix-interrupt-synchronization-error.patch
new file mode 100644 (file)
index 0000000..e2e3580
--- /dev/null
@@ -0,0 +1,99 @@
+From 2ca9e46f8f1f5a297eb0ac83f79d35d5b3a02541 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Sun, 15 Mar 2026 14:31:00 -0400
+Subject: USB: dummy-hcd: Fix interrupt synchronization error
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 2ca9e46f8f1f5a297eb0ac83f79d35d5b3a02541 upstream.
+
+This fixes an error in synchronization in the dummy-hcd driver.  The
+error has a somewhat involved history.  The synchronization mechanism
+was introduced by commit 7dbd8f4cabd9 ("USB: dummy-hcd: Fix erroneous
+synchronization change"), which added an emulated "interrupts enabled"
+flag together with code emulating synchronize_irq() (it waits until
+all current handler callbacks have returned).
+
+But the emulated interrupt-disable occurred too late, after the driver
+containing the handler callback routines had been told that it was
+unbound and no more callbacks would occur.  Commit 4a5d797a9f9c ("usb:
+gadget: dummy_hcd: fix gpf in gadget_setup") tried to fix this by
+moving the synchronize_irq() emulation code from dummy_stop() to
+dummy_pullup(), which runs before the unbind callback.
+
+There still were races, though, because the emulated interrupt-disable
+still occurred too late.  It couldn't be moved to dummy_pullup(),
+because that routine can be called for reasons other than an impending
+unbind.  Therefore commits 7dc0c55e9f30 ("USB: UDC core: Add
+udc_async_callbacks gadget op") and 04145a03db9d ("USB: UDC: Implement
+udc_async_callbacks in dummy-hcd") added an API allowing the UDC core
+to tell dummy-hcd exactly when emulated interrupts and their callbacks
+should be disabled.
+
+That brings us to the current state of things, which is still wrong
+because the emulated synchronize_irq() occurs before the emulated
+interrupt-disable!  That's no good, beause it means that more emulated
+interrupts can occur after the synchronize_irq() emulation has run,
+leading to the possibility that a callback handler may be running when
+the gadget driver is unbound.
+
+To fix this, we have to move the synchronize_irq() emulation code yet
+again, to the dummy_udc_async_callbacks() routine, which takes care of
+enabling and disabling emulated interrupt requests.  The
+synchronization will now run immediately after emulated interrupts are
+disabled, which is where it belongs.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Fixes: 04145a03db9d ("USB: UDC: Implement udc_async_callbacks in dummy-hcd")
+Cc: stable <stable@kernel.org>
+Link: https://patch.msgid.link/c7bc93fe-4241-4d04-bd56-27c12ba35c97@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c |   29 ++++++++++++++---------------
+ 1 file changed, 14 insertions(+), 15 deletions(-)
+
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -912,21 +912,6 @@ static int dummy_pullup(struct usb_gadge
+       spin_lock_irqsave(&dum->lock, flags);
+       dum->pullup = (value != 0);
+       set_link_state(dum_hcd);
+-      if (value == 0) {
+-              /*
+-               * Emulate synchronize_irq(): wait for callbacks to finish.
+-               * This seems to be the best place to emulate the call to
+-               * synchronize_irq() that's in usb_gadget_remove_driver().
+-               * Doing it in dummy_udc_stop() would be too late since it
+-               * is called after the unbind callback and unbind shouldn't
+-               * be invoked until all the other callbacks are finished.
+-               */
+-              while (dum->callback_usage > 0) {
+-                      spin_unlock_irqrestore(&dum->lock, flags);
+-                      usleep_range(1000, 2000);
+-                      spin_lock_irqsave(&dum->lock, flags);
+-              }
+-      }
+       spin_unlock_irqrestore(&dum->lock, flags);
+       usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
+@@ -949,6 +934,20 @@ static void dummy_udc_async_callbacks(st
+       spin_lock_irq(&dum->lock);
+       dum->ints_enabled = enable;
++      if (!enable) {
++              /*
++               * Emulate synchronize_irq(): wait for callbacks to finish.
++               * This has to happen after emulated interrupts are disabled
++               * (dum->ints_enabled is clear) and before the unbind callback,
++               * just like the call to synchronize_irq() in
++               * gadget/udc/core:gadget_unbind_driver().
++               */
++              while (dum->callback_usage > 0) {
++                      spin_unlock_irq(&dum->lock);
++                      usleep_range(1000, 2000);
++                      spin_lock_irq(&dum->lock);
++              }
++      }
+       spin_unlock_irq(&dum->lock);
+ }
diff --git a/queue-6.12/usb-dummy-hcd-fix-locking-synchronization-error.patch b/queue-6.12/usb-dummy-hcd-fix-locking-synchronization-error.patch
new file mode 100644 (file)
index 0000000..55eaf0e
--- /dev/null
@@ -0,0 +1,70 @@
+From 616a63ff495df12863692ab3f9f7b84e3fa7a66d Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Sun, 15 Mar 2026 14:30:43 -0400
+Subject: USB: dummy-hcd: Fix locking/synchronization error
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 616a63ff495df12863692ab3f9f7b84e3fa7a66d upstream.
+
+Syzbot testing was able to provoke an addressing exception and crash
+in the usb_gadget_udc_reset() routine in
+drivers/usb/gadgets/udc/core.c, resulting from the fact that the
+routine was called with a second ("driver") argument of NULL.  The bad
+caller was set_link_state() in dummy_hcd.c, and the problem arose
+because of a race between a USB reset and driver unbind.
+
+These sorts of races were not supposed to be possible; commit
+7dbd8f4cabd9 ("USB: dummy-hcd: Fix erroneous synchronization change"),
+along with a few followup commits, was written specifically to prevent
+them.  As it turns out, there are (at least) two errors remaining in
+the code.  Another patch will address the second error; this one is
+concerned with the first.
+
+The error responsible for the syzbot crash occurred because the
+stop_activity() routine will sometimes drop and then re-acquire the
+dum->lock spinlock.  A call to stop_activity() occurs in
+set_link_state() when handling an emulated USB reset, after the test
+of dum->ints_enabled and before the increment of dum->callback_usage.
+This allowed another thread (doing a driver unbind) to sneak in and
+grab the spinlock, and then clear dum->ints_enabled and dum->driver.
+Normally this other thread would have to wait for dum->callback_usage
+to go down to 0 before it would clear dum->driver, but in this case it
+didn't have to wait since dum->callback_usage had not yet been
+incremented.
+
+The fix is to increment dum->callback_usage _before_ calling
+stop_activity() instead of after.  Then the thread doing the unbind
+will not clear dum->driver until after the call to
+usb_gadget_udc_reset() safely returns and dum->callback_usage has been
+decremented again.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Reported-by: syzbot+19bed92c97bee999e5db@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/linux-usb/68fc7c9c.050a0220.346f24.023c.GAE@google.com/
+Tested-by: syzbot+19bed92c97bee999e5db@syzkaller.appspotmail.com
+Fixes: 7dbd8f4cabd9 ("USB: dummy-hcd: Fix erroneous synchronization change")
+Cc: stable <stable@kernel.org>
+Link: https://patch.msgid.link/46135f42-fdbe-46b5-aac0-6ca70492af15@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -461,8 +461,13 @@ static void set_link_state(struct dummy_
+               /* Report reset and disconnect events to the driver */
+               if (dum->ints_enabled && (disconnect || reset)) {
+-                      stop_activity(dum);
+                       ++dum->callback_usage;
++                      /*
++                       * stop_activity() can drop dum->lock, so it must
++                       * not come between the dum->ints_enabled test
++                       * and the ++dum->callback_usage.
++                       */
++                      stop_activity(dum);
+                       spin_unlock(&dum->lock);
+                       if (reset)
+                               usb_gadget_udc_reset(&dum->gadget, dum->driver);
diff --git a/queue-6.12/usb-gadget-dummy_hcd-fix-premature-urb-completion-when-zlp-follows-partial-transfer.patch b/queue-6.12/usb-gadget-dummy_hcd-fix-premature-urb-completion-when-zlp-follows-partial-transfer.patch
new file mode 100644 (file)
index 0000000..d3cea54
--- /dev/null
@@ -0,0 +1,70 @@
+From f50200dd44125e445a6164e88c217472fa79cdbc Mon Sep 17 00:00:00 2001
+From: Sebastian Urban <surban@surban.net>
+Date: Sun, 15 Mar 2026 16:10:45 +0100
+Subject: usb: gadget: dummy_hcd: fix premature URB completion when ZLP follows partial transfer
+
+From: Sebastian Urban <surban@surban.net>
+
+commit f50200dd44125e445a6164e88c217472fa79cdbc upstream.
+
+When a gadget request is only partially transferred in transfer()
+because the per-frame bandwidth budget is exhausted, the loop advances
+to the next queued request. If that next request is a zero-length
+packet (ZLP), len evaluates to zero and the code takes the
+unlikely(len == 0) path, which sets is_short = 1. This bypasses the
+bandwidth guard ("limit < ep->ep.maxpacket && limit < len") that
+lives in the else branch and would otherwise break out of the loop for
+non-zero requests. The is_short path then completes the URB before all
+data from the first request has been transferred.
+
+Reproducer (bulk IN, high speed):
+
+  Device side (FunctionFS with Linux AIO):
+    1. Queue a 65024-byte write via io_submit (127 * 512, i.e. a
+       multiple of the HS bulk max packet size).
+    2. Immediately queue a zero-length write (ZLP) via io_submit.
+
+  Host side:
+    3. Submit a 65536-byte bulk IN URB.
+
+  Expected: URB completes with actual_length = 65024.
+  Actual:   URB completes with actual_length = 53248, losing 11776
+            bytes that leak into subsequent URBs.
+
+At high speed the per-frame budget is 53248 bytes (512 * 13 * 8).
+The 65024-byte request exhausts this budget after 53248 bytes, leaving
+the request incomplete (req->req.actual < req->req.length). Neither
+the request nor the URB is finished, and rescan is 0, so the loop
+advances to the ZLP. For the ZLP, dev_len = 0, so len = min(12288, 0)
+= 0, taking the unlikely(len == 0) path and setting is_short = 1.
+The is_short handler then sets *status = 0, completing the URB with
+only 53248 of the expected 65024 bytes.
+
+Fix this by breaking out of the loop when the current request has
+remaining data (req->req.actual < req->req.length). The request
+resumes on the next timer tick, preserving correct data ordering.
+
+Signed-off-by: Sebastian Urban <surban@surban.net>
+Cc: stable <stable@kernel.org>
+Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://patch.msgid.link/20260315151045.1155850-1-surban@surban.net
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -1537,6 +1537,12 @@ top:
+               /* rescan to continue with any other queued i/o */
+               if (rescan)
+                       goto top;
++
++              /* request not fully transferred; stop iterating to
++               * preserve data ordering across queued requests.
++               */
++              if (req->req.actual < req->req.length)
++                      break;
+       }
+       return sent;
+ }
diff --git a/queue-6.12/usb-typec-ucsi-validate-connector-number-in-ucsi_notify_common.patch b/queue-6.12/usb-typec-ucsi-validate-connector-number-in-ucsi_notify_common.patch
new file mode 100644 (file)
index 0000000..8a776e3
--- /dev/null
@@ -0,0 +1,50 @@
+From d2d8c17ac01a1b1f638ea5d340a884ccc5015186 Mon Sep 17 00:00:00 2001
+From: Nathan Rebello <nathan.c.rebello@gmail.com>
+Date: Fri, 13 Mar 2026 18:24:53 -0400
+Subject: usb: typec: ucsi: validate connector number in ucsi_notify_common()
+
+From: Nathan Rebello <nathan.c.rebello@gmail.com>
+
+commit d2d8c17ac01a1b1f638ea5d340a884ccc5015186 upstream.
+
+The connector number extracted from CCI via UCSI_CCI_CONNECTOR() is a
+7-bit field (0-127) that is used to index into the connector array in
+ucsi_connector_change(). However, the array is only allocated for the
+number of connectors reported by the device (typically 2-4 entries).
+
+A malicious or malfunctioning device could report an out-of-range
+connector number in the CCI, causing an out-of-bounds array access in
+ucsi_connector_change().
+
+Add a bounds check in ucsi_notify_common(), the central point where CCI
+is parsed after arriving from hardware, so that bogus connector numbers
+are rejected before they propagate further.
+
+Fixes: bdc62f2bae8f ("usb: typec: ucsi: Simplified registration and I/O API")
+Cc: stable <stable@kernel.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Signed-off-by: Nathan Rebello <nathan.c.rebello@gmail.com>
+Link: https://patch.msgid.link/20260313222453.123-1-nathan.c.rebello@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -42,8 +42,13 @@ void ucsi_notify_common(struct ucsi *ucs
+       if (cci & UCSI_CCI_BUSY)
+               return;
+-      if (UCSI_CCI_CONNECTOR(cci))
+-              ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
++      if (UCSI_CCI_CONNECTOR(cci)) {
++              if (UCSI_CCI_CONNECTOR(cci) <= ucsi->cap.num_connectors)
++                      ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
++              else
++                      dev_err(ucsi->dev, "bogus connector number in CCI: %lu\n",
++                              UCSI_CCI_CONNECTOR(cci));
++      }
+       if (cci & UCSI_CCI_ACK_COMPLETE &&
+           test_and_clear_bit(ACK_PENDING, &ucsi->flags))
diff --git a/queue-6.12/vxlan-validate-nd-option-lengths-in-vxlan_na_create.patch b/queue-6.12/vxlan-validate-nd-option-lengths-in-vxlan_na_create.patch
new file mode 100644 (file)
index 0000000..83ebbb8
--- /dev/null
@@ -0,0 +1,54 @@
+From afa9a05e6c4971bd5586f1b304e14d61fb3d9385 Mon Sep 17 00:00:00 2001
+From: Yang Yang <n05ec@lzu.edu.cn>
+Date: Thu, 26 Mar 2026 03:44:41 +0000
+Subject: vxlan: validate ND option lengths in vxlan_na_create
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+commit afa9a05e6c4971bd5586f1b304e14d61fb3d9385 upstream.
+
+vxlan_na_create() walks ND options according to option-provided
+lengths. A malformed option can make the parser advance beyond the
+computed option span or use a too-short source LLADDR option payload.
+
+Validate option lengths against the remaining NS option area before
+advancing, and only read source LLADDR when the option is large enough
+for an Ethernet address.
+
+Fixes: 4b29dba9c085 ("vxlan: fix nonfunctional neigh_reduce()")
+Cc: stable@vger.kernel.org
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-4-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/vxlan/vxlan_core.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/vxlan/vxlan_core.c
++++ b/drivers/net/vxlan/vxlan_core.c
+@@ -1988,12 +1988,14 @@ static struct sk_buff *vxlan_na_create(s
+       ns_olen = request->len - skb_network_offset(request) -
+               sizeof(struct ipv6hdr) - sizeof(*ns);
+       for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
+-              if (!ns->opt[i + 1]) {
++              if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) {
+                       kfree_skb(reply);
+                       return NULL;
+               }
+               if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
+-                      daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
++                      if ((ns->opt[i + 1] << 3) >=
++                          sizeof(struct nd_opt_hdr) + ETH_ALEN)
++                              daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+                       break;
+               }
+       }