On 12/06/2026 17.37, Feifan Qian wrote:
cmd_features_set_feature() derives bytes_to_copy from the mailbox input length and uses hdr->offset as the destination offset into per-feature write attribute buffers.The patrol scrub and ECS paths already reject writes where hdr->offset plus bytes_to_copy exceeds the destination structure. Add the same check to the soft PPR, hard PPR and memory sparing feature paths before copying into their write attribute buffers. Without the check, a malformed Set Feature request can write past the selected write attribute object and corrupt adjacent CXL type 3 device state. Fixes: 5e5a86bab830 ("hw/cxl: Add support for Maintenance command and Post Package Repair (PPR)") Fixes: da5cafdc4ddd ("hw/cxl: Add emulation for memory sparing control feature") Signed-off-by: Feifan Qian <[email protected]> --- This is submitted as a regular bug fix for the CXL non-virtualization use case. hw/cxl/cxl-mailbox-utils.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index d8ba7e8625..1724b09a6d 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -1813,6 +1813,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->soft_ppr_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->soft_ppr_wr_attrs + hdr->offset, sppr_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; @@ -1832,6 +1836,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->hard_ppr_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->hard_ppr_wr_attrs + hdr->offset, hppr_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; @@ -1851,6 +1859,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->cacheline_sparing_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->cacheline_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; @@ -1869,6 +1881,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->row_sparing_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->row_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; @@ -1887,6 +1903,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->bank_sparing_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->bank_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; @@ -1905,6 +1925,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->rank_sparing_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->rank_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; -- 2.43.0
Reviewed-by: Thomas Huth <[email protected]> I'll pick this up for my next PR if nobody minds.
