All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] firmware: arm_scmi: fix an OF node reference leak in scmi_txrx_setup()
@ 2024-12-17  2:31 Joe Hattori
  2024-12-17  5:51 ` Dan Carpenter
  0 siblings, 1 reply; 4+ messages in thread
From: Joe Hattori @ 2024-12-17  2:31 UTC (permalink / raw)
  To: sudeep.holla, cristian.marussi; +Cc: arm-scmi, Joe Hattori

scmi_txrx_setup() calls scmi_chan_setup(), which increments the refcount
of the given OF node. When the Rx channel setup fails with ENOMEM,
scmi_chan_setup() returns the error, but does not release the OF node
obtained in the Tx channel setup. Thus, add an of_node_put() call when
the Rx setup fails with ENOMEM.

This bug was found by an experimental static analysis tool that I am
developing.

Fixes: be9ba1f7f9e0 ("firmware: arm_scmi: Make Rx chan_setup fail on memory errors")
Signed-off-by: Joe Hattori <joe@pf.is.s.u-tokyo.ac.jp>
---
 drivers/firmware/arm_scmi/driver.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 1b5fb2c4ce86..5d8f877d75f3 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2700,7 +2700,9 @@ scmi_txrx_setup(struct scmi_info *info, struct device_node *of_node,
 	if (!ret) {
 		/* Rx is optional, report only memory errors */
 		ret = scmi_chan_setup(info, of_node, prot_id, false);
-		if (ret && ret != -ENOMEM)
+		if (ret == -ENOMEM)
+			of_node_put(of_node);
+		else if (ret)
 			ret = 0;
 	}
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] firmware: arm_scmi: fix an OF node reference leak in scmi_txrx_setup()
  2024-12-17  2:31 [PATCH] firmware: arm_scmi: fix an OF node reference leak in scmi_txrx_setup() Joe Hattori
@ 2024-12-17  5:51 ` Dan Carpenter
  2024-12-17 10:50   ` Krzysztof Kozlowski
  0 siblings, 1 reply; 4+ messages in thread
From: Dan Carpenter @ 2024-12-17  5:51 UTC (permalink / raw)
  To: Joe Hattori; +Cc: sudeep.holla, cristian.marussi, arm-scmi

On Tue, Dec 17, 2024 at 11:31:22AM +0900, Joe Hattori wrote:
> scmi_txrx_setup() calls scmi_chan_setup(), which increments the refcount
> of the given OF node. When the Rx channel setup fails with ENOMEM,
> scmi_chan_setup() returns the error, but does not release the OF node
> obtained in the Tx channel setup. Thus, add an of_node_put() call when
> the Rx setup fails with ENOMEM.
> 
> This bug was found by an experimental static analysis tool that I am
> developing.
>

No, the patch is wrong.

Your static checker has missed the call to of_node_get(of_node).  Only
the success path takes a reference to the of_node.  To be honest, I
think the success path should drop the reference.  Generally with
firmware nodes, we hold the reference for very short time.

drivers/firmware/arm_scmi/driver.c
  2615  static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
  2616                             int prot_id, bool tx)
  2617  {
  2618          int ret, idx;
  2619          char name[32];
  2620          struct scmi_chan_info *cinfo;
  2621          struct idr *idr;
  2622          struct scmi_device *tdev = NULL;
  2623  
  2624          /* Transmit channel is first entry i.e. index 0 */
  2625          idx = tx ? 0 : 1;
  2626          idr = tx ? &info->tx_idr : &info->rx_idr;
  2627  
  2628          if (!info->desc->ops->chan_available(of_node, idx)) {
  2629                  cinfo = idr_find(idr, SCMI_PROTOCOL_BASE);
  2630                  if (unlikely(!cinfo)) /* Possible only if platform has no Rx */
  2631                          return -EINVAL;

Why does your checker not complain about any of these error paths?

  2632                  goto idr_alloc;

This goto is succes, but doesn't boost the refcount.  Which is correct.

  2633          }
  2634  
  2635          cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL);
  2636          if (!cinfo)
  2637                  return -ENOMEM;

I guess this is what your checker sees?

  2638  
  2639          cinfo->is_p2a = !tx;
  2640          cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms;
  2641          cinfo->max_msg_size = info->desc->max_msg_size;
  2642  
  2643          /* Create a unique name for this transport device */
  2644          snprintf(name, 32, "__scmi_transport_device_%s_%02X",
  2645                   idx ? "rx" : "tx", prot_id);
  2646          /* Create a uniquely named, dedicated transport device for this chan */
  2647          tdev = scmi_device_create(of_node, info->dev, prot_id, name);
  2648          if (!tdev) {
  2649                  dev_err(info->dev,
  2650                          "failed to create transport device (%s)\n", name);
  2651                  devm_kfree(info->dev, cinfo);
  2652                  return -EINVAL;
  2653          }
  2654          of_node_get(of_node);

Bump the refcount.

  2655  
  2656          cinfo->id = prot_id;
  2657          cinfo->dev = &tdev->dev;
  2658          ret = info->desc->ops->chan_setup(cinfo, info->dev, tx);
  2659          if (ret) {
  2660                  of_node_put(of_node);

Drop the refcount on failure

  2661                  scmi_device_destroy(info->dev, prot_id, name);
  2662                  devm_kfree(info->dev, cinfo);
  2663                  return ret;
  2664          }
  2665  
  2666          if (tx && is_polling_required(cinfo, info->desc)) {
  2667                  if (is_transport_polling_capable(info->desc))
  2668                          dev_info(&tdev->dev,
  2669                                   "Enabled polling mode TX channel - prot_id:%d\n",
  2670                                   prot_id);
  2671                  else
  2672                          dev_warn(&tdev->dev,
  2673                                   "Polling mode NOT supported by transport.\n");
  2674          }
  2675  
  2676  idr_alloc:
  2677          ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
  2678          if (ret != prot_id) {
  2679                  dev_err(info->dev,
  2680                          "unable to allocate SCMI idr slot err %d\n", ret);
  2681                  /* Destroy channel and device only if created by this call. */
  2682                  if (tdev) {
  2683                          of_node_put(of_node);

Drop the refcount on failure

  2684                          scmi_device_destroy(info->dev, prot_id, name);
  2685                          devm_kfree(info->dev, cinfo);
  2686                  }
  2687                  return ret;
  2688          }
  2689  
  2690          cinfo->handle = &info->handle;
  2691          return 0;
  2692  }

Btw, have you looked at the refcount tracking in Smatch?  It's does
cross function analysis.  But scmi_chan_setup() the success path only
increments the refcount sometimes so it doesn't get recorded.  If I
comment out goto idr_alloc and the label then it works.

$ smdb return_states scmi_chan_setup | grep REFCOUNT
drivers/firmware/arm_scmi/driver.c | scmi_chan_setup | 730 |             0|    REFCOUNT_INC |  1 | $->kobj.kref.refcount.refs.counter |                      |
drivers/firmware/arm_scmi/driver.c | scmi_chan_setup | 731 |             0|    REFCOUNT_INC |  1 | $->kobj.kref.refcount.refs.counter |                      |

The last success path is split into multiple returns based on some
heuristics and two of them are success...  Need to investigate.  That
seems like a waste.

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] firmware: arm_scmi: fix an OF node reference leak in scmi_txrx_setup()
  2024-12-17  5:51 ` Dan Carpenter
@ 2024-12-17 10:50   ` Krzysztof Kozlowski
  2024-12-17 14:27     ` Sudeep Holla
  0 siblings, 1 reply; 4+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-17 10:50 UTC (permalink / raw)
  To: Dan Carpenter, Joe Hattori; +Cc: sudeep.holla, cristian.marussi, arm-scmi

On 17/12/2024 06:51, Dan Carpenter wrote:
> On Tue, Dec 17, 2024 at 11:31:22AM +0900, Joe Hattori wrote:
>> scmi_txrx_setup() calls scmi_chan_setup(), which increments the refcount
>> of the given OF node. When the Rx channel setup fails with ENOMEM,
>> scmi_chan_setup() returns the error, but does not release the OF node
>> obtained in the Tx channel setup. Thus, add an of_node_put() call when
>> the Rx setup fails with ENOMEM.
>>
>> This bug was found by an experimental static analysis tool that I am
>> developing.
>>
> 
> No, the patch is wrong.
> 
There are more patches like this without understanding the OF
drop/retain reference behavior. I suggest careful review of all results
of this "static analysis tool".

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] firmware: arm_scmi: fix an OF node reference leak in scmi_txrx_setup()
  2024-12-17 10:50   ` Krzysztof Kozlowski
@ 2024-12-17 14:27     ` Sudeep Holla
  0 siblings, 0 replies; 4+ messages in thread
From: Sudeep Holla @ 2024-12-17 14:27 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Dan Carpenter, Sudeep Holla, Joe Hattori, cristian.marussi,
	arm-scmi

On Tue, Dec 17, 2024 at 11:50:27AM +0100, Krzysztof Kozlowski wrote:
> On 17/12/2024 06:51, Dan Carpenter wrote:
> > On Tue, Dec 17, 2024 at 11:31:22AM +0900, Joe Hattori wrote:
> >> scmi_txrx_setup() calls scmi_chan_setup(), which increments the refcount
> >> of the given OF node. When the Rx channel setup fails with ENOMEM,
> >> scmi_chan_setup() returns the error, but does not release the OF node
> >> obtained in the Tx channel setup. Thus, add an of_node_put() call when
> >> the Rx setup fails with ENOMEM.
> >>
> >> This bug was found by an experimental static analysis tool that I am
> >> developing.
> >>
> > 
> > No, the patch is wrong.
> > 
> There are more patches like this without understanding the OF
> drop/retain reference behavior. I suggest careful review of all results
> of this "static analysis tool".
> 

Thanks Dan and Krzysztof for the quick heads up and suggestions. Much
appreciated.

--
Regards,
Sudeep

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-12-17 14:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-17  2:31 [PATCH] firmware: arm_scmi: fix an OF node reference leak in scmi_txrx_setup() Joe Hattori
2024-12-17  5:51 ` Dan Carpenter
2024-12-17 10:50   ` Krzysztof Kozlowski
2024-12-17 14:27     ` Sudeep Holla

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.