Commit c65efe36 authored by Ira Weiny's avatar Ira Weiny Committed by Dan Williams
Browse files

cxl/cdat: Free correct buffer on checksum error



The new 6.7-rc1 kernel now checks the checksum on CDAT data.  While
using a branch of Fan's DCD qemu work (and specifying DCD devices), the
following splat was observed.

	WARNING: CPU: 1 PID: 1384 at drivers/base/devres.c:1064 devm_kfree+0x4f/0x60
	...
	RIP: 0010:devm_kfree+0x4f/0x60
	...
 	? devm_kfree+0x4f/0x60
 	read_cdat_data+0x1a0/0x2a0 [cxl_core]
 	cxl_port_probe+0xdf/0x200 [cxl_port]
	...

The issue in qemu is still unknown but the spat is a straight forward
bug in the CDAT checksum processing code.  Use a CDAT buffer variable to
ensure the devm_free() works correctly on error.

Fixes: 670e4e88 ("cxl: Add checksum verification to CDAT from CXL")
Signed-off-by: default avatarIra Weiny <ira.weiny@intel.com>
Reviewed-by: default avatarDave Jiang <dave.jiang@intel.com>
Reviewed-by: default avatarFan Ni <fan.ni@samsung.com>
Reviewed-by: default avatarRobert Richter <rrichter@amd.com>
Link: http://lore.kernel.org/r/20231116-fix-cdat-devm-free-v1-1-b148b40707d7@intel.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 6f5c4eca
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -620,7 +620,7 @@ void read_cdat_data(struct cxl_port *port)
	struct pci_dev *pdev = NULL;
	struct cxl_memdev *cxlmd;
	size_t cdat_length;
	void *cdat_table;
	void *cdat_table, *cdat_buf;
	int rc;

	if (is_cxl_memdev(uport)) {
@@ -651,16 +651,15 @@ void read_cdat_data(struct cxl_port *port)
		return;
	}

	cdat_table = devm_kzalloc(dev, cdat_length + sizeof(__le32),
				  GFP_KERNEL);
	if (!cdat_table)
	cdat_buf = devm_kzalloc(dev, cdat_length + sizeof(__le32), GFP_KERNEL);
	if (!cdat_buf)
		return;

	rc = cxl_cdat_read_table(dev, cdat_doe, cdat_table, &cdat_length);
	rc = cxl_cdat_read_table(dev, cdat_doe, cdat_buf, &cdat_length);
	if (rc)
		goto err;

	cdat_table = cdat_table + sizeof(__le32);
	cdat_table = cdat_buf + sizeof(__le32);
	if (cdat_checksum(cdat_table, cdat_length))
		goto err;

@@ -670,7 +669,7 @@ void read_cdat_data(struct cxl_port *port)

err:
	/* Don't leave table data allocated on error */
	devm_kfree(dev, cdat_table);
	devm_kfree(dev, cdat_buf);
	dev_err(dev, "Failed to read/validate CDAT.\n");
}
EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);