qom: Introduce object_property_try_add_child()

object_property_add() does not allow object_property_try_add()
to gracefully fail as &error_abort is passed as an error handle.

However such failure can easily be triggered from the QMP shell when,
for instance, one attempts to create an object with an id that already
exists. This is achieved from the following call path:

qmp_object_add -> user_creatable_add_dict -> user_creatable_add_type ->
object_property_add_child -> object_property_add

For instance, from the qmp-shell, call twice:
object-add qom-type=memory-backend-ram id=mem1 props.size=1073741824
and QEMU aborts.

This behavior is undesired as a user/management application mistake
in reusing a property ID shouldn't result in loss of the VM and live
data within.

This patch introduces a new function, object_property_try_add_child()
which takes an error handle and turn object_property_try_add() into
a non-static one.

Now the call path becomes:

user_creatable_add_type -> object_property_try_add_child ->
object_property_try_add

and the error is returned gracefully to the QMP client.

(QEMU) object-add qom-type=memory-backend-ram id=mem2  props.size=4294967296
{"return": {}}
(QEMU) object-add qom-type=memory-backend-ram id=mem2  props.size=4294967296
{"error": {"class": "GenericError", "desc": "attempt to add duplicate property
'mem2' to object (type 'container')"}}

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Fixes: d2623129a7 ("qom: Drop parameter @errp of object_property_add() & friends")
Reviewed-by: Markus Armbruster <armbru@redhat.com>

Reviewed-by: Greg Kurz <groug@kaod.org>
Tested-by: Greg Kurz <groug@kaod.org>
Message-Id: <20200629193424.30280-2-eric.auger@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Eric Auger 2020-06-29 21:34:22 +02:00 committed by Paolo Bonzini
parent 2880ffb089
commit db57fef1e2
3 changed files with 45 additions and 9 deletions

View file

@ -1146,7 +1146,7 @@ void object_unref(Object *obj)
}
}
static ObjectProperty *
ObjectProperty *
object_property_try_add(Object *obj, const char *name, const char *type,
ObjectPropertyAccessor *get,
ObjectPropertyAccessor *set,
@ -1675,8 +1675,8 @@ static void object_finalize_child_property(Object *obj, const char *name,
}
ObjectProperty *
object_property_add_child(Object *obj, const char *name,
Object *child)
object_property_try_add_child(Object *obj, const char *name,
Object *child, Error **errp)
{
g_autofree char *type = NULL;
ObjectProperty *op;
@ -1685,14 +1685,25 @@ object_property_add_child(Object *obj, const char *name,
type = g_strdup_printf("child<%s>", object_get_typename(child));
op = object_property_add(obj, name, type, object_get_child_property, NULL,
object_finalize_child_property, child);
op = object_property_try_add(obj, name, type, object_get_child_property,
NULL, object_finalize_child_property,
child, errp);
if (!op) {
return NULL;
}
op->resolve = object_resolve_child_property;
object_ref(child);
child->parent = obj;
return op;
}
ObjectProperty *
object_property_add_child(Object *obj, const char *name,
Object *child)
{
return object_property_try_add_child(obj, name, child, &error_abort);
}
void object_property_allow_set_link(const Object *obj, const char *name,
Object *val, Error **errp)
{