@samitouri / QOSamiQemu / commits / 034baf047f

hw/nvme: ensure sgl forward progress

A degenerate host can create segment loops of zero-byte data descriptors that the controller never breaks out of. While the spec allows zero length segments, it provides no guidance on handling loops. It makes no sense for a host to submit such a descriptor anyway since it can and trivially should point to the next transfer segment, so don't even try to work with such behavior. Just reject the command, terminating the loop. Cc: qemu-stable@nongnu.org Reported-by: Feifan Qian <bea1e@proton.me> Reported-by: boy juju <agx1657748706@gmail.com> Signed-off-by: Keith Busch <kbusch@kernel.org> Reviewed-by: Klaus Jensen <k.jensen@samsung.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>

Keith Busch committed May 29, 2026 at 06:59 UTC 034baf047fe143c2713f35fa640407d9da2f6fc3
1 file changed +13
hw/nvme/ctrl.c
+13
@@ -1090,6 +1090,8 @@ static uint16_t nvme_map_sgl(NvmeCtrl *n, NvmeSg *sg, NvmeSglDescriptor sgl,
1090 }
1091
1092 for (;;) {
1093 + size_t prev_len = len;
1094 +
1095 switch (NVME_SGL_TYPE(sgld->type)) {
1096 case NVME_SGL_DESCR_TYPE_SEGMENT:
1097 case NVME_SGL_DESCR_TYPE_LAST_SEGMENT:
@@ -1170,6 +1172,17 @@ static uint16_t nvme_map_sgl(NvmeCtrl *n, NvmeSg *sg, NvmeSglDescriptor sgl,
1172 if (status) {
1173 goto unmap;
1174 }
1175 +
1176 + /*
1177 + * Reject if this segment made no forward progress. The host should
1178 + * have skipped linking an empty segment. While not strictly spec
1179 + * compliant, allowing this makes it easy for a pathological host to
1180 + * create an infinite loop.
1181 + */
1182 + if (len == prev_len) {
1183 + status = NVME_INVALID_SGL_SEG_DESCR | NVME_DNR;
1184 + goto unmap;
1185 + }
1186 }
1187
1188 out: