[PATCH v8 2/5] drm/bridge: get the bridge returned by drm_bridge_chain_get_first_bridge()

Luca Ceresoli posted 5 patches 3 months, 2 weeks ago
There is a newer version of this series
[PATCH v8 2/5] drm/bridge: get the bridge returned by drm_bridge_chain_get_first_bridge()
Posted by Luca Ceresoli 3 months, 2 weeks ago
drm_bridge_chain_get_first_bridge() returns a bridge pointer that the
caller could hold for a long time. Increment the refcount of the returned
bridge and document it must be put by the caller.

Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---

This patch was added in v7.
---
 include/drm/drm_bridge.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index b110c5bba8c0612a71f749ad51345e7a8ccdc910..f98044581d67c380c3bc3a1943bd6ab09b764ec3 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1336,6 +1336,9 @@ drm_bridge_get_prev_bridge(struct drm_bridge *bridge)
  * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain
  * @encoder: encoder object
  *
+ * The refcount of the returned bridge is incremented. Use drm_bridge_put()
+ * when done with it.
+ *
  * RETURNS:
  * the first bridge in the chain, or NULL if @encoder has no bridge attached
  * to it.
@@ -1343,8 +1346,8 @@ drm_bridge_get_prev_bridge(struct drm_bridge *bridge)
 static inline struct drm_bridge *
 drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder)
 {
-	return list_first_entry_or_null(&encoder->bridge_chain,
-					struct drm_bridge, chain_node);
+	return drm_bridge_get(list_first_entry_or_null(&encoder->bridge_chain,
+						       struct drm_bridge, chain_node));
 }
 
 /**

-- 
2.49.0
Re: [PATCH v8 2/5] drm/bridge: get the bridge returned by drm_bridge_chain_get_first_bridge()
Posted by Liu Ying 3 months, 2 weeks ago
On 06/21/2025, Luca Ceresoli wrote:
> drm_bridge_chain_get_first_bridge() returns a bridge pointer that the
> caller could hold for a long time. Increment the refcount of the returned
> bridge and document it must be put by the caller.

To make sure the incremented refcount is decremented once this patch is
applied, does it make sense to squash patch 3, 4 and 5 into this one?

> 
> Reviewed-by: Maxime Ripard <mripard@kernel.org>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> ---
> 
> This patch was added in v7.
> ---
>  include/drm/drm_bridge.h | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index b110c5bba8c0612a71f749ad51345e7a8ccdc910..f98044581d67c380c3bc3a1943bd6ab09b764ec3 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -1336,6 +1336,9 @@ drm_bridge_get_prev_bridge(struct drm_bridge *bridge)
>   * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain
>   * @encoder: encoder object
>   *
> + * The refcount of the returned bridge is incremented. Use drm_bridge_put()
> + * when done with it.
> + *
>   * RETURNS:
>   * the first bridge in the chain, or NULL if @encoder has no bridge attached
>   * to it.
> @@ -1343,8 +1346,8 @@ drm_bridge_get_prev_bridge(struct drm_bridge *bridge)
>  static inline struct drm_bridge *
>  drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder)
>  {
> -	return list_first_entry_or_null(&encoder->bridge_chain,
> -					struct drm_bridge, chain_node);
> +	return drm_bridge_get(list_first_entry_or_null(&encoder->bridge_chain,
> +						       struct drm_bridge, chain_node));
>  }
>  
>  /**
> 

-- 
Regards,
Liu Ying
Re: [PATCH v8 2/5] drm/bridge: get the bridge returned by drm_bridge_chain_get_first_bridge()
Posted by Luca Ceresoli 3 months, 2 weeks ago
Hello Liu,

On Mon, 23 Jun 2025 10:56:13 +0800
Liu Ying <victor.liu@nxp.com> wrote:

> On 06/21/2025, Luca Ceresoli wrote:
> > drm_bridge_chain_get_first_bridge() returns a bridge pointer that the
> > caller could hold for a long time. Increment the refcount of the returned
> > bridge and document it must be put by the caller.  
> 
> To make sure the incremented refcount is decremented once this patch is
> applied, does it make sense to squash patch 3, 4 and 5 into this one?

I see there is a trade off here between bisectability and patch
readability.

However about bisectability the problem is limited for this series. To
get an actual get/put imbalance you'd have to be able to remove the
bridge, but removing (part of) the bridge chain is not at all supported
right now, and it won't be until after chapter 4 of this work (see
cover letter).

However I realize there is an issue if:
* patch 2 is applied but patches 3/4/5 are not
  (it does not make sense to apply this series partially, but this
  might happen when cherry-picking?)
* an entire DRM card is removed where
  drm_bridge_chain_get_first_bridge() is used by some components

If both happen we'd have a get without put, thus a missing free and a
memory leak for the container struct.

Note that, besides drm_bridge_chain_get_first_bridge() that this
series covers, there are various other accessors: see items 1.E.{2..8}
in cover letter. For some of those there are many more changes to apply
because they are called in more places. Squashing them would result in
a really large patch that is likely hard to review and manage.

So I'll leave the decision to DRM subsystem maintainers. For the time
being I'm keeping the current approach given that Maxime already
reviewed these patches in the past, not squashed.

Best regards,
Luca

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Re: [PATCH v8 2/5] drm/bridge: get the bridge returned by drm_bridge_chain_get_first_bridge()
Posted by Liu Ying 3 months, 2 weeks ago
On 06/23/2025, Luca Ceresoli wrote:
> Hello Liu,

Luca,

> 
> On Mon, 23 Jun 2025 10:56:13 +0800
> Liu Ying <victor.liu@nxp.com> wrote:
> 
>> On 06/21/2025, Luca Ceresoli wrote:
>>> drm_bridge_chain_get_first_bridge() returns a bridge pointer that the
>>> caller could hold for a long time. Increment the refcount of the returned
>>> bridge and document it must be put by the caller.  
>>
>> To make sure the incremented refcount is decremented once this patch is
>> applied, does it make sense to squash patch 3, 4 and 5 into this one?
> 
> I see there is a trade off here between bisectability and patch
> readability.
> 
> However about bisectability the problem is limited for this series. To
> get an actual get/put imbalance you'd have to be able to remove the
> bridge, but removing (part of) the bridge chain is not at all supported
> right now, and it won't be until after chapter 4 of this work (see
> cover letter).
> 
> However I realize there is an issue if:
> * patch 2 is applied but patches 3/4/5 are not
>   (it does not make sense to apply this series partially, but this
>   might happen when cherry-picking?)

Yes for cherry-picking and bisecting.

> * an entire DRM card is removed where
>   drm_bridge_chain_get_first_bridge() is used by some components
> 
> If both happen we'd have a get without put, thus a missing free and a
> memory leak for the container struct.

Yes, that's a memory leak.

> 
> Note that, besides drm_bridge_chain_get_first_bridge() that this
> series covers, there are various other accessors: see items 1.E.{2..8}

IIUC, without those items addressed, the issue we have is use-after-free,
but not the memory leak this patch introduces(without squash).

> in cover letter. For some of those there are many more changes to apply
> because they are called in more places. Squashing them would result in
> a really large patch that is likely hard to review and manage.

If the squash is done for each item separately and properly, I'd say
the memory leak issue can be avoided.  I assume patches for each item
would not be large.

> 
> So I'll leave the decision to DRM subsystem maintainers. For the time
> being I'm keeping the current approach given that Maxime already
> reviewed these patches in the past, not squashed.
> 
> Best regards,
> Luca
> 

-- 
Regards,
Liu Ying
Re: [PATCH v8 2/5] drm/bridge: get the bridge returned by drm_bridge_chain_get_first_bridge()
Posted by Maxime Ripard 3 months, 2 weeks ago
On Tue, Jun 24, 2025 at 10:44:03AM +0800, Liu Ying wrote:
> On 06/23/2025, Luca Ceresoli wrote:
> > On Mon, 23 Jun 2025 10:56:13 +0800
> > Liu Ying <victor.liu@nxp.com> wrote:
> > 
> >> On 06/21/2025, Luca Ceresoli wrote:
> >>> drm_bridge_chain_get_first_bridge() returns a bridge pointer that the
> >>> caller could hold for a long time. Increment the refcount of the returned
> >>> bridge and document it must be put by the caller.  
> >>
> >> To make sure the incremented refcount is decremented once this patch is
> >> applied, does it make sense to squash patch 3, 4 and 5 into this one?
> > 
> > I see there is a trade off here between bisectability and patch
> > readability.
> > 
> > However about bisectability the problem is limited for this series. To
> > get an actual get/put imbalance you'd have to be able to remove the
> > bridge, but removing (part of) the bridge chain is not at all supported
> > right now, and it won't be until after chapter 4 of this work (see
> > cover letter).
> > 
> > However I realize there is an issue if:
> > * patch 2 is applied but patches 3/4/5 are not
> >   (it does not make sense to apply this series partially, but this
> >   might happen when cherry-picking?)
> 
> Yes for cherry-picking and bisecting.
> 
> > * an entire DRM card is removed where
> >   drm_bridge_chain_get_first_bridge() is used by some components
> > 
> > If both happen we'd have a get without put, thus a missing free and a
> > memory leak for the container struct.
> 
> Yes, that's a memory leak.
> 
> > Note that, besides drm_bridge_chain_get_first_bridge() that this
> > series covers, there are various other accessors: see items 1.E.{2..8}
> 
> IIUC, without those items addressed, the issue we have is use-after-free,
> but not the memory leak this patch introduces(without squash).

Given that this structure is going to be allocated a couple of times in
the system life at best, and that the situation prior to the work Luca
has been doing was a use-after-free, I'm not really concerned about a
transient memory leak in a situation that cannot happen.

If people want to come and backport random patches without looking at
the whole thing, that's their problem.

Maxime