Re: [PATCH] drm/bridge: aux-hpd-bridge: replay last HPD status on hpd_enable
[email protected] Mon, 03 Aug 2026 08:54:15 +0000
| Newsgroups | org.freedesktop.lists.dri-devel |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Missing cancellation of `hpd_work` on device unbind leads to access of a destroyed mutex and use-after-free. - [High] Lockless read of `last_status` in `hpd_work` creates a TOCTOU race condition that can deliver stale HPD events out of order. -- --- Patch [1]: [PATCH] drm/bridge: aux-hpd-bridge: replay last HPD status on hpd_enable --- commit ac67055ec791a818497d8d0b82453f5ad00a28d3 Author: Yongxing Mou <[email protected]> drm/bridge: aux-hpd-bridge: replay last HPD status on hpd_enable This commit caches the last HPD status reported by an upstream driver and replays it when a downstream consumer enables HPD handling on the bridge. The replay is deferred to a work item to run outside the .hpd_enable() call context. > diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c > index a2e525aa57887..bb81aabf58d49 100644 > --- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c > +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c [ ... ] > @@ -154,6 +166,8 @@ void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status sta > if (!data) > return; > > + WRITE_ONCE(data->last_status, status); > + > drm_bridge_hpd_notify(&data->bridge, status); [Severity: High] Could this create a race condition with drm_aux_hpd_bridge_hpd_work() where stale HPD events are delivered out of order? If drm_aux_hpd_bridge_hpd_work() reads the status locklessly but gets preempted before calling drm_bridge_hpd_notify(), a concurrent hardware event here could update the status and dispatch it synchronously. When drm_aux_hpd_bridge_hpd_work() resumes, it might then dispatch the older, stale status it cached earlier, leaving the consumer with an outdated connection state. > } > EXPORT_SYMBOL_GPL(drm_aux_hpd_bridge_notify); > @@ -165,11 +179,45 @@ static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge, > return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; > } > > +static void drm_aux_hpd_bridge_hpd_work(struct work_struct *work) > +{ > + struct drm_aux_hpd_bridge_data *data = > + container_of(work, struct drm_aux_hpd_bridge_data, hpd_work); > + enum drm_connector_status status = READ_ONCE(data->last_status); > + > + if (status == connector_status_unknown) > + return; > + > + drm_bridge_hpd_notify(&data->bridge, status); [Severity: High] Can this work item execute after the device is unbound? If the auxiliary device unbinds while this work item is pending, devres teardown will call drm_bridge_remove_void(), which in turn destroys bridge->hpd_mutex and can free the data structure. If this work item executes after that teardown, wouldn't it result in a use-after-free on data and an attempt to lock a destroyed mutex inside drm_bridge_hpd_notify()? [ ... ] > @@ -192,6 +240,9 @@ static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev, > data->bridge.interlace_allowed = true; > data->bridge.ycbcr_420_allowed = true; > > + data->last_status = connector_status_unknown; > + INIT_WORK(&data->hpd_work, drm_aux_hpd_bridge_hpd_work); > + [Severity: High] Since INIT_WORK() is used here, should there be a corresponding devm cleanup action to ensure the work is cancelled on unbind? Adding something like devm_add_action_or_reset() to call cancel_work_sync() would ensure the work item doesn't outlive the data structure it operates on. > auxiliary_set_drvdata(auxdev, data); > > return devm_drm_bridge_add(data->dev, &data->bridge); -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1