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.


Reply via email to