@samitouri / QOSamiQemu / commits / b71a179148

hw/cxl: Validate Set Feature payload bounds

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 <bea1e@proton.me> Reviewed-by: Thomas Huth <thuth@redhat.com> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3458 Reported-by: Jia Jia <physicalmtea@gmail.com> Signed-off-by: Thomas Huth <thuth@redhat.com>

Feifan Qian committed Jun 12, 2026 at 15:37 UTC b71a179148ff49ed236cffb98af8891aeed94159
1 file changed +24
hw/cxl/cxl-mailbox-utils.c
+24
@@ -1813,6 +1813,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
1813 return CXL_MBOX_UNSUPPORTED;
1814 }
1815
1816 + if ((uint32_t)hdr->offset + bytes_to_copy >
1817 + sizeof(ct3d->soft_ppr_wr_attrs)) {
1818 + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
1819 + }
1820 memcpy((uint8_t *)&ct3d->soft_ppr_wr_attrs + hdr->offset,
1821 sppr_write_attrs, bytes_to_copy);
1822 set_feat_info->data_size += bytes_to_copy;
@@ -1832,6 +1836,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
1836 return CXL_MBOX_UNSUPPORTED;
1837 }
1838
1839 + if ((uint32_t)hdr->offset + bytes_to_copy >
1840 + sizeof(ct3d->hard_ppr_wr_attrs)) {
1841 + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
1842 + }
1843 memcpy((uint8_t *)&ct3d->hard_ppr_wr_attrs + hdr->offset,
1844 hppr_write_attrs, bytes_to_copy);
1845 set_feat_info->data_size += bytes_to_copy;
@@ -1851,6 +1859,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
1859 return CXL_MBOX_UNSUPPORTED;
1860 }
1861
1862 + if ((uint32_t)hdr->offset + bytes_to_copy >
1863 + sizeof(ct3d->cacheline_sparing_wr_attrs)) {
1864 + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
1865 + }
1866 memcpy((uint8_t *)&ct3d->cacheline_sparing_wr_attrs + hdr->offset,
1867 mem_sparing_write_attrs, bytes_to_copy);
1868 set_feat_info->data_size += bytes_to_copy;
@@ -1869,6 +1881,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
1881 return CXL_MBOX_UNSUPPORTED;
1882 }
1883
1884 + if ((uint32_t)hdr->offset + bytes_to_copy >
1885 + sizeof(ct3d->row_sparing_wr_attrs)) {
1886 + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
1887 + }
1888 memcpy((uint8_t *)&ct3d->row_sparing_wr_attrs + hdr->offset,
1889 mem_sparing_write_attrs, bytes_to_copy);
1890 set_feat_info->data_size += bytes_to_copy;
@@ -1887,6 +1903,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
1903 return CXL_MBOX_UNSUPPORTED;
1904 }
1905
1906 + if ((uint32_t)hdr->offset + bytes_to_copy >
1907 + sizeof(ct3d->bank_sparing_wr_attrs)) {
1908 + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
1909 + }
1910 memcpy((uint8_t *)&ct3d->bank_sparing_wr_attrs + hdr->offset,
1911 mem_sparing_write_attrs, bytes_to_copy);
1912 set_feat_info->data_size += bytes_to_copy;
@@ -1905,6 +1925,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
1925 return CXL_MBOX_UNSUPPORTED;
1926 }
1927
1928 + if ((uint32_t)hdr->offset + bytes_to_copy >
1929 + sizeof(ct3d->rank_sparing_wr_attrs)) {
1930 + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
1931 + }
1932 memcpy((uint8_t *)&ct3d->rank_sparing_wr_attrs + hdr->offset,
1933 mem_sparing_write_attrs, bytes_to_copy);
1934 set_feat_info->data_size += bytes_to_copy;