From nobody Fri Apr 17 02:59:48 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 67B921F30A9 for ; Tue, 24 Feb 2026 08:40:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771922405; cv=none; b=Ba91RxGMwXwoDrzqw5R6EAeCKr0R43RMUURj7TzHAvhBoniHm8/FrNORj6Lg4+N1VRwsIa3B/yvZRGaHxi5FMQ5QOcllS4DfGATwcqnJVDUVMBlZTIVhTk8aAioMiTmfV+uNtMZn30oEuTV6Dx1HLyKfTiyz0j0tu8hzFeqsYps= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771922405; c=relaxed/simple; bh=U/TgxUQYVzZqCgle8jF8DXPoqtJ16jLgQc6UMKe3QvM=; h=Date:Mime-Version:Message-ID:Subject:From:To:Cc:Content-Type; b=U727VMzuu3JRh5ykUB67mC5OP2/1oNMWcNOX4U6owsN5AEy4qD5dyVWxDpgNZsMX4en1ZaHTOg4nxkktZDgSBBGNt0ZUu7eC/slR+a0PvbYYEJM6DrnDHiIZCTZU9dICM63E1+Z8V9XJCFSGOCTe04ZrkP4IosFC/0uaEIuqLSQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--hhhuuu.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=eYoS2pAP; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--hhhuuu.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="eYoS2pAP" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c6e78c4aa50so3448459a12.0 for ; Tue, 24 Feb 2026 00:40:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771922403; x=1772527203; darn=vger.kernel.org; h=cc:to:from:subject:message-id:mime-version:date:from:to:cc:subject :date:message-id:reply-to; bh=AA20LKX/qg4rXIAP9XbWMbFshuFo56WlS+omTggeYsk=; b=eYoS2pAPwMqaCT9YmF3U9mleycoYxO5c/my893bGADyVzXLGCcIAY1yC/9A+MFV/Kn K7cjHeLrQrxlzJAkFUId77a+uD0zgKntBBHoDh1/az3PGzpXXCuZaOizxObLFlB9dU40 mqJiElYDTFyQsIz+B6dtJpQq+EnqUIwyveNx2dYkTrMuM7EOMj1PItFVpRbGlTAEizCy TQq88D+R2kStyt4qh5E9up1INZEv2RKY17/gcl18hUPWJ2T+SJslY6LtGbNi1AGZVxb0 VDQKZ2jiGPlCUTRn606kcTXxey0ZZOTLOtFhHoCPZrBkvfjgG0daL9/LxSrj+MqPFTDf o3Iw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771922403; x=1772527203; h=cc:to:from:subject:message-id:mime-version:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=AA20LKX/qg4rXIAP9XbWMbFshuFo56WlS+omTggeYsk=; b=KOqScuybEJgc16nrQFCcionzF+jry/Nq4XqG39of2/E+lS2Of0zBvRPPl7cLpdWIDi z+rJtIjAEhWr8qzdDbuCQ0U+XbZt5xHZHuSI+rJWLjZRCVymW/YOVviw1NlQCwSK0qvf H3MQ9dEXk4JKAk4RVhBURqXh/hKJtOoe5COkGG4LFoTkAXq+qkG6j355ZNFdnUQwZoF3 kPBAkZ1KyfsgsDB44lavNeWQTL9I/xpLTqjV2yDCYF0UtZiTjScJ3FToVCAp90BhLznA 6wkwn7Kq9xRJMG7+EbLM64aOnx1R+kL2byT9bc4fHHn9VXhJWWsWevCAari6K1Nhb6FE ayQQ== X-Forwarded-Encrypted: i=1; AJvYcCUDgC/SBJftVX63q6pZIh49/pXMicDo9L0uM3lW4TR0FbeCfM/CNfdMu0aIFF5pd55IPE7y5nMB9qYyCZE=@vger.kernel.org X-Gm-Message-State: AOJu0YyZ11/8GiMbzb5rLg/22G8Y0K8nz7lQFXqZKppiru+JW9Hbx04q zU38xbkAwF9HmPUDDLe8oBWDJibtIat6v+FjMMWt2XMCjDxxfpmqbhgAdlP0hd4OLRNYof2wYOO vLlYeoA== X-Received: from pgc16.prod.google.com ([2002:a05:6a02:2f90:b0:c70:ab5b:1d92]) (user=hhhuuu job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:6a04:b0:394:8455:d1a9 with SMTP id adf61e73a8af0-39545e5081dmr8121765637.2.1771922402547; Tue, 24 Feb 2026 00:40:02 -0800 (PST) Date: Tue, 24 Feb 2026 16:39:55 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224083955.1375032-1-hhhuuu@google.com> Subject: [PATCH] usb: gadget: f_uvc: fix NULL pointer dereference during unbind race From: Jimmy Hu To: Greg Kroah-Hartman , Laurent Pinchart Cc: Dan Vacura , Jimmy Hu , Xu Yang , Frank Li , Hans Verkuil , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, badhri@google.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 =3D NULL): [ 814.123447][ T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbin= d() [ 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_unbin= d 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 The fix introduces a 'func_unbinding' flag in struct uvc_device to protect critical sections: 1. In uvc_function_disconnect(), it prevents accessing the nullified cdev->gadget pointer. 2. In uvc_v4l2_release(), it ensures uvcg_free_buffers() is skipped if unbind is already in progress, avoiding races with concurrent bind operations or use-after-free on the video queue memory. Fixes: b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly sh= utdown") Cc: Signed-off-by: Jimmy Hu --- drivers/usb/gadget/function/f_uvc.c | 7 +++++++ drivers/usb/gadget/function/uvc.h | 1 + drivers/usb/gadget/function/uvc_v4l2.c | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/funct= ion/f_uvc.c index a96476507d2f..f8c609ad1a43 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -413,6 +413,11 @@ uvc_function_disconnect(struct uvc_device *uvc) { int ret; =20 + if (uvc->func_unbinding) { + pr_info("uvc: unbinding, skipping function deactivate\n"); + return; + } + if ((ret =3D usb_function_deactivate(&uvc->func)) < 0) uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); } @@ -659,6 +664,7 @@ uvc_function_bind(struct usb_configuration *c, struct u= sb_function *f) int ret =3D -EINVAL; =20 uvcg_info(f, "%s()\n", __func__); + uvc->func_unbinding =3D false; =20 opts =3D fi_to_f_uvc_opts(f->fi); /* Sanity check the streaming endpoint module parameters. */ @@ -994,6 +1000,7 @@ static void uvc_function_unbind(struct usb_configurati= on *c, long wait_ret =3D 1; =20 uvcg_info(f, "%s()\n", __func__); + uvc->func_unbinding =3D true; =20 kthread_cancel_work_sync(&video->hw_submit); =20 diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 676419a04976..7ca56ff737a4 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -155,6 +155,7 @@ struct uvc_device { enum uvc_state state; struct usb_function func; struct uvc_video video; + bool func_unbinding; bool func_connected; wait_queue_head_t func_connected_queue; =20 diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/fu= nction/uvc_v4l2.c index fd4b998ccd16..a8a15b584648 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -594,7 +594,13 @@ static void uvc_v4l2_disable(struct uvc_device *uvc) { uvc_function_disconnect(uvc); uvcg_video_disable(&uvc->video); + if (uvc->func_unbinding) { + pr_info("uvc: unbinding, skipping buffer cleanup\n"); + goto skip_buffer_cleanup; + } uvcg_free_buffers(&uvc->video.queue); + +skip_buffer_cleanup: uvc->func_connected =3D false; wake_up_interruptible(&uvc->func_connected_queue); } base-commit: 24d479d26b25bce5faea3ddd9fa8f3a6c3129ea7 --=20 2.53.0.371.g1d285c8824-goog