Thread (9 messages) flat view 9 messages, 4 authors, 3d ago

Re: [PATCH net v3 3/3] pds_core: check info_regs in the identity debugfs reader

From: netdev-bot+sashiko@kernel.org
Date: 2026-09-05 01:06:52

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:

Critical: 0 · High: 0 (1) · Medium: 1 · Low: 0

- [Medium] The newly added guard in `identity_show()` is an
  unsynchronized check-then-use of an `__iomem` pointer that a…

Pre-existing issues:
- [High] NULL-pointer dereference in the sibling debugfs reader
  `viftype_show()` (drivers/net/ethernet/amd/pds_core/debugfs.c:81-96).

--

pds_core: check info_regs in the identity debugfs reader

This adds a NULL test around the fw_heartbeat read in identity_show() so
the identity debugfs file does not dereference pdsc->info_regs after
pdsc_unmap_bars() has cleared it. The identity file is deliberately kept
across a reset, so the reader can run while the BARs are unmapped.

Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260804235946.177762-1-nikhil.rao%40amd.com
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/ethernet/amd/pds_core/debugfs.c b/drivers/net/ethernet/amd/pds_core/debugfs.c
index ef0a1b7d159b5..c458e6758959a 100644
--- a/drivers/net/ethernet/amd/pds_core/debugfs.c
+++ b/drivers/net/ethernet/amd/pds_core/debugfs.c
@@ -38,8 +38,9 @@ static int identity_show(struct seq_file *seq, void *v)
 
 	ident = &pdsc->dev_ident;
 
-	seq_printf(seq, "fw_heartbeat:     0x%x\n",
-		   ioread32(&pdsc->info_regs->fw_heartbeat));
+	if (pdsc->info_regs)
+		seq_printf(seq, "fw_heartbeat:     0x%x\n",
+			   ioread32(&pdsc->info_regs->fw_heartbeat));
[Severity: Medium]
Is the guard enough when the unmap happens concurrently with the read?
The test and the use are two separate plain loads of pdsc->info_regs,
and identity_show() holds none of the driver's locks:

	if (pdsc->info_regs)
		seq_printf(seq, "fw_heartbeat:     0x%x\n",
			   ioread32(&pdsc->info_regs->fw_heartbeat));

Meanwhile pdsc_unmap_bars() in main.c clears the pointer and then drops
the mapping:

	pdsc->info_regs = NULL;
	pdsc->cmd_regs = NULL;
	...
		if (bars[i].vaddr)
			pci_iounmap(pdsc->pdev, bars[i].vaddr);

So can the second load still observe NULL and make ioread32() fault at
offsetof(struct pds_core_dev_info_regs, fw_heartbeat)?  And even if the
compiler keeps the first value, can pci_iounmap() have already torn the
mapping down, leaving the ioread32() touching an unmapped ioremap range?

The other info_regs readers appear to be serialized against the unmap:
pdsc_check_pci_health() and pdsc_is_fw_running() run from the health work
under config_lock, which pdsc_reset_prepare() stops first, and the adminq
readers are gated by PDSC_S_FW_DEAD plus the adminq_refcnt drain in
pdsc_fw_down().  pdsc_reset_prepare() serializes the unmap only with
devcmd_lock:

	mutex_lock(&pdsc->devcmd_lock);
	pdsc_unmap_bars(pdsc);
	mutex_unlock(&pdsc->devcmd_lock);
	pci_release_regions(pdev);

which identity_show() never takes.  In pdsc_remove() the ordering looks
worse, since the lock is gone before the unmap and the debugfs consumer of
the mapping is only removed afterwards:

	mutex_destroy(&pdsc->devcmd_lock);
	...
	pdsc_unmap_bars(pdsc);
	pci_release_regions(pdev);
	...
	pdsc_debugfs_del_dev(pdsc);

Would snapshotting the pointer into a local plus serializing against
map/unmap (or removing the debugfs entries before unmapping the BARs) close
this properly?

[Severity: High]
This isn't a bug introduced by this patch, but the sibling reader in the
same file, viftype_show(), has the same shape of problem and no NULL test
at all:

	for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) {
		if (!pdsc->viftype_status[vt].name)
			continue;

pdsc_teardown() with PDSC_TEARDOWN_REMOVING frees and clears the base
pointer:

	if (removing) {
		kfree(pdsc->viftype_status);
		pdsc->viftype_status = NULL;
	}

In pdsc_remove() that teardown runs well before pdsc_debugfs_del_dev(),
with destroy_workqueue(), two mutex_destroy() calls, pdsc_unmap_bars(),
pci_release_regions(), pci_disable_device(), pdsc_deferred_dma_free() and
ida_free() in between, so can a read of the still-registered viftypes file
dereference a NULL pdsc->viftype_status?  The same window looks present on
the pdsc_init_pf() error path, where err_out_teardown runs long before
pdsc_debugfs_del_dev().

The other readers of that member treat NULL as reachable, for example
pdsc_dl_find_viftype_by_id() in devlink.c:

	if (!pdsc->viftype_status)
		return NULL;

and host_mem_show() in this same file NULL-checks pdsc->host_mem_reqs.
Should viftype_show() get the same treatment while this area is being
touched?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260901044219.1361466-1-nikhil.rao%40amd.com
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help