From nobody Sat Jul 4 19:59:53 2026 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) (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 5B6B03A9854 for ; Sat, 4 Jul 2026 12:55:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783169720; cv=none; b=VP1UlgfXgYkLww8O/30JTxotiXkf7TjnOq4fVT6gnuyUOfcZ8COKvBWo/9jjlFFir4g4fcouheX+jNBPv+7emY3sQoXfy2sjdXDmh9YxfzsXGT+eewrbMGsK0du9SSoke1QYOLojmKGfLgBUERECPilsKvA6LedrKZy4GRs5IQI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783169720; c=relaxed/simple; bh=7Ti4birx9ZhBE8tHz/XlcHdoOwrE9eEoweTUNZOgVMc=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=tKmITLvj8oZevUh6WoabILlijry33gFvMyPAylr781yfuwK2H+M/mMOiK0NRBxOrJv85BpHmzQSQqu87xiD6sTcZVES4o1dXNdXKZ3B6nzywsjI28uHGP3qHSyDag1y65S1AxZb6yCaL4FQKudAUwJCD10AOFMbblZzpz777jN0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Iqsewdgc; arc=none smtp.client-ip=209.85.210.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Iqsewdgc" Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-8471013fac2so1498209b3a.1 for ; Sat, 04 Jul 2026 05:55:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783169709; x=1783774509; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=MS3BIkzvEU3uW1zM8eJb13sdee+BvNhbNdXbN75EOwQ=; b=IqsewdgclUdNe0fWbDXc9YpZm+Q/dHKQpbveYHfVKHwOP+cgXGRY3HJrKq0rN2GFtc rPTNemGyEAnMdd3lHLf2WIIhxySNNoG10LYWU5Tivjp4JWJG6wV+wMGbI9WrP3+fiydo B7p+Ax73wU4WPrGb3+MjN68Jvq1aGoVsD4U2ddzRMnNdTIFNNHpNjHdph/vYnuinfk97 ZU3NEYkjvciiGicK2WXfzkB6XJIVmBHq5g7LWKN/sl/z1aOiud9SbqBSuRnRsAklg4bX b8kbW3kGU2Q+OdXNt1vWGQIn3edTBxFtkbu97EeveWWcIMtPXa2OENLbPr9trAGYYJZf Ogqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783169709; x=1783774509; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=MS3BIkzvEU3uW1zM8eJb13sdee+BvNhbNdXbN75EOwQ=; b=cNK+nAH/B/SVDGvVOfoAou5H9wg20C2mdKqMo3wHyEZVcp68jQbut3AKRTdxnztldR fdmYpE0haPrSr0CsP4/KdVZFtcd1iHXk3We9InvpHRysGSRMvFyBsp2+Hxhu1MX23WSI 46fnJNy3enSTnKtZ+o2UoaLz3KsoNwSULUzBB+3UtwMsaoRyl1hlHdX5mMxpHyVNNi7e 631fuhFVQRme3kzmZbLbMBNwDUxeCinv9H+3GwRiLDzV7eLpdvIrqBQtFfaEWi7NSLzO aeTADYLAQg2WDH5K/uRY1S80iyNkor4iRmteiQ5MlcZKiXpjsqPoSpO02AfpYGVbsQ3r gbIg== X-Forwarded-Encrypted: i=1; AFNElJ/hSXMJwpV08knhC18OkvhSZoBfFz3dLGkaRNy9JuUPu0DdGlSH/FLGleUy1va0hM10dmhTXF3yXVEIjHk=@vger.kernel.org X-Gm-Message-State: AOJu0YybdkcPHsaYPWtfbDRgXO1NdlzHCz1GUjQuHIfW8vpE1x//eJ/i QnCGwxtWpODoHiQrFKoggAY7WW/kX8pxq4BrB1HE/nAkIH7OO4SBiZQi X-Gm-Gg: AfdE7ckI29whcX5p67rp/qnaA4A6k7gFtVFeJlDpq7vrQLu1/wE7oC+GR6Hy3kNh1FY hgKyjsrGoGq17YxBwvo77qQel50TbyF4g+HtdDzHGXUQm+61C0CSgCoGw2w4jBRkp+f4BcggNEH +DcIfP5HRU/vow59ZzUm5iq0zQCFllr5h8ZspgfgqpJyXy5o2JHd6osUhGKjZvuA5iEGOZEWLq3 Vwc4yBguMXOEQegWhiAbwmEggHT+4ydNjoMSYjM/BVNPTFlHFBAOnpjByFFEzoXt8AWXMkH+/BM Ua/tyICmyrx7aA8zaDNTpm2PxgYxZkD7UNLqsZk+n1WdEi4ubPFEdWOxD8Rsr5tmtuTfXfnBqBs gSCA81ONQAon1sEDsBiq+CgOr3kSKUp+cfceWsVjLe4sqIaXDQ811M/i0Z11ArhulCYLPu0Z+ZY mriA== X-Received: by 2002:a05:6a00:22c7:b0:845:48be:b046 with SMTP id d2e1a72fcca58-847f6f1025fmr3033740b3a.36.1783169709364; Sat, 04 Jul 2026 05:55:09 -0700 (PDT) Received: from lgs.. ([118.193.39.24]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-847f6b95c89sm1262976b3a.15.2026.07.04.05.55.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 04 Jul 2026 05:55:08 -0700 (PDT) From: Guangshuo Li To: Greg Kroah-Hartman , Jiasheng Jiang , Kees Cook , Mike Christie , Christophe JAILLET , Guangshuo Li , Thinh Nguyen , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2] usb: gadget: f_tcm: fix remaining nexus NULL dereferences Date: Sat, 4 Jul 2026 20:54:59 +0800 Message-ID: <20260704125459.4008712-1-lgs201920130244@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The previous nexus NULL-dereference fix added checks to the normal command submission paths, but two UASP paths still dereference tpg->tpg_nexus without checking it first. A TASK MANAGEMENT request reaches usbg_submit_tmr(), which fetches tvn_se_sess directly from tpg->tpg_nexus. The RC_OVERLAPPED_TAG path in usbg_cmd_work() does the same before walking sess_cmd_map for the active command with the same tag. If userspace drops the nexus after the command is queued, these paths can observe a NULL tpg_nexus and crash before they can ignore the command like the already-fixed command paths do. Commands that reach the workqueue have already been allocated from the session tag pool by usbg_get_cmd(), and UASP commands may have been inserted into the stream hash. Clean up those resources before returning from nexus-missing paths. Store the session pointer in struct usbg_cmd so the cleanup path does not need to dereference tpg_nexus after it becomes NULL. Fixes: b9fde5073553 ("usb: gadget: f_tcm: Fix NULL pointer dereferences in = nexus handling") Signed-off-by: Guangshuo Li --- v2: - Clean up the session tag pool and stream hash before returning from nexus-missing paths, as suggested by Thinh. - Store the session pointer in struct usbg_cmd so the cleanup path does not need to dereference tpg_nexus after it becomes NULL. drivers/usb/gadget/function/f_tcm.c | 48 ++++++++++++++++++++++++++--- drivers/usb/gadget/function/tcm.h | 1 + 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/funct= ion/f_tcm.c index 34d9f49e9987..89f9b3c97209 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -725,7 +725,7 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, st= ruct usb_request *req) cmd->tmr_rsp !=3D RC_RESPONSE_UNKNOWN) { struct se_session *se_sess; =20 - se_sess =3D fu->tpg->tpg_nexus->tvn_se_sess; + se_sess =3D cmd->se_sess; sbitmap_queue_clear(&se_sess->sess_tag_pool, cmd->se_cmd.map_tag, cmd->se_cmd.map_cpu); @@ -1186,14 +1186,41 @@ static int usbg_send_read_response(struct se_cmd *s= e_cmd) =20 static void usbg_aborted_task(struct se_cmd *se_cmd); =20 +static void usbg_cleanup_queued_cmd(struct usbg_cmd *cmd) +{ + struct se_session *se_sess =3D cmd->se_sess; + + if (cmd->fu->flags & USBG_IS_UAS) { + struct uas_stream *stream; + + stream =3D &cmd->fu->stream[cmd->se_cmd.map_tag]; + if (hash_hashed(&stream->node)) + hash_del(&stream->node); + } + + sbitmap_queue_clear(&se_sess->sess_tag_pool, + cmd->se_cmd.map_tag, + cmd->se_cmd.map_cpu); +} + static void usbg_submit_tmr(struct usbg_cmd *cmd) { + struct tcm_usbg_nexus *tv_nexus; struct se_session *se_sess; struct se_cmd *se_cmd; int flags =3D TARGET_SCF_ACK_KREF; =20 se_cmd =3D &cmd->se_cmd; - se_sess =3D cmd->fu->tpg->tpg_nexus->tvn_se_sess; + tv_nexus =3D cmd->fu->tpg->tpg_nexus; + if (!tv_nexus) { + struct usb_gadget *gadget =3D fuas_to_gadget(cmd->fu); + + dev_err(&gadget->dev, "Missing nexus for TMR, ignoring command\n"); + usbg_cleanup_queued_cmd(cmd); + return; + } + + se_sess =3D tv_nexus->tvn_se_sess; =20 target_submit_tmr(se_cmd, se_sess, cmd->response_iu.add_response_info, @@ -1226,6 +1253,7 @@ static void usbg_submit_cmd(struct usbg_cmd *cmd) struct usb_gadget *gadget =3D fuas_to_gadget(cmd->fu); =20 dev_err(&gadget->dev, "Missing nexus, ignoring command\n"); + usbg_cleanup_queued_cmd(cmd); return; } =20 @@ -1271,12 +1299,22 @@ static void usbg_cmd_work(struct work_struct *work) skip: if (cmd->tmr_rsp =3D=3D RC_OVERLAPPED_TAG) { struct f_uas *fu =3D cmd->fu; + struct tcm_usbg_nexus *tv_nexus; struct se_session *se_sess; struct uas_stream *stream =3D NULL; struct hlist_node *tmp; struct usbg_cmd *active_cmd =3D NULL; =20 - se_sess =3D cmd->fu->tpg->tpg_nexus->tvn_se_sess; + tv_nexus =3D fu->tpg->tpg_nexus; + if (!tv_nexus) { + struct usb_gadget *gadget =3D fuas_to_gadget(fu); + + dev_err(&gadget->dev, "Missing nexus for overlapped tag, ignoring comma= nd\n"); + usbg_cleanup_queued_cmd(cmd); + return; + } + + se_sess =3D tv_nexus->tvn_se_sess; =20 hash_for_each_possible_safe(fu->stream_hash, stream, tmp, node, cmd->tag= ) { int i =3D stream - &fu->stream[0]; @@ -1357,6 +1395,7 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, cmd->se_cmd.map_cpu =3D cpu; cmd->se_cmd.cpuid =3D cpu; cmd->se_cmd.tag =3D cmd->tag =3D scsi_tag; + cmd->se_sess =3D se_sess; cmd->fu =3D fu; =20 return cmd; @@ -1413,7 +1452,7 @@ static int usbg_submit_command(struct f_uas *fu, stru= ct usb_request *req) struct se_session *se_sess; int i =3D stream - &fu->stream[0]; =20 - se_sess =3D cmd->fu->tpg->tpg_nexus->tvn_se_sess; + se_sess =3D tv_nexus->tvn_se_sess; active_cmd =3D &((struct usbg_cmd *)se_sess->sess_cmd_map)[i]; =20 if (active_cmd->tag =3D=3D scsi_tag) { @@ -1494,6 +1533,7 @@ static void bot_cmd_work(struct work_struct *work) struct usb_gadget *gadget =3D fuas_to_gadget(cmd->fu); =20 dev_err(&gadget->dev, "Missing nexus, ignoring command\n"); + usbg_cleanup_queued_cmd(cmd); return; } =20 diff --git a/drivers/usb/gadget/function/tcm.h b/drivers/usb/gadget/functio= n/tcm.h index 009974d81d66..1ae1f8383bd0 100644 --- a/drivers/usb/gadget/function/tcm.h +++ b/drivers/usb/gadget/function/tcm.h @@ -73,6 +73,7 @@ struct usbg_cmd { struct work_struct work; int unpacked_lun; struct se_cmd se_cmd; + struct se_session *se_sess; void *data_buf; /* used if no sg support available */ struct f_uas *fu; struct kref ref; --=20 2.43.0