Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cxl/region: Avoid null pointer dereference in region lookup

cxl_dpa_to_region() looks up a region based on a memdev and DPA.
It wrongly assumes an endpoint found mapping the DPA is also of
a fully assembled region. When not true it leads to a null pointer
dereference looking up the region name.

This appears during testing of region lookup after a failure to
assemble a BIOS defined region or if the lookup raced with the
assembly of the BIOS defined region.

Failure to clean up BIOS defined regions that fail assembly is an
issue in itself and a fix to that problem will alleviate some of
the impact. It will not alleviate the race condition so let's harden
this path.

The behavior change is that the kernel oops due to a null pointer
dereference is replaced with a dev_dbg() message noting that an
endpoint was mapped.

Additional comments are added so that future users of this function
can more clearly understand what it provides.

Fixes: 0a105ab28a4d ("cxl/memdev: Warn of poison inject or clear to a mapped region")
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://patch.msgid.link/20240604003609.202682-1-alison.schofield@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

authored by

Alison Schofield and committed by
Dave Jiang
285f2a08 84ec9859

+15 -4
+15 -4
drivers/cxl/core/region.c
··· 2688 2688 { 2689 2689 struct cxl_dpa_to_region_context *ctx = arg; 2690 2690 struct cxl_endpoint_decoder *cxled; 2691 + struct cxl_region *cxlr; 2691 2692 u64 dpa = ctx->dpa; 2692 2693 2693 2694 if (!is_endpoint_decoder(dev)) 2694 2695 return 0; 2695 2696 2696 2697 cxled = to_cxl_endpoint_decoder(dev); 2697 - if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) 2698 + if (!cxled || !cxled->dpa_res || !resource_size(cxled->dpa_res)) 2698 2699 return 0; 2699 2700 2700 2701 if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) 2701 2702 return 0; 2702 2703 2703 - dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, 2704 - dev_name(&cxled->cxld.region->dev)); 2704 + /* 2705 + * Stop the region search (return 1) when an endpoint mapping is 2706 + * found. The region may not be fully constructed so offering 2707 + * the cxlr in the context structure is not guaranteed. 2708 + */ 2709 + cxlr = cxled->cxld.region; 2710 + if (cxlr) 2711 + dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, 2712 + dev_name(&cxlr->dev)); 2713 + else 2714 + dev_dbg(dev, "dpa:0x%llx mapped in endpoint:%s\n", dpa, 2715 + dev_name(dev)); 2705 2716 2706 - ctx->cxlr = cxled->cxld.region; 2717 + ctx->cxlr = cxlr; 2707 2718 2708 2719 return 1; 2709 2720 }