]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees
authorSasha Levin <sashal@kernel.org>
Thu, 11 Jun 2026 15:25:54 +0000 (11:25 -0400)
committerSasha Levin <sashal@kernel.org>
Thu, 11 Jun 2026 15:25:54 +0000 (11:25 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.1/series
queue-6.1/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch [new file with mode: 0644]
queue-6.1/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch [new file with mode: 0644]
queue-6.12/series
queue-6.12/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch [new file with mode: 0644]
queue-6.12/xfrm-hold-dev-ref-until-after-transport_finish-nf_ho.patch [new file with mode: 0644]
queue-6.18/series
queue-6.18/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch [new file with mode: 0644]
queue-6.6/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch [new file with mode: 0644]

index f89387be72d55f83a34a3a6ee869448d074f5c40..59f06c3bb80c735a612eefc5f9f6c7c2fe6daf12 100644 (file)
@@ -228,3 +228,5 @@ signal-clear-jobctl_pending_mask-for-caller-in-zap_o.patch
 time-fix-off-by-one-in-settimeofday-usec-validation.patch
 alsa-pcm-fix-wait-queue-list-corruption-in-snd_pcm_d.patch
 fs-ntfs3-return-error-for-inconsistent-extended-attr.patch
+usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch
+usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch
diff --git a/queue-6.1/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch b/queue-6.1/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch
new file mode 100644 (file)
index 0000000..10b1035
--- /dev/null
@@ -0,0 +1,220 @@
+From 490d16710ee9f20772d12a207737c29263a735f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jun 2026 18:08:36 +0000
+Subject: usb: gadget: f_ncm: Fix net_device lifecycle with device_move
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+[ Upstream commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 ]
+
+The network device outlived its parent gadget device during
+disconnection, resulting in dangling sysfs links and null pointer
+dereference problems.
+
+A prior attempt to solve this by removing SET_NETDEV_DEV entirely [1]
+was reverted due to power management ordering concerns and a NO-CARRIER
+regression.
+
+A subsequent attempt to defer net_device allocation to bind [2] broke
+1:1 mapping between function instance and network device, making it
+impossible for configfs to report the resolved interface name. This
+results in a regression where the DHCP server fails on pmOS.
+
+Use device_move to reparent the net_device between the gadget device and
+/sys/devices/virtual/ across bind/unbind cycles. This preserves the
+network interface across USB reconnection, allowing the DHCP server to
+retain their binding.
+
+Introduce gether_attach_gadget()/gether_detach_gadget() helpers and use
+__free(detach_gadget) macro to undo attachment on bind failure. The
+bind_count ensures device_move executes only on the first bind.
+
+[1] https://lore.kernel.org/lkml/f2a4f9847617a0929d62025748384092e5f35cce.camel@crapouillou.net/
+[2] https://lore.kernel.org/linux-usb/795ea759-7eaf-4f78-81f4-01ffbf2d7961@ixit.cz/
+
+Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-7-ea2afbc7d9b2@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ Use no_free_ptr() since retain_and_null_ptr() is unavailable in Linux 6.1. ]
+Signed-off-by: Jianqiang kang <jianqkang@sina.cn>
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/function/f_ncm.c   | 35 ++++++++++++++++++---------
+ drivers/usb/gadget/function/u_ether.c | 22 +++++++++++++++++
+ drivers/usb/gadget/function/u_ether.h | 26 ++++++++++++++++++++
+ drivers/usb/gadget/function/u_ncm.h   |  2 +-
+ 4 files changed, 73 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
+index addd016ffbb3f7..5e240cafbe9ee8 100644
+--- a/drivers/usb/gadget/function/f_ncm.c
++++ b/drivers/usb/gadget/function/f_ncm.c
+@@ -1440,6 +1440,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+       struct f_ncm_opts       *ncm_opts;
+       struct usb_os_desc_table        *os_desc_table __free(kfree) = NULL;
++      struct net_device               *net __free(detach_gadget) = NULL;
+       struct usb_request              *request __free(free_usb_request) = NULL;
+       if (!can_support_ecm(cdev->gadget))
+@@ -1453,16 +1454,18 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+                       return -ENOMEM;
+       }
+-      mutex_lock(&ncm_opts->lock);
+-      gether_set_gadget(ncm_opts->net, cdev->gadget);
+-      if (!ncm_opts->bound)
+-              status = gether_register_netdev(ncm_opts->net);
+-      mutex_unlock(&ncm_opts->lock);
+-
+-      if (status)
+-              return status;
+-
+-      ncm_opts->bound = true;
++      scoped_guard(mutex, &ncm_opts->lock)
++              if (ncm_opts->bind_count == 0) {
++                      if (!device_is_registered(&ncm_opts->net->dev)) {
++                              gether_set_gadget(ncm_opts->net, cdev->gadget);
++                              status = gether_register_netdev(ncm_opts->net);
++                      } else
++                              status = gether_attach_gadget(ncm_opts->net, cdev->gadget);
++
++                      if (status)
++                              return status;
++                      net = ncm_opts->net;
++              }
+       ncm_string_defs[1].s = ncm->ethaddr;
+@@ -1562,6 +1565,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+       }
+         ncm->notify_req = no_free_ptr(request);
++      ncm_opts->bind_count++;
++      no_free_ptr(net);
++
+       DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
+                       gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+@@ -1610,7 +1616,7 @@ static void ncm_free_inst(struct usb_function_instance *f)
+       struct f_ncm_opts *opts;
+       opts = container_of(f, struct f_ncm_opts, func_inst);
+-      if (opts->bound)
++      if (device_is_registered(&opts->net->dev))
+               gether_cleanup(netdev_priv(opts->net));
+       else
+               free_netdev(opts->net);
+@@ -1672,9 +1678,12 @@ static void ncm_free(struct usb_function *f)
+ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
+ {
+       struct f_ncm *ncm = func_to_ncm(f);
++      struct f_ncm_opts *ncm_opts;
+       DBG(c->cdev, "ncm unbind\n");
++      ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
++
+       hrtimer_cancel(&ncm->task_timer);
+       kfree(f->os_desc_table);
+@@ -1690,6 +1699,10 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
+       kfree(ncm->notify_req->buf);
+       usb_ep_free_request(ncm->notify, ncm->notify_req);
++
++      ncm_opts->bind_count--;
++      if (ncm_opts->bind_count == 0)
++              gether_detach_gadget(ncm_opts->net);
+ }
+ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
+diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
+index e84178bffe7803..e972de236be5e2 100644
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -910,6 +910,28 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
+ }
+ EXPORT_SYMBOL_GPL(gether_set_gadget);
++int gether_attach_gadget(struct net_device *net, struct usb_gadget *g)
++{
++      int ret;
++
++      ret = device_move(&net->dev, &g->dev, DPM_ORDER_DEV_AFTER_PARENT);
++      if (ret)
++              return ret;
++
++      gether_set_gadget(net, g);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(gether_attach_gadget);
++
++void gether_detach_gadget(struct net_device *net)
++{
++      struct eth_dev *dev = netdev_priv(net);
++
++      device_move(&net->dev, NULL, DPM_ORDER_NONE);
++      dev->gadget = NULL;
++}
++EXPORT_SYMBOL_GPL(gether_detach_gadget);
++
+ int gether_set_dev_addr(struct net_device *net, const char *dev_addr)
+ {
+       struct eth_dev *dev;
+diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
+index 40144546d1b07f..3e12d60053c136 100644
+--- a/drivers/usb/gadget/function/u_ether.h
++++ b/drivers/usb/gadget/function/u_ether.h
+@@ -149,6 +149,32 @@ static inline struct net_device *gether_setup_default(void)
+  */
+ void gether_set_gadget(struct net_device *net, struct usb_gadget *g);
++/**
++ * gether_attach_gadget - Reparent net_device to the gadget device.
++ * @net: The network device to reparent.
++ * @g: The target USB gadget device to parent to.
++ *
++ * This function moves the network device to be a child of the USB gadget
++ * device in the device hierarchy. This is typically done when the function
++ * is bound to a configuration.
++ *
++ * Returns 0 on success, or a negative error code on failure.
++ */
++int gether_attach_gadget(struct net_device *net, struct usb_gadget *g);
++
++/**
++ * gether_detach_gadget - Detach net_device from its gadget parent.
++ * @net: The network device to detach.
++ *
++ * This function moves the network device to be a child of the virtual
++ * devices parent, effectively detaching it from the USB gadget device
++ * hierarchy. This is typically done when the function is unbound
++ * from a configuration but the instance is not yet freed.
++ */
++void gether_detach_gadget(struct net_device *net);
++
++DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T))
++
+ /**
+  * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address
+  * @net: device representing this link
+diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h
+index 5408854d84072d..297e5087872f3f 100644
+--- a/drivers/usb/gadget/function/u_ncm.h
++++ b/drivers/usb/gadget/function/u_ncm.h
+@@ -18,7 +18,7 @@
+ struct f_ncm_opts {
+       struct usb_function_instance    func_inst;
+       struct net_device               *net;
+-      bool                            bound;
++      int                             bind_count;
+       struct config_group             *ncm_interf_group;
+       struct usb_os_desc              ncm_os_desc;
+-- 
+2.53.0
+
diff --git a/queue-6.1/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch b/queue-6.1/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch
new file mode 100644 (file)
index 0000000..dd7aff9
--- /dev/null
@@ -0,0 +1,61 @@
+From fa6a3228f1f888db5a3bd6192b1a79c2563cb7bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jun 2026 18:08:37 +0000
+Subject: usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+[ Upstream commit e002e92e88e12457373ed096b18716d97e7bbb20 ]
+
+Commit ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with
+device_move") reparents the gadget device to /sys/devices/virtual during
+unbind, clearing the gadget pointer. If the userspace tool queries on
+the surviving interface during this detached window, this leads to a
+NULL pointer dereference.
+
+Unable to handle kernel NULL pointer dereference
+Call trace:
+ eth_get_drvinfo+0x50/0x90
+ ethtool_get_drvinfo+0x5c/0x1f0
+ __dev_ethtool+0xaec/0x1fe0
+ dev_ethtool+0x134/0x2e0
+ dev_ioctl+0x338/0x560
+
+Add a NULL check for dev->gadget in eth_get_drvinfo(). When detached,
+skip copying the fw_version and bus_info strings, which is natively
+handled by ethtool_get_drvinfo for empty strings.
+
+Suggested-by: Val Packett <val@packett.cool>
+Reported-by: Val Packett <val@packett.cool>
+Closes: https://lore.kernel.org/linux-usb/10890524-cf83-4a71-b879-93e2b2cc1fcc@packett.cool/
+Fixes: ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with device_move")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260316-eth-null-deref-v1-1-07005f33be85@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/function/u_ether.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
+index e972de236be5e2..83dfc5008b689e 100644
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -147,8 +147,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+       strscpy(p->driver, "g_ether", sizeof(p->driver));
+       strscpy(p->version, UETH__VERSION, sizeof(p->version));
+-      strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+-      strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
++      if (dev->gadget) {
++              strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
++              strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
++      }
+ }
+ /* REVISIT can also support:
+-- 
+2.53.0
+
index 1f9d1e752603168c7b588212da6d37234453db2c..faa22b72aab5d1ea4b2db35d8daa18a6cbb639c0 100644 (file)
@@ -63,3 +63,5 @@ alsa-pcm-fix-wait-queue-list-corruption-in-snd_pcm_d.patch
 alsa-seq-dummy-fix-ump-event-stack-overread.patch
 ima-kexec-skip-ima-segment-validation-after-kexec-so.patch
 ima-kexec-move-ima-log-copy-from-kexec-load-to-execu.patch
+xfrm-hold-dev-ref-until-after-transport_finish-nf_ho.patch
+spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch
diff --git a/queue-6.12/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch b/queue-6.12/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch
new file mode 100644 (file)
index 0000000..57c409d
--- /dev/null
@@ -0,0 +1,53 @@
+From fa5916fc86d185335a7c3e3d559b435723341476 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jun 2026 10:08:09 +0800
+Subject: spi: cadence-quadspi: fix unclocked access on unbind
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 233db2cb14db8b1935dda52a6affd97276462b82 ]
+
+Make sure that the controller is runtime resumed before disabling it
+during driver unbind to avoid an unclocked register access.
+
+This issue was flagged by Sashiko when reviewing a controller
+deregistration fix.
+
+Fixes: 0578a6dbfe75 ("spi: spi-cadence-quadspi: add runtime pm support")
+Cc: stable@vger.kernel.org     # 6.7
+Cc: Dhruva Gole <d-gole@ti.com>
+Link: https://sashiko.dev/#/patchset/20260414134319.978196-1-johan%40kernel.org?part=2
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260421125354.1534871-4-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ Context adaptation performed. ]
+Signed-off-by: Robert Garcia <rob_garcia@163.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-cadence-quadspi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
+index 72262b6fb62b43..da8401261bbc3e 100644
+--- a/drivers/spi/spi-cadence-quadspi.c
++++ b/drivers/spi/spi-cadence-quadspi.c
+@@ -2013,13 +2013,14 @@ static void cqspi_remove(struct platform_device *pdev)
+               cqspi_wait_idle(cqspi);
+       spi_unregister_controller(cqspi->host);
+-      cqspi_controller_enable(cqspi, 0);
+       if (cqspi->rx_chan)
+               dma_release_channel(cqspi->rx_chan);
+-      if (pm_runtime_get_sync(&pdev->dev) >= 0)
++      if (pm_runtime_get_sync(&pdev->dev) >= 0) {
++              cqspi_controller_enable(cqspi, 0);
+               clk_disable(cqspi->clk);
++      }
+       if (cqspi->is_jh7110)
+               cqspi_jh7110_disable_clk(pdev, cqspi);
+-- 
+2.53.0
+
diff --git a/queue-6.12/xfrm-hold-dev-ref-until-after-transport_finish-nf_ho.patch b/queue-6.12/xfrm-hold-dev-ref-until-after-transport_finish-nf_ho.patch
new file mode 100644 (file)
index 0000000..9c3fdba
--- /dev/null
@@ -0,0 +1,111 @@
+From bd3bf302b345b6a160221064792f0d0c6bfa6684 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jun 2026 12:11:27 +0000
+Subject: xfrm: hold dev ref until after transport_finish NF_HOOK
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 1c428b03840094410c5fb6a5db30640486bbbfcb ]
+
+After async crypto completes, xfrm_input_resume() calls dev_put()
+immediately on re-entry before the skb reaches transport_finish.
+The skb->dev pointer is then used inside NF_HOOK and its okfn,
+which can race with device teardown.
+
+Remove the dev_put from the async resumption entry and instead
+drop the reference after the NF_HOOK call in transport_finish,
+using a saved device pointer since NF_HOOK may consume the skb.
+This covers NF_DROP, NF_QUEUE and NF_STOLEN paths that skip
+the okfn.
+
+For non-transport exits (decaps, gro, drop) and secondary
+async return points, release the reference inline when
+async is set.
+
+Suggested-by: Florian Westphal <fw@strlen.de>
+Fixes: acf568ee859f ("xfrm: Reinject transport-mode packets through tasklet")
+Cc: stable@vger.kernel.org
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+[ net/xfrm/xfrm_input.c: dev_hold/dev_put are unconditional here rather
+than inside !crypto_done as in mainline, and the dev_put in the
+encap_type == -1 async-resumption block does not exist. Adapted by
+taking a fresh dev_hold (when async && !xfrm_gro) immediately before
+transport_finish, which releases it after NF_HOOK. The per-iteration
+dev_hold/dev_put pair at loop-top/resume: is left unchanged.]
+Signed-off-by: Simon Liebold <simonlie@amazon.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/xfrm4_input.c | 5 ++++-
+ net/ipv6/xfrm6_input.c | 5 ++++-
+ net/xfrm/xfrm_input.c  | 5 ++++-
+ 3 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
+index 12a1a0f421956c..adf21d6b6076c1 100644
+--- a/net/ipv4/xfrm4_input.c
++++ b/net/ipv4/xfrm4_input.c
+@@ -50,6 +50,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
+ {
+       struct xfrm_offload *xo = xfrm_offload(skb);
+       struct iphdr *iph = ip_hdr(skb);
++      struct net_device *dev = skb->dev;
+       iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
+@@ -73,8 +74,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
+       }
+       NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
+-              dev_net(skb->dev), NULL, skb, skb->dev, NULL,
++              dev_net(dev), NULL, skb, dev, NULL,
+               xfrm4_rcv_encap_finish);
++      if (async)
++              dev_put(dev);
+       return 0;
+ }
+diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
+index 9005fc156a20e6..699a001ac16629 100644
+--- a/net/ipv6/xfrm6_input.c
++++ b/net/ipv6/xfrm6_input.c
+@@ -43,6 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
+ int xfrm6_transport_finish(struct sk_buff *skb, int async)
+ {
+       struct xfrm_offload *xo = xfrm_offload(skb);
++      struct net_device *dev = skb->dev;
+       int nhlen = -skb_network_offset(skb);
+       skb_network_header(skb)[IP6CB(skb)->nhoff] =
+@@ -68,8 +69,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
+       }
+       NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
+-              dev_net(skb->dev), NULL, skb, skb->dev, NULL,
++              dev_net(dev), NULL, skb, dev, NULL,
+               xfrm6_transport_finish2);
++      if (async)
++              dev_put(dev);
+       return 0;
+ }
+diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
+index 8edcb32735e595..0288d98e66ee48 100644
+--- a/net/xfrm/xfrm_input.c
++++ b/net/xfrm/xfrm_input.c
+@@ -726,8 +726,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+               err = -EAFNOSUPPORT;
+               rcu_read_lock();
+               afinfo = xfrm_state_afinfo_get_rcu(x->props.family);
+-              if (likely(afinfo))
++              if (likely(afinfo)) {
++                      if (async && !xfrm_gro)
++                              dev_hold(skb->dev);
+                       err = afinfo->transport_finish(skb, xfrm_gro || async);
++              }
+               rcu_read_unlock();
+               if (xfrm_gro) {
+                       sp = skb_sec_path(skb);
+-- 
+2.53.0
+
index 8ff79d9ba81d30a7c0b4613308e16e1876b3b70d..8aa8a548dd0de80a4763e486607508106779caec 100644 (file)
@@ -73,3 +73,4 @@ hyperv-clean-up-and-fix-the-guest-id-comment-in-hvgd.patch
 time-fix-off-by-one-in-settimeofday-usec-validation.patch
 alsa-pcm-fix-wait-queue-list-corruption-in-snd_pcm_d.patch
 alsa-seq-dummy-fix-ump-event-stack-overread.patch
+spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch
diff --git a/queue-6.18/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch b/queue-6.18/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch
new file mode 100644 (file)
index 0000000..ff708b1
--- /dev/null
@@ -0,0 +1,56 @@
+From 030e7fec4716f983e874dcfeebfe1c33f2033388 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jun 2026 14:37:19 +0800
+Subject: spi: cadence-quadspi: fix unclocked access on unbind
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 233db2cb14db8b1935dda52a6affd97276462b82 ]
+
+Make sure that the controller is runtime resumed before disabling it
+during driver unbind to avoid an unclocked register access.
+
+This issue was flagged by Sashiko when reviewing a controller
+deregistration fix.
+
+Fixes: 0578a6dbfe75 ("spi: spi-cadence-quadspi: add runtime pm support")
+Cc: stable@vger.kernel.org     # 6.7
+Cc: Dhruva Gole <d-gole@ti.com>
+Link: https://sashiko.dev/#/patchset/20260414134319.978196-1-johan%40kernel.org?part=2
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260421125354.1534871-4-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ Context adaptation performed. ]
+Signed-off-by: Robert Garcia <rob_garcia@163.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-cadence-quadspi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
+index d61bc678b6f83b..0a32e28eefd515 100644
+--- a/drivers/spi/spi-cadence-quadspi.c
++++ b/drivers/spi/spi-cadence-quadspi.c
+@@ -2055,7 +2055,6 @@ static void cqspi_remove(struct platform_device *pdev)
+               cqspi_wait_idle(cqspi);
+       spi_unregister_controller(cqspi->host);
+-      cqspi_controller_enable(cqspi, 0);
+       if (cqspi->rx_chan)
+               dma_release_channel(cqspi->rx_chan);
+@@ -2063,8 +2062,10 @@ static void cqspi_remove(struct platform_device *pdev)
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+               ret = pm_runtime_get_sync(&pdev->dev);
+-      if (ret >= 0)
++      if (ret >= 0) {
++              cqspi_controller_enable(cqspi, 0);
+               clk_disable(cqspi->clk);
++      }
+       if (cqspi->is_jh7110)
+               cqspi_jh7110_disable_clk(pdev, cqspi);
+-- 
+2.53.0
+
index 3f408cf7678eff1388a7516dd2cb0a0dedae629e..c2f6d36d9907772d267a7935f49e873d01353136 100644 (file)
@@ -247,3 +247,5 @@ ipmi-fix-rcu_read_unlock-to-srcu_read_unlock-in-hand.patch
 signal-clear-jobctl_pending_mask-for-caller-in-zap_o.patch
 time-fix-off-by-one-in-settimeofday-usec-validation.patch
 alsa-pcm-fix-wait-queue-list-corruption-in-snd_pcm_d.patch
+usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch
+usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch
diff --git a/queue-6.6/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch b/queue-6.6/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch
new file mode 100644 (file)
index 0000000..fad1ebb
--- /dev/null
@@ -0,0 +1,220 @@
+From 6310da86d3410af28a2a8a1b0430d958e69aaa7b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jun 2026 18:09:23 +0000
+Subject: usb: gadget: f_ncm: Fix net_device lifecycle with device_move
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+[ Upstream commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 ]
+
+The network device outlived its parent gadget device during
+disconnection, resulting in dangling sysfs links and null pointer
+dereference problems.
+
+A prior attempt to solve this by removing SET_NETDEV_DEV entirely [1]
+was reverted due to power management ordering concerns and a NO-CARRIER
+regression.
+
+A subsequent attempt to defer net_device allocation to bind [2] broke
+1:1 mapping between function instance and network device, making it
+impossible for configfs to report the resolved interface name. This
+results in a regression where the DHCP server fails on pmOS.
+
+Use device_move to reparent the net_device between the gadget device and
+/sys/devices/virtual/ across bind/unbind cycles. This preserves the
+network interface across USB reconnection, allowing the DHCP server to
+retain their binding.
+
+Introduce gether_attach_gadget()/gether_detach_gadget() helpers and use
+__free(detach_gadget) macro to undo attachment on bind failure. The
+bind_count ensures device_move executes only on the first bind.
+
+[1] https://lore.kernel.org/lkml/f2a4f9847617a0929d62025748384092e5f35cce.camel@crapouillou.net/
+[2] https://lore.kernel.org/linux-usb/795ea759-7eaf-4f78-81f4-01ffbf2d7961@ixit.cz/
+
+Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-7-ea2afbc7d9b2@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ Use no_free_ptr() since retain_and_null_ptr() is unavailable in Linux 6.6. ]
+Signed-off-by: Jianqiang kang <jianqkang@sina.cn>
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/function/f_ncm.c   | 35 ++++++++++++++++++---------
+ drivers/usb/gadget/function/u_ether.c | 22 +++++++++++++++++
+ drivers/usb/gadget/function/u_ether.h | 26 ++++++++++++++++++++
+ drivers/usb/gadget/function/u_ncm.h   |  2 +-
+ 4 files changed, 73 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
+index 9e9601f12b8862..d8ab1adec63e6d 100644
+--- a/drivers/usb/gadget/function/f_ncm.c
++++ b/drivers/usb/gadget/function/f_ncm.c
+@@ -1425,6 +1425,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+       struct f_ncm_opts       *ncm_opts;
+       struct usb_os_desc_table        *os_desc_table __free(kfree) = NULL;
++      struct net_device               *net __free(detach_gadget) = NULL;
+       struct usb_request              *request __free(free_usb_request) = NULL;
+       if (!can_support_ecm(cdev->gadget))
+@@ -1438,16 +1439,18 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+                       return -ENOMEM;
+       }
+-      mutex_lock(&ncm_opts->lock);
+-      gether_set_gadget(ncm_opts->net, cdev->gadget);
+-      if (!ncm_opts->bound)
+-              status = gether_register_netdev(ncm_opts->net);
+-      mutex_unlock(&ncm_opts->lock);
+-
+-      if (status)
+-              return status;
+-
+-      ncm_opts->bound = true;
++      scoped_guard(mutex, &ncm_opts->lock)
++              if (ncm_opts->bind_count == 0) {
++                      if (!device_is_registered(&ncm_opts->net->dev)) {
++                              gether_set_gadget(ncm_opts->net, cdev->gadget);
++                              status = gether_register_netdev(ncm_opts->net);
++                      } else
++                              status = gether_attach_gadget(ncm_opts->net, cdev->gadget);
++
++                      if (status)
++                              return status;
++                      net = ncm_opts->net;
++              }
+       ncm_string_defs[1].s = ncm->ethaddr;
+@@ -1547,6 +1550,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+       }
+       ncm->notify_req = no_free_ptr(request);
++      ncm_opts->bind_count++;
++      no_free_ptr(net);
++
+       DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n",
+                       ncm->port.in_ep->name, ncm->port.out_ep->name,
+                       ncm->notify->name);
+@@ -1593,7 +1599,7 @@ static void ncm_free_inst(struct usb_function_instance *f)
+       struct f_ncm_opts *opts;
+       opts = container_of(f, struct f_ncm_opts, func_inst);
+-      if (opts->bound)
++      if (device_is_registered(&opts->net->dev))
+               gether_cleanup(netdev_priv(opts->net));
+       else
+               free_netdev(opts->net);
+@@ -1655,9 +1661,12 @@ static void ncm_free(struct usb_function *f)
+ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
+ {
+       struct f_ncm *ncm = func_to_ncm(f);
++      struct f_ncm_opts *ncm_opts;
+       DBG(c->cdev, "ncm unbind\n");
++      ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
++
+       hrtimer_cancel(&ncm->task_timer);
+       kfree(f->os_desc_table);
+@@ -1673,6 +1682,10 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
+       kfree(ncm->notify_req->buf);
+       usb_ep_free_request(ncm->notify, ncm->notify_req);
++
++      ncm_opts->bind_count--;
++      if (ncm_opts->bind_count == 0)
++              gether_detach_gadget(ncm_opts->net);
+ }
+ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
+diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
+index 62e2018d0357c7..49ff3fc62f7469 100644
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -896,6 +896,28 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
+ }
+ EXPORT_SYMBOL_GPL(gether_set_gadget);
++int gether_attach_gadget(struct net_device *net, struct usb_gadget *g)
++{
++      int ret;
++
++      ret = device_move(&net->dev, &g->dev, DPM_ORDER_DEV_AFTER_PARENT);
++      if (ret)
++              return ret;
++
++      gether_set_gadget(net, g);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(gether_attach_gadget);
++
++void gether_detach_gadget(struct net_device *net)
++{
++      struct eth_dev *dev = netdev_priv(net);
++
++      device_move(&net->dev, NULL, DPM_ORDER_NONE);
++      dev->gadget = NULL;
++}
++EXPORT_SYMBOL_GPL(gether_detach_gadget);
++
+ int gether_set_dev_addr(struct net_device *net, const char *dev_addr)
+ {
+       struct eth_dev *dev;
+diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
+index 34be220cef77c4..c85a1cf3c115d2 100644
+--- a/drivers/usb/gadget/function/u_ether.h
++++ b/drivers/usb/gadget/function/u_ether.h
+@@ -150,6 +150,32 @@ static inline struct net_device *gether_setup_default(void)
+  */
+ void gether_set_gadget(struct net_device *net, struct usb_gadget *g);
++/**
++ * gether_attach_gadget - Reparent net_device to the gadget device.
++ * @net: The network device to reparent.
++ * @g: The target USB gadget device to parent to.
++ *
++ * This function moves the network device to be a child of the USB gadget
++ * device in the device hierarchy. This is typically done when the function
++ * is bound to a configuration.
++ *
++ * Returns 0 on success, or a negative error code on failure.
++ */
++int gether_attach_gadget(struct net_device *net, struct usb_gadget *g);
++
++/**
++ * gether_detach_gadget - Detach net_device from its gadget parent.
++ * @net: The network device to detach.
++ *
++ * This function moves the network device to be a child of the virtual
++ * devices parent, effectively detaching it from the USB gadget device
++ * hierarchy. This is typically done when the function is unbound
++ * from a configuration but the instance is not yet freed.
++ */
++void gether_detach_gadget(struct net_device *net);
++
++DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T))
++
+ /**
+  * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address
+  * @net: device representing this link
+diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h
+index 5408854d84072d..297e5087872f3f 100644
+--- a/drivers/usb/gadget/function/u_ncm.h
++++ b/drivers/usb/gadget/function/u_ncm.h
+@@ -18,7 +18,7 @@
+ struct f_ncm_opts {
+       struct usb_function_instance    func_inst;
+       struct net_device               *net;
+-      bool                            bound;
++      int                             bind_count;
+       struct config_group             *ncm_interf_group;
+       struct usb_os_desc              ncm_os_desc;
+-- 
+2.53.0
+
diff --git a/queue-6.6/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch b/queue-6.6/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch
new file mode 100644 (file)
index 0000000..e056580
--- /dev/null
@@ -0,0 +1,61 @@
+From b090f4aef7ac5fd129b1ee4fba2213febc1ea9f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jun 2026 18:09:24 +0000
+Subject: usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+[ Upstream commit e002e92e88e12457373ed096b18716d97e7bbb20 ]
+
+Commit ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with
+device_move") reparents the gadget device to /sys/devices/virtual during
+unbind, clearing the gadget pointer. If the userspace tool queries on
+the surviving interface during this detached window, this leads to a
+NULL pointer dereference.
+
+Unable to handle kernel NULL pointer dereference
+Call trace:
+ eth_get_drvinfo+0x50/0x90
+ ethtool_get_drvinfo+0x5c/0x1f0
+ __dev_ethtool+0xaec/0x1fe0
+ dev_ethtool+0x134/0x2e0
+ dev_ioctl+0x338/0x560
+
+Add a NULL check for dev->gadget in eth_get_drvinfo(). When detached,
+skip copying the fw_version and bus_info strings, which is natively
+handled by ethtool_get_drvinfo for empty strings.
+
+Suggested-by: Val Packett <val@packett.cool>
+Reported-by: Val Packett <val@packett.cool>
+Closes: https://lore.kernel.org/linux-usb/10890524-cf83-4a71-b879-93e2b2cc1fcc@packett.cool/
+Fixes: ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with device_move")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260316-eth-null-deref-v1-1-07005f33be85@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/function/u_ether.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
+index 49ff3fc62f7469..91b2d1f5ed005b 100644
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -112,8 +112,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+       strscpy(p->driver, "g_ether", sizeof(p->driver));
+       strscpy(p->version, UETH__VERSION, sizeof(p->version));
+-      strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+-      strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
++      if (dev->gadget) {
++              strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
++              strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
++      }
+ }
+ /* REVISIT can also support:
+-- 
+2.53.0
+