All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness
@ 2026-07-24 17:19 Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error() Shubhrajyoti Datta
                   ` (8 more replies)
  0 siblings, 9 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

    This series addresses several correctness and robustness issues in
    the VersalNet EDAC driver

    The main fixes are:

    * Robustness fixes
      - Add NULL checks for mci in handle_error() and remove_one_mc()
        to prevent NULL pointer dereferences when a controller has not
        been fully initialized.
      - Add bounds validation in rpmsg_cb().

    * Teardown improvements
      - Fix teardown ordering in mc_remove() and remove_one_mc() to
        prevent use-after-free conditions.

    * Probe and initialization cleanup
      - Move platform_set_drvdata() from init_one_mc() to mc_probe().
      - Reorder probe flow to initialize MCDI before RPMsg registration.
      - Remove unused pdev parameters from internal initialization
        functions.

    * Resource management fixes
      - Fix error handling in init_one_mc() to avoid a potential
        double-free by reordering device_register() and edac_mc_alloc().
      - Replace sprintf() with init_name by dev_set_name() to avoid
        use-after-free issues caused by deferred kobject cleanup.

    * Code cleanup
      - Use a designated initializer for rpmsg_channel_info.



Prasanna Kumar T S M (1):
  EDAC/versalnet: Fix device_register() error handling in init_one_mc()

Shubhrajyoti Datta (8):
  EDAC/versalnet: Add NULL check for mci in handle_error()
  EDAC/versalnet: Add NULL check for mci in remove_one_mc()
  EDAC/versalnet: Move platform_set_drvdata() to mc_probe()
  EDAC/versalnet: Use dev_set_name() instead of sprintf with init_name
  EDAC/versalnet: Initialize MCDI before RPMsg registration
  EDAC/versalnet: Add bounds validation in rpmsg_cb()
  EDAC/versalnet: Fix use-after-free in remove_one_mc()
  EDAC/versalnet: Use designated initializer for rpmsg_channel_info

 drivers/edac/versalnet_edac.c | 95 +++++++++++++++++++----------------
 1 file changed, 51 insertions(+), 44 deletions(-)

-- 
2.34.1


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

* [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error()
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-26 23:52   ` Borislav Petkov
  2026-07-24 17:19 ` [PATCH 2/9] EDAC/versalnet: Add NULL check for mci in remove_one_mc() Shubhrajyoti Datta
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

Add a NULL pointer check for mci before use in handle_error() to
prevent a potential NULL dereference when the memory controller
instance is not initialized for a given controller number.

This is added as a defensive check. In our current firmware
the event will not be generated.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index d1af5e175f7e..316f8f79c4d8 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -439,6 +439,8 @@ static void handle_error(struct mc_priv  *priv, struct ecc_status *stat,
 		return;
 
 	mci = priv->mci[ctl_num];
+	if (!mci)
+		return;
 
 	if (stat->error_type == MC5_ERR_TYPE_CE) {
 		pinf = stat->ceinfo[stat->channel];
-- 
2.34.1


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

* [PATCH 2/9] EDAC/versalnet: Add NULL check for mci in remove_one_mc()
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error() Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-27  8:11   ` Pandey, Radhey Shyam
  2026-07-24 17:19 ` [PATCH 3/9] EDAC/versalnet: Move platform_set_drvdata() to mc_probe() Shubhrajyoti Datta
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

If a controller's configuration specifies an unrecognized bus width,
init_one_mc() returns 0 but skips allocating priv->mci[ctl_num], leaving
it NULL. On module unload or probe failure, remove_one_mc() is called for
all controllers and unconditionally dereferences priv->mci[i], causing a
kernel panic.

Add a NULL pointer check for mci before dereferencing it.

 Unable to handle kernel NULL pointer dereference at virtual address 0000000000000390
 Internal error: Oops: 0000000096000004 [#1] SMP
 Hardware name: Xilinx Versal NET VNX (DT)
 pc : mc_remove+0x34/0x88
 lr : mc_remove+0x4c/0x88
 Call trace:
  mc_remove+0x34/0x88
  platform_remove+0x2c/0x70
  device_remove+0x48/0x7c
  device_release_driver_internal+0x1c8/0x224
  device_driver_detach+0x18/0x28
  unbind_store+0xb4/0xb8

Fixes: 62a9fc50e8d9 ("EDAC/versalnet: Refactor memory controller initialization and cleanup")
Cc: stable@vger.kernel.org
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index 316f8f79c4d8..05dc34504cc2 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -769,6 +769,9 @@ static void remove_one_mc(struct mc_priv *priv, int i)
 	struct mem_ctl_info *mci;
 
 	mci = priv->mci[i];
+	if (!mci)
+		return;
+
 	device_unregister(mci->pdev);
 	edac_mc_del_mc(mci->pdev);
 	edac_mc_free(mci);
-- 
2.34.1


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

* [PATCH 3/9] EDAC/versalnet: Move platform_set_drvdata() to mc_probe()
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error() Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 2/9] EDAC/versalnet: Add NULL check for mci in remove_one_mc() Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-27  8:35   ` Pandey, Radhey Shyam
  2026-07-24 17:19 ` [PATCH 4/9] EDAC/versalnet: Fix device_register() error handling in init_one_mc() Shubhrajyoti Datta
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

Move platform_set_drvdata() out of init_one_mc() and into mc_probe()
so that the driver data is set once during probe rather than being
redundantly set on each memory controller initialization.

The pdev parameter in init_one_mc() and init_versalnet() is no longer
referenced. Remove it from both function signatures.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index 05dc34504cc2..03b6e0958f17 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -777,7 +777,7 @@ static void remove_one_mc(struct mc_priv *priv, int i)
 	edac_mc_free(mci);
 }
 
-static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i)
+static int init_one_mc(struct mc_priv *priv, int i)
 {
 	u32 num_chans, rank, dwidth, config;
 	struct edac_mc_layer layers[2];
@@ -849,8 +849,6 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
 	priv->mci[i] = mci;
 	priv->dwidth = dt;
 
-	platform_set_drvdata(pdev, priv);
-
 	return 0;
 
 err_unreg:
@@ -863,12 +861,12 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
 	return rc;
 }
 
-static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev)
+static int init_versalnet(struct mc_priv *priv)
 {
 	int rc, i;
 
 	for (i = 0; i < NUM_CONTROLLERS; i++) {
-		rc = init_one_mc(priv, pdev, i);
+		rc = init_one_mc(priv, i);
 		if (rc) {
 			while (i--)
 				remove_one_mc(priv, i);
@@ -914,6 +912,7 @@ static int mc_probe(struct platform_device *pdev)
 		goto err_alloc;
 	}
 
+	platform_set_drvdata(pdev, priv);
 	amd_rpmsg_id_table[0].driver_data = (kernel_ulong_t)priv;
 
 	rc = register_rpmsg_driver(&amd_rpmsg_driver);
@@ -928,7 +927,7 @@ static int mc_probe(struct platform_device *pdev)
 
 	priv->mcdi->r5_rproc = rp;
 
-	rc = init_versalnet(priv, pdev);
+	rc = init_versalnet(priv);
 	if (rc)
 		goto err_init;
 
-- 
2.34.1


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

* [PATCH 4/9] EDAC/versalnet: Fix device_register() error handling in init_one_mc()
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
                   ` (2 preceding siblings ...)
  2026-07-24 17:19 ` [PATCH 3/9] EDAC/versalnet: Move platform_set_drvdata() to mc_probe() Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 5/9] EDAC/versalnet: Use dev_set_name() instead of sprintf with init_name Shubhrajyoti Datta
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

From: Prasanna Kumar T S M <ptsm@linux.microsoft.com>

When device_register() fails, it must be followed by put_device()
rather than kfree(), because device_register() calls
device_initialize() which sets up the device refcount. The matching
release function versal_edac_release() handles the actual kfree().

To simplify error handling and avoid complex unwinding, split
device_register() into device_initialize() and device_add().
Initialize the device early so put_device() can be used in all
error paths.

Fixes: d5fe2fec6c40 ("EDAC: Add a driver for the AMD Versal NET DDR controller")
Cc: stable@vger.kernel.org
Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index 03b6e0958f17..3c9eaea5a106 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -785,7 +785,7 @@ static int init_one_mc(struct mc_priv *priv, int i)
 	char name[MC_NAME_LEN];
 	struct device *dev;
 	enum dev_type dt;
-	int rc;
+	int rc = -ENOMEM;
 
 	config = priv->adec[CONF + i * ADEC_NUM];
 	num_chans = FIELD_GET(MC5_NUM_CHANS_MASK, config);
@@ -817,23 +817,23 @@ static int init_one_mc(struct mc_priv *priv, int i)
 	layers[1].size = num_chans;
 	layers[1].is_virt_csrow = false;
 
-	rc = -ENOMEM;
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return rc;
 
-	mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv));
-	if (!mci) {
-		edac_printk(KERN_ERR, EDAC_MC, "Failed memory allocation for MC%d\n", i);
-		goto err_dev_free;
-	}
-
 	sprintf(name, "versal-net-ddrmc5-edac-%d", i);
 
 	dev->init_name = name;
 	dev->release = versal_edac_release;
+	device_initialize(dev);
 
-	rc = device_register(dev);
+	mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv));
+	if (!mci) {
+		edac_printk(KERN_ERR, EDAC_MC, "Failed memory allocation for MC%d\n", i);
+		goto err_put_dev;
+	}
+
+	rc = device_add(dev);
 	if (rc)
 		goto err_mc_free;
 
@@ -843,7 +843,7 @@ static int init_one_mc(struct mc_priv *priv, int i)
 	rc = edac_mc_add_mc(mci);
 	if (rc) {
 		edac_printk(KERN_ERR, EDAC_MC, "Failed to register MC%d with EDAC core\n", i);
-		goto err_unreg;
+		goto err_dev_del;
 	}
 
 	priv->mci[i] = mci;
@@ -851,12 +851,12 @@ static int init_one_mc(struct mc_priv *priv, int i)
 
 	return 0;
 
-err_unreg:
-	device_unregister(mci->pdev);
+err_dev_del:
+	device_del(dev);
 err_mc_free:
 	edac_mc_free(mci);
-err_dev_free:
-	kfree(dev);
+err_put_dev:
+	put_device(dev);
 
 	return rc;
 }
-- 
2.34.1


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

* [PATCH 5/9] EDAC/versalnet: Use dev_set_name() instead of sprintf with init_name
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
                   ` (3 preceding siblings ...)
  2026-07-24 17:19 ` [PATCH 4/9] EDAC/versalnet: Fix device_register() error handling in init_one_mc() Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 6/9] EDAC/versalnet: Initialize MCDI before RPMsg registration Shubhrajyoti Datta
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

The previous code used sprintf() to format a device name into a local
stack buffer and then assigned it to dev->init_name. Since kobject
cleanup can be deferred asynchronously (e.g. when
CONFIG_DEBUG_KOBJECT_RELEASE is enabled), dev_name(dev) could be
accessed after init_one_mc() returns and the stack frame containing the
name buffer is gone, resulting in a use-after-free.

This is fixed by switching to dev_set_name(), which dynamically
allocates and manages the name string internally, but the now-unused
local char name[MC_NAME_LEN] buffer and the MC_NAME_LEN macro are
not needed so remove them.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index 3c9eaea5a106..1caaba653fc0 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -70,8 +70,6 @@
 #define XDDR5_BUS_WIDTH_32		1
 #define XDDR5_BUS_WIDTH_16		2
 
-#define MC_NAME_LEN			32
-
 /**
  * struct ecc_error_info - ECC error log information.
  * @burstpos:		Burst position.
@@ -782,7 +780,6 @@ static int init_one_mc(struct mc_priv *priv, int i)
 	u32 num_chans, rank, dwidth, config;
 	struct edac_mc_layer layers[2];
 	struct mem_ctl_info *mci;
-	char name[MC_NAME_LEN];
 	struct device *dev;
 	enum dev_type dt;
 	int rc = -ENOMEM;
@@ -821,9 +818,7 @@ static int init_one_mc(struct mc_priv *priv, int i)
 	if (!dev)
 		return rc;
 
-	sprintf(name, "versal-net-ddrmc5-edac-%d", i);
 
-	dev->init_name = name;
 	dev->release = versal_edac_release;
 	device_initialize(dev);
 
@@ -833,6 +828,10 @@ static int init_one_mc(struct mc_priv *priv, int i)
 		goto err_put_dev;
 	}
 
+	rc = dev_set_name(dev, "versal-net-ddrmc5-edac-%d", i);
+	if (rc)
+		goto err_mc_free;
+
 	rc = device_add(dev);
 	if (rc)
 		goto err_mc_free;
-- 
2.34.1


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

* [PATCH 6/9] EDAC/versalnet: Initialize MCDI before RPMsg registration
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
                   ` (4 preceding siblings ...)
  2026-07-24 17:19 ` [PATCH 5/9] EDAC/versalnet: Use dev_set_name() instead of sprintf with init_name Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 7/9] EDAC/versalnet: Add bounds validation in rpmsg_cb() Shubhrajyoti Datta
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

setup_mcdi() currently allocates the MCDI instance, assigns the RPMsg
endpoint, and retrieves DDR configuration data. The DDR configuration
path invokes cdx_mcdi_rpc(), which requires a functional RPMsg endpoint.

Split setup_mcdi() so that only MCDI allocation and initialization are
performed before RPMsg registration. Move endpoint assignment and DDR
configuration retrieval until after register_rpmsg_driver() succeeds.
Update the error paths to match the new initialization order, ensuring
resources are released in reverse order of acquisition.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index 1caaba653fc0..e9561242f292 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -559,7 +559,7 @@ static void get_ddr_config(u32 index, u32 *buffer, struct cdx_mcdi *amd_mcdi)
 static int setup_mcdi(struct mc_priv *mc_priv)
 {
 	struct cdx_mcdi *amd_mcdi;
-	int ret, i;
+	int ret;
 
 	amd_mcdi = kzalloc_obj(*amd_mcdi);
 	if (!amd_mcdi)
@@ -572,12 +572,7 @@ static int setup_mcdi(struct mc_priv *mc_priv)
 		return ret;
 	}
 
-	amd_mcdi->ept = mc_priv->ept;
 	mc_priv->mcdi = amd_mcdi;
-
-	for (i = 0; i < NUM_CONTROLLERS; i++)
-		get_ddr_config(i, &mc_priv->adec[ADEC_NUM * i], amd_mcdi);
-
 	return 0;
 }
 
@@ -886,7 +881,7 @@ static int mc_probe(struct platform_device *pdev)
 {
 	struct mc_priv *priv;
 	struct rproc *rp;
-	int rc;
+	int rc, i;
 
 	struct device_node *r5_core_node __free(device_node) =
 		of_parse_phandle(pdev->dev.of_node, "amd,rproc", 0);
@@ -914,18 +909,22 @@ static int mc_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, priv);
 	amd_rpmsg_id_table[0].driver_data = (kernel_ulong_t)priv;
 
+	rc = setup_mcdi(priv);
+	if (rc)
+		goto err_alloc;
+
 	rc = register_rpmsg_driver(&amd_rpmsg_driver);
 	if (rc) {
 		edac_printk(KERN_ERR, EDAC_MC, "Failed to register RPMsg driver: %d\n", rc);
-		goto err_alloc;
-	}
-
-	rc = setup_mcdi(priv);
-	if (rc)
 		goto err_unreg;
+	}
 
+	priv->mcdi->ept = priv->ept;
 	priv->mcdi->r5_rproc = rp;
 
+	for (i = 0; i < NUM_CONTROLLERS; i++)
+		get_ddr_config(i, &priv->adec[ADEC_NUM * i], priv->mcdi);
+
 	rc = init_versalnet(priv);
 	if (rc)
 		goto err_init;
@@ -933,11 +932,11 @@ static int mc_probe(struct platform_device *pdev)
 	return 0;
 
 err_init:
-	cdx_mcdi_finish(priv->mcdi);
-	kfree(priv->mcdi);
+	unregister_rpmsg_driver(&amd_rpmsg_driver);
 
 err_unreg:
-	unregister_rpmsg_driver(&amd_rpmsg_driver);
+	cdx_mcdi_finish(priv->mcdi);
+	kfree(priv->mcdi);
 
 err_alloc:
 	rproc_shutdown(rp);
-- 
2.34.1


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

* [PATCH 7/9] EDAC/versalnet: Add bounds validation in rpmsg_cb()
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
                   ` (5 preceding siblings ...)
  2026-07-24 17:19 ` [PATCH 6/9] EDAC/versalnet: Initialize MCDI before RPMsg registration Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 8/9] EDAC/versalnet: Fix use-after-free in remove_one_mc() Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 9/9] EDAC/versalnet: Use designated initializer for rpmsg_channel_info Shubhrajyoti Datta
  8 siblings, 0 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

The firmware-supplied offset and length values from the RPMsg payload
are used without validation to index into mc_priv->regs[] (REG_MAX=152
entries). A malformed or buggy firmware message could write past the end
of the array, corrupting adjacent structure members and the kernel heap.
Add check for the same.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index e9561242f292..baca90f44c58 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -602,6 +602,9 @@ static int rpmsg_cb(struct rpmsg_device *rpdev, void *data,
 	length = result[MSG_ERR_LENGTH];
 	offset = result[MSG_ERR_OFFSET];
 
+	if (offset + length > REG_MAX)
+		return -EINVAL;
+
 	/*
 	 * The data can come in two stretches. Construct the regs from two
 	 * messages. The offset indicates the offset from which the data is to
-- 
2.34.1


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

* [PATCH 8/9] EDAC/versalnet: Fix use-after-free in remove_one_mc()
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
                   ` (6 preceding siblings ...)
  2026-07-24 17:19 ` [PATCH 7/9] EDAC/versalnet: Add bounds validation in rpmsg_cb() Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  2026-07-24 17:19 ` [PATCH 9/9] EDAC/versalnet: Use designated initializer for rpmsg_channel_info Shubhrajyoti Datta
  8 siblings, 0 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

device_unregister() drops the last reference on the device and invokes
versal_edac_release() which calls kfree(dev). The subsequent call to
edac_mc_del_mc(mci->pdev) then dereferences the freed pointer.

Fix by saving the device pointer, calling edac_mc_del_mc() and
edac_mc_free() first, then device_unregister() last so the device
is freed only after all users are done with it.

Fixes: 62a9fc50e8d9 ("EDAC/versalnet: Refactor memory controller initialization and cleanup")
Cc: stable@vger.kernel.org
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index baca90f44c58..ba295714d972 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -763,14 +763,16 @@ static void versal_edac_release(struct device *dev)
 static void remove_one_mc(struct mc_priv *priv, int i)
 {
 	struct mem_ctl_info *mci;
+	struct device *dev;
 
 	mci = priv->mci[i];
 	if (!mci)
 		return;
 
-	device_unregister(mci->pdev);
-	edac_mc_del_mc(mci->pdev);
+	dev = mci->pdev;
+	edac_mc_del_mc(dev);
 	edac_mc_free(mci);
+	device_unregister(dev);
 }
 
 static int init_one_mc(struct mc_priv *priv, int i)
-- 
2.34.1


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

* [PATCH 9/9] EDAC/versalnet: Use designated initializer for rpmsg_channel_info
  2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
                   ` (7 preceding siblings ...)
  2026-07-24 17:19 ` [PATCH 8/9] EDAC/versalnet: Fix use-after-free in remove_one_mc() Shubhrajyoti Datta
@ 2026-07-24 17:19 ` Shubhrajyoti Datta
  8 siblings, 0 replies; 14+ messages in thread
From: Shubhrajyoti Datta @ 2026-07-24 17:19 UTC (permalink / raw)
  To: linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

Replace field-by-field assignment of struct rpmsg_channel_info with a
designated initializer. This also fixes the incorrect use of strscpy
with strlen which could lead to silent truncation of the channel name.

Fixes: d5fe2fec6c40 ("EDAC: Add a driver for the AMD Versal NET DDR controller")
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

 drivers/edac/versalnet_edac.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
index ba295714d972..88b24eec4206 100644
--- a/drivers/edac/versalnet_edac.c
+++ b/drivers/edac/versalnet_edac.c
@@ -720,14 +720,14 @@ MODULE_DEVICE_TABLE(rpmsg, amd_rpmsg_id_table);
 
 static int rpmsg_probe(struct rpmsg_device *rpdev)
 {
-	struct rpmsg_channel_info chinfo;
 	struct mc_priv *pg;
+	struct rpmsg_channel_info chinfo = {
+		.src = RPMSG_ADDR_ANY,
+		.dst = rpdev->dst,
+		.name = "error_ipc",
+	};
 
 	pg = (struct mc_priv *)amd_rpmsg_id_table[0].driver_data;
-	chinfo.src = RPMSG_ADDR_ANY;
-	chinfo.dst = rpdev->dst;
-	strscpy(chinfo.name, amd_rpmsg_id_table[0].name,
-		strlen(amd_rpmsg_id_table[0].name));
 
 	pg->ept = rpmsg_create_ept(rpdev, rpmsg_cb, NULL, chinfo);
 	if (!pg->ept)
-- 
2.34.1


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

* Re: [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error()
  2026-07-24 17:19 ` [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error() Shubhrajyoti Datta
@ 2026-07-26 23:52   ` Borislav Petkov
  2026-07-27  6:48     ` Pandey, Radhey Shyam
  0 siblings, 1 reply; 14+ messages in thread
From: Borislav Petkov @ 2026-07-26 23:52 UTC (permalink / raw)
  To: Shubhrajyoti Datta
  Cc: linux-edac, git, shubhrajyoti.datta, Michal Simek, Tony Luck,
	linux-kernel

On Fri, Jul 24, 2026 at 10:49:37PM +0530, Shubhrajyoti Datta wrote:
> diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
> index d1af5e175f7e..316f8f79c4d8 100644
> --- a/drivers/edac/versalnet_edac.c
> +++ b/drivers/edac/versalnet_edac.c
> @@ -439,6 +439,8 @@ static void handle_error(struct mc_priv  *priv, struct ecc_status *stat,
>  		return;
>  
>  	mci = priv->mci[ctl_num];
> +	if (!mci)
> +		return;

You have a WARN_ON_ONCE right before that line which checks against
NUM_CONTROLLERS and init_versalnet() unwinds all the setup the moment
init_one_mc() fails for one of the MCs.

So why are we adding dead code?

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

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

* Re: [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error()
  2026-07-26 23:52   ` Borislav Petkov
@ 2026-07-27  6:48     ` Pandey, Radhey Shyam
  0 siblings, 0 replies; 14+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-27  6:48 UTC (permalink / raw)
  To: Borislav Petkov, Shubhrajyoti Datta
  Cc: linux-edac, git, shubhrajyoti.datta, Michal Simek, Tony Luck,
	linux-kernel

On 7/27/2026 5:22 AM, Borislav Petkov wrote:
> On Fri, Jul 24, 2026 at 10:49:37PM +0530, Shubhrajyoti Datta wrote:
>> diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
>> index d1af5e175f7e..316f8f79c4d8 100644
>> --- a/drivers/edac/versalnet_edac.c
>> +++ b/drivers/edac/versalnet_edac.c
>> @@ -439,6 +439,8 @@ static void handle_error(struct mc_priv  *priv, struct ecc_status *stat,
>>   		return;
>>   
>>   	mci = priv->mci[ctl_num];
>> +	if (!mci)
>> +		return;
> 
> You have a WARN_ON_ONCE right before that line which checks against
> NUM_CONTROLLERS and init_versalnet() unwinds all the setup the moment
> init_one_mc() fails for one of the MCs.

The gap in the driver is that init_one_mc() returns success without
setting priv->mci[i] when the bus width decodes to DEV_UNKNOWN, while
buggy firmware / future firmware rpmsg error path can still calls
handle_error().

Happy to drop the check if you prefer otherwise we can keep it as a
cheap guard for a firmware/driver mismatch.

Shubrajyoti: Please feel free to add/correct. I'm still ramping up on
this driver and may have overlooked details.

> 
> So why are we adding dead code?
> 


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

* Re: [PATCH 2/9] EDAC/versalnet: Add NULL check for mci in remove_one_mc()
  2026-07-24 17:19 ` [PATCH 2/9] EDAC/versalnet: Add NULL check for mci in remove_one_mc() Shubhrajyoti Datta
@ 2026-07-27  8:11   ` Pandey, Radhey Shyam
  0 siblings, 0 replies; 14+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-27  8:11 UTC (permalink / raw)
  To: Shubhrajyoti Datta, linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

On 7/24/2026 10:49 PM, Shubhrajyoti Datta wrote:
> If a controller's configuration specifies an unrecognized bus width,
> init_one_mc() returns 0 but skips allocating priv->mci[ctl_num], leaving
> it NULL. On module unload or probe failure, remove_one_mc() is called for
> all controllers and unconditionally dereferences priv->mci[i], causing a
> kernel panic.
> 
> Add a NULL pointer check for mci before dereferencing it.
> 
>   Unable to handle kernel NULL pointer dereference at virtual address 0000000000000390
>   Internal error: Oops: 0000000096000004 [#1] SMP
>   Hardware name: Xilinx Versal NET VNX (DT)
>   pc : mc_remove+0x34/0x88
>   lr : mc_remove+0x4c/0x88
>   Call trace:
>    mc_remove+0x34/0x88
>    platform_remove+0x2c/0x70
>    device_remove+0x48/0x7c
>    device_release_driver_internal+0x1c8/0x224
>    device_driver_detach+0x18/0x28
>    unbind_store+0xb4/0xb8
> 
> Fixes: 62a9fc50e8d9 ("EDAC/versalnet: Refactor memory controller initialization and cleanup")

Confirm on fixes tag. The bug likely goes back to the original driver.
> Cc: stable@vger.kernel.org

There is no CC to stable kernel in email.

Below changes looks fine to me. With above tag fixed.

Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!

> Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
> ---
> 
>   drivers/edac/versalnet_edac.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
> index 316f8f79c4d8..05dc34504cc2 100644
> --- a/drivers/edac/versalnet_edac.c
> +++ b/drivers/edac/versalnet_edac.c
> @@ -769,6 +769,9 @@ static void remove_one_mc(struct mc_priv *priv, int i)
>   	struct mem_ctl_info *mci;
>   
>   	mci = priv->mci[i];
> +	if (!mci)
> +		return;
> +
>   	device_unregister(mci->pdev);
>   	edac_mc_del_mc(mci->pdev);
>   	edac_mc_free(mci);


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

* Re: [PATCH 3/9] EDAC/versalnet: Move platform_set_drvdata() to mc_probe()
  2026-07-24 17:19 ` [PATCH 3/9] EDAC/versalnet: Move platform_set_drvdata() to mc_probe() Shubhrajyoti Datta
@ 2026-07-27  8:35   ` Pandey, Radhey Shyam
  0 siblings, 0 replies; 14+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-27  8:35 UTC (permalink / raw)
  To: Shubhrajyoti Datta, linux-edac
  Cc: git, shubhrajyoti.datta, Michal Simek, Borislav Petkov, Tony Luck,
	linux-kernel

On 7/24/2026 10:49 PM, Shubhrajyoti Datta wrote:
> Move platform_set_drvdata() out of init_one_mc() and into mc_probe()
> so that the driver data is set once during probe rather than being
> redundantly set on each memory controller initialization.
> 
> The pdev parameter in init_one_mc() and init_versalnet() is no longer
> referenced. Remove it from both function signatures.
> 
> Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>

Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!
> ---
> 
>   drivers/edac/versalnet_edac.c | 11 +++++------
>   1 file changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c
> index 05dc34504cc2..03b6e0958f17 100644
> --- a/drivers/edac/versalnet_edac.c
> +++ b/drivers/edac/versalnet_edac.c
> @@ -777,7 +777,7 @@ static void remove_one_mc(struct mc_priv *priv, int i)
>   	edac_mc_free(mci);
>   }
>   
> -static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i)
> +static int init_one_mc(struct mc_priv *priv, int i)
>   {
>   	u32 num_chans, rank, dwidth, config;
>   	struct edac_mc_layer layers[2];
> @@ -849,8 +849,6 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
>   	priv->mci[i] = mci;
>   	priv->dwidth = dt;
>   
> -	platform_set_drvdata(pdev, priv);
> -
>   	return 0;
>   
>   err_unreg:
> @@ -863,12 +861,12 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
>   	return rc;
>   }
>   
> -static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev)
> +static int init_versalnet(struct mc_priv *priv)
>   {
>   	int rc, i;
>   
>   	for (i = 0; i < NUM_CONTROLLERS; i++) {
> -		rc = init_one_mc(priv, pdev, i);
> +		rc = init_one_mc(priv, i);
>   		if (rc) {
>   			while (i--)
>   				remove_one_mc(priv, i);
> @@ -914,6 +912,7 @@ static int mc_probe(struct platform_device *pdev)
>   		goto err_alloc;
>   	}
>   
> +	platform_set_drvdata(pdev, priv);
>   	amd_rpmsg_id_table[0].driver_data = (kernel_ulong_t)priv;
>   
>   	rc = register_rpmsg_driver(&amd_rpmsg_driver);
> @@ -928,7 +927,7 @@ static int mc_probe(struct platform_device *pdev)
>   
>   	priv->mcdi->r5_rproc = rp;
>   
> -	rc = init_versalnet(priv, pdev);
> +	rc = init_versalnet(priv);
>   	if (rc)
>   		goto err_init;
>   


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

end of thread, other threads:[~2026-07-27  8:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 17:19 [PATCH 0/9] EDAC/versalnet: Fix error handling, teardown, and robustness Shubhrajyoti Datta
2026-07-24 17:19 ` [PATCH 1/9] EDAC/versalnet: Add NULL check for mci in handle_error() Shubhrajyoti Datta
2026-07-26 23:52   ` Borislav Petkov
2026-07-27  6:48     ` Pandey, Radhey Shyam
2026-07-24 17:19 ` [PATCH 2/9] EDAC/versalnet: Add NULL check for mci in remove_one_mc() Shubhrajyoti Datta
2026-07-27  8:11   ` Pandey, Radhey Shyam
2026-07-24 17:19 ` [PATCH 3/9] EDAC/versalnet: Move platform_set_drvdata() to mc_probe() Shubhrajyoti Datta
2026-07-27  8:35   ` Pandey, Radhey Shyam
2026-07-24 17:19 ` [PATCH 4/9] EDAC/versalnet: Fix device_register() error handling in init_one_mc() Shubhrajyoti Datta
2026-07-24 17:19 ` [PATCH 5/9] EDAC/versalnet: Use dev_set_name() instead of sprintf with init_name Shubhrajyoti Datta
2026-07-24 17:19 ` [PATCH 6/9] EDAC/versalnet: Initialize MCDI before RPMsg registration Shubhrajyoti Datta
2026-07-24 17:19 ` [PATCH 7/9] EDAC/versalnet: Add bounds validation in rpmsg_cb() Shubhrajyoti Datta
2026-07-24 17:19 ` [PATCH 8/9] EDAC/versalnet: Fix use-after-free in remove_one_mc() Shubhrajyoti Datta
2026-07-24 17:19 ` [PATCH 9/9] EDAC/versalnet: Use designated initializer for rpmsg_channel_info Shubhrajyoti Datta

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.