Re: [PATCH v7 6/7] cxl/region: Reject poison scan for decoder without a partition

From: Alison Schofield

Date: Fri Sep 04 2026 - 02:10:53 EST


On Wed, Sep 02, 2026 at 01:38:38PM +0800, Richard Cheng wrote:
> __cxl_dpa_reserve() may leave cxled->part at -1 when a decoder's DPA
> range doesn't map to any reported partition, while still keeping
> dpa_res. poison_by_decoder() then indexes cxlds->part[-1], causing an
> out-of-bounds read when poison collection is triggered.
>
> Return -ENODEV before accessing the partition array when no partition was
> assigned.
>
> Fixes: be5cbd084027 ("cxl: Kill enum cxl_decoder_mode")
> Signed-off-by: Richard Cheng <icheng@xxxxxxxxxx>
> ---
> drivers/cxl/core/region.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index b7dc5d4988da..afe3fb57b7fe 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -2954,6 +2954,8 @@ static int poison_by_decoder(struct device *dev, void *arg)
> cxled = to_cxl_endpoint_decoder(dev);
> if (!cxled->dpa_res)
> return rc;
> + if (cxled->part < 0)
> + return -ENODEV;

-ENODEV disables poison listing for the whole memdev since this is a
device_for_each_child() callback.

Before be5cbd084027 that decoder was scanned like any other and the mode was
only ever compared, never used as an index, so CXL_DECODER_NONE and
CXL_DECODER_DEAD both still got their DPA read and the walk continued.

Can the fix be less instrusive and not fail the scan?

Here's a diff, totally untested:
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index afe3fb57b7fe..ebf06edf23be 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2942,9 +2942,9 @@ static int poison_by_decoder(struct device *dev, void *arg)
{
struct cxl_poison_context *ctx = arg;
struct cxl_endpoint_decoder *cxled;
- enum cxl_partition_mode mode;
struct cxl_dev_state *cxlds;
struct cxl_memdev *cxlmd;
+ bool tolerate_efault;
u64 offset, length;
int rc = 0;

@@ -2954,18 +2954,18 @@ static int poison_by_decoder(struct device *dev, void *arg)
cxled = to_cxl_endpoint_decoder(dev);
if (!cxled->dpa_res)
return rc;
- if (cxled->part < 0)
- return -ENODEV;

cxlmd = cxled_to_memdev(cxled);
cxlds = cxlmd->cxlds;
- mode = cxlds->part[cxled->part].mode;
+ /* Without a partition the mode is unknown, do not tolerate -EFAULT */
+ tolerate_efault = cxled->part >= 0 &&
+ cxlds->part[cxled->part].mode == CXL_PARTMODE_RAM;

if (cxled->skip) {
offset = cxled->dpa_res->start - cxled->skip;
length = cxled->skip;
rc = cxl_mem_get_poison(cxlmd, offset, length, NULL);
- if (rc == -EFAULT && mode == CXL_PARTMODE_RAM)
+ if (rc == -EFAULT && tolerate_efault)
rc = 0;
if (rc)
return rc;
@@ -2974,7 +2974,7 @@ static int poison_by_decoder(struct device *dev, void *arg)
offset = cxled->dpa_res->start;
length = cxled->dpa_res->end - offset + 1;
rc = cxl_mem_get_poison(cxlmd, offset, length, cxled->cxld.region);
- if (rc == -EFAULT && mode == CXL_PARTMODE_RAM)
+ if (rc == -EFAULT && tolerate_efault)
rc = 0;
if (rc)
return rc;
(END)


>
> cxlmd = cxled_to_memdev(cxled);
> cxlds = cxlmd->cxlds;
> --
> 2.53.0
>