All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.