@samitouri / QOSamiQemu / commits / 8dc8f7b5bc

qdev-monitor: Fix qdev ID validation regression

User-created qdevs with ID show up at /machine/peripheral/ID. When we restricted QemOpts IDs to letters, digits, '-', '.', '_', starting with a letter in commit b560a9ab9be: (qemu-option: Reject anti-social IDs) a long time ago, this also covered qdev IDs. Looks like this: (qemu) device_add usb-mouse,id=/ qemu-system-x86_64: Parameter 'id' expects an identifier Identifiers consist of letters, digits, '-', '.', '_', starting with a letter. Try "help device_add" for more information QMP, however: {"execute": "device_add", "arguments": {"driver": "usb-mouse", "id": "/"}} {"return": {}} This creates a device with canonical path "/machine/peripheral//". That way is madness. We accidentally bypassed qdev ID validation for QMP when we cut the detour through QemuOpts in commit b30d8054642. Fix by validating IDs one layer down, in qdev_set_id(). Arguably, QOM should protect itself from QOM path components containing '/', but let's just fix the regression for now. Fixes: be93fd53723c (qdev-monitor: avoid QemuOpts in QMP device_add) Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-ID: <20260123085924.1392134-1-armbru@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

Markus Armbruster committed Jan 23, 2026 at 09:59 UTC 8dc8f7b5bc755227c72eb74aa332e7a6bbb90066
1 file changed +10 -2
system/qdev-monitor.c
+10 -2
@@ -34,6 +34,7 @@
34 #include "qemu/config-file.h"
35 #include "qemu/error-report.h"
36 #include "qemu/help_option.h"
37 +#include "qemu/id.h"
38 #include "qemu/option.h"
39 #include "qemu/qemu-print.h"
40 #include "qemu/option_int.h"
@@ -601,14 +602,17 @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
602 * has no parent
603 */
604 if (id) {
605 + if (!id_wellformed(id)) {
606 + error_setg(errp, "Invalid qdev ID '%s'", id);
607 + goto err;
608 + }
609 prop = object_property_try_add_child(qdev_get_peripheral(), id,
610 OBJECT(dev), NULL);
611 if (prop) {
612 dev->id = id;
613 } else {
614 error_setg(errp, "Duplicate device ID '%s'", id);
610 - g_free(id);
611 - return NULL;
615 + goto err;
616 }
617 } else {
618 static int anon_count;
@@ -619,6 +623,10 @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
623 }
624
625 return prop->name;
626 +
627 +err:
628 + g_free(id);
629 + return NULL;
630 }
631
632 BusState *qdev_find_default_bus(DeviceClass *dc, Error **errp)