From nobody Mon Jun 8 14:34:26 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gYvgl3KRFz6g9QJ for ; Mon, 08 Jun 2026 14:34:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gYvgk60Hhz4FfZ for ; Mon, 08 Jun 2026 14:34:26 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1780929266; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=e4FJMwcsjfBEIcyShCYh+h0aT8OYyPjvrE9LeXLs3qo=; b=TlndZP9Dfcl6s2NCaF8wrLP1h3jqrVGIzgTwegII7Y1xj1okXyMm4VVDnEF4ZxalfroTRH SjG88z2lpTIlAFr04pBrR50WlopIARTTjL9H3cHF7FkjTf6yXHVBd5vPIeGoK99IjCvouD eu8NykkPik7OHV9KA4RNT4vOaCRFRHDBtpHOffkcqnG2hq2Dcx7gJ5Ge0uNi5yw3N12yVp aagZ83a3aX3SmCRNSimq5neBMe3SFfsMkEy6ivwFFGIezCPPq7We22OCxlj+YDADvLZywX tgan1JFMj4aQucCvgExrc6O9byCdz0vguDUyLDd2f+gFrJnzhac/xxqW94Opog== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1780929266; a=rsa-sha256; cv=none; b=TIFcevvr4J4nvRsPt2Sg815SRqoMOQ0hUdHoFHYqsboulwZ2bOEKXoleDVUr7k6BCBxLUp cuzRviAWtcCWPUqVl+L2vY20QBsYDLUnbhEF1QExCmS7uJKcDi0vluUz1V7nAIWFF0VK2T h9NSIr3NO5AZl4/vB4X2af6j5xN8QmUP/RN6zeuxu0PvReYOfln2VEi2a5nKC8YKhKgFrt vLMagEWxOysG3iUidzSywIaLFkzJkjemMBllzjYuCWqNqBQqtyrwuKgkIcKSZuo3vaI7xT MXFKjMWcfCLyY4MeMg2L42EZIo7I6tGcd7p8S/FP87W8NDD4yACwOT4aohN1yw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1780929266; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=e4FJMwcsjfBEIcyShCYh+h0aT8OYyPjvrE9LeXLs3qo=; b=rA/d2H30Yu0nckWP6jIsF0p/Ilkpc2FLTsTXVPI9MAv4BlijFCeahxeQxaZhA0P5qcT6QV 8+4M+zOu6gATy5UZLexkD++HXmmNjeM93jMyDcU7XI5neMUMaTUQfUryNvcNNp5dwp3c3p Y82UlijiPpS3Pzf+71BSlrZoOuP9UG65XwzEc2tdtTuUcEYoT8WbQR0BGopX92KZhzmB0L f3pJbYk+FsZeF84aDitkkcbIoTsPDjQu4VkaivyJJbcv2ZkQCIvsdtpOSSW5oUfJSmVXoX RyRd4TkFYVjFBXrhXgQCVqrBsg2hEFN9PeS8fDYbk+/+++fF6NMsQ6NSDvEIWw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gYvgk4fGLzsSp for ; Mon, 08 Jun 2026 14:34:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 46f84 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 08 Jun 2026 14:34:26 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Abdelkader Boudih From: Adrian Chadd Subject: git: a9519f7821c0 - main - firewire: Fix watchdog_clock aliasing and fw_tl2xfer UAF race List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: adrian X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a9519f7821c066c393690603eab33043f3804a0c Auto-Submitted: auto-generated Date: Mon, 08 Jun 2026 14:34:26 +0000 Message-Id: <6a26d2f2.46f84.4c1d12e1@gitrepo.freebsd.org> The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=a9519f7821c066c393690603eab33043f3804a0c commit a9519f7821c066c393690603eab33043f3804a0c Author: Abdelkader Boudih AuthorDate: 2026-06-08 14:30:29 +0000 Commit: Adrian Chadd CommitDate: 2026-06-08 14:30:29 +0000 firewire: Fix watchdog_clock aliasing and fw_tl2xfer UAF race Two bugs in the firewire bus layer that affect all consumers ( if_fwip, sbp): watchdog_clock was a static local in firewire_watchdog(), shared across all firewire_comm instances. With two controllers (e.g. built-in + Thunderbolt Display), both advance the same counter, so the second controller's 15-second boot-time timeout guard expires prematurely. fw_tl2xfer() released tlabel_lock before returning the xfer pointer. Reviewed by: zlei, adrian Differential Revision: https://reviews.freebsd.org/D57496 --- sys/dev/firewire/firewire.c | 67 +++++++++++++++++++++++------------------- sys/dev/firewire/firewirereg.h | 1 + 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 079a50413ffa..a54cbf9cdf0b 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -372,23 +372,21 @@ firewire_xfer_timeout(void *arg, int pending) static void firewire_watchdog(void *arg) { - struct firewire_comm *fc; - static int watchdog_clock = 0; - - fc = arg; + struct firewire_softc *sc = arg; + struct firewire_comm *fc = sc->fc; /* * At boot stage, the device interrupt is disabled and - * We encounter a timeout easily. To avoid this, - * ignore clock interrupt for a while. + * we encounter a timeout easily. To avoid this, + * ignore clock ticks for a while. */ - if (watchdog_clock > WATCHDOG_HZ * 15) + if (sc->watchdog_clock > WATCHDOG_HZ * 15) taskqueue_enqueue(fc->taskqueue, &fc->task_timeout); else - watchdog_clock++; + sc->watchdog_clock++; callout_reset(&fc->timeout_callout, hz / WATCHDOG_HZ, - firewire_watchdog, fc); + firewire_watchdog, sc); } /* @@ -444,8 +442,9 @@ firewire_attach(device_t dev) CALLOUT_INIT(&fc->busprobe_callout); TASK_INIT(&fc->task_timeout, 0, firewire_xfer_timeout, fc); + sc->watchdog_clock = 0; callout_reset(&sc->fc->timeout_callout, hz, - firewire_watchdog, sc->fc); + firewire_watchdog, sc); /* create thread */ kproc_create(fw_bus_probe_thread, fc, &fc->probe_thread, @@ -1048,39 +1047,47 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) } /* - * To obtain XFER structure by transaction label. + * Look up an XFER by transaction label. + * Removes the xfer from fc->tlabels only when AT transmit has completed + * (FWXF_SENT); FWXF_START xfers remain so fw_drain_txq() can find them + * on a bus reset. */ static struct fw_xfer * fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel, int tcode) { struct fw_xfer *xfer; - int s = splfw(); int req; mtx_lock(&fc->tlabel_lock); - STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel) - if (xfer->send.hdr.mode.hdr.dst == node) { + STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel) { + if (xfer->send.hdr.mode.hdr.dst != node) + continue; + /* Validate tcode match before claiming the xfer. */ + req = xfer->send.hdr.mode.hdr.tcode; + if (xfer->fc->tcode[req].valid_res != tcode) { + printf("%s: invalid response tcode " + "(0x%x for 0x%x)\n", __func__, tcode, req); mtx_unlock(&fc->tlabel_lock); - splx(s); - KASSERT(xfer->tl == tlabel, - ("xfer->tl 0x%x != 0x%x", xfer->tl, tlabel)); - /* extra sanity check */ - req = xfer->send.hdr.mode.hdr.tcode; - if (xfer->fc->tcode[req].valid_res != tcode) { - printf("%s: invalid response tcode " - "(0x%x for 0x%x)\n", __FUNCTION__, - tcode, req); - return (NULL); - } - - if (firewire_debug > 2) - printf("fw_tl2xfer: found tl=%d\n", tlabel); - return (xfer); + return (NULL); } + /* + * Remove from tlabels only after AT transmit completes + * (FWXF_SENT). Early responses (FWXF_START) must stay + * in the list until fwohci_txd() drains the descriptor. + */ + if (xfer->flag & FWXF_SENT) { + STAILQ_REMOVE(&fc->tlabels[tlabel], xfer, + fw_xfer, tlabel); + xfer->tl = -1; + } + mtx_unlock(&fc->tlabel_lock); + if (firewire_debug > 2) + printf("fw_tl2xfer: found tl=%d\n", tlabel); + return (xfer); + } mtx_unlock(&fc->tlabel_lock); if (firewire_debug > 1) printf("fw_tl2xfer: not found tl=%d\n", tlabel); - splx(s); return (NULL); } diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h index d17f7a15785a..97a53606c001 100644 --- a/sys/dev/firewire/firewirereg.h +++ b/sys/dev/firewire/firewirereg.h @@ -69,6 +69,7 @@ struct fw_device { struct firewire_softc { struct cdev *dev; struct firewire_comm *fc; + int watchdog_clock; }; #define FW_MAX_DMACH 0x20