diff mbox

[v2] qmp: object-add: Validate class before creating object

Message ID 1397669978-26339-1-git-send-email-ehabkost@redhat.com
State New
Headers show

Commit Message

Eduardo Habkost April 16, 2014, 5:39 p.m. UTC
Currently it is very easy to crash QEMU by issuing an object-add command
using an abstract class or a class that doesn't support
TYPE_USER_CREATABLE as parameter.

Example: with the following QMP command:

    (QEMU) object-add qom-type=cpu id=foo

QEMU aborts at:

    ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)

This patch moves the check for TYPE_USER_CREATABLE before object_new(),
and adds a check to prevent the code from trying to instantiate abstract
classes.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Changes v2:
 * Change ordering: first check for TYPE_USER_CREATABLE and then check
   if class is abstract. This makes the ordering of checks closer to
   what's already done on device_add.
---
 qmp.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

Comments

Matthew Rosato April 16, 2014, 8:47 p.m. UTC | #1
On 04/16/2014 01:39 PM, Eduardo Habkost wrote:
> Currently it is very easy to crash QEMU by issuing an object-add command
> using an abstract class or a class that doesn't support
> TYPE_USER_CREATABLE as parameter.
> 
> Example: with the following QMP command:
> 
>     (QEMU) object-add qom-type=cpu id=foo
> 
> QEMU aborts at:
> 
>     ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)
> 
> This patch moves the check for TYPE_USER_CREATABLE before object_new(),
> and adds a check to prevent the code from trying to instantiate abstract
> classes.
> 
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
> Changes v2:
>  * Change ordering: first check for TYPE_USER_CREATABLE and then check
>    if class is abstract. This makes the ordering of checks closer to
>    what's already done on device_add.


Changes look fine to me, re-tested to verify.

Reviewed-by: Matthew Rosato <mjrosato@linux.vnet.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.vnet.ibm.com>


> ---
>  qmp.c | 21 ++++++++++++++-------
>  1 file changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/qmp.c b/qmp.c
> index 87a28f7..9a93ab1 100644
> --- a/qmp.c
> +++ b/qmp.c
> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>                  Visitor *v, Error **errp)
>  {
>      Object *obj;
> +    ObjectClass *klass;
>      const QDictEntry *e;
>      Error *local_err = NULL;
> 
> -    if (!object_class_by_name(type)) {
> +    klass = object_class_by_name(type);
> +    if (!klass) {
>          error_setg(errp, "invalid class name");
>          return;
>      }
> 
> +    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
> +        error_setg(errp, "object type '%s' isn't supported by object-add",
> +                   type);
> +        return;
> +    }
> +
> +    if (object_class_is_abstract(klass)) {
> +        error_setg(errp, "object type '%s' is abstract", type);
> +        return;
> +    }
> +
>      obj = object_new(type);
>      if (qdict) {
>          for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
> @@ -558,12 +571,6 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>          }
>      }
> 
> -    if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
> -        error_setg(&local_err, "object type '%s' isn't supported by object-add",
> -                   type);
> -        goto out;
> -    }
> -
>      user_creatable_complete(obj, &local_err);
>      if (local_err) {
>          goto out;
>
Luiz Capitulino April 25, 2014, 3:12 p.m. UTC | #2
On Wed, 16 Apr 2014 14:39:38 -0300
Eduardo Habkost <ehabkost@redhat.com> wrote:

> Currently it is very easy to crash QEMU by issuing an object-add command
> using an abstract class or a class that doesn't support
> TYPE_USER_CREATABLE as parameter.
> 
> Example: with the following QMP command:
> 
>     (QEMU) object-add qom-type=cpu id=foo
> 
> QEMU aborts at:
> 
>     ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)
> 
> This patch moves the check for TYPE_USER_CREATABLE before object_new(),
> and adds a check to prevent the code from trying to instantiate abstract
> classes.
> 
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>

Applied to the qmp branch, thanks Eduardo.

> ---
> Changes v2:
>  * Change ordering: first check for TYPE_USER_CREATABLE and then check
>    if class is abstract. This makes the ordering of checks closer to
>    what's already done on device_add.
> ---
>  qmp.c | 21 ++++++++++++++-------
>  1 file changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/qmp.c b/qmp.c
> index 87a28f7..9a93ab1 100644
> --- a/qmp.c
> +++ b/qmp.c
> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>                  Visitor *v, Error **errp)
>  {
>      Object *obj;
> +    ObjectClass *klass;
>      const QDictEntry *e;
>      Error *local_err = NULL;
>  
> -    if (!object_class_by_name(type)) {
> +    klass = object_class_by_name(type);
> +    if (!klass) {
>          error_setg(errp, "invalid class name");
>          return;
>      }
>  
> +    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
> +        error_setg(errp, "object type '%s' isn't supported by object-add",
> +                   type);
> +        return;
> +    }
> +
> +    if (object_class_is_abstract(klass)) {
> +        error_setg(errp, "object type '%s' is abstract", type);
> +        return;
> +    }
> +
>      obj = object_new(type);
>      if (qdict) {
>          for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
> @@ -558,12 +571,6 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>          }
>      }
>  
> -    if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
> -        error_setg(&local_err, "object type '%s' isn't supported by object-add",
> -                   type);
> -        goto out;
> -    }
> -
>      user_creatable_complete(obj, &local_err);
>      if (local_err) {
>          goto out;
Andreas Färber April 25, 2014, 3:57 p.m. UTC | #3
Am 25.04.2014 17:12, schrieb Luiz Capitulino:
> On Wed, 16 Apr 2014 14:39:38 -0300
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
>> Currently it is very easy to crash QEMU by issuing an object-add command
>> using an abstract class or a class that doesn't support
>> TYPE_USER_CREATABLE as parameter.
>>
>> Example: with the following QMP command:
>>
>>     (QEMU) object-add qom-type=cpu id=foo
>>
>> QEMU aborts at:
>>
>>     ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)
>>
>> This patch moves the check for TYPE_USER_CREATABLE before object_new(),
>> and adds a check to prevent the code from trying to instantiate abstract
>> classes.
>>
>> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> 
> Applied to the qmp branch, thanks Eduardo.
> 
>> ---
>> Changes v2:
>>  * Change ordering: first check for TYPE_USER_CREATABLE and then check
>>    if class is abstract. This makes the ordering of checks closer to
>>    what's already done on device_add.
>> ---
>>  qmp.c | 21 ++++++++++++++-------
>>  1 file changed, 14 insertions(+), 7 deletions(-)
>>
>> diff --git a/qmp.c b/qmp.c
>> index 87a28f7..9a93ab1 100644
>> --- a/qmp.c
>> +++ b/qmp.c
>> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>>                  Visitor *v, Error **errp)
>>  {
>>      Object *obj;
>> +    ObjectClass *klass;

Luiz, can you rename klass to oc please?

Thanks,
Andreas

>>      const QDictEntry *e;
>>      Error *local_err = NULL;
>>  
>> -    if (!object_class_by_name(type)) {
>> +    klass = object_class_by_name(type);
>> +    if (!klass) {
>>          error_setg(errp, "invalid class name");
>>          return;
>>      }
>>  
>> +    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
>> +        error_setg(errp, "object type '%s' isn't supported by object-add",
>> +                   type);
>> +        return;
>> +    }
>> +
>> +    if (object_class_is_abstract(klass)) {
>> +        error_setg(errp, "object type '%s' is abstract", type);
>> +        return;
>> +    }
>> +
>>      obj = object_new(type);
>>      if (qdict) {
>>          for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
>> @@ -558,12 +571,6 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>>          }
>>      }
>>  
>> -    if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
>> -        error_setg(&local_err, "object type '%s' isn't supported by object-add",
>> -                   type);
>> -        goto out;
>> -    }
>> -
>>      user_creatable_complete(obj, &local_err);
>>      if (local_err) {
>>          goto out;
> 
>
Luiz Capitulino April 25, 2014, 6:02 p.m. UTC | #4
On Fri, 25 Apr 2014 17:57:12 +0200
Andreas Färber <afaerber@suse.de> wrote:

> Am 25.04.2014 17:12, schrieb Luiz Capitulino:
> > On Wed, 16 Apr 2014 14:39:38 -0300
> > Eduardo Habkost <ehabkost@redhat.com> wrote:
> > 
> >> Currently it is very easy to crash QEMU by issuing an object-add command
> >> using an abstract class or a class that doesn't support
> >> TYPE_USER_CREATABLE as parameter.
> >>
> >> Example: with the following QMP command:
> >>
> >>     (QEMU) object-add qom-type=cpu id=foo
> >>
> >> QEMU aborts at:
> >>
> >>     ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)
> >>
> >> This patch moves the check for TYPE_USER_CREATABLE before object_new(),
> >> and adds a check to prevent the code from trying to instantiate abstract
> >> classes.
> >>
> >> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > 
> > Applied to the qmp branch, thanks Eduardo.
> > 
> >> ---
> >> Changes v2:
> >>  * Change ordering: first check for TYPE_USER_CREATABLE and then check
> >>    if class is abstract. This makes the ordering of checks closer to
> >>    what's already done on device_add.
> >> ---
> >>  qmp.c | 21 ++++++++++++++-------
> >>  1 file changed, 14 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/qmp.c b/qmp.c
> >> index 87a28f7..9a93ab1 100644
> >> --- a/qmp.c
> >> +++ b/qmp.c
> >> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
> >>                  Visitor *v, Error **errp)
> >>  {
> >>      Object *obj;
> >> +    ObjectClass *klass;
> 
> Luiz, can you rename klass to oc please?

My pull request is almost ready (finishing last few tests), so I think
it's a bit late for a style change.

> 
> Thanks,
> Andreas
> 
> >>      const QDictEntry *e;
> >>      Error *local_err = NULL;
> >>  
> >> -    if (!object_class_by_name(type)) {
> >> +    klass = object_class_by_name(type);
> >> +    if (!klass) {
> >>          error_setg(errp, "invalid class name");
> >>          return;
> >>      }
> >>  
> >> +    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
> >> +        error_setg(errp, "object type '%s' isn't supported by object-add",
> >> +                   type);
> >> +        return;
> >> +    }
> >> +
> >> +    if (object_class_is_abstract(klass)) {
> >> +        error_setg(errp, "object type '%s' is abstract", type);
> >> +        return;
> >> +    }
> >> +
> >>      obj = object_new(type);
> >>      if (qdict) {
> >>          for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
> >> @@ -558,12 +571,6 @@ void object_add(const char *type, const char *id, const QDict *qdict,
> >>          }
> >>      }
> >>  
> >> -    if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
> >> -        error_setg(&local_err, "object type '%s' isn't supported by object-add",
> >> -                   type);
> >> -        goto out;
> >> -    }
> >> -
> >>      user_creatable_complete(obj, &local_err);
> >>      if (local_err) {
> >>          goto out;
> > 
> > 
> 
>
Andreas Färber April 25, 2014, 6:42 p.m. UTC | #5
Am 25.04.2014 20:02, schrieb Luiz Capitulino:
> On Fri, 25 Apr 2014 17:57:12 +0200
> Andreas Färber <afaerber@suse.de> wrote:
>> Am 25.04.2014 17:12, schrieb Luiz Capitulino:
>>> On Wed, 16 Apr 2014 14:39:38 -0300
>>> Eduardo Habkost <ehabkost@redhat.com> wrote:
>>>
>>>> Currently it is very easy to crash QEMU by issuing an object-add command
>>>> using an abstract class or a class that doesn't support
>>>> TYPE_USER_CREATABLE as parameter.
>>>>
>>>> Example: with the following QMP command:
>>>>
>>>>     (QEMU) object-add qom-type=cpu id=foo
>>>>
>>>> QEMU aborts at:
>>>>
>>>>     ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)
>>>>
>>>> This patch moves the check for TYPE_USER_CREATABLE before object_new(),
>>>> and adds a check to prevent the code from trying to instantiate abstract
>>>> classes.
>>>>
>>>> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
>>>
>>> Applied to the qmp branch, thanks Eduardo.
[...]
>>>> diff --git a/qmp.c b/qmp.c
>>>> index 87a28f7..9a93ab1 100644
>>>> --- a/qmp.c
>>>> +++ b/qmp.c
>>>> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>>>>                  Visitor *v, Error **errp)
>>>>  {
>>>>      Object *obj;
>>>> +    ObjectClass *klass;
>>
>> Luiz, can you rename klass to oc please?
> 
> My pull request is almost ready (finishing last few tests), so I think
> it's a bit late for a style change.

Then either one of you please follow-up with a fix before you forget.
I've been asked to change patches that way, so I expect others do, too.

Andreas
Eduardo Habkost April 25, 2014, 7:16 p.m. UTC | #6
On Fri, Apr 25, 2014 at 08:42:59PM +0200, Andreas Färber wrote:
> Am 25.04.2014 20:02, schrieb Luiz Capitulino:
> > On Fri, 25 Apr 2014 17:57:12 +0200
> > Andreas Färber <afaerber@suse.de> wrote:
> >> Am 25.04.2014 17:12, schrieb Luiz Capitulino:
> >>> On Wed, 16 Apr 2014 14:39:38 -0300
> >>> Eduardo Habkost <ehabkost@redhat.com> wrote:
> >>>
> >>>> Currently it is very easy to crash QEMU by issuing an object-add command
> >>>> using an abstract class or a class that doesn't support
> >>>> TYPE_USER_CREATABLE as parameter.
> >>>>
> >>>> Example: with the following QMP command:
> >>>>
> >>>>     (QEMU) object-add qom-type=cpu id=foo
> >>>>
> >>>> QEMU aborts at:
> >>>>
> >>>>     ERROR:qom/object.c:335:object_initialize_with_type: assertion failed: (type->abstract == false)
> >>>>
> >>>> This patch moves the check for TYPE_USER_CREATABLE before object_new(),
> >>>> and adds a check to prevent the code from trying to instantiate abstract
> >>>> classes.
> >>>>
> >>>> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> >>>
> >>> Applied to the qmp branch, thanks Eduardo.
> [...]
> >>>> diff --git a/qmp.c b/qmp.c
> >>>> index 87a28f7..9a93ab1 100644
> >>>> --- a/qmp.c
> >>>> +++ b/qmp.c
> >>>> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
> >>>>                  Visitor *v, Error **errp)
> >>>>  {
> >>>>      Object *obj;
> >>>> +    ObjectClass *klass;
> >>
> >> Luiz, can you rename klass to oc please?
> > 
> > My pull request is almost ready (finishing last few tests), so I think
> > it's a bit late for a style change.
> 
> Then either one of you please follow-up with a fix before you forget.
> I've been asked to change patches that way, so I expect others do, too.

Could you explain why this is a bug? The patch matches the existing
style in qmp.c, and if I grep the whole tree I see 482 matches for
'ObjectClass *klass' and 165 for 'ObjectClass *oc'.
Andreas Färber May 16, 2014, 3:39 p.m. UTC | #7
Am 25.04.2014 21:16, schrieb Eduardo Habkost:
> On Fri, Apr 25, 2014 at 08:42:59PM +0200, Andreas Färber wrote:
>> Am 25.04.2014 20:02, schrieb Luiz Capitulino:
>>> On Fri, 25 Apr 2014 17:57:12 +0200
>>> Andreas Färber <afaerber@suse.de> wrote:
>>>> Am 25.04.2014 17:12, schrieb Luiz Capitulino:
>>>>> On Wed, 16 Apr 2014 14:39:38 -0300
>>>>> Eduardo Habkost <ehabkost@redhat.com> wrote:
>>>>>
>>>>>> diff --git a/qmp.c b/qmp.c
>>>>>> index 87a28f7..9a93ab1 100644
>>>>>> --- a/qmp.c
>>>>>> +++ b/qmp.c
>>>>>> @@ -540,14 +540,27 @@ void object_add(const char *type, const char *id, const QDict *qdict,
>>>>>>                  Visitor *v, Error **errp)
>>>>>>  {
>>>>>>      Object *obj;
>>>>>> +    ObjectClass *klass;
>>>>
>>>> Luiz, can you rename klass to oc please?
>>>
>>> My pull request is almost ready (finishing last few tests), so I think
>>> it's a bit late for a style change.
>>
>> Then either one of you please follow-up with a fix before you forget.
>> I've been asked to change patches that way, so I expect others do, too.
> 
> Could you explain why this is a bug? The patch matches the existing
> style in qmp.c, and if I grep the whole tree I see 482 matches for
> 'ObjectClass *klass' and 165 for 'ObjectClass *oc'.

Simple explanation for the numbers: "klass" was introduced through
Anthony's Python-automated qdev -> QOM conversion, because C++ reserves
"class". Then when I started making use of QOM for CPUs I was asked to
change my copied "klass" to "oc", with the argument that "klass" is a
deliberate misspelling and that we already used dc for DeviceClass, etc.
Therefore I expect others to update their patches to the new style, too.

ObjectClass *oc
#define MY_CLASS(class) # or MY_CLASS(cls) -- not forbidden in macros

Just like DO_UPCAST() and other pre-QOM macros, the only remedy to avoid
bad copy&paste will be to pass over the source tree and fix it
consistently. No time for that myself now, maybe a GSoC/OPW task?

Regards,
Andreas
diff mbox

Patch

diff --git a/qmp.c b/qmp.c
index 87a28f7..9a93ab1 100644
--- a/qmp.c
+++ b/qmp.c
@@ -540,14 +540,27 @@  void object_add(const char *type, const char *id, const QDict *qdict,
                 Visitor *v, Error **errp)
 {
     Object *obj;
+    ObjectClass *klass;
     const QDictEntry *e;
     Error *local_err = NULL;
 
-    if (!object_class_by_name(type)) {
+    klass = object_class_by_name(type);
+    if (!klass) {
         error_setg(errp, "invalid class name");
         return;
     }
 
+    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
+        error_setg(errp, "object type '%s' isn't supported by object-add",
+                   type);
+        return;
+    }
+
+    if (object_class_is_abstract(klass)) {
+        error_setg(errp, "object type '%s' is abstract", type);
+        return;
+    }
+
     obj = object_new(type);
     if (qdict) {
         for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
@@ -558,12 +571,6 @@  void object_add(const char *type, const char *id, const QDict *qdict,
         }
     }
 
-    if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
-        error_setg(&local_err, "object type '%s' isn't supported by object-add",
-                   type);
-        goto out;
-    }
-
     user_creatable_complete(obj, &local_err);
     if (local_err) {
         goto out;