gfs2-improve-gfs2_consist_inode-usage.patch
gfs2-validate-i_depth-for-exhash-directories.patch
loongarch-vdso-emit-gnu_eh_frame-correctly.patch
+usb-gadget-u_ether-fix-race-between-gether_disconnect-and-eth_stop.patch
+usb-gadget-uvc-fix-null-pointer-dereference-during-unbind-race.patch
+usb-gadget-f_subset-fix-unbalanced-refcnt-in-geth_free.patch
+usb-gadget-f_rndis-protect-rndis-options-with-mutex.patch
+usb-gadget-f_uac1_legacy-validate-control-request-size.patch
--- /dev/null
+From 8d8c68b1fc06ece60cf43e1306ff0f4ac121547e Mon Sep 17 00:00:00 2001
+From: Kuen-Han Tsai <khtsai@google.com>
+Date: Fri, 20 Mar 2026 16:54:45 +0800
+Subject: usb: gadget: f_rndis: Protect RNDIS options with mutex
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+commit 8d8c68b1fc06ece60cf43e1306ff0f4ac121547e upstream.
+
+The class/subclass/protocol options are suspectible to race conditions
+as they can be accessed concurrently through configfs.
+
+Use existing mutex to protect these options. This issue was identified
+during code inspection.
+
+Fixes: 73517cf49bd4 ("usb: gadget: add RNDIS configfs options for class/subclass/protocol")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260320-usb-net-lifecycle-v1-2-4886b578161b@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_rndis.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_rndis.c
++++ b/drivers/usb/gadget/function/f_rndis.c
+@@ -11,6 +11,7 @@
+
+ /* #define VERBOSE_DEBUG */
+
++#include <linux/cleanup.h>
+ #include <linux/slab.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -678,9 +679,11 @@ rndis_bind(struct usb_configuration *c,
+ return -ENOMEM;
+ }
+
+- rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
+- rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
+- rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
++ scoped_guard(mutex, &rndis_opts->lock) {
++ rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
++ rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
++ rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
++ }
+
+ /*
+ * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
--- /dev/null
+From caa27923aacd8a5869207842f2ab1657c6c0c7bc Mon Sep 17 00:00:00 2001
+From: Kuen-Han Tsai <khtsai@google.com>
+Date: Fri, 20 Mar 2026 16:54:44 +0800
+Subject: usb: gadget: f_subset: Fix unbalanced refcnt in geth_free
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+commit caa27923aacd8a5869207842f2ab1657c6c0c7bc upstream.
+
+geth_alloc() increments the reference count, but geth_free() fails to
+decrement it. This prevents the configuration of attributes via configfs
+after unlinking the function.
+
+Decrement the reference count in geth_free() to ensure proper cleanup.
+
+Fixes: 02832e56f88a ("usb: gadget: f_subset: add configfs support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260320-usb-net-lifecycle-v1-1-4886b578161b@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_subset.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/gadget/function/f_subset.c
++++ b/drivers/usb/gadget/function/f_subset.c
+@@ -6,6 +6,7 @@
+ * Copyright (C) 2008 Nokia Corporation
+ */
+
++#include <linux/cleanup.h>
+ #include <linux/slab.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -449,8 +450,13 @@ static struct usb_function_instance *get
+ static void geth_free(struct usb_function *f)
+ {
+ struct f_gether *eth;
++ struct f_gether_opts *opts;
++
++ opts = container_of(f->fi, struct f_gether_opts, func_inst);
+
+ eth = func_to_geth(f);
++ scoped_guard(mutex, &opts->lock)
++ opts->refcnt--;
+ kfree(eth);
+ }
+
--- /dev/null
+From 6e0e34d85cd46ceb37d16054e97a373a32770f6c Mon Sep 17 00:00:00 2001
+From: Taegu Ha <hataegu0826@gmail.com>
+Date: Thu, 2 Apr 2026 04:13:11 +0900
+Subject: usb: gadget: f_uac1_legacy: validate control request size
+
+From: Taegu Ha <hataegu0826@gmail.com>
+
+commit 6e0e34d85cd46ceb37d16054e97a373a32770f6c upstream.
+
+f_audio_complete() copies req->length bytes into a 4-byte stack
+variable:
+
+ u32 data = 0;
+ memcpy(&data, req->buf, req->length);
+
+req->length is derived from the host-controlled USB request path,
+which can lead to a stack out-of-bounds write.
+
+Validate req->actual against the expected payload size for the
+supported control selectors and decode only the expected amount
+of data.
+
+This avoids copying a host-influenced length into a fixed-size
+stack object.
+
+Signed-off-by: Taegu Ha <hataegu0826@gmail.com>
+Cc: stable <stable@kernel.org>
+Link: https://patch.msgid.link/20260401191311.3604898-1-hataegu0826@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_uac1_legacy.c | 47 ++++++++++++++++++++++------
+ 1 file changed, 37 insertions(+), 10 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_uac1_legacy.c
++++ b/drivers/usb/gadget/function/f_uac1_legacy.c
+@@ -360,19 +360,46 @@ static int f_audio_out_ep_complete(struc
+ static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
+ {
+ struct f_audio *audio = req->context;
+- int status = req->status;
+- u32 data = 0;
+ struct usb_ep *out_ep = audio->out_ep;
+
+- switch (status) {
+-
+- case 0: /* normal completion? */
+- if (ep == out_ep)
++ switch (req->status) {
++ case 0:
++ if (ep == out_ep) {
+ f_audio_out_ep_complete(ep, req);
+- else if (audio->set_con) {
+- memcpy(&data, req->buf, req->length);
+- audio->set_con->set(audio->set_con, audio->set_cmd,
+- le16_to_cpu(data));
++ } else if (audio->set_con) {
++ struct usb_audio_control *con = audio->set_con;
++ u8 type = con->type;
++ u32 data;
++ bool valid_request = false;
++
++ switch (type) {
++ case UAC_FU_MUTE: {
++ u8 value;
++
++ if (req->actual == sizeof(value)) {
++ memcpy(&value, req->buf, sizeof(value));
++ data = value;
++ valid_request = true;
++ }
++ break;
++ }
++ case UAC_FU_VOLUME: {
++ __le16 value;
++
++ if (req->actual == sizeof(value)) {
++ memcpy(&value, req->buf, sizeof(value));
++ data = le16_to_cpu(value);
++ valid_request = true;
++ }
++ break;
++ }
++ }
++
++ if (valid_request)
++ con->set(con, audio->set_cmd, data);
++ else
++ usb_ep_set_halt(ep);
++
+ audio->set_con = NULL;
+ }
+ break;
--- /dev/null
+From e1eabb072c75681f78312c484ccfffb7430f206e Mon Sep 17 00:00:00 2001
+From: Kuen-Han Tsai <khtsai@google.com>
+Date: Wed, 11 Mar 2026 17:12:15 +0800
+Subject: usb: gadget: u_ether: Fix race between gether_disconnect and eth_stop
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+commit e1eabb072c75681f78312c484ccfffb7430f206e upstream.
+
+A race condition between gether_disconnect() and eth_stop() leads to a
+NULL pointer dereference. Specifically, if eth_stop() is triggered
+concurrently while gether_disconnect() is tearing down the endpoints,
+eth_stop() attempts to access the cleared endpoint descriptor, causing
+the following NPE:
+
+ Unable to handle kernel NULL pointer dereference
+ Call trace:
+ __dwc3_gadget_ep_enable+0x60/0x788
+ dwc3_gadget_ep_enable+0x70/0xe4
+ usb_ep_enable+0x60/0x15c
+ eth_stop+0xb8/0x108
+
+Because eth_stop() crashes while holding the dev->lock, the thread
+running gether_disconnect() fails to acquire the same lock and spins
+forever, resulting in a hardlockup:
+
+ Core - Debugging Information for Hardlockup core(7)
+ Call trace:
+ queued_spin_lock_slowpath+0x94/0x488
+ _raw_spin_lock+0x64/0x6c
+ gether_disconnect+0x19c/0x1e8
+ ncm_set_alt+0x68/0x1a0
+ composite_setup+0x6a0/0xc50
+
+The root cause is that the clearing of dev->port_usb in
+gether_disconnect() is delayed until the end of the function.
+
+Move the clearing of dev->port_usb to the very beginning of
+gether_disconnect() while holding dev->lock. This cuts off the link
+immediately, ensuring eth_stop() will see dev->port_usb as NULL and
+safely bail out.
+
+Fixes: 2b3d942c4878 ("usb ethernet gadget: split out network core")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Link: https://patch.msgid.link/20260311-gether-disconnect-npe-v1-1-454966adf7c7@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/u_ether.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -1200,6 +1200,11 @@ void gether_disconnect(struct gether *li
+
+ DBG(dev, "%s\n", __func__);
+
++ spin_lock(&dev->lock);
++ dev->port_usb = NULL;
++ link->is_suspend = false;
++ spin_unlock(&dev->lock);
++
+ netif_stop_queue(dev->net);
+ netif_carrier_off(dev->net);
+
+@@ -1237,11 +1242,6 @@ void gether_disconnect(struct gether *li
+ dev->header_len = 0;
+ dev->unwrap = NULL;
+ dev->wrap = NULL;
+-
+- spin_lock(&dev->lock);
+- dev->port_usb = NULL;
+- link->is_suspend = false;
+- spin_unlock(&dev->lock);
+ }
+ EXPORT_SYMBOL_GPL(gether_disconnect);
+
--- /dev/null
+From eba2936bbe6b752a31725a9eb5c674ecbf21ee7d Mon Sep 17 00:00:00 2001
+From: Jimmy Hu <hhhuuu@google.com>
+Date: Fri, 20 Mar 2026 14:54:27 +0800
+Subject: usb: gadget: uvc: fix NULL pointer dereference during unbind race
+
+From: Jimmy Hu <hhhuuu@google.com>
+
+commit eba2936bbe6b752a31725a9eb5c674ecbf21ee7d upstream.
+
+Commit b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly
+shutdown") introduced two stages of synchronization waits totaling 1500ms
+in uvc_function_unbind() to prevent several types of kernel panics.
+However, this timing-based approach is insufficient during power
+management (PM) transitions.
+
+When the PM subsystem starts freezing user space processes, the
+wait_event_interruptible_timeout() is aborted early, which allows the
+unbind thread to proceed and nullify the gadget pointer
+(cdev->gadget = NULL):
+
+[ 814.123447][ T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind()
+[ 814.178583][ T3173] PM: suspend entry (deep)
+[ 814.192487][ T3173] Freezing user space processes
+[ 814.197668][ T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind no clean disconnect, wait for release
+
+When the PM subsystem resumes or aborts the suspend and tasks are
+restarted, the V4L2 release path is executed and attempts to access the
+already nullified gadget pointer, triggering a kernel panic:
+
+[ 814.292597][ C0] PM: pm_system_irq_wakeup: 479 triggered dhdpcie_host_wake
+[ 814.386727][ T3173] Restarting tasks ...
+[ 814.403522][ T4558] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000030
+[ 814.404021][ T4558] pc : usb_gadget_deactivate+0x14/0xf4
+[ 814.404031][ T4558] lr : usb_function_deactivate+0x54/0x94
+[ 814.404078][ T4558] Call trace:
+[ 814.404080][ T4558] usb_gadget_deactivate+0x14/0xf4
+[ 814.404083][ T4558] usb_function_deactivate+0x54/0x94
+[ 814.404087][ T4558] uvc_function_disconnect+0x1c/0x5c
+[ 814.404092][ T4558] uvc_v4l2_release+0x44/0xac
+[ 814.404095][ T4558] v4l2_release+0xcc/0x130
+
+Address the race condition and NULL pointer dereference by:
+
+1. State Synchronization (flag + mutex)
+Introduce a 'func_unbound' flag in struct uvc_device. This allows
+uvc_function_disconnect() to safely skip accessing the nullified
+cdev->gadget pointer. As suggested by Alan Stern, this flag is protected
+by a new mutex (uvc->lock) to ensure proper memory ordering and prevent
+instruction reordering or speculative loads. This mutex is also used to
+protect 'func_connected' for consistent state management.
+
+2. Explicit Synchronization (completion)
+Use a completion to synchronize uvc_function_unbind() with the
+uvc_vdev_release() callback. This prevents Use-After-Free (UAF) by
+ensuring struct uvc_device is freed after all video device resources
+are released.
+
+Fixes: b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly shutdown")
+Cc: stable <stable@kernel.org>
+Suggested-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Jimmy Hu <hhhuuu@google.com>
+Link: https://patch.msgid.link/20260320065427.1374555-1-hhhuuu@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_uvc.c | 39 ++++++++++++++++++++++++++++++---
+ drivers/usb/gadget/function/uvc.h | 3 ++
+ drivers/usb/gadget/function/uvc_v4l2.c | 5 +++-
+ 3 files changed, 43 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_uvc.c
++++ b/drivers/usb/gadget/function/f_uvc.c
+@@ -410,6 +410,12 @@ uvc_function_disconnect(struct uvc_devic
+ {
+ int ret;
+
++ guard(mutex)(&uvc->lock);
++ if (uvc->func_unbound) {
++ dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n");
++ return;
++ }
++
+ if ((ret = usb_function_deactivate(&uvc->func)) < 0)
+ uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
+ }
+@@ -428,6 +434,15 @@ static ssize_t function_name_show(struct
+
+ static DEVICE_ATTR_RO(function_name);
+
++static void uvc_vdev_release(struct video_device *vdev)
++{
++ struct uvc_device *uvc = video_get_drvdata(vdev);
++
++ /* Signal uvc_function_unbind() that the video device has been released */
++ if (uvc->vdev_release_done)
++ complete(uvc->vdev_release_done);
++}
++
+ static int
+ uvc_register_video(struct uvc_device *uvc)
+ {
+@@ -440,7 +455,7 @@ uvc_register_video(struct uvc_device *uv
+ uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev;
+ uvc->vdev.fops = &uvc_v4l2_fops;
+ uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops;
+- uvc->vdev.release = video_device_release_empty;
++ uvc->vdev.release = uvc_vdev_release;
+ uvc->vdev.vfl_dir = VFL_DIR_TX;
+ uvc->vdev.lock = &uvc->video.mutex;
+ uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+@@ -653,6 +668,8 @@ uvc_function_bind(struct usb_configurati
+ int ret = -EINVAL;
+
+ uvcg_info(f, "%s()\n", __func__);
++ scoped_guard(mutex, &uvc->lock)
++ uvc->func_unbound = false;
+
+ opts = fi_to_f_uvc_opts(f->fi);
+ /* Sanity check the streaming endpoint module parameters. */
+@@ -975,12 +992,19 @@ static void uvc_free(struct usb_function
+ static void uvc_function_unbind(struct usb_configuration *c,
+ struct usb_function *f)
+ {
++ DECLARE_COMPLETION_ONSTACK(vdev_release_done);
+ struct usb_composite_dev *cdev = c->cdev;
+ struct uvc_device *uvc = to_uvc(f);
+ struct uvc_video *video = &uvc->video;
+ long wait_ret = 1;
++ bool connected;
+
+ uvcg_info(f, "%s()\n", __func__);
++ scoped_guard(mutex, &uvc->lock) {
++ uvc->func_unbound = true;
++ uvc->vdev_release_done = &vdev_release_done;
++ connected = uvc->func_connected;
++ }
+
+ if (video->async_wq)
+ destroy_workqueue(video->async_wq);
+@@ -991,7 +1015,7 @@ static void uvc_function_unbind(struct u
+ * though the video device removal uevent. Allow some time for the
+ * application to close out before things get deleted.
+ */
+- if (uvc->func_connected) {
++ if (connected) {
+ uvcg_dbg(f, "waiting for clean disconnect\n");
+ wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
+ uvc->func_connected == false, msecs_to_jiffies(500));
+@@ -1002,7 +1026,10 @@ static void uvc_function_unbind(struct u
+ video_unregister_device(&uvc->vdev);
+ v4l2_device_unregister(&uvc->v4l2_dev);
+
+- if (uvc->func_connected) {
++ scoped_guard(mutex, &uvc->lock)
++ connected = uvc->func_connected;
++
++ if (connected) {
+ /*
+ * Wait for the release to occur to ensure there are no longer any
+ * pending operations that may cause panics when resources are cleaned
+@@ -1014,6 +1041,10 @@ static void uvc_function_unbind(struct u
+ uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
+ }
+
++ /* Wait for the video device to be released */
++ wait_for_completion(&vdev_release_done);
++ uvc->vdev_release_done = NULL;
++
+ usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+ kfree(uvc->control_buf);
+
+@@ -1032,6 +1063,8 @@ static struct usb_function *uvc_alloc(st
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&uvc->video.mutex);
++ mutex_init(&uvc->lock);
++ uvc->func_unbound = true;
+ uvc->state = UVC_STATE_DISCONNECTED;
+ init_waitqueue_head(&uvc->func_connected_queue);
+ opts = fi_to_f_uvc_opts(fi);
+--- a/drivers/usb/gadget/function/uvc.h
++++ b/drivers/usb/gadget/function/uvc.h
+@@ -131,6 +131,9 @@ struct uvc_device {
+ enum uvc_state state;
+ struct usb_function func;
+ struct uvc_video video;
++ struct completion *vdev_release_done;
++ struct mutex lock; /* protects func_unbound and func_connected */
++ bool func_unbound;
+ bool func_connected;
+ wait_queue_head_t func_connected_queue;
+
+--- a/drivers/usb/gadget/function/uvc_v4l2.c
++++ b/drivers/usb/gadget/function/uvc_v4l2.c
+@@ -491,6 +491,8 @@ uvc_v4l2_subscribe_event(struct v4l2_fh
+ if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
+ return -EINVAL;
+
++ guard(mutex)(&uvc->lock);
++
+ if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
+ return -EBUSY;
+
+@@ -512,7 +514,8 @@ static void uvc_v4l2_disable(struct uvc_
+ uvc_function_disconnect(uvc);
+ uvcg_video_enable(&uvc->video, 0);
+ uvcg_free_buffers(&uvc->video.queue);
+- uvc->func_connected = false;
++ scoped_guard(mutex, &uvc->lock)
++ uvc->func_connected = false;
+ wake_up_interruptible(&uvc->func_connected_queue);
+ }
+