CVE-2026-46221
Description
In the Linux kernel, the following vulnerability has been resolved:
EDAC/versalnet: Fix device name memory leak
The device name allocated via kzalloc() in init_one_mc() is assigned to dev->init_name but never freed on the normal removal path. device_register() copies init_name and then sets dev->init_name to NULL, so the name pointer becomes unreachable from the device. Thus leaking memory.
Use a stack-local char array instead of using kzalloc() for name.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A memory leak in the Linux kernel's EDAC/versalnet driver occurs when device name allocation is never freed, fixed by using a stack-local char array.
Vulnerability
In the Linux kernel's EDAC/versalnet driver, the function init_one_mc() allocates a device name via kzalloc() and assigns it to dev->init_name. However, on the normal removal path, this allocation is never freed. When device_register() is called, it copies the init_name and then sets dev->init_name to NULL, making the originally allocated pointer unreachable and causing a memory leak. This bug affects versions of the Linux kernel that include this driver code [1].
Exploitation
An attacker must have the ability to trigger the removal or unbinding of the EDAC/versalnet device, such as through hot-unplug or module unloading. No authentication is required, but local access or the ability to load/unload kernel modules is typically necessary. The exact sequence involves initializing a device via init_one_mc(), then removing it, causing the memory leak each time [1].
Impact
The vulnerability results in a kernel memory leak. Over repeated device initialization and removal, this can lead to memory exhaustion, potentially causing system instability or denial of service. No other impact on confidentiality, integrity, or privilege escalation is described [1].
Mitigation
The fix is included in commit 8cf5dd235eff6008cb04c3d8064d2acfa90616f1 in the stable Linux kernel tree, which replaces the kzalloc() allocation with a stack-local char array. Users should update to a kernel version containing this patch. No workaround is available other than applying the patch [1].
AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
624d2912962d0EDAC/versalnet: Fix device name memory leak
1 file changed · +1 −3
drivers/edac/versalnet_edac.c+1 −3 modifieddiff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index f90723bc93d5c5..4053ee2e0beef4 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -765,9 +765,9 @@ static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) u32 num_chans, rank, dwidth, config; struct edac_mc_layer layers[2]; struct mem_ctl_info *mci; + char name[32]; struct device *dev; enum dev_type dt; - char *name; int rc, i; for (i = 0; i < NUM_CONTROLLERS; i++) { @@ -814,7 +814,6 @@ static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev->release = versal_edac_release; - name = kmalloc(32, GFP_KERNEL); sprintf(name, "versal-net-ddrmc5-edac-%d", i); dev->init_name = name; rc = device_register(dev); -- cgit 1.3-korg
b16033c8774fEDAC/versalnet: Fix device name memory leak
1 file changed · +2 −9
drivers/edac/versalnet_edac.c+2 −9 modifieddiff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index ec13155824141d..97ec05d68bbbce 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -777,9 +777,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, 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; - char *name; int rc; config = priv->adec[CONF + i * ADEC_NUM]; @@ -813,13 +813,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i layers[1].is_virt_csrow = false; rc = -ENOMEM; - name = kzalloc(MC_NAME_LEN, GFP_KERNEL); - if (!name) - return rc; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) - goto err_name_free; + return rc; mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv)); if (!mci) { @@ -858,8 +854,6 @@ err_mc_free: edac_mc_free(mci); err_dev_free: kfree(dev); -err_name_free: - kfree(name); return rc; } -- cgit 1.3-korg
8cf5dd235effEDAC/versalnet: Fix device name memory leak
1 file changed · +2 −9
drivers/edac/versalnet_edac.c+2 −9 modifieddiff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index ec13155824141d..97ec05d68bbbce 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -777,9 +777,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, 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; - char *name; int rc; config = priv->adec[CONF + i * ADEC_NUM]; @@ -813,13 +813,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i layers[1].is_virt_csrow = false; rc = -ENOMEM; - name = kzalloc(MC_NAME_LEN, GFP_KERNEL); - if (!name) - return rc; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) - goto err_name_free; + return rc; mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv)); if (!mci) { @@ -858,8 +854,6 @@ err_mc_free: edac_mc_free(mci); err_dev_free: kfree(dev); -err_name_free: - kfree(name); return rc; } -- cgit 1.3-korg
24d2912962d0EDAC/versalnet: Fix device name memory leak
1 file changed · +1 −3
drivers/edac/versalnet_edac.c+1 −3 modifieddiff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index f90723bc93d5c5..4053ee2e0beef4 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -765,9 +765,9 @@ static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) u32 num_chans, rank, dwidth, config; struct edac_mc_layer layers[2]; struct mem_ctl_info *mci; + char name[32]; struct device *dev; enum dev_type dt; - char *name; int rc, i; for (i = 0; i < NUM_CONTROLLERS; i++) { @@ -814,7 +814,6 @@ static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev->release = versal_edac_release; - name = kmalloc(32, GFP_KERNEL); sprintf(name, "versal-net-ddrmc5-edac-%d", i); dev->init_name = name; rc = device_register(dev); -- cgit 1.3-korg
b16033c8774fEDAC/versalnet: Fix device name memory leak
1 file changed · +2 −9
drivers/edac/versalnet_edac.c+2 −9 modifieddiff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index ec13155824141d..97ec05d68bbbce 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -777,9 +777,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, 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; - char *name; int rc; config = priv->adec[CONF + i * ADEC_NUM]; @@ -813,13 +813,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i layers[1].is_virt_csrow = false; rc = -ENOMEM; - name = kzalloc(MC_NAME_LEN, GFP_KERNEL); - if (!name) - return rc; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) - goto err_name_free; + return rc; mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv)); if (!mci) { @@ -858,8 +854,6 @@ err_mc_free: edac_mc_free(mci); err_dev_free: kfree(dev); -err_name_free: - kfree(name); return rc; } -- cgit 1.3-korg
8cf5dd235effEDAC/versalnet: Fix device name memory leak
1 file changed · +2 −9
drivers/edac/versalnet_edac.c+2 −9 modifieddiff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index ec13155824141d..97ec05d68bbbce 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -777,9 +777,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, 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; - char *name; int rc; config = priv->adec[CONF + i * ADEC_NUM]; @@ -813,13 +813,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i layers[1].is_virt_csrow = false; rc = -ENOMEM; - name = kzalloc(MC_NAME_LEN, GFP_KERNEL); - if (!name) - return rc; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) - goto err_name_free; + return rc; mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv)); if (!mci) { @@ -858,8 +854,6 @@ err_mc_free: edac_mc_free(mci); err_dev_free: kfree(dev); -err_name_free: - kfree(name); return rc; } -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Heap-allocated device name string assigned to dev->init_name is never freed after device_register() consumes it, causing a memory leak."
Attack vector
An attacker does not directly trigger this bug; it is a memory leak that occurs during normal driver probe and removal. When the EDAC driver for the AMD Versal NET DDR controller initializes, `init_one_mc()` allocates a device name string via `kzalloc()` and assigns it to `dev->init_name`. After `device_register()` copies the name and sets `dev->init_name` to NULL, the original heap buffer becomes unreachable and is never freed on the removal path, causing a gradual memory leak over repeated probe/remove cycles.
Affected code
The vulnerability is in `drivers/edac/versalnet_edac.c` in the `init_one_mc()` function (or the equivalent loop in `init_versalnet()` in the backported stable patches). The heap-allocated device name buffer was never freed after `device_register()` consumed it.
What the fix does
The patch replaces the heap-allocated `char *name` (via `kzalloc()`) with a stack-local `char name[MC_NAME_LEN]` (or `char name[32]` in the backported version). This eliminates the need for dynamic allocation and the corresponding `kfree()` on error/removal paths. The `err_name_free` label and its `kfree(name)` are removed, and the early-return on `dev` allocation failure no longer needs to jump to that label. Because the name now lives on the stack, it is automatically reclaimed when the function returns, closing the leak.
Preconditions
- configThe kernel must be built with CONFIG_EDAC_VERSALNET enabled and the AMD Versal NET DDR controller must be present.
- authNo special privileges are needed; the leak occurs during normal driver probe/remove cycles.
Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.