All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Kumar G, Naresh" <naresh.kumar.g@intel.com>
To: Balasubramani Vivekanandan <balasubramani.vivekanandan@intel.com>,
	<intel-xe@lists.freedesktop.org>
Cc: <rodrigo.vivi@intel.com>,
	Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>,
	Danilo Krummrich <dakr@kernel.org>,
	Heikki Krogerus <heikki.krogerus@linux.intel.com>,
	"Upadhyay, Tejas" <tejas.upadhyay@intel.com>
Subject: Re: [PATCH] drm/xe/i2c: Fix use-after-free on driver unload
Date: Mon, 12 Oct 2026 17:16:16 +0530	[thread overview]
Message-ID: <7939f69c-bc63-4465-a578-8024e20c4eb8@intel.com> (raw)
In-Reply-To: <20261009164241.923756-2-balasubramani.vivekanandan@intel.com>

[-- Attachment #1: Type: text/plain, Size: 7612 bytes --]

Hi Bala,

I was investigating this issue earlier in sometime and found the root 
cause in software _node_notify_remove().

It is a kind of ownership bug in driver/base/swnode.c 
sofware_node_notify_remove(). when a manged swnode is mirrored onto a

second device(which is exactly what i2c-core does for the adapter's own 
struct device), the old code does an extra 
set_secondary_fwnode()/swnode_put()

for every device that tears down, not just the true owner. this is a 
double-release/UAF risk. The following fix solves the issue without 
changing i2c adapter registration flow.

The following code patch is suggested/provided to @heikki: waiting for 
his inputs on the same.

Fixes: 151f6ff78cdf ("software node: Provide replacement for device_add_properties()")
Assisted-by: GitHub_Copilot:claude-sonnet-5
Signed-off-by: Nareshkumar Gollakoti<naresh.kumar.g@intel.com>
---
  drivers/base/swnode.c | 18 +++++++++++++++---
  1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 84a77ffa3dc4..2efcf12b4c21 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -1190,6 +1190,7 @@ void software_node_notify(struct device *dev)
  void software_node_notify_remove(struct device *dev)
  {
  	struct swnode *swnode;
+	bool owns_managed_fwnode;
  
  	swnode = dev_to_swnode(dev);
  	if (!swnode)
@@ -1198,6 +1199,16 @@ void software_node_notify_remove(struct device *dev)
  	sysfs_remove_link(&swnode->kobj, dev_name(dev));
  	sysfs_remove_link(&dev->kobj, "software_node");
  
+	/*
+	 * A managed node can end up mirrored onto more than one device (e.g.
+	 * a bus core copying the fwnode onto a child device, as i2c-core does
+	 * for an adapter's own struct device). Only the device that actually
+	 * owns the fwnode releases the creation reference and detaches it;
+	 * every other device only releases the reference software_node_notify()
+	 * took for it.
+	 */
+	owns_managed_fwnode = swnode->managed && swnode->fwnode.dev == dev;
+
  	/*
  	 * Drop the device pointer mirrored onto a secondary software node in
  	 * software_node_notify(). For a primary software node the core owns
@@ -1206,12 +1217,13 @@ void software_node_notify_remove(struct device *dev)
  	if (!device_match_fwnode(dev, &swnode->fwnode) && swnode->fwnode.dev == dev)
  		swnode->fwnode.dev = NULL;
  
+	if (owns_managed_fwnode)
+		set_secondary_fwnode(dev, NULL);
+
  	swnode_put(swnode);
  
-	if (swnode->managed) {
-		set_secondary_fwnode(dev, NULL);
+	if (owns_managed_fwnode)
  		swnode_put(swnode);
-	}
  }


Given that,

Is this rework still needed once the core fix landed?


Thanks,

Naresh

On 10/9/2026 10:12 PM, Balasubramani Vivekanandan wrote:
> The kernel crashes when unloading the xe driver on CRI:
>
>   Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b73
>   RIP: 0010:platform_device_release+0x80/0x90
>   Call Trace:
>    device_release+0x44/0xa0
>    kobject_put+0x9b/0x250
>    put_device+0x13/0x30
>    platform_device_unregister+0x29/0x40
>    xe_i2c_remove+0x80/0xa0 [xe]
>    devm_action_release+0x16/0x30
>    release_nodes+0x3d/0x140
>    devres_release_all+0x96/0xd0
>
> This started after commit 0f485f88656af ("drm/xe/i2c: use
> device_create_managed_software_node()"), which attaches a managed
> software node to a platform device created with platform_device_alloc().
>
> Comment above the device_create_managed_software_node function cautions
> that the software node created by it should not be shared or reused as
> the lifetime of the node is linked to the device.
>
> But the DesignWare i2c driver which creates an adapter device as a child
> of the platform device reuses the software node as its fwnode.
> (device_set_node() in i2c_dw_probe()).
>
> During module unbind, when the adapter device is deleted, it drops the
> reference count for the software node and frees the software node.
> Later when the platform device is removed, it tries to dereference the
> software node pointer and results in use-after-free.
>
> Instead of managed software node use a static struct software_node
> passed through platform_device_info.swnode to
> platform_device_register_full().
> But we have a blocker which doesn't allow to use
> platform_device_register_full() simply.
>
> Currently the driver is using the two step alloc/add sequence while
> creating the platform device so that i2c->pdev is set before
> platform_device_add(), because xe_i2c_notifier() needs i2c->dev and it
> can run before platform_device_register_full() returns.
>
> We can fix it by removing the dependency on i2c->dev in
> xe_i2c_notifier(). It is using it to match against the right adapter.
> Instead of using the device, use its parent to match.
>
> Fixes: 0f485f88656af ("drm/xe/i2c: use device_create_managed_software_node()")
> Cc: Bartosz Golaszewski<bartosz.golaszewski@oss.qualcomm.com>
> Cc: Danilo Krummrich<dakr@kernel.org>
> Cc: Heikki Krogerus<heikki.krogerus@linux.intel.com>
> Signed-off-by: Balasubramani Vivekanandan<balasubramani.vivekanandan@intel.com>
> ---
>   drivers/gpu/drm/xe/xe_i2c.c | 45 +++++++++++++------------------------
>   1 file changed, 15 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c
> index b82caaff80d7b..c54a2375f07ef 100644
> --- a/drivers/gpu/drm/xe/xe_i2c.c
> +++ b/drivers/gpu/drm/xe/xe_i2c.c
> @@ -55,6 +55,10 @@ static const struct property_entry xe_i2c_adapter_properties[] = {
>   	{ }
>   };
>   
> +static const struct software_node xe_i2c_adapter_node = {
> +	.properties = xe_i2c_adapter_properties,
> +};
> +
>   static inline void xe_i2c_read_endpoint(struct xe_mmio *mmio, void *ep)
>   {
>   	u32 *val = ep;
> @@ -98,7 +102,7 @@ static int xe_i2c_notifier(struct notifier_block *nb, unsigned long action, void
>   	struct device *dev = data;
>   
>   	if (action == BUS_NOTIFY_ADD_DEVICE &&
> -	    adapter && dev->parent == &i2c->pdev->dev) {
> +	    adapter && dev->parent && dev->parent->parent == i2c->drm_dev) {
>   		i2c->adapter = adapter;
>   		schedule_work(&i2c->work);
>   		return NOTIFY_OK;
> @@ -110,41 +114,22 @@ static int xe_i2c_notifier(struct notifier_block *nb, unsigned long action, void
>   static int xe_i2c_register_adapter(struct xe_i2c *i2c)
>   {
>   	struct pci_dev *pci = to_pci_dev(i2c->drm_dev);
> +	struct platform_device_info info = {
> +		.parent = i2c->drm_dev,
> +		.name = adapter_name,
> +		.swnode = &xe_i2c_adapter_node,
> +	};
>   	struct platform_device *pdev;
> -	int ret;
> -	u32 id;
> -
> -	id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci);
> -
> -	/*
> -	 * Not using platform_device_register_full() here because we don't have
> -	 * a handle to the platform_device before it returns. xe_i2c_notifier()
> -	 * uses that handle, but it may be called before
> -	 * platform_device_register_full() is done.
> -	 */
> -	pdev = platform_device_alloc(adapter_name, id);
> -	if (!pdev)
> -		return -ENOMEM;
>   
> -	ret = device_create_managed_software_node(&pdev->dev,
> -						  xe_i2c_adapter_properties,
> -						  NULL);
> -	if (ret)
> -		goto err_pdev_put;
> +	info.id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci);
>   
> -	pdev->dev.parent = i2c->drm_dev;
> -	i2c->pdev = pdev;
> +	pdev = platform_device_register_full(&info);
> +	if (IS_ERR(pdev))
> +		return PTR_ERR(pdev);
>   
> -	ret = platform_device_add(pdev);
> -	if (ret)
> -		goto err_pdev_put;
> +	i2c->pdev = pdev;
>   
>   	return 0;
> -
> -err_pdev_put:
> -	platform_device_put(pdev);
> -
> -	return ret;
>   }
>   
>   static void xe_i2c_unregister_adapter(struct xe_i2c *i2c)

[-- Attachment #2: Type: text/html, Size: 9111 bytes --]

  parent reply	other threads:[~2026-10-12 11:46 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-09 16:42 [PATCH] drm/xe/i2c: Fix use-after-free on driver unload Balasubramani Vivekanandan
2026-10-09 16:42 ` ✗ CI.checkpatch: warning for " Patchwork
2026-10-09 16:44 ` ✓ CI.KUnit: success " Patchwork
2026-10-09 16:47 ` [PATCH] " sashiko-bot
2026-10-12 12:25   ` Vivekanandan, Balasubramani
2026-10-09 18:19 ` ✓ Xe.CI.BAT: success for " Patchwork
2026-10-09 21:19 ` ✓ Xe.CI.FULL: " Patchwork
2026-10-10 20:14 ` [PATCH] " Danilo Krummrich
2026-10-12 12:15   ` Vivekanandan, Balasubramani
2026-10-12 11:46 ` Kumar G, Naresh [this message]
2026-10-12 13:16   ` Vivekanandan, Balasubramani

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=7939f69c-bc63-4465-a578-8024e20c4eb8@intel.com \
    --to=naresh.kumar.g@intel.com \
    --cc=balasubramani.vivekanandan@intel.com \
    --cc=bartosz.golaszewski@oss.qualcomm.com \
    --cc=dakr@kernel.org \
    --cc=heikki.krogerus@linux.intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=rodrigo.vivi@intel.com \
    --cc=tejas.upadhyay@intel.com \
    /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.