From nobody Mon Feb 9 05:55:45 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 75D5C421A07 for ; Fri, 6 Feb 2026 14:28:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770388099; cv=none; b=fNs8GFt21k22dQfuwtMV23o+GAzpIKCKzzztJpkmztBJpKX6oj0+ru2oOATwftRJUPs3qWTI3ryUUYILug9CBX63L6S5vSWp4PP78J5hhwWZzoB7mURpNAOHzFalmXaZUmwIDaV6mXfZtpP2pWGTEKVD7HLDJERFC4qpnTcaqvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770388099; c=relaxed/simple; bh=gbXc7l+x8BLCwMujNegBaaWm6oe6mEhZgcCRCPmcuX0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ak/zJ61J07EeoLoU+MEXpG2qs4QseS0wvbJa6pe9K6ZD3m3IqywLpi8kKAmPZe22x5qPcuIuNUWQdY6csZaz0sQFNrjVuXLEXfviaMWgwTHOnXWfJftmCtmAHt8Egw0JL0zysQyBfTh6VubuAbltvlm9ZygGnQekTBfh+bWu8Eg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=aEKApwaa; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="aEKApwaa" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id AA630C24F81; Fri, 6 Feb 2026 14:28:24 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 1B8F660729; Fri, 6 Feb 2026 14:28:18 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 2AFAC119D1D44; Fri, 6 Feb 2026 15:28:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1770388096; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=Hb2S8TQQB5gVXQwoVTh7MH3rQHkTeCE5saOiNRJ026c=; b=aEKApwaa3rfnyRoDePayUOjxFm93dNDId2WTHesdT0Asp4eyrnkRf+MOIF87hM0gX0x6+n HCoGwOXixx0ay4b01cYaI2jFJZclo9YL6Ea3xI1SI06nFbaB1Kk6ND0rEEcHC7OBhHxK7k 3H45OEY/4sRABEK8KMT7DRscnd4an1aKrjHvNnXyQ6OIx5LYJcu3B+5fuLnQrQAq5fVcqG wlj+npwjg0cS9ypkguIseZ8Bzm+ybm3oZHxbe3LB6OJZpJuQEVl3B3qsvKgmpOFBZx1hze EnE6KbZNLV9bjcmJS/siUSiuq2gHcA0ldNeEJ0VKKIaiXG35rq+zUHX6sIM9iw== From: Luca Ceresoli Date: Fri, 06 Feb 2026 15:27:55 +0100 Subject: [PATCH 1/2] drm/bridge: add drm_bridge_clear_and_put() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260206-drm-bridge-atomic-vs-remove-clear_and_put-v1-1-6f1a7d03c45f@bootlin.com> References: <20260206-drm-bridge-atomic-vs-remove-clear_and_put-v1-0-6f1a7d03c45f@bootlin.com> In-Reply-To: <20260206-drm-bridge-atomic-vs-remove-clear_and_put-v1-0-6f1a7d03c45f@bootlin.com> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Inki Dae , Jagan Teki , Marek Szyprowski Cc: Hui Pu , Ian Ray , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Drivers having a struct drm_bridge pointer pointing to a bridge in many cases hold that reference until the owning device is removed. In those cases the reference to the bridge can be put in the .remove callback (possibly using devm actions) or in the .destroy func (possibly with the help of struct drm_bridge::next_bridge). At those moments the driver should not be operating anymore and won't dereference the bridge pointer after it is put. However there are cases when drivers need to stop holding a reference to a bridge even when their device is not being removed. This is the case for bridge hot-unplug, when a bridge is removed but the previous entity (bridge or encoder) is staying. In such case the "previous entity" needs to put it but cannot do it via devm or .destroy, because it is not being removed. The easy way to dispose of such pointer is: drm_bridge_put(my_priv->some_bridge); my_priv->some_bridge =3D NULL; However this is risky because there is a time window between the two lines where the reference is put, and thus the bridge could be deallocated, but the pointer is still assigned. If other functions of the same driver were invoked concurrently they might dereference my_priv->some_bridge during that window, resulting in use-after-free. A correct solution is to clear the pointer before putting the reference, but that needs a temporary variable: struct drm_bridge *temp =3D my_priv->some_bridge; my_priv->some_bridge =3D NULL; drm_bridge_put(temp); This solution is however annoying to write, so the incorrect version might still sneak in. Add a simple, easy to use function to put a bridge after setting its pointer to NULL in the correct way. Signed-off-by: Luca Ceresoli --- This is a renamed version of drm_bridge_put_and_clear() which was sent as part of a larger patch [0] but with largely rewritten documentation and a detailed commit message. [0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-14-9d6f2c9c= 3058@bootlin.com/ --- drivers/gpu/drm/drm_bridge.c | 34 ++++++++++++++++++++++++++++++++++ include/drm/drm_bridge.h | 1 + 2 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 3b165a0d1e77..cbe9f17c3690 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -304,6 +304,9 @@ EXPORT_SYMBOL(drm_bridge_get); * * This function decrements the bridge's reference count and frees the * object if the reference count drops to zero. + * + * See also drm_bridge_clear_and_put() if you also need to set the pointer + * to NULL */ void drm_bridge_put(struct drm_bridge *bridge) { @@ -312,6 +315,37 @@ void drm_bridge_put(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_put); =20 +/** + * drm_bridge_clear_and_put - Given a bridge pointer, clear the pointer + * then put the bridge + * @bridge_pp: pointer to pointer to a struct drm_bridge; ``bridge_pp`` + * must be non-NULL; if ``*bridge_pp`` is NULL this function + * does nothing + * + * Helper to put a DRM bridge, but only after setting its pointer to + * NULL. Useful when a struct drm_bridge reference must be dropped without + * leaving a use-after-free window where the pointed bridge might have been + * freed while still holding a pointer to it. + * + * For struct ``drm_bridge *some_bridge``, this code:: + * + * drm_bridge_clear_and_put(&some_bridge); + * + * is equivalent to the more complex:: + * + * struct drm_bridge *temp =3D some_bridge; + * some_bridge =3D NULL; + * drm_bridge_put(temp); + */ +void drm_bridge_clear_and_put(struct drm_bridge **bridge_pp) +{ + struct drm_bridge *bridge =3D *bridge_pp; + + *bridge_pp =3D NULL; + drm_bridge_put(bridge); +} +EXPORT_SYMBOL(drm_bridge_clear_and_put); + /** * drm_bridge_put_void - wrapper to drm_bridge_put() taking a void pointer * diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 4f19f7064ee3..66ab89cf48aa 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -1290,6 +1290,7 @@ void drm_bridge_unplug(struct drm_bridge *bridge); =20 struct drm_bridge *drm_bridge_get(struct drm_bridge *bridge); void drm_bridge_put(struct drm_bridge *bridge); +void drm_bridge_clear_and_put(struct drm_bridge **bridge_pp); =20 /* Cleanup action for use with __free() */ DEFINE_FREE(drm_bridge_put, struct drm_bridge *, if (_T) drm_bridge_put(_T= )) --=20 2.52.0 From nobody Mon Feb 9 05:55:45 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B4432421886 for ; Fri, 6 Feb 2026 14:28:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770388102; cv=none; b=LvTDUFj4BnbU1wdg/xn4fqksPyVLhbRwtJ617WnRORrCCFyqIl+/QlcyMsD/MV/ngRYdDClNvTvdh02GdEDj6KBXU1XozpdwhxOeWGemwttKEW1U04tBisq3iRe1dyYus8ru77wpbSpjKLtmKmAUS+q3n8R8UFZusAnuLDigzYk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770388102; c=relaxed/simple; bh=kUD90gufEouqo9lqKKPBCb9sDGG+Y9M6YCyqlrgiOGs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=i5c+lnCKli+8xd1YKWyJ3h9onT9zx8c5QcEDqtRJOymmVJXFY8Iwzccle1TddbiV0p2JWDTR/VROy+b+gL+xSWQ0U0R/FaUWF9oDTlCrQQj8SHMpt0u58siLo8dOC5JgmRb+MrrKQQ/6wg9xWvZIRdQixGU796e7SWBH4SiF300= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=vNTxuJOq; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="vNTxuJOq" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 4B29E4E42443; Fri, 6 Feb 2026 14:28:21 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 206DE60729; Fri, 6 Feb 2026 14:28:21 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 65C4A119D1D0C; Fri, 6 Feb 2026 15:28:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1770388100; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=7ojoqEnd4KP21WGxwwSriM+SWgoBM/mvChCKNCOG+D4=; b=vNTxuJOqIbKLr3Jgz+7j0x8DQq3YycMZVeXpVpZGrFxZdiqgY98vk0y2XCCDGtXiNQZNjl W1qoS7lHvI+mrsBFscsfXXAeptRIVIogWtVFuraZ2WCvVrJhw/96KDTxZFr55YhD9cD2T0 CnVcmSgyarV7sWiwcpV/YwMcJ/4/dBVdcJeCGjmvpjlEGbYwuT2aHRAC7Bew1rYKppYjx/ +5DPBxPYg3FgtacTISRj+NwaiZD8QXR+nsXagrhshmvEQhrvIoAWnDyIVNIcZWwJNaAjas HYpcywz2PNkn57Uc9tF0ih8f38eJDiw3JXm4fL2qAaU+YtJEVJf4VWVDdCWIHg== From: Luca Ceresoli Date: Fri, 06 Feb 2026 15:27:56 +0100 Subject: [PATCH 2/2] drm/bridge: samsung-dsim: use drm_bridge_clear_and_put() to put the next bridge Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260206-drm-bridge-atomic-vs-remove-clear_and_put-v1-2-6f1a7d03c45f@bootlin.com> References: <20260206-drm-bridge-atomic-vs-remove-clear_and_put-v1-0-6f1a7d03c45f@bootlin.com> In-Reply-To: <20260206-drm-bridge-atomic-vs-remove-clear_and_put-v1-0-6f1a7d03c45f@bootlin.com> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Inki Dae , Jagan Teki , Marek Szyprowski Cc: Hui Pu , Ian Ray , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 drm_bridge_clear_and_put() is simpler to write and it prevents any potential future use-after-free. Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/samsung-dsim.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge= /samsung-dsim.c index 1d85e706c74b..568fc0f5b416 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1980,8 +1980,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_h= ost *host, return 0; =20 err_release_next_bridge: - drm_bridge_put(dsi->bridge.next_bridge); - dsi->bridge.next_bridge =3D NULL; + drm_bridge_clear_and_put(&dsi->bridge.next_bridge); return ret; } =20 @@ -2002,8 +2001,7 @@ static int samsung_dsim_host_detach(struct mipi_dsi_h= ost *host, if (pdata->host_ops && pdata->host_ops->detach) pdata->host_ops->detach(dsi, device); =20 - drm_bridge_put(dsi->bridge.next_bridge); - dsi->bridge.next_bridge =3D NULL; + drm_bridge_clear_and_put(&dsi->bridge.next_bridge); =20 samsung_dsim_unregister_te_irq(dsi); =20 --=20 2.52.0