From: Sasha Levin Date: Thu, 11 Jun 2026 15:25:54 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=9a42c749a4f2f1dd379da3bb548cb720716f376e;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-6.1/series b/queue-6.1/series index f89387be72..59f06c3bb8 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -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 index 0000000000..10b1035f7c --- /dev/null +++ b/queue-6.1/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch @@ -0,0 +1,220 @@ +From 490d16710ee9f20772d12a207737c29263a735f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-7-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +[ Use no_free_ptr() since retain_and_null_ptr() is unavailable in Linux 6.1. ] +Signed-off-by: Jianqiang kang +Signed-off-by: Carlos Llamas +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..dd7aff952d --- /dev/null +++ b/queue-6.1/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch @@ -0,0 +1,61 @@ +From fa6a3228f1f888db5a3bd6192b1a79c2563cb7bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Val Packett +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 +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260316-eth-null-deref-v1-1-07005f33be85@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Carlos Llamas +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/series b/queue-6.12/series index 1f9d1e7526..faa22b72aa 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -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 index 0000000000..57c409d781 --- /dev/null +++ b/queue-6.12/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch @@ -0,0 +1,53 @@ +From fa5916fc86d185335a7c3e3d559b435723341476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jun 2026 10:08:09 +0800 +Subject: spi: cadence-quadspi: fix unclocked access on unbind + +From: Johan Hovold + +[ 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 +Link: https://sashiko.dev/#/patchset/20260414134319.978196-1-johan%40kernel.org?part=2 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260421125354.1534871-4-johan@kernel.org +Signed-off-by: Mark Brown +[ Context adaptation performed. ] +Signed-off-by: Robert Garcia +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..9c3fdba345 --- /dev/null +++ b/queue-6.12/xfrm-hold-dev-ref-until-after-transport_finish-nf_ho.patch @@ -0,0 +1,111 @@ +From bd3bf302b345b6a160221064792f0d0c6bfa6684 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Jun 2026 12:11:27 +0000 +Subject: xfrm: hold dev ref until after transport_finish NF_HOOK + +From: Qi Tang + +[ 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 +Fixes: acf568ee859f ("xfrm: Reinject transport-mode packets through tasklet") +Cc: stable@vger.kernel.org +Signed-off-by: Qi Tang +Signed-off-by: Steffen Klassert +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/series b/queue-6.18/series index 8ff79d9ba8..8aa8a548dd 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -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 index 0000000000..ff708b1c64 --- /dev/null +++ b/queue-6.18/spi-cadence-quadspi-fix-unclocked-access-on-unbind.patch @@ -0,0 +1,56 @@ +From 030e7fec4716f983e874dcfeebfe1c33f2033388 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Jun 2026 14:37:19 +0800 +Subject: spi: cadence-quadspi: fix unclocked access on unbind + +From: Johan Hovold + +[ 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 +Link: https://sashiko.dev/#/patchset/20260414134319.978196-1-johan%40kernel.org?part=2 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260421125354.1534871-4-johan@kernel.org +Signed-off-by: Mark Brown +[ Context adaptation performed. ] +Signed-off-by: Robert Garcia +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/series b/queue-6.6/series index 3f408cf767..c2f6d36d99 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -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 index 0000000000..fad1ebb4db --- /dev/null +++ b/queue-6.6/usb-gadget-f_ncm-fix-net_device-lifecycle-with-devic.patch @@ -0,0 +1,220 @@ +From 6310da86d3410af28a2a8a1b0430d958e69aaa7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-7-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +[ Use no_free_ptr() since retain_and_null_ptr() is unavailable in Linux 6.6. ] +Signed-off-by: Jianqiang kang +Signed-off-by: Carlos Llamas +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..e056580b18 --- /dev/null +++ b/queue-6.6/usb-gadget-u_ether-fix-null-pointer-deref-in-eth_get.patch @@ -0,0 +1,61 @@ +From b090f4aef7ac5fd129b1ee4fba2213febc1ea9f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Val Packett +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 +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260316-eth-null-deref-v1-1-07005f33be85@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Carlos Llamas +Signed-off-by: Sasha Levin +--- + 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 +