From nobody Mon Jun 8 23:56:24 2026 Received: from mail-qv1-f52.google.com (mail-qv1-f52.google.com [209.85.219.52]) (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 22BCE34DCF3 for ; Mon, 25 May 2026 12:57:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779713875; cv=none; b=AuTcObUuY7PC/4Ys6Mzz5ykQtaN2ZwAN3QeSbtwiLv03yyrxbNtnPy3hykbJ4hV0IFouT+vS1MhVuNf9r2C8m/Ze348Lso4M1SDLKpxhAy945XfXCKvJOA2WnKX1xGdkKXPWxfcsINoBEk/9rbsJ5IJG5IYCzy0wnmd+o9JfcHs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779713875; c=relaxed/simple; bh=99aXVm/qYR76ZGN2GPcr6L+i0EGIZZYJzjh5Zkrt2p4=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=C9T16u9UBJh4jwGaFZ1IqPpKBVw8YyaQxsheEZIBhMOLY2xQpBAP1jvC3ji3rkaXSx3amfJXu0L5bWyI6OvFmxtfbMuUy33oiO0eA2mUkBlYPlYBFtqxKHQSoN7mg9yHm8dusfV9eFv6Ci38uEVsu2suAe5Q6uIhCMAuvGAHUfY= 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=BhqToCpJ; arc=none smtp.client-ip=209.85.219.52 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="BhqToCpJ" Received: by mail-qv1-f52.google.com with SMTP id 6a1803df08f44-8b4298d271fso185996676d6.3 for ; Mon, 25 May 2026 05:57:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779713873; x=1780318673; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=xsaU2QFciQt/t5B1EUxXsHdEngrBZxj8roxLnaxSrAc=; b=BhqToCpJPkuVqsyC5Ze6CUYQUFGsG4VwVmAFYaZyXCEt0sQKIEW9m1G/FOy79AIX0P SIBuupv/23QSKF1Wk/hTCRCpby04p7pAuCJfjB1L5sYgXIXGHovmJ5+TQmoJeFTflq4S XZd6oz6OJSOcPW5TdQKYIcnjXPeR8Ww7OPhA6upSZ8fIfPjpQibahIWnmX/x+sNgVimz +2UuQdO40BlDoirw2oqzN2dcOZdsqvCBv6JZn4zvYIf6a9b17PHsbJrEmqwkKswie+9b +6uRs/3XXgAnYf2Ljwc9nafOI6pf7V9jyN0Hx4Oc5S3T8FyM8QI7lprFBkch7bgCwrft g8oA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779713873; x=1780318673; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xsaU2QFciQt/t5B1EUxXsHdEngrBZxj8roxLnaxSrAc=; b=ltNHZlEoT3GgS19JICVvBuqJ/i6q98OYznJDu4Jli9eXv3fmrOBB2chtU+19KkJFmc VxcIwEeX8lKLcQ9N7h14Qi02G8n4cJDEhKLvKNZIoip4BTqynmdDY14EHvsJ0rLg42Kv SzXEIsw1wAj/SBwq2AIyGleGdA1qwyk0kNi0dkxb82oL9YkCfrVpISncypZm3EwRKEc1 FgKNVYWXr3Zv10O1mi6lubMOCg7OTtd1X8062wvwgyQ1zvomRfRdvQoKU4VlprJYb6Qm 1SFIAfNCVKN2gKlBCJumQ+FoXBrTlTXGCJWo/OxrjOSdwc8PMAM6aymc4AT+1DuItDFp QQOg== X-Forwarded-Encrypted: i=1; AFNElJ9cam/R1jCCT4k47uxtXeZue70MXEmSgLZoV5TqbqpaBEdD/OQL4aXenTJ1z9XD3fK6uVUZ118oWEm7PA0=@vger.kernel.org X-Gm-Message-State: AOJu0YyGCJ8mfbLrNfsbOk74AINnu9IGh9V5SGbGnUAGddbhHN/nPf8p /TwOS+5jDa5qDnv3zyRd0xf3E6a3biXmXVdO5eJ1FrWzEAw1wAduc8gpUfbyS2o0 X-Gm-Gg: Acq92OEGXx9swwLhKVc+M9wEmYHxL8XV/dSHNSSIN7lhWczAf/g78MQi2/SZHEgHfRw 5q7ZWWHZjQtTzNTtbv8adARTz2WMlKXlE676Z45oqr3CdCCt0UWeTfQlABCU6+XCaeQ3EYTlvAI uTK3RbOZl2ebEOW76ldh9nn7tgN0lCtqy/w7y+HkBCdbLPNT5YiJxb3wyQFhQDBOii9vsglC016 mlI2LmGZ2e8XIR4q19MKI27GBmQAcCnn+vnz/Yc6TZdr1nBe/q9j0Vx2gmtZhaETV9yX0XgMrDq v7v8qPQuDH2LvX7OvIZ0iJd916eopuqkK/pd5t9s/pt4+A8E/QGtQs1vLIsldcThsLNFxFRTiX/ 8lwxL5htXGRQy15WMZ+5UbJLrTOeQa8Jui7Z/KhuW3KFDbDOL5iXMiek+bXN5A8y4+rAs7Ct7lL NbzMVyL5VqRxNeOxrcE/jJRYIsrYGHvf1CDeAW2BIKU9k/cm1JSlH1bs+cR79hnzs2D/swqVbSf F3Fc4jVX++nnTDTgYfth2rnKDAM1IMDLHySDFBwRUQ= X-Received: by 2002:a05:6214:242a:b0:8ca:15b8:a37c with SMTP id 6a1803df08f44-8cc7b583e4bmr234934456d6.9.1779713872949; Mon, 25 May 2026 05:57:52 -0700 (PDT) Received: from server0.tail6e7dd.ts.net (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8cc80dcedb3sm108973336d6.8.2026.05.25.05.57.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 05:57:52 -0700 (PDT) From: Michael Bommarito To: Mika Westerberg , Andreas Noever , Yehezkel Bernat Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] thunderbolt: prevent XDomain delayed work use-after-free on disconnect Date: Mon, 25 May 2026 08:57:36 -0400 Message-ID: <20260525125736.1268929-1-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.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" tb_xdp_handle_request() runs on system_wq and queues xd->state_work via queue_delayed_work() in three request handlers: PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues xd->properties_changed_work from bus_for_each_dev() when local properties change. Concurrently, tb_xdomain_remove() calls stop_handshake() which does cancel_delayed_work_sync() on both delayed works, then device_unregister() which eventually frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") moved the request handler off tb->wq, the handler and the remove path are no longer serialized. If queue_delayed_work() executes after cancel_delayed_work_sync() but before the xdomain is freed, the delayed work fires on a freed object. Add xd->removing that tb_xdomain_remove() sets under xd->lock before calling stop_handshake(). Each external queue site holds the same lock and checks removing before calling queue_delayed_work(). This provides the mutual exclusion needed: either the queue site acquires the lock first and queues work that the subsequent cancel will see, or the remove path acquires the lock first and the queue site observes removing =3D=3D true and skips the queue. Fixes: 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system wo= rkqueue") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito --- drivers/thunderbolt/xdomain.c | 40 ++++++++++++++++++++++++++--------- include/linux/thunderbolt.h | 3 +++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index 1fd1cf4295a2a..55f91ead8f13b 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -785,9 +785,13 @@ static void tb_xdp_handle_request(struct work_struct *= work) * the xdomain related to this connection as well in * case there is a change in services it offers. */ - if (xd && device_is_registered(&xd->dev)) - queue_delayed_work(tb->wq, &xd->state_work, - msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); + if (xd) { + mutex_lock(&xd->lock); + if (!xd->removing && device_is_registered(&xd->dev)) + queue_delayed_work(tb->wq, &xd->state_work, + msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); + mutex_unlock(&xd->lock); + } break; =20 case UUID_REQUEST_OLD: @@ -800,8 +804,12 @@ static void tb_xdp_handle_request(struct work_struct *= work) * received UUID request from the remote host. */ if (!ret && xd && xd->state =3D=3D XDOMAIN_STATE_ERROR) { - dev_dbg(&xd->dev, "restarting handshake\n"); - start_handshake(xd); + mutex_lock(&xd->lock); + if (!xd->removing) { + dev_dbg(&xd->dev, "restarting handshake\n"); + start_handshake(xd); + } + mutex_unlock(&xd->lock); } break; =20 @@ -829,9 +837,13 @@ static void tb_xdp_handle_request(struct work_struct *= work) =20 ret =3D tb_xdp_link_state_change_response(ctl, route, sequence, 0); - xd->target_link_width =3D lsc->tlw; - queue_delayed_work(tb->wq, &xd->state_work, - msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); + mutex_lock(&xd->lock); + if (!xd->removing) { + xd->target_link_width =3D lsc->tlw; + queue_delayed_work(tb->wq, &xd->state_work, + msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); + } + mutex_unlock(&xd->lock); } else { tb_xdp_error_response(ctl, route, sequence, ERROR_NOT_READY); @@ -2074,6 +2086,10 @@ void tb_xdomain_remove(struct tb_xdomain *xd) { tb_xdomain_debugfs_remove(xd); =20 + mutex_lock(&xd->lock); + xd->removing =3D true; + mutex_unlock(&xd->lock); + stop_handshake(xd); =20 device_for_each_child_reverse(&xd->dev, xd, unregister_service); @@ -2484,8 +2500,12 @@ static int update_xdomain(struct device *dev, void *= data) =20 xd =3D tb_to_xdomain(dev); if (xd) { - queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, - msecs_to_jiffies(50)); + mutex_lock(&xd->lock); + if (!xd->removing) + queue_delayed_work(xd->tb->wq, + &xd->properties_changed_work, + msecs_to_jiffies(50)); + mutex_unlock(&xd->lock); } =20 return 0; diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 0ba112175bb39..7204586c10c3e 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -209,6 +209,8 @@ enum tb_link_width { * @link_width: Width of the downstream facing link * @link_usb4: Downstream link is USB4 * @is_unplugged: The XDomain is unplugged + * @removing: Set by tb_xdomain_remove() under @lock to prevent + * concurrent delayed work queueing * @needs_uuid: If the XDomain does not have @remote_uuid it will be * queried first * @service_ids: Used to generate IDs for the services @@ -257,6 +259,7 @@ struct tb_xdomain { enum tb_link_width link_width; bool link_usb4; bool is_unplugged; + bool removing; bool needs_uuid; struct ida service_ids; struct ida in_hopids; base-commit: 928abe19fbf0127003abcb1ea69cabc1c897d0ab prerequisite-patch-id: 568123ac4badeed61126aaa6ea4b751522da24a6 prerequisite-patch-id: bbb8fb9eb5ecf865daf2dd1daec056054aead3df prerequisite-patch-id: 34c0bcaacf7f5a77b1cde8878516b8bbd5ca19dc prerequisite-patch-id: a7e026bebb71889c4158d186b85eccf5bf64d6bc prerequisite-patch-id: a6d22495595875ad794fe9fcfcda64b8344b97d6 prerequisite-patch-id: 20125baeeb45edacd9cc1167a89e876e14a88882 --=20 2.53.0