diff mbox

spapr-vty: Fix bad assert() statement

Message ID 1478768797-26401-1-git-send-email-thuth@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Huth Nov. 10, 2016, 9:06 a.m. UTC
When using the serial console in the GTK interface of QEMU (and
QEMU has been compiled with CONFIG_VTE), it is possible to trigger
the assert() statement in vty_receive() in spapr_vty.c by pasting
a chunk of text with length > 16 into the QEMU window.
Most of the other serial backends seem to simply drop characters
that they can not handle, so I think we should also do the same in
spapr-vty to fix this issue. And since it is quite ugly when pasted
text is chopped after 16 bytes, we also increase the size of the
input buffer here so that we can at least handle a couple of text
lines.

Buglink: https://bugs.launchpad.net/qemu/+bug/1639322
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/char/spapr_vty.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

Comments

Paolo Bonzini Nov. 10, 2016, 2:41 p.m. UTC | #1
On 10/11/2016 10:06, Thomas Huth wrote:
> When using the serial console in the GTK interface of QEMU (and
> QEMU has been compiled with CONFIG_VTE), it is possible to trigger
> the assert() statement in vty_receive() in spapr_vty.c by pasting
> a chunk of text with length > 16 into the QEMU window.
> Most of the other serial backends seem to simply drop characters
> that they can not handle, so I think we should also do the same in
> spapr-vty to fix this issue. And since it is quite ugly when pasted
> text is chopped after 16 bytes, we also increase the size of the
> input buffer here so that we can at least handle a couple of text
> lines.
> 
> Buglink: https://bugs.launchpad.net/qemu/+bug/1639322
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  hw/char/spapr_vty.c | 13 +++++++++++--
>  1 file changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
> index 31822fe..bee6c34 100644
> --- a/hw/char/spapr_vty.c
> +++ b/hw/char/spapr_vty.c
> @@ -1,4 +1,5 @@
>  #include "qemu/osdep.h"
> +#include "qemu/error-report.h"
>  #include "qapi/error.h"
>  #include "qemu-common.h"
>  #include "cpu.h"
> @@ -7,7 +8,7 @@
>  #include "hw/ppc/spapr.h"
>  #include "hw/ppc/spapr_vio.h"
>  
> -#define VTERM_BUFSIZE   16
> +#define VTERM_BUFSIZE   2048

This change causes a change in the migration protocol.

Paolo

>  
>  typedef struct VIOsPAPRVTYDevice {
>      VIOsPAPRDevice sdev;
> @@ -37,7 +38,15 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
>          qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
>      }
>      for (i = 0; i < size; i++) {
> -        assert((dev->in - dev->out) < VTERM_BUFSIZE);
> +        if (dev->in - dev->out >= VTERM_BUFSIZE) {
> +            static bool reported;
> +            if (!reported) {
> +                error_report("VTY input buffer exhausted - characters dropped."
> +                             " (input size = %i)", size);
> +                reported = true;
> +            }
> +            break;
> +        }
>          dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
>      }
>  }
>
Thomas Huth Nov. 10, 2016, 5:41 p.m. UTC | #2
On 10.11.2016 15:41, Paolo Bonzini wrote:
> 
> 
> On 10/11/2016 10:06, Thomas Huth wrote:
>> When using the serial console in the GTK interface of QEMU (and
>> QEMU has been compiled with CONFIG_VTE), it is possible to trigger
>> the assert() statement in vty_receive() in spapr_vty.c by pasting
>> a chunk of text with length > 16 into the QEMU window.
>> Most of the other serial backends seem to simply drop characters
>> that they can not handle, so I think we should also do the same in
>> spapr-vty to fix this issue. And since it is quite ugly when pasted
>> text is chopped after 16 bytes, we also increase the size of the
>> input buffer here so that we can at least handle a couple of text
>> lines.
>>
>> Buglink: https://bugs.launchpad.net/qemu/+bug/1639322
>> Signed-off-by: Thomas Huth <thuth@redhat.com>
>> ---
>>  hw/char/spapr_vty.c | 13 +++++++++++--
>>  1 file changed, 11 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
>> index 31822fe..bee6c34 100644
>> --- a/hw/char/spapr_vty.c
>> +++ b/hw/char/spapr_vty.c
>> @@ -1,4 +1,5 @@
>>  #include "qemu/osdep.h"
>> +#include "qemu/error-report.h"
>>  #include "qapi/error.h"
>>  #include "qemu-common.h"
>>  #include "cpu.h"
>> @@ -7,7 +8,7 @@
>>  #include "hw/ppc/spapr.h"
>>  #include "hw/ppc/spapr_vio.h"
>>  
>> -#define VTERM_BUFSIZE   16
>> +#define VTERM_BUFSIZE   2048
> 
> This change causes a change in the migration protocol.

Bummer! You're right, the buffer is listed in the vmstate_spapr_vty
description ... so please ignore this patch, I've got to think about a
better solution here...

 Thomas
Paolo Bonzini Nov. 10, 2016, 5:42 p.m. UTC | #3
On 10/11/2016 18:41, Thomas Huth wrote:
> On 10.11.2016 15:41, Paolo Bonzini wrote:
>>
>>
>> On 10/11/2016 10:06, Thomas Huth wrote:
>>> When using the serial console in the GTK interface of QEMU (and
>>> QEMU has been compiled with CONFIG_VTE), it is possible to trigger
>>> the assert() statement in vty_receive() in spapr_vty.c by pasting
>>> a chunk of text with length > 16 into the QEMU window.
>>> Most of the other serial backends seem to simply drop characters
>>> that they can not handle, so I think we should also do the same in
>>> spapr-vty to fix this issue. And since it is quite ugly when pasted
>>> text is chopped after 16 bytes, we also increase the size of the
>>> input buffer here so that we can at least handle a couple of text
>>> lines.
>>>
>>> Buglink: https://bugs.launchpad.net/qemu/+bug/1639322
>>> Signed-off-by: Thomas Huth <thuth@redhat.com>
>>> ---
>>>  hw/char/spapr_vty.c | 13 +++++++++++--
>>>  1 file changed, 11 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
>>> index 31822fe..bee6c34 100644
>>> --- a/hw/char/spapr_vty.c
>>> +++ b/hw/char/spapr_vty.c
>>> @@ -1,4 +1,5 @@
>>>  #include "qemu/osdep.h"
>>> +#include "qemu/error-report.h"
>>>  #include "qapi/error.h"
>>>  #include "qemu-common.h"
>>>  #include "cpu.h"
>>> @@ -7,7 +8,7 @@
>>>  #include "hw/ppc/spapr.h"
>>>  #include "hw/ppc/spapr_vio.h"
>>>  
>>> -#define VTERM_BUFSIZE   16
>>> +#define VTERM_BUFSIZE   2048
>>
>> This change causes a change in the migration protocol.
> 
> Bummer! You're right, the buffer is listed in the vmstate_spapr_vty
> description ... so please ignore this patch, I've got to think about a
> better solution here...

Well, the assert change is still good and should be in 2.8.

Paolo
David Gibson Nov. 10, 2016, 11:01 p.m. UTC | #4
On Thu, Nov 10, 2016 at 10:06:37AM +0100, Thomas Huth wrote:
> When using the serial console in the GTK interface of QEMU (and
> QEMU has been compiled with CONFIG_VTE), it is possible to trigger
> the assert() statement in vty_receive() in spapr_vty.c by pasting
> a chunk of text with length > 16 into the QEMU window.
> Most of the other serial backends seem to simply drop characters
> that they can not handle, so I think we should also do the same in
> spapr-vty to fix this issue. And since it is quite ugly when pasted
> text is chopped after 16 bytes, we also increase the size of the
> input buffer here so that we can at least handle a couple of text
> lines.

Adding Paolo to CC, as qemu-char maintainer.

So, vastly increasing the buffer like this doesn't seem right - the
plain 16550 serial driver doesn't maintain a buffer bigger than its
small internal FIFO (32 characters IIRC) - or a single byte if the
FIFO is disabled.

I thought the other side of the char driver was supposed to call
can_receive() first and not deliver more bytes than we can handle -
hence the assert.

That said, I think vty_can_receive() has a bug - looking at other
drivers, I think it's supposed to return the amount of buffer space
available, but we're just returning 0 or 1.  Although AFAICT that
should still work, just inefficiently.

If you use a serial port with the same GTK interface, do you get the
same problem with pastes of >16 characters being truncated?

> 
> Buglink: https://bugs.launchpad.net/qemu/+bug/1639322
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  hw/char/spapr_vty.c | 13 +++++++++++--
>  1 file changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
> index 31822fe..bee6c34 100644
> --- a/hw/char/spapr_vty.c
> +++ b/hw/char/spapr_vty.c
> @@ -1,4 +1,5 @@
>  #include "qemu/osdep.h"
> +#include "qemu/error-report.h"
>  #include "qapi/error.h"
>  #include "qemu-common.h"
>  #include "cpu.h"
> @@ -7,7 +8,7 @@
>  #include "hw/ppc/spapr.h"
>  #include "hw/ppc/spapr_vio.h"
>  
> -#define VTERM_BUFSIZE   16
> +#define VTERM_BUFSIZE   2048
>  
>  typedef struct VIOsPAPRVTYDevice {
>      VIOsPAPRDevice sdev;
> @@ -37,7 +38,15 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
>          qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
>      }
>      for (i = 0; i < size; i++) {
> -        assert((dev->in - dev->out) < VTERM_BUFSIZE);
> +        if (dev->in - dev->out >= VTERM_BUFSIZE) {
> +            static bool reported;
> +            if (!reported) {
> +                error_report("VTY input buffer exhausted - characters dropped."
> +                             " (input size = %i)", size);
> +                reported = true;
> +            }
> +            break;
> +        }
>          dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
>      }
>  }
Thomas Huth Nov. 11, 2016, 8:13 a.m. UTC | #5
On 11.11.2016 00:01, David Gibson wrote:
> On Thu, Nov 10, 2016 at 10:06:37AM +0100, Thomas Huth wrote:
>> When using the serial console in the GTK interface of QEMU (and
>> QEMU has been compiled with CONFIG_VTE), it is possible to trigger
>> the assert() statement in vty_receive() in spapr_vty.c by pasting
>> a chunk of text with length > 16 into the QEMU window.
>> Most of the other serial backends seem to simply drop characters
>> that they can not handle, so I think we should also do the same in
>> spapr-vty to fix this issue. And since it is quite ugly when pasted
>> text is chopped after 16 bytes, we also increase the size of the
>> input buffer here so that we can at least handle a couple of text
>> lines.
> 
> Adding Paolo to CC, as qemu-char maintainer.
> 
> So, vastly increasing the buffer like this doesn't seem right - the
> plain 16550 serial driver doesn't maintain a buffer bigger than its
> small internal FIFO (32 characters IIRC) - or a single byte if the
> FIFO is disabled.
> 
> I thought the other side of the char driver was supposed to call
> can_receive() first and not deliver more bytes than we can handle -
> hence the assert.

Right. The real bug seems to be on the front end side:

gd_vc_in() in ui/gtk.c calls qemu_chr_be_write() without checking the
qemu_chr_be_can_write() first (which internally calls the can_receive()
function of the backend).

So we likely need to fix gd_vc_in() to use qemu_chr_be_can_write()
instead ... but I'm currently puzzled whether that can be done at all,
since this seems to be a callback function - and we likely can not
simply loop/yield here, can we?

> That said, I think vty_can_receive() has a bug - looking at other
> drivers, I think it's supposed to return the amount of buffer space
> available, but we're just returning 0 or 1.  Although AFAICT that
> should still work, just inefficiently.

Right, it should return the amount of free space instead.

> If you use a serial port with the same GTK interface, do you get the
> same problem with pastes of >16 characters being truncated?

Yes, I tried the coldfire image from
http://wiki.qemu.org/download/coldfire-test-0.1.tar.bz2 and that even
only accepts 1 byte when doing the copy-n-paste and drops everything
else. So copy-n-paste is currently completely broken there, too.

 Thomas

>> Buglink: https://bugs.launchpad.net/qemu/+bug/1639322
Paolo Bonzini Nov. 11, 2016, 10:40 a.m. UTC | #6
----- Original Message -----
> From: "Thomas Huth" <thuth@redhat.com>
> To: "David Gibson" <david@gibson.dropbear.id.au>
> Cc: qemu-ppc@nongnu.org, "Alexander Graf" <agraf@suse.de>, qemu-devel@nongnu.org, pbonzini@redhat.com, "Gerd
> Hoffmann" <kraxel@redhat.com>
> Sent: Friday, November 11, 2016 9:13:00 AM
> Subject: Re: [PATCH] spapr-vty: Fix bad assert() statement
> 
> On 11.11.2016 00:01, David Gibson wrote:
> > So, vastly increasing the buffer like this doesn't seem right - the
> > plain 16550 serial driver doesn't maintain a buffer bigger than its
> > small internal FIFO (32 characters IIRC) - or a single byte if the
> > FIFO is disabled.
> > 
> > I thought the other side of the char driver was supposed to call
> > can_receive() first and not deliver more bytes than we can handle -
> > hence the assert.
> 
> Right. The real bug seems to be on the front end side:
> 
> gd_vc_in() in ui/gtk.c calls qemu_chr_be_write() without checking the
> qemu_chr_be_can_write() first (which internally calls the can_receive()
> function of the backend).
> 
> So we likely need to fix gd_vc_in() to use qemu_chr_be_can_write()
> instead ... but I'm currently puzzled whether that can be done at all,
> since this seems to be a callback function - and we likely can not
> simply loop/yield here, can we?

You'd have to use a buffer in the GTK+ backend, in order to have
working cut and paste.  But at least using qemu_chr_be_can_write,
and limiting the size of the written data to the return value,
would fix the assertion.

> > That said, I think vty_can_receive() has a bug - looking at other
> > drivers, I think it's supposed to return the amount of buffer space
> > available, but we're just returning 0 or 1.  Although AFAICT that
> > should still work, just inefficiently.
> 
> Right, it should return the amount of free space instead.

Yes.

Paolo
diff mbox

Patch

diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 31822fe..bee6c34 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -1,4 +1,5 @@ 
 #include "qemu/osdep.h"
+#include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
 #include "cpu.h"
@@ -7,7 +8,7 @@ 
 #include "hw/ppc/spapr.h"
 #include "hw/ppc/spapr_vio.h"
 
-#define VTERM_BUFSIZE   16
+#define VTERM_BUFSIZE   2048
 
 typedef struct VIOsPAPRVTYDevice {
     VIOsPAPRDevice sdev;
@@ -37,7 +38,15 @@  static void vty_receive(void *opaque, const uint8_t *buf, int size)
         qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
     }
     for (i = 0; i < size; i++) {
-        assert((dev->in - dev->out) < VTERM_BUFSIZE);
+        if (dev->in - dev->out >= VTERM_BUFSIZE) {
+            static bool reported;
+            if (!reported) {
+                error_report("VTY input buffer exhausted - characters dropped."
+                             " (input size = %i)", size);
+                reported = true;
+            }
+            break;
+        }
         dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
     }
 }