From: sashiko-bot@kernel.org
To: "Luca Ceresoli" <luca.ceresoli@bootlin.com>
Cc: imx@lists.linux.dev, dri-devel@lists.freedesktop.org,
Frank.Li@kernel.org
Subject: Re: [PATCH RFC v2 12/24] drm/bridge: shutdown and cleanup on bridge unplug
Date: Thu, 01 Oct 2026 13:14:25 +0000 [thread overview]
Message-ID: <20261001131425.A001E1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20261001-drm-bridge-hotplug-v2-12-8e34986dcb68@bootlin.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] drm/bridge: UAF from dangling encoder pointer in drm_bridge_remove()
- [Critical] drm/bridge: list corruption in drm_encoder_cleanup_from() on concurrent unplug
- [Critical] drm/bridge: data race on privobj_list during hot-unplug detachment
- [High] drm/bridge: overbroad shutdown via drm_atomic_shutdown() on unplug
- [High] drm/bridge: lockless TOCTOU race on encoder pointer in drm_bridge_remove()
--
commit d7e62834c6a405667b2b0039bc07bf8c9f4cd74d
Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
drm/bridge: shutdown and cleanup on bridge unplug
This commit adds logic to shut down the pipeline and detach the removed
bridge (and subsequent ones) from the encoder chain when a bridge is
hot-unplugged. It modifies drm_bridge_remove() to invoke
drm_atomic_shutdown() and drm_encoder_cleanup_from() if the bridge is
attached to an encoder.
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 3cf84f2da33ba..468ceed36eb9c 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -507,9 +507,17 @@ EXPORT_SYMBOL(devm_drm_bridge_add);
> * it won't be found by users via of_drm_find_and_get_bridge(), and add it
> * to the lingering bridge list, to keep track of it until its allocated
> * memory is eventually freed.
> + *
> + * If the bridge was attached, also shutdown CRTCs and detach this bridge
> + * and the following ones.
> */
> void drm_bridge_remove(struct drm_bridge *bridge)
> {
> + if (bridge->encoder) {
[Severity: Critical]
Is it possible for bridge->encoder to be a dangling pointer here?
When a display driver unbinds, drm_encoder_cleanup() calls drm_bridge_detach().
The detachment logic clears bridge->dev but fails to clear bridge->encoder:
drivers/gpu/drm/drm_bridge.c:drm_bridge_detach() {
...
bridge->dev = NULL;
drm_bridge_put(bridge);
}
If the encoder memory is then freed, and the bridge driver later unbinds,
drm_bridge_remove() will observe the dangling bridge->encoder pointer and pass
it to drm_encoder_cleanup_from(), which immediately attempts to acquire the
freed encoder's bridge_chain_mutex.
[Severity: High]
Is this lockless read of bridge->encoder susceptible to a TOCTOU race?
If this races with drm_bridge_attach(), it can observe the newly assigned
bridge->encoder before drm_bridge_attach() links the bridge into the encoder
chain under bridge_chain_mutex.
drm_bridge_remove() would then call drm_encoder_cleanup_from(), which acquires
the mutex, sees the bridge is not yet in the list, and skips detachment. The
bridge is then linked into the chain by drm_bridge_attach(), while
drm_bridge_remove() proceeds to destroy bridge->hpd_mutex and drops its
refcount.
> + drm_atomic_shutdown(bridge->dev);
[Severity: High]
Does this unconditionally disable all display pipelines on the DRM device during
a single bridge unplug?
Looking at drm_atomic_shutdown(), it invokes drm_atomic_disable_all() on the
entire device. For systems with multiple independent displays (e.g., an internal
eDP panel and an external hot-pluggable HDMI bridge), couldn't this blank the
internal display when the external one is unplugged?
> + drm_encoder_cleanup_from(bridge->encoder, bridge);
[Severity: Critical]
Can this lead to list corruption on concurrent unplugs?
In drm_encoder_cleanup_from(), the code evaluates !list_empty(&bridge->chain_node)
to check if a bridge is attached:
drivers/gpu/drm/drm_encoder.c:drm_encoder_cleanup_from() {
...
if (!list_empty(&bridge->chain_node))
list_for_each_entry_safe_from(bridge, next,
&encoder->bridge_chain, chain_node)
list_move_tail(&bridge->chain_node, &tmplist);
...
}
If Thread A removes an upstream bridge, it moves downstream bridges to its local
stack tmplist. If Thread B concurrently removes one of these downstream bridges,
it acquires the mutex and evaluates !list_empty(). Since the node is in Thread
A's tmplist, it evaluates to true.
Thread B then executes list_for_each_entry_safe_from(), which expects to terminate
at &encoder->bridge_chain. Because the node is actually on Thread A's stack
list, the loop never reaches the encoder's list head, wrapping around the stack
LIST_HEAD and interpreting arbitrary memory as struct drm_bridge.
[Severity: Critical]
Does detaching a bridge here introduce a data race on privobj_list?
drm_encoder_cleanup_from() calls drm_bridge_detach(), which calls
drm_atomic_private_obj_fini(). This executes list_del(&obj->head) to remove the
bridge from dev->mode_config.privobj_list.
However, privobj_list is documented as invariant over the lifetime of the device
and doesn't need locks:
include/drm/drm_mode_config.h:struct drm_mode_config {
...
/**
* @privobj_list:
*
* List of private objects linked with &drm_private_obj.head. This is
* invariant over the lifetime of a device and hence doesn't need any
* locks.
*/
...
}
Modifying it dynamically on hot-unplug without protective locks (like RCU)
introduces a data race with concurrent atomic operations or mode settings that
iterate the list locklessly.
> + }
> +
> mutex_lock(&bridge_lock);
> list_move_tail(&bridge->list, &bridge_lingering_list);
> mutex_unlock(&bridge_lock);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261001-drm-bridge-hotplug-v2-0-8e34986dcb68@bootlin.com?part=12
next prev parent reply other threads:[~2026-10-01 13:14 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 12:42 [PATCH RFC v2 00/24] drm bridge hotplug Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 01/24] drm/connector: split drmm_connector_hdmi_init() in 3 parts Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 02/24] drm/connector: add drm_connector_hdmi_dynamic_init() Luca Ceresoli
2026-10-01 12:48 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 03/24] drm/display: bridge-connector: split code allocation from initialization Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 04/24] drm/display: bridge-connector: hoist error management to common code Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 05/24] drm/display: bridge-connector: use a dynamic connector Luca Ceresoli
2026-10-01 12:56 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 06/24] drm/display: bridge-connector: add APIs to add/remove the connector dynamically Luca Ceresoli
2026-10-01 12:56 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 07/24] drm/bridge: samsung-dsim: move drm_bridge_add() call to probe Luca Ceresoli
2026-10-01 13:01 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 08/24] drm/bridge: initialize chain_node list head on allocation Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 09/24] drm/bridge: initialize chain_node list head on detach and attach errors Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 10/24] drm/encoder: add drm_encoder_cleanup_from() Luca Ceresoli
2026-10-01 13:05 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 11/24] drm/atomic: move drm_atomic_helper_disable_all() and drm_atomic_helper_shutdown() from drm_atomic_helper to drm_atomic Luca Ceresoli
2026-10-01 13:03 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 12/24] drm/bridge: shutdown and cleanup on bridge unplug Luca Ceresoli
2026-10-01 13:14 ` sashiko-bot [this message]
2026-10-01 12:42 ` [PATCH RFC v2 13/24] drm/mipi-dsi: turn DRM_MIPI_DSI into a tristate Luca Ceresoli
2026-10-01 13:17 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 14/24] drm: event-notifier: add mechanism to notify about hotplug events Luca Ceresoli
2026-10-01 13:12 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 15/24] drm/bridge: notify about detached bridges Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 16/24] drm/mipi-dsi: notify about DSI attach Luca Ceresoli
2026-10-01 13:15 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 17/24] drm/bridge: add drm_bridge_get_next() and supporting func Luca Ceresoli
2026-10-01 13:20 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 18/24] drm/panel: implement .get_next_bridge Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 19/24] drm/bridge: display-connector: " Luca Ceresoli
2026-10-01 12:42 ` [PATCH RFC v2 20/24] drm/bridge: ti-sn65dsi83: " Luca Ceresoli
2026-10-01 13:23 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 21/24] drm/bridge: ti-sn65dsi86: " Luca Ceresoli
2026-10-01 13:25 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 22/24] drm/bridge: samsung-dsim: " Luca Ceresoli
2026-10-01 13:27 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 23/24] drm: drm_hotplug_helper: new helper to implement bridge hotplug Luca Ceresoli
2026-10-01 13:31 ` sashiko-bot
2026-10-01 12:42 ` [PATCH RFC v2 24/24] drm/mxsfb/lcdif: enable " Luca Ceresoli
2026-10-01 13:31 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261001131425.A001E1F000FF@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=imx@lists.linux.dev \
--cc=luca.ceresoli@bootlin.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.