The Post Package Repair and memory sparing Set Feature branches still
copy mailbox payload data into fixed-size write-attribute objects
without checking that hdr->offset + bytes_to_copy stays within the
target buffer.
patrol scrub and ECS already reject oversized writes, but the later PPR
and sparing feature additions missed the same validation. A full
mailbox payload can therefore overrun the target write-attribute object,
for example in the rank sparing branch.
Use cxl_set_feature_copy() there as well and return
CXL_MBOX_INVALID_PAYLOAD_LENGTH for oversized requests.
Fixes: 5e5a86bab83 ("hw/cxl: Add support for Maintenance command and Post
Package Repair (PPR)")
Fixes: da5cafdc4dd ("hw/cxl: Add emulation for memory sparing control feature")
Link: https://gitlab.com/qemu-project/qemu/-/work_items/3458
Cc: [email protected]
Signed-off-by: Jia Jia <[email protected]>
---
hw/cxl/cxl-mailbox-utils.c | 54 +++++++++++++++++++++++++++++---------
1 file changed, 42 insertions(+), 12 deletions(-)
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 2e4cc5824d..4c7a083e4c 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -1829,8 +1829,13 @@ static CXLRetCode cmd_features_set_feature(const struct
cxl_cmd *cmd,
return CXL_MBOX_UNSUPPORTED;
}
- memcpy((uint8_t *)&ct3d->soft_ppr_wr_attrs + hdr->offset,
- sppr_write_attrs, bytes_to_copy);
+ ret = cxl_set_feature_copy(&ct3d->soft_ppr_wr_attrs,
+ sizeof(ct3d->soft_ppr_wr_attrs),
+ hdr->offset, sppr_write_attrs,
+ bytes_to_copy);
+ if (ret) {
+ return ret;
+ }
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
@@ -1848,8 +1853,13 @@ static CXLRetCode cmd_features_set_feature(const struct
cxl_cmd *cmd,
return CXL_MBOX_UNSUPPORTED;
}
- memcpy((uint8_t *)&ct3d->hard_ppr_wr_attrs + hdr->offset,
- hppr_write_attrs, bytes_to_copy);
+ ret = cxl_set_feature_copy(&ct3d->hard_ppr_wr_attrs,
+ sizeof(ct3d->hard_ppr_wr_attrs),
+ hdr->offset, hppr_write_attrs,
+ bytes_to_copy);
+ if (ret) {
+ return ret;
+ }
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
@@ -1867,8 +1877,13 @@ static CXLRetCode cmd_features_set_feature(const struct
cxl_cmd *cmd,
return CXL_MBOX_UNSUPPORTED;
}
- memcpy((uint8_t *)&ct3d->cacheline_sparing_wr_attrs + hdr->offset,
- mem_sparing_write_attrs, bytes_to_copy);
+ ret = cxl_set_feature_copy(&ct3d->cacheline_sparing_wr_attrs,
+ sizeof(ct3d->cacheline_sparing_wr_attrs),
+ hdr->offset, mem_sparing_write_attrs,
+ bytes_to_copy);
+ if (ret) {
+ return ret;
+ }
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
@@ -1885,8 +1900,13 @@ static CXLRetCode cmd_features_set_feature(const struct
cxl_cmd *cmd,
return CXL_MBOX_UNSUPPORTED;
}
- memcpy((uint8_t *)&ct3d->row_sparing_wr_attrs + hdr->offset,
- mem_sparing_write_attrs, bytes_to_copy);
+ ret = cxl_set_feature_copy(&ct3d->row_sparing_wr_attrs,
+ sizeof(ct3d->row_sparing_wr_attrs),
+ hdr->offset, mem_sparing_write_attrs,
+ bytes_to_copy);
+ if (ret) {
+ return ret;
+ }
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
@@ -1903,8 +1923,13 @@ static CXLRetCode cmd_features_set_feature(const struct
cxl_cmd *cmd,
return CXL_MBOX_UNSUPPORTED;
}
- memcpy((uint8_t *)&ct3d->bank_sparing_wr_attrs + hdr->offset,
- mem_sparing_write_attrs, bytes_to_copy);
+ ret = cxl_set_feature_copy(&ct3d->bank_sparing_wr_attrs,
+ sizeof(ct3d->bank_sparing_wr_attrs),
+ hdr->offset, mem_sparing_write_attrs,
+ bytes_to_copy);
+ if (ret) {
+ return ret;
+ }
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
@@ -1921,8 +1946,13 @@ static CXLRetCode cmd_features_set_feature(const struct
cxl_cmd *cmd,
return CXL_MBOX_UNSUPPORTED;
}
- memcpy((uint8_t *)&ct3d->rank_sparing_wr_attrs + hdr->offset,
- mem_sparing_write_attrs, bytes_to_copy);
+ ret = cxl_set_feature_copy(&ct3d->rank_sparing_wr_attrs,
+ sizeof(ct3d->rank_sparing_wr_attrs),
+ hdr->offset, mem_sparing_write_attrs,
+ bytes_to_copy);
+ if (ret) {
+ return ret;
+ }
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
--
2.34.1