Re: [PATCH 1/1] hw/cxl: fix OOB access in cxl_doe_cdat_rsp via entry_handle

Jonathan Cameron <[email protected]>
Newsgroups org.kernel.vger.linux-cxl,org.nongnu.qemu-devel
Message-ID <20260721015805.616e869a@jic23-huawei>
On Mon, 13 Jul 2026 15:23:36 +0800
[email protected] wrote:

> From: Haotian Jiang <[email protected]>
> 
> cxl_doe_cdat_rsp() takes ent = req->entry_handle (uint16_t, fully
> guest-controlled, 0..0xFFFF) and directly indexes cdat->entry[ent]
> without checking ent < cdat->entry_len. For a default cxl-type3 with
> one volatile memory region, entry_len = 1 + CT3_CDAT_NUM_ENTRIES = 7,
> so any entry_handle >= 7 reads past the CDATEntry array into host heap.
> 
> The OOB-read base/length are then used in
> memcpy(read_mbox + offset, base, len) at cxl_type3.c:298-299, leaking
> host heap memory to the guest via PCI_EXP_DOE_RD_DATA_MBOX, and
> potentially overflowing the 1 MiB read_mbox heap buffer when the OOB
> length field is large.
> 
> The same bug exists in the cxl-upstream implementation.
> 
> Existing checks do not bound ent: assert(cdat->entry_len) only ensures
> the table is loaded; the minimum-length check only guards against a
> truncated CDATReq; the entry_handle ternary at line 293 only decides
> the next-handle echo, not the current access; pcie_doe_get_obj_len
> reads header.length, not entry_handle.
> 
> Reproduce: build QEMU with CONFIG_CXL, boot
>   -M q35,cxl=on -device pxb-cxl,bus_nr=52 ... -device cxl-type3,...
> then send a CDATReq with entry_handle=0xFFFF via the DOE mailbox at
> config offset 0x190. Under ASAN this reports SEGV in cxl_doe_cdat_rsp
> at cxl_type3.c:281.
> 
> Fixes: f5ee7413d5 ("hw/mem/cxl-type3: Add CXL CDAT Data Object Exchange")
> Fixes: 882877fc35 ("hw/pci-bridge/cxl-upstream: Add a CDAT table access DOE")
> Signed-off-by: Haotian Jiang <[email protected]>
> Cc: [email protected]

Reviewed-by: Jonathan Cameron <[email protected]>

Will be a little while before I can spin up a staging tree, so Michael,
if you want to pick this up directly that would be great.

Thanks,

Jonathan

> ---
>  hw/mem/cxl_type3.c           | 3 +++
>  hw/pci-bridge/cxl_upstream.c | 3 +++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
> index cba05ec57d..28f41fa623 100644
> --- a/hw/mem/cxl_type3.c
> +++ b/hw/mem/cxl_type3.c
> @@ -278,6 +278,9 @@ static bool cxl_doe_cdat_rsp(DOECap *doe_cap)
>      }
>  
>      ent = req->entry_handle;
> +    if (ent >= cdat->entry_len) {
> +        return false;
> +    }

Blank line here ideally.

>      base = cdat->entry[ent].base;
>      len = cdat->entry[ent].length;
>  
> diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
> index b6281cbd4c..69773ff163 100644
> --- a/hw/pci-bridge/cxl_upstream.c
> +++ b/hw/pci-bridge/cxl_upstream.c
> @@ -158,6 +158,9 @@ static bool cxl_doe_cdat_rsp(DOECap *doe_cap)
>      }
>  
>      ent = req->entry_handle;
> +    if (ent >= cdat->entry_len) {
> +        return false;
> +    }
>      base = cdat->entry[ent].base;
>      len = cdat->entry[ent].length;
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.