qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Amos Kong <akong@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: afaerber@suse.com, qemu-devel@nongnu.org, stefanha@redhat.com
Subject: Re: [Qemu-devel] [PATCH] libqtest: escape strings in QMP commands, fix leak
Date: Wed, 25 Jun 2014 09:06:30 +0800	[thread overview]
Message-ID: <20140625010557.GC21124@z.redhat.com> (raw)
In-Reply-To: <1402647300-27861-1-git-send-email-pbonzini@redhat.com>

On Fri, Jun 13, 2014 at 10:15:00AM +0200, Paolo Bonzini wrote:
> libqtest is using g_strdup_printf to format QMP commands, but
> this does not work if the argument strings need to be escaped.
> Instead, use the fancy %-formatting functionality of QObject.
> The only change required in tests is that strings have to be
> formatted as %s, not '%s' or \"%s\".  Luckily this usage of
> parameterized QMP commands is not that frequent.
> 
> The leak is in socket_sendf.  Since we are extracting the send
> loop to a new function, fix it now.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Amos Kong <akong@redhat.com>

> ---
>  tests/fdc-test.c    |  2 +-
>  tests/libqtest.c    | 47 +++++++++++++++++++++++++++++++++++++----------
>  tests/qom-test.c    |  6 +++---
>  tests/tmp105-test.c |  4 ++--
>  4 files changed, 43 insertions(+), 16 deletions(-)
> 
> diff --git a/tests/fdc-test.c b/tests/fdc-test.c
> index 37096dc..c8e1e7b 100644
> --- a/tests/fdc-test.c
> +++ b/tests/fdc-test.c
> @@ -291,7 +291,7 @@ static void test_media_insert(void)
>      /* Insert media in drive. DSKCHK should not be reset until a step pulse
>       * is sent. */
>      qmp_discard_response("{'execute':'change', 'arguments':{"
> -                         " 'device':'floppy0', 'target': '%s' }}",
> +                         " 'device':'floppy0', 'target': %s }}",
>                           test_image);
>      qmp_discard_response(""); /* ignore event
>                                   (FIXME open -> open transition?!) */
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 71468ac..98e8f4b 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -30,8 +30,9 @@
>  
>  #include "qemu/compiler.h"
>  #include "qemu/osdep.h"
> -#include "qapi/qmp/json-streamer.h"
>  #include "qapi/qmp/json-parser.h"
> +#include "qapi/qmp/json-streamer.h"
> +#include "qapi/qmp/qjson.h"
>  
>  #define MAX_IRQ 256
>  #define SOCKET_TIMEOUT 5
> @@ -220,19 +221,15 @@ void qtest_quit(QTestState *s)
>      g_free(s);
>  }
>  
> -static void socket_sendf(int fd, const char *fmt, va_list ap)
> +static void socket_send(int fd, const char *buf, size_t size)
>  {
> -    gchar *str;
> -    size_t size, offset;
> -
> -    str = g_strdup_vprintf(fmt, ap);
> -    size = strlen(str);
> +    size_t offset;
>  
>      offset = 0;
>      while (offset < size) {
>          ssize_t len;
>  
> -        len = write(fd, str + offset, size - offset);
> +        len = write(fd, buf + offset, size - offset);
>          if (len == -1 && errno == EINTR) {
>              continue;
>          }
> @@ -244,6 +241,15 @@ static void socket_sendf(int fd, const char *fmt, va_list ap)
>      }
>  }
>  
> +static void socket_sendf(int fd, const char *fmt, va_list ap)
> +{
> +    gchar *str = g_strdup_vprintf(fmt, ap);
> +    size_t size = strlen(str);
> +
> +    socket_send(fd, str, size);
> +    g_free(str);
> +}
> +
>  static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
>  {
>      va_list ap;
> @@ -378,8 +384,29 @@ QDict *qtest_qmp_receive(QTestState *s)
>  
>  QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
>  {
> -    /* Send QMP request */
> -    socket_sendf(s->qmp_fd, fmt, ap);
> +    va_list ap_copy;
> +    QObject *qobj;
> +
> +    /* Going through qobject ensures we escape strings properly.
> +     * This seemingly unnecessary copy is required in case va_list
> +     * is an array type.
> +     */
> +    va_copy(ap_copy, ap);
> +    qobj = qobject_from_jsonv(fmt, &ap_copy);
> +    va_end(ap_copy);
> +
> +    /* No need to send anything for an empty QObject.  */
> +    if (qobj) {
> +        QString *qstr = qobject_to_json(qobj);
> +        const char *str = qstring_get_str(qstr);
> +        size_t size = qstring_get_length(qstr);
> +
> +        /* Send QMP request */
> +        socket_send(s->qmp_fd, str, size);
> +
> +        QDECREF(qstr);
> +        qobject_decref(qobj);
> +    }
>  
>      /* Receive reply */
>      return qtest_qmp_receive(s);
> diff --git a/tests/qom-test.c b/tests/qom-test.c
> index d8d1d8d..4246382 100644
> --- a/tests/qom-test.c
> +++ b/tests/qom-test.c
> @@ -53,7 +53,7 @@ static void test_properties(const char *path, bool recurse)
>  
>      g_test_message("Obtaining properties of %s", path);
>      response = qmp("{ 'execute': 'qom-list',"
> -                   "  'arguments': { 'path': '%s' } }", path);
> +                   "  'arguments': { 'path': %s } }", path);
>      g_assert(response);
>  
>      if (!recurse) {
> @@ -76,8 +76,8 @@ static void test_properties(const char *path, bool recurse)
>              const char *prop = qdict_get_str(tuple, "name");
>              g_test_message("Testing property %s.%s", path, prop);
>              response = qmp("{ 'execute': 'qom-get',"
> -                           "  'arguments': { 'path': '%s',"
> -                           "                 'property': '%s' } }",
> +                           "  'arguments': { 'path': %s,"
> +                           "                 'property': %s } }",
>                             path, prop);
>              /* qom-get may fail but should not, e.g., segfault. */
>              g_assert(response);
> diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
> index 15ddaf3..99db538 100644
> --- a/tests/tmp105-test.c
> +++ b/tests/tmp105-test.c
> @@ -69,7 +69,7 @@ static int qmp_tmp105_get_temperature(const char *id)
>      QDict *response;
>      int ret;
>  
> -    response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': '%s', "
> +    response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
>                     "'property': 'temperature' } }", id);
>      g_assert(qdict_haskey(response, "return"));
>      ret = qdict_get_int(response, "return");
> @@ -81,7 +81,7 @@ static void qmp_tmp105_set_temperature(const char *id, int value)
>  {
>      QDict *response;
>  
> -    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': '%s', "
> +    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
>                     "'property': 'temperature', 'value': %d } }", id, value);
>      g_assert(qdict_haskey(response, "return"));
>      QDECREF(response);
> -- 
> 1.8.3.1
> 

-- 
			Amos.

      parent reply	other threads:[~2014-06-25  1:06 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-13  8:15 [Qemu-devel] [PATCH] libqtest: escape strings in QMP commands, fix leak Paolo Bonzini
2014-06-18  4:06 ` Stefan Hajnoczi
2014-06-18  7:41 ` Amos Kong
2014-06-18  9:56   ` Paolo Bonzini
2014-06-25  1:06 ` Amos Kong [this message]

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=20140625010557.GC21124@z.redhat.com \
    --to=akong@redhat.com \
    --cc=afaerber@suse.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /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).