Re: [PATCH v12 6/8] cxl/mem: Configure dynamic capacity interrupts

Anisa Su <[email protected]> Sat, 1 Aug 2026 02:30:24 -0700
Newsgroups dev.linux.lists.nvdimm,dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-cxl
Message-ID <[email protected]>
On Fri, Jul 31, 2026 at 09:04:43AM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> 
> New issues:
> - [High] Infinite IRQ Thread Loop / CPU Spin when handling DCD events
> 
False Positive. DCD events are ignored because DCD is turned off
(mds->dcd_supported = false).

> Pre-existing issues:
> - [High] Out-of-Bounds Read and Information Leak in Event logs
> - [High] Out-of-Bounds Read and Information Leak in Poison logs
> --
> 
> --- Patch [6]: [PATCH v12 6/8] cxl/mem: Configure dynamic capacity interrupts ---
> commit 5b173c122c3602992c4ceeafd1c2d87a80accacb
> Author: Ira Weiny <[email protected]>
> 
> cxl/mem: Configure dynamic capacity interrupts
> 
> Dynamic Capacity Devices (DCD) support extent change notifications
> through the event log mechanism. Configure DCD event log interrupts
> on devices supporting dynamic capacity. Disable DCD if interrupts
> are not supported.
> 
> > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > index df13fb8802c38..6cb344ec4f3a7 100644
> > --- a/drivers/cxl/pci.c
> > +++ b/drivers/cxl/pci.c
> > @@ -509,11 +509,30 @@ static bool cxl_alloc_irq_vectors(struct pci_dev *pdev)
> >  	return true;
> >  }
> >  
> > +/*
> > + * Event logs the driver drains: standard logs when native_cxl, DCD when
> > + * supported.
> > + */
> > +static u32 cxl_event_drain_mask(struct pci_host_bridge *host_bridge,
> > +				struct cxl_memdev_state *mds)
> > +{
> > +	u32 mask = 0;
> > +
> > +	if (host_bridge->native_cxl_error)
> > +		mask |= CXLDEV_EVENT_STATUS_ALL & ~CXLDEV_EVENT_STATUS_DCD;
> > +	if (cxl_dcd_supported(mds))
> > +		mask |= CXLDEV_EVENT_STATUS_DCD;
> > +	return mask;
> > +}
> > +
> >  static irqreturn_t cxl_event_thread(int irq, void *id)
> >  {
> >  	struct cxl_dev_id *dev_id = id;
> >  	struct cxl_dev_state *cxlds = dev_id->cxlds;
> >  	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> > +	struct pci_host_bridge *host_bridge =
> > +		pci_find_host_bridge(to_pci_dev(cxlds->dev)->bus);
> > +	u32 mask = cxl_event_drain_mask(host_bridge, mds);
> >  	u32 status;
> >  
> >  	do {
> > @@ -522,8 +541,8 @@ static irqreturn_t cxl_event_thread(int irq, void *id)
> >  		 * ignore the reserved upper 32 bits
> >  		 */
> >  		status = readl(cxlds->regs.status + CXLDEV_DEV_EVENT_STATUS_OFFSET);
> > -		/* Ignore logs unknown to the driver */
> > -		status &= CXLDEV_EVENT_STATUS_ALL;
> > +		/* Ignore logs unknown to the driver or owned by BIOS */
> > +		status &= mask;
> >  		if (!status)
> >  			break;
> >  		cxl_mem_get_event_records(mds, status);
> 
> [Severity: High]
> Since mask now includes CXLDEV_EVENT_STATUS_DCD, status can have this bit set.
> However, cxl_mem_get_event_records() does not appear to handle the DCD event:
> 
The mask never includes CXLDEV_EVENT_STATUS_DCD.
Above in cxl_event_drain_mask:

if (cxl_dcd_supported(mds))
              mask |= CXLDEV_EVENT_STATUS_DCD;

mds->dcd_supported is set to false in Patch 1 so the DCD bit is never
set.

So status &= mask becomes zero and we break from the loop.

- Anisa
> drivers/cxl/core/mbox.c:cxl_mem_get_event_records() {
>     ...
>     if (status & CXLDEV_EVENT_STATUS_FATAL)
>         cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_FATAL);
>     if (status & CXLDEV_EVENT_STATUS_FAIL)
>         cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_FAIL);
>     if (status & CXLDEV_EVENT_STATUS_WARN)
>         cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_WARN);
>     if (status & CXLDEV_EVENT_STATUS_INFO)
>         cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_INFO);
>     ...
> }
> 
> Will this fail to clear the DCD event from the device? If the event is never
> cleared, will the hardware register retain the bit and cause the while (status)
> loop to spin infinitely on the exact same status bit, potentially causing a CPU
> soft lockup?
> 
> >  		cond_resched();
> >  	} while (status);
> 
> [ ... ]
> 
> [Severity: High]
> This is a pre-existing issue, but I noticed a potential out-of-bounds read when
> fetching event logs:
> 
> drivers/cxl/core/mbox.c:cxl_mem_get_records_log() {
>     ...
>     nr_rec = le16_to_cpu(payload->record_count);
>     if (!nr_rec)
>         break;
> 
>     for (i = 0; i < nr_rec; i++)
>         __cxl_event_trace_record(cxlmd, type,
>                                  &payload->records[i]);
>     ...
> }
> 
> Does this code validate the hardware-provided nr_rec against the allocated
> payload size? If an untrusted or compromised device returns an artificially
> large count, could this read out of bounds?
> 
> Similarly, when clearing those records:
> 
> drivers/cxl/core/mbox.c:cxl_clear_event_record() {
>     ...
>     for (cnt = 0; cnt < total; cnt++) {
>         struct cxl_event_record_raw *raw = &get_pl->records[cnt];
>         struct cxl_event_generic *gen = &raw->event.generic;
> 
>         payload->handles[i++] = gen->hdr.handle;
>     ...
> }
> 
> Could this write the out-of-bounds memory values into the clear event payload
> sent back to the device, leading to an information leak?
> 
> [Severity: High]
> This is also a pre-existing issue, but a similar pattern exists in the poison
> log handling:
> 
> drivers/cxl/core/mbox.c:cxl_mem_get_poison() {
>     ...
>     for (int i = 0; i < le16_to_cpu(po->count); i++)
>         trace_cxl_poison(cxlmd, cxlr, &po->record[i],
>                          po->flags, po->overflow_ts,
>                          CXL_POISON_TRACE_LIST);
>     ...
> }
> 
> Does this validate po->count against the buffer size, or could it result
> in an out-of-bounds read if the device returns a large count?
> 
> -- 
> Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=6