qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: Paolo Bonzini <pbonzini@redhat.com>, qemu-devel@nongnu.org
Cc: lcapitulino@redhat.com, famz@redhat.com, qemu-stable@nongnu.org,
	armbru@redhat.com
Subject: Re: [Qemu-devel] [PATCH 1/3] qapi: add visit_start_union and visit_end_union
Date: Fri, 12 Sep 2014 10:34:47 -0500	[thread overview]
Message-ID: <20140912153447.19243.81596@loki> (raw)
In-Reply-To: <5412C828.2070004@redhat.com>

Quoting Paolo Bonzini (2014-09-12 05:17:12)
> Il 12/09/2014 01:20, Michael Roth ha scritto:
> > In some cases an input visitor might bail out on filling out a
> > struct for various reasons, such as missing fields when running
> > in strict mode. In the case of a QAPI Union type, this may lead
> > to cases where the .kind field which encodes the union type
> > is uninitialized. Subsequently, other visitors, such as the
> > dealloc visitor, may use this .kind value as if it were
> > initialized, leading to assumptions about the union type which
> > in this case may lead to segfaults. For example, freeing an
> > integer value.
> > 
> > However, we can generally rely on the fact that the always-present
> > .data void * field that we generate for these union types will
> > always be NULL in cases where .kind is uninitialized (at least,
> > there shouldn't be a reason where we'd do this purposefully).
> > 
> > So pass this information on to Visitor implementation via these
> > optional start_union/end_union interfaces so this information
> > can be used to guard against the situation above. We will make
> > use of this information in a subsequent patch for the dealloc
> > visitor.
> > 
> > Cc: qemu-stable@nongnu.org
> > Reported-by: Fam Zheng <famz@redhat.com>
> > Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> > ---
> >  include/qapi/visitor-impl.h |  2 ++
> >  include/qapi/visitor.h      |  2 ++
> >  qapi/qapi-visit-core.c      | 15 +++++++++++++++
> >  scripts/qapi-visit.py       |  6 ++++++
> >  4 files changed, 25 insertions(+)
> > 
> > diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
> > index ecc0183..09bb0fd 100644
> > --- a/include/qapi/visitor-impl.h
> > +++ b/include/qapi/visitor-impl.h
> > @@ -55,6 +55,8 @@ struct Visitor
> >      void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp);
> >      /* visit_type_size() falls back to (*type_uint64)() if type_size is unset */
> >      void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp);
> > +    bool (*start_union)(Visitor *v, bool data_present, Error **errp);
> > +    void (*end_union)(Visitor *v, bool data_present, Error **errp);
> >  };
> >  
> >  void input_type_enum(Visitor *v, int *obj, const char *strings[],
> > diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
> > index 4a0178f..5934f59 100644
> > --- a/include/qapi/visitor.h
> > +++ b/include/qapi/visitor.h
> > @@ -58,5 +58,7 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
> >  void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
> >  void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
> >  void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
> > +bool visit_start_union(Visitor *v, bool data_present, Error **errp);
> > +void visit_end_union(Visitor *v, bool data_present, Error **errp);
> >  
> >  #endif
> > diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
> > index 55f8d40..b66b93a 100644
> > --- a/qapi/qapi-visit-core.c
> > +++ b/qapi/qapi-visit-core.c
> > @@ -58,6 +58,21 @@ void visit_end_list(Visitor *v, Error **errp)
> >      v->end_list(v, errp);
> >  }
> >  
> > +bool visit_start_union(Visitor *v, bool data_present, Error **errp)
> > +{
> > +    if (v->start_union) {
> > +        return v->start_union(v, data_present, errp);
> > +    }
> > +    return true;
> > +}
> 
> Should output visitors set an error, or even abort, if the data is not
> present, thus avoiding a NULL-pointer dereference later on?

I think there's at least one corner case where this might cause issues:

{ 'union': 'UserDefUnion',
  'base': 'UserDefZero',
  'data': { 'a' : 'int', 'b' : 'UserDefB' } }

If UserDefUnion.a is 0, UserDefUnion.data will cast it to a NULL value and
cause the output visitor to bail, when really it should just be left to
continue on serializing the integer.

To guard against that sort of thing I think we'd need a way to verify .kind
field is initialized, so that kind of brings us back to original problem.
But if we do decide to audit or change visitors/users to encode this
information in .kind it would be fairly simply to extend
visit_start_union/visit_end_union to pass that information along as well.

> 
> But I guess this is really just cosmetic, so you can add my
> 
> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
> 
> for the whole series.
> 
> Paolo
> 
> > +void visit_end_union(Visitor *v, bool data_present, Error **errp)
> > +{
> > +    if (v->end_union) {
> > +        v->end_union(v, data_present, errp);
> > +    }
> > +}
> > +
> >  void visit_optional(Visitor *v, bool *present, const char *name,
> >                      Error **errp)
> >  {
> > diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> > index c129697..4520da9 100644
> > --- a/scripts/qapi-visit.py
> > +++ b/scripts/qapi-visit.py
> > @@ -357,6 +357,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
> >          if (err) {
> >              goto out_obj;
> >          }
> > +        if (!visit_start_union(m, !!(*obj)->data, &err)) {
> > +            goto out_obj;
> > +        }
> >          switch ((*obj)->kind) {
> >  ''',
> >                   disc_type = disc_type,
> > @@ -385,6 +388,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
> >  out_obj:
> >          error_propagate(errp, err);
> >          err = NULL;
> > +        visit_end_union(m, !!(*obj)->data, &err);
> > +        error_propagate(errp, err);
> > +        err = NULL;
> >      }
> >      visit_end_struct(m, &err);
> >  out:
> >

  reply	other threads:[~2014-09-12 15:35 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-11 23:20 [Qemu-devel] [PATCH 0/3] qapi: fix crash in dealloc visitor for union types Michael Roth
2014-09-11 23:20 ` [Qemu-devel] [PATCH 1/3] qapi: add visit_start_union and visit_end_union Michael Roth
2014-09-12  2:29   ` Eric Blake
2014-09-12 15:22     ` Michael Roth
2014-09-12 10:17   ` Paolo Bonzini
2014-09-12 15:34     ` Michael Roth [this message]
2014-09-12 15:39       ` Paolo Bonzini
2014-09-12 16:17         ` Michael Roth
2014-09-12 16:29           ` Paolo Bonzini
2014-09-12 18:28             ` Michael Roth
2014-09-11 23:20 ` [Qemu-devel] [PATCH 2/3] qapi: dealloc visitor, implement visit_start_union Michael Roth
2014-09-12  2:34   ` Eric Blake
2014-09-11 23:20 ` [Qemu-devel] [PATCH 3/3] tests: add QMP input visitor test for unions with no discriminator Michael Roth
2014-09-12  3:04 ` [Qemu-devel] [PATCH 4/3] qemu-iotests: Test missing "driver" key for blockdev-add Fam Zheng
2014-09-12  4:17   ` Eric Blake
2014-09-12  3:06 ` [Qemu-devel] [PATCH 0/3] qapi: fix crash in dealloc visitor for union types Fam Zheng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140912153447.19243.81596@loki \
    --to=mdroth@linux.vnet.ibm.com \
    --cc=armbru@redhat.com \
    --cc=famz@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-stable@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).