@samitouri / QOSamiQemu / commits / 84752281bb

vfio-user: validate VERSION replies

The vfio-user protocol makes the VERSION payload optional, so a reply may legally stop after the major and minor fields. vfio_user_validate_version() currently assumes a capabilities string is always present and NUL-terminated. When the server replies without version data, QEMU ends up reusing the request-side capabilities buffer and the terminating-NUL check underflows. Replies shorter than the fixed VERSION header are also accessed before they are validated. Reject replies shorter than the fixed VERSION header and only parse capabilities when the reply actually carries version data. Fixes: 36227628d824 (vfio-user: implement message send infrastructure) Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> Reviewed-by: John Levon <john.levon@nutanix.com> Link: https://lore.kernel.org/qemu-devel/20260603062138.4008583-1-zhaoguohan@kylinos.cn Signed-off-by: Cédric Le Goater <clg@redhat.com>

GuoHan Zhao committed Jun 3, 2026 at 14:21 UTC 84752281bbcab3020c1df867ba9f535ef101b959
1 file changed +14 -7
hw/vfio-user/proxy.c
+14 -7
@@ -1292,7 +1292,7 @@ bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
1292 {
1293 g_autofree VFIOUserVersion *msgp = NULL;
1294 GString *caps;
1295 - char *reply;
1295 + const char *reply = "";
1296 int size, caplen;
1297
1298 caps = caps_json();
@@ -1322,17 +1322,24 @@ bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
1322 return false;
1323 }
1324
1325 - reply = msgp->capabilities;
1326 - if (reply[msgp->hdr.size - sizeof(*msgp) - 1] != '\0') {
1327 - error_setg(errp, "corrupt version reply");
1325 + if (msgp->hdr.size < sizeof(*msgp)) {
1326 + error_setg(errp, "short version reply");
1327 return false;
1328 }
1329
1331 - if (!caps_check(proxy, msgp->minor, reply, errp)) {
1332 - return false;
1330 + if (msgp->hdr.size > sizeof(*msgp)) {
1331 + reply = msgp->capabilities;
1332 + if (reply[msgp->hdr.size - sizeof(*msgp) - 1] != '\0') {
1333 + error_setg(errp, "corrupt version reply");
1334 + return false;
1335 + }
1336 +
1337 + if (!caps_check(proxy, msgp->minor, reply, errp)) {
1338 + return false;
1339 + }
1340 }
1341
1335 - trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
1342 + trace_vfio_user_version(msgp->major, msgp->minor, reply);
1343 return true;
1344 }
1345