All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
@ 2019-02-26 23:03 Julien Grall
  2019-02-27 10:25 ` Jan Beulich
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Julien Grall @ 2019-02-26 23:03 UTC (permalink / raw)
  To: xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Julien Grall, Jan Beulich

After upgrading Debian to Buster, I started noticing console mangling
when using zsh. This is happenning because output sent by zsh to the
console may contain NUL character in the middle of the buffer.

Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
However, the implementation in Xen considers NUL character is used to
terminate the buffer and therefore will ignore anything after it.

The actual documentation of CONSOLEIO_write is pretty limited. From the
declaration, the hypercall takes a buffer and size. So this could lead
to think the NUL character is allowed in the middle of the buffer.

This patch updates the console API to pass the size along the buffer
down so we can remove the reliance on buffer terminating by a NUL
character.

Signed-off-by: Julien Grall <julien.grall@arm.com>

---

This is an early RFC to start getting feedback on the issue and raise
awareness on the problem.

This patch is candidate for Xen 4.12. Without it zsh output gets mangled
when using the upcoming Debian Buster. A workaround is to add in your
.zshrc:

setopt single_line_zle

For the longer bits, it looks like zsh is now adding NUL characters in
the middle of the output sent onto the console. Below an easy way to
repro it the bug on Xen:

int main(void)
{
    write(1,
          "\r\33[0m\0\0\0\0\0\0\0\0\33[27m\33[24m\33[j\33[32mjulien\33[31m@\33[00m\33[36mjuno2-julieng:~\33[37m>",
          75);
    write(1,
          "\33[K\33[32C\33[01;33m--juno2-julieng-13:44--\33[00m\33[37m\33[55D",
          54);
    write(1, "\33[?2004h", 8);

    return 0;
}

Without this patch, the only --juno2-julieng-13:44-- will be printed in
yellow.

This patch was tested on Arm using serial console. I am not entirely
whether the video and PV console is correct. I would appreciate help for
testing here.

TODO: Actually document CONSOLEIO_write in the public header.

---
 xen/arch/arm/early_printk.c       | 14 +++++++++-----
 xen/drivers/char/console.c        | 37 +++++++++++++++++++------------------
 xen/drivers/char/consoled.c       |  4 ++--
 xen/drivers/char/serial.c         |  8 +++++---
 xen/drivers/char/xen_pv_console.c | 10 +++++-----
 xen/drivers/video/lfb.c           | 14 ++++++++------
 xen/drivers/video/lfb.h           |  4 ++--
 xen/drivers/video/vga.c           | 14 ++++++++------
 xen/include/xen/console.h         |  2 +-
 xen/include/xen/early_printk.h    |  2 +-
 xen/include/xen/pv_console.h      |  4 ++--
 xen/include/xen/serial.h          |  4 ++--
 xen/include/xen/video.h           |  4 ++--
 13 files changed, 66 insertions(+), 55 deletions(-)

diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c
index 97466a12b1..dd2e9fb46f 100644
--- a/xen/arch/arm/early_printk.c
+++ b/xen/arch/arm/early_printk.c
@@ -17,13 +17,17 @@
 void early_putch(char c);
 void early_flush(void);
 
-void early_puts(const char *s)
+void early_puts(const char *s, unsigned int nr)
 {
-    while (*s != '\0') {
-        if (*s == '\n')
+    unsigned int i;
+
+    for ( i = 0; i < nr; i++ )
+    {
+        char c = *s;
+
+        if (c == '\n')
             early_putch('\r');
-        early_putch(*s);
-        s++;
+        early_putch(c);
     }
 
     /*
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 4315588f05..cce1211a0c 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -325,9 +325,9 @@ long read_console_ring(struct xen_sysctl_readconsole *op)
 static char serial_rx_ring[SERIAL_RX_SIZE];
 static unsigned int serial_rx_cons, serial_rx_prod;
 
-static void (*serial_steal_fn)(const char *) = early_puts;
+static void (*serial_steal_fn)(const char *, unsigned int nr) = early_puts;
 
-int console_steal(int handle, void (*fn)(const char *))
+int console_steal(int handle, void (*fn)(const char *, unsigned int nr))
 {
     if ( (handle == -1) || (handle != sercon_handle) )
         return 0;
@@ -345,15 +345,15 @@ void console_giveback(int id)
         serial_steal_fn = NULL;
 }
 
-static void sercon_puts(const char *s)
+static void sercon_puts(const char *s, unsigned int nr)
 {
     if ( serial_steal_fn != NULL )
-        (*serial_steal_fn)(s);
+        (*serial_steal_fn)(s, nr);
     else
-        serial_puts(sercon_handle, s);
+        serial_puts(sercon_handle, s, nr);
 
     /* Copy all serial output into PV console */
-    pv_console_puts(s);
+    pv_console_puts(s, nr);
 }
 
 static void dump_console_ring_key(unsigned char key)
@@ -388,8 +388,8 @@ static void dump_console_ring_key(unsigned char key)
     }
     buf[sofar] = '\0';
 
-    sercon_puts(buf);
-    video_puts(buf);
+    sercon_puts(buf, sofar);
+    video_puts(buf, sofar);
 
     free_xenheap_pages(buf, order);
 }
@@ -527,7 +527,7 @@ static inline void xen_console_write_debug_port(const char *buf, size_t len)
 static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
 {
     char kbuf[128];
-    int kcount = 0;
+    unsigned int kcount = 0;
     struct domain *cd = current->domain;
 
     while ( count > 0 )
@@ -547,8 +547,8 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
             /* Use direct console output as it could be interactive */
             spin_lock_irq(&console_lock);
 
-            sercon_puts(kbuf);
-            video_puts(kbuf);
+            sercon_puts(kbuf, kcount);
+            video_puts(kbuf, kcount);
 
 #ifdef CONFIG_X86
             if ( opt_console_xen )
@@ -666,16 +666,16 @@ static bool_t console_locks_busted;
 
 static void __putstr(const char *str)
 {
+    size_t len = strlen(str);
+
     ASSERT(spin_is_locked(&console_lock));
 
-    sercon_puts(str);
-    video_puts(str);
+    sercon_puts(str, len);
+    video_puts(str, len);
 
 #ifdef CONFIG_X86
     if ( opt_console_xen )
     {
-        size_t len = strlen(str);
-
         if ( xen_guest )
             xen_hypercall_console_write(str, len);
         else
@@ -1233,6 +1233,7 @@ void debugtrace_printk(const char *fmt, ...)
     va_list       args;
     char         *p;
     unsigned long flags;
+    unsigned int nr;
 
     if ( debugtrace_bytes == 0 )
         return;
@@ -1246,12 +1247,12 @@ void debugtrace_printk(const char *fmt, ...)
     snprintf(buf, sizeof(buf), "%u ", ++count);
 
     va_start(args, fmt);
-    (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, args);
+    nr = vscnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, args);
     va_end(args);
 
     if ( debugtrace_send_to_console )
     {
-        serial_puts(sercon_handle, buf);
+        serial_puts(sercon_handle, buf, nr);
     }
     else
     {
@@ -1357,7 +1358,7 @@ void panic(const char *fmt, ...)
  * **************************************************************
  */
 
-static void suspend_steal_fn(const char *str) { }
+static void suspend_steal_fn(const char *str, unsigned int nr) { }
 static int suspend_steal_id;
 
 int console_suspend(void)
diff --git a/xen/drivers/char/consoled.c b/xen/drivers/char/consoled.c
index 552abf5766..3e849a2557 100644
--- a/xen/drivers/char/consoled.c
+++ b/xen/drivers/char/consoled.c
@@ -77,7 +77,7 @@ size_t consoled_guest_rx(void)
 
         if ( idx >= BUF_SZ )
         {
-            pv_console_puts(buf);
+            pv_console_puts(buf, BUF_SZ);
             idx = 0;
         }
     }
@@ -85,7 +85,7 @@ size_t consoled_guest_rx(void)
     if ( idx )
     {
         buf[idx] = '\0';
-        pv_console_puts(buf);
+        pv_console_puts(buf, idx);
     }
 
     /* No need for a mem barrier because every character was already consumed */
diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
index 221a14c092..7498299807 100644
--- a/xen/drivers/char/serial.c
+++ b/xen/drivers/char/serial.c
@@ -223,11 +223,11 @@ void serial_putc(int handle, char c)
     spin_unlock_irqrestore(&port->tx_lock, flags);
 }
 
-void serial_puts(int handle, const char *s)
+void serial_puts(int handle, const char *s, unsigned int nr)
 {
     struct serial_port *port;
     unsigned long flags;
-    char c;
+    unsigned int i;
 
     if ( handle == -1 )
         return;
@@ -238,8 +238,10 @@ void serial_puts(int handle, const char *s)
 
     spin_lock_irqsave(&port->tx_lock, flags);
 
-    while ( (c = *s++) != '\0' )
+    for ( i = 0; i < nr; i++ )
     {
+        char c = s[i];
+
         if ( (c == '\n') && (handle & SERHND_COOKED) )
             __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
 
diff --git a/xen/drivers/char/xen_pv_console.c b/xen/drivers/char/xen_pv_console.c
index cc1c1d743f..5bb303d4c8 100644
--- a/xen/drivers/char/xen_pv_console.c
+++ b/xen/drivers/char/xen_pv_console.c
@@ -129,13 +129,13 @@ size_t pv_console_rx(struct cpu_user_regs *regs)
     return recv;
 }
 
-static size_t pv_ring_puts(const char *buf)
+static size_t pv_ring_puts(const char *buf, unsigned int nr)
 {
     XENCONS_RING_IDX cons, prod;
     size_t sent = 0, avail;
     bool put_r = false;
 
-    while ( buf[sent] != '\0' || put_r )
+    while ( sent < nr || put_r )
     {
         cons = ACCESS_ONCE(cons_ring->out_cons);
         prod = cons_ring->out_prod;
@@ -156,7 +156,7 @@ static size_t pv_ring_puts(const char *buf)
             continue;
         }
 
-        while ( avail && (buf[sent] != '\0' || put_r) )
+        while ( avail && (sent < nr || put_r) )
         {
             if ( put_r )
             {
@@ -185,7 +185,7 @@ static size_t pv_ring_puts(const char *buf)
     return sent;
 }
 
-void pv_console_puts(const char *buf)
+void pv_console_puts(const char *buf, unsigned int nr)
 {
     unsigned long flags;
 
@@ -193,7 +193,7 @@ void pv_console_puts(const char *buf)
         return;
 
     spin_lock_irqsave(&tx_lock, flags);
-    pv_ring_puts(buf);
+    pv_ring_puts(buf, nr);
     spin_unlock_irqrestore(&tx_lock, flags);
 }
 
diff --git a/xen/drivers/video/lfb.c b/xen/drivers/video/lfb.c
index d0c8c492b0..93b6a33a41 100644
--- a/xen/drivers/video/lfb.c
+++ b/xen/drivers/video/lfb.c
@@ -59,14 +59,15 @@ static void lfb_show_line(
 }
 
 /* Fast mode which redraws all modified parts of a 2D text buffer. */
-void lfb_redraw_puts(const char *s)
+void lfb_redraw_puts(const char *s, unsigned int nr)
 {
     unsigned int i, min_redraw_y = lfb.ypos;
-    char c;
 
     /* Paste characters into text buffer. */
-    while ( (c = *s++) != '\0' )
+    for ( i = 0; i < nr; i++ )
     {
+        char c = s[i];
+
         if ( (c == '\n') || (lfb.xpos >= lfb.lfbp.text_columns) )
         {
             if ( ++lfb.ypos >= lfb.lfbp.text_rows )
@@ -103,13 +104,14 @@ void lfb_redraw_puts(const char *s)
 }
 
 /* Slower line-based scroll mode which interacts better with dom0. */
-void lfb_scroll_puts(const char *s)
+void lfb_scroll_puts(const char *s, unsigned int nr)
 {
     unsigned int i;
-    char c;
 
-    while ( (c = *s++) != '\0' )
+    for ( i = 0; i < nr; i++ )
     {
+        char c = s[i];
+
         if ( (c == '\n') || (lfb.xpos >= lfb.lfbp.text_columns) )
         {
             unsigned int bytes = (lfb.lfbp.width *
diff --git a/xen/drivers/video/lfb.h b/xen/drivers/video/lfb.h
index ac40a66379..15599e22ef 100644
--- a/xen/drivers/video/lfb.h
+++ b/xen/drivers/video/lfb.h
@@ -35,8 +35,8 @@ struct lfb_prop {
     unsigned int text_rows;
 };
 
-void lfb_redraw_puts(const char *s);
-void lfb_scroll_puts(const char *s);
+void lfb_redraw_puts(const char *s, unsigned int nr);
+void lfb_scroll_puts(const char *s, unsigned int nr);
 void lfb_carriage_return(void);
 void lfb_free(void);
 
diff --git a/xen/drivers/video/vga.c b/xen/drivers/video/vga.c
index 6a64fd9013..01f12aae42 100644
--- a/xen/drivers/video/vga.c
+++ b/xen/drivers/video/vga.c
@@ -18,9 +18,9 @@ static int vgacon_keep;
 static unsigned int xpos, ypos;
 static unsigned char *video;
 
-static void vga_text_puts(const char *s);
-static void vga_noop_puts(const char *s) {}
-void (*video_puts)(const char *) = vga_noop_puts;
+static void vga_text_puts(const char *s, unsigned int nr);
+static void vga_noop_puts(const char *s, unsigned int nr) {}
+void (*video_puts)(const char *, unsigned int nr) = vga_noop_puts;
 
 /*
  * 'vga=<mode-specifier>[,keep]' where <mode-specifier> is one of:
@@ -177,12 +177,14 @@ void __init video_endboot(void)
     }
 }
 
-static void vga_text_puts(const char *s)
+static void vga_text_puts(const char *s, unsigned int nr)
 {
-    char c;
+    unsigned int i;
 
-    while ( (c = *s++) != '\0' )
+    for ( i = 0; i < nr; i++ )
     {
+        char c = s[i];
+
         if ( (c == '\n') || (xpos >= columns) )
         {
             if ( ++ypos >= lines )
diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
index b4f9463936..dafa53ba6b 100644
--- a/xen/include/xen/console.h
+++ b/xen/include/xen/console.h
@@ -38,7 +38,7 @@ struct domain *console_input_domain(void);
  * Steal output from the console. Returns +ve identifier, else -ve error.
  * Takes the handle of the serial line to steal, and steal callback function.
  */
-int console_steal(int handle, void (*fn)(const char *));
+int console_steal(int handle, void (*fn)(const char *, unsigned int nr));
 
 /* Give back stolen console. Takes the identifier returned by console_steal. */
 void console_giveback(int id);
diff --git a/xen/include/xen/early_printk.h b/xen/include/xen/early_printk.h
index 2c3e1b3519..22f8009a5f 100644
--- a/xen/include/xen/early_printk.h
+++ b/xen/include/xen/early_printk.h
@@ -5,7 +5,7 @@
 #define __XEN_EARLY_PRINTK_H__
 
 #ifdef CONFIG_EARLY_PRINTK
-void early_puts(const char *s);
+void early_puts(const char *s, unsigned int nr);
 #else
 #define early_puts NULL
 #endif
diff --git a/xen/include/xen/pv_console.h b/xen/include/xen/pv_console.h
index cb92539666..41144890e4 100644
--- a/xen/include/xen/pv_console.h
+++ b/xen/include/xen/pv_console.h
@@ -8,7 +8,7 @@
 void pv_console_init(void);
 void pv_console_set_rx_handler(serial_rx_fn fn);
 void pv_console_init_postirq(void);
-void pv_console_puts(const char *buf);
+void pv_console_puts(const char *buf, unsigned int nr);
 size_t pv_console_rx(struct cpu_user_regs *regs);
 evtchn_port_t pv_console_evtchn(void);
 
@@ -17,7 +17,7 @@ evtchn_port_t pv_console_evtchn(void);
 static inline void pv_console_init(void) {}
 static inline void pv_console_set_rx_handler(serial_rx_fn fn) { }
 static inline void pv_console_init_postirq(void) { }
-static inline void pv_console_puts(const char *buf) { }
+static inline void pv_console_puts(const char *buf, unsigned int nr) { }
 static inline size_t pv_console_rx(struct cpu_user_regs *regs) { return 0; }
 evtchn_port_t pv_console_evtchn(void)
 {
diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h
index f2994d4093..e11d6d3ebc 100644
--- a/xen/include/xen/serial.h
+++ b/xen/include/xen/serial.h
@@ -114,8 +114,8 @@ int serial_parse_handle(char *conf);
 /* Transmit a single character via the specified COM port. */
 void serial_putc(int handle, char c);
 
-/* Transmit a NULL-terminated string via the specified COM port. */
-void serial_puts(int handle, const char *s);
+/* Transmit a string via the specified COM port. */
+void serial_puts(int handle, const char *s, unsigned int nr);
 
 /*
  * An alternative to registering a character-receive hook. This function
diff --git a/xen/include/xen/video.h b/xen/include/xen/video.h
index 2e897f9df5..ddd21f374d 100644
--- a/xen/include/xen/video.h
+++ b/xen/include/xen/video.h
@@ -13,11 +13,11 @@
 
 #ifdef CONFIG_VIDEO
 void video_init(void);
-extern void (*video_puts)(const char *);
+extern void (*video_puts)(const char *, unsigned int nr);
 void video_endboot(void);
 #else
 #define video_init()    ((void)0)
-#define video_puts(s)   ((void)0)
+#define video_puts(s, nr)   ((void)0)
 #define video_endboot() ((void)0)
 #endif
 
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-26 23:03 [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write Julien Grall
@ 2019-02-27 10:25 ` Jan Beulich
  2019-02-27 10:42   ` Julien Grall
  2019-02-27 12:55   ` Wei Liu
  2019-02-27 10:45 ` Julien Grall
  2019-02-27 12:55 ` Wei Liu
  2 siblings, 2 replies; 17+ messages in thread
From: Jan Beulich @ 2019-02-27 10:25 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan, xen-devel

>>> On 27.02.19 at 00:03, <julien.grall@arm.com> wrote:
> After upgrading Debian to Buster, I started noticing console mangling
> when using zsh. This is happenning because output sent by zsh to the
> console may contain NUL character in the middle of the buffer.
> 
> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
> However, the implementation in Xen considers NUL character is used to
> terminate the buffer and therefore will ignore anything after it.
> 
> The actual documentation of CONSOLEIO_write is pretty limited. From the
> declaration, the hypercall takes a buffer and size. So this could lead
> to think the NUL character is allowed in the middle of the buffer.
> 
> This patch updates the console API to pass the size along the buffer
> down so we can remove the reliance on buffer terminating by a NUL
> character.

We don't need the behavior for internal producers, so I think the change
touches way too much code. I think all you need to do is make the
hypercall handler sense null characters, and perhaps simply invoke lower
level handlers multiple times. Or replace them by something else (e.g. a
blank).

Jan



_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-27 10:25 ` Jan Beulich
@ 2019-02-27 10:42   ` Julien Grall
  2019-02-27 12:55   ` Wei Liu
  1 sibling, 0 replies; 17+ messages in thread
From: Julien Grall @ 2019-02-27 10:42 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan, xen-devel

Hi,

On 2/27/19 10:25 AM, Jan Beulich wrote:
>>>> On 27.02.19 at 00:03, <julien.grall@arm.com> wrote:
>> After upgrading Debian to Buster, I started noticing console mangling
>> when using zsh. This is happenning because output sent by zsh to the
>> console may contain NUL character in the middle of the buffer.
>>
>> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
>> However, the implementation in Xen considers NUL character is used to
>> terminate the buffer and therefore will ignore anything after it.
>>
>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>> declaration, the hypercall takes a buffer and size. So this could lead
>> to think the NUL character is allowed in the middle of the buffer.
>>
>> This patch updates the console API to pass the size along the buffer
>> down so we can remove the reliance on buffer terminating by a NUL
>> character.
> 
> We don't need the behavior for internal producers, so I think the change
> touches way too much code. I think all you need to do is make the
> hypercall handler sense null characters, and perhaps simply invoke lower
> level handlers multiple times. Or replace them by something else (e.g. a
> blank).

I have to disagree here. If the OS decides to pass a buffer containing 
NUL character, then we should honor it and send the NUL character to the 
serial. Otherwise you may have a different behavior when running on 
baremetal and on Xen. One case I have in mind is debugging over HVC console.

So we need to modify the console API for handling this purpose. Yes, it 
will allow the internal producers to put NUL character in it. But that's 
not a real issue by itself.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-26 23:03 [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write Julien Grall
  2019-02-27 10:25 ` Jan Beulich
@ 2019-02-27 10:45 ` Julien Grall
  2019-03-05 12:57   ` Juergen Gross
  2019-02-27 12:55 ` Wei Liu
  2 siblings, 1 reply; 17+ messages in thread
From: Julien Grall @ 2019-02-27 10:45 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Stefano Stabellini, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Jan Beulich

(+ Juergen Gross as RM)

I forgot to CC Juergen for this.

On 2/26/19 11:03 PM, Julien Grall wrote:
> After upgrading Debian to Buster, I started noticing console mangling
> when using zsh. This is happenning because output sent by zsh to the
> console may contain NUL character in the middle of the buffer.
> 
> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
> However, the implementation in Xen considers NUL character is used to
> terminate the buffer and therefore will ignore anything after it.
> 
> The actual documentation of CONSOLEIO_write is pretty limited. From the
> declaration, the hypercall takes a buffer and size. So this could lead
> to think the NUL character is allowed in the middle of the buffer.
> 
> This patch updates the console API to pass the size along the buffer
> down so we can remove the reliance on buffer terminating by a NUL
> character.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> 
> ---
> 
> This is an early RFC to start getting feedback on the issue and raise
> awareness on the problem.
> 
> This patch is candidate for Xen 4.12. Without it zsh output gets mangled
> when using the upcoming Debian Buster. A workaround is to add in your
> .zshrc:
> 
> setopt single_line_zle
> 
> For the longer bits, it looks like zsh is now adding NUL characters in
> the middle of the output sent onto the console. Below an easy way to
> repro it the bug on Xen:
> 
> int main(void)
> {
>      write(1,
>            "\r\33[0m\0\0\0\0\0\0\0\0\33[27m\33[24m\33[j\33[32mjulien\33[31m@\33[00m\33[36mjuno2-julieng:~\33[37m>",
>            75);
>      write(1,
>            "\33[K\33[32C\33[01;33m--juno2-julieng-13:44--\33[00m\33[37m\33[55D",
>            54);
>      write(1, "\33[?2004h", 8);
> 
>      return 0;
> }
> 
> Without this patch, the only --juno2-julieng-13:44-- will be printed in
> yellow.
> 
> This patch was tested on Arm using serial console. I am not entirely
> whether the video and PV console is correct. I would appreciate help for
> testing here.
> 
> TODO: Actually document CONSOLEIO_write in the public header.
> 
> ---
>   xen/arch/arm/early_printk.c       | 14 +++++++++-----
>   xen/drivers/char/console.c        | 37 +++++++++++++++++++------------------
>   xen/drivers/char/consoled.c       |  4 ++--
>   xen/drivers/char/serial.c         |  8 +++++---
>   xen/drivers/char/xen_pv_console.c | 10 +++++-----
>   xen/drivers/video/lfb.c           | 14 ++++++++------
>   xen/drivers/video/lfb.h           |  4 ++--
>   xen/drivers/video/vga.c           | 14 ++++++++------
>   xen/include/xen/console.h         |  2 +-
>   xen/include/xen/early_printk.h    |  2 +-
>   xen/include/xen/pv_console.h      |  4 ++--
>   xen/include/xen/serial.h          |  4 ++--
>   xen/include/xen/video.h           |  4 ++--
>   13 files changed, 66 insertions(+), 55 deletions(-)
> 
> diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c
> index 97466a12b1..dd2e9fb46f 100644
> --- a/xen/arch/arm/early_printk.c
> +++ b/xen/arch/arm/early_printk.c
> @@ -17,13 +17,17 @@
>   void early_putch(char c);
>   void early_flush(void);
>   
> -void early_puts(const char *s)
> +void early_puts(const char *s, unsigned int nr)
>   {
> -    while (*s != '\0') {
> -        if (*s == '\n')
> +    unsigned int i;
> +
> +    for ( i = 0; i < nr; i++ )
> +    {
> +        char c = *s;
> +
> +        if (c == '\n')
>               early_putch('\r');
> -        early_putch(*s);
> -        s++;
> +        early_putch(c);
>       }
>   
>       /*
> diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
> index 4315588f05..cce1211a0c 100644
> --- a/xen/drivers/char/console.c
> +++ b/xen/drivers/char/console.c
> @@ -325,9 +325,9 @@ long read_console_ring(struct xen_sysctl_readconsole *op)
>   static char serial_rx_ring[SERIAL_RX_SIZE];
>   static unsigned int serial_rx_cons, serial_rx_prod;
>   
> -static void (*serial_steal_fn)(const char *) = early_puts;
> +static void (*serial_steal_fn)(const char *, unsigned int nr) = early_puts;
>   
> -int console_steal(int handle, void (*fn)(const char *))
> +int console_steal(int handle, void (*fn)(const char *, unsigned int nr))
>   {
>       if ( (handle == -1) || (handle != sercon_handle) )
>           return 0;
> @@ -345,15 +345,15 @@ void console_giveback(int id)
>           serial_steal_fn = NULL;
>   }
>   
> -static void sercon_puts(const char *s)
> +static void sercon_puts(const char *s, unsigned int nr)
>   {
>       if ( serial_steal_fn != NULL )
> -        (*serial_steal_fn)(s);
> +        (*serial_steal_fn)(s, nr);
>       else
> -        serial_puts(sercon_handle, s);
> +        serial_puts(sercon_handle, s, nr);
>   
>       /* Copy all serial output into PV console */
> -    pv_console_puts(s);
> +    pv_console_puts(s, nr);
>   }
>   
>   static void dump_console_ring_key(unsigned char key)
> @@ -388,8 +388,8 @@ static void dump_console_ring_key(unsigned char key)
>       }
>       buf[sofar] = '\0';
>   
> -    sercon_puts(buf);
> -    video_puts(buf);
> +    sercon_puts(buf, sofar);
> +    video_puts(buf, sofar);
>   
>       free_xenheap_pages(buf, order);
>   }
> @@ -527,7 +527,7 @@ static inline void xen_console_write_debug_port(const char *buf, size_t len)
>   static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>   {
>       char kbuf[128];
> -    int kcount = 0;
> +    unsigned int kcount = 0;
>       struct domain *cd = current->domain;
>   
>       while ( count > 0 )
> @@ -547,8 +547,8 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>               /* Use direct console output as it could be interactive */
>               spin_lock_irq(&console_lock);
>   
> -            sercon_puts(kbuf);
> -            video_puts(kbuf);
> +            sercon_puts(kbuf, kcount);
> +            video_puts(kbuf, kcount);
>   
>   #ifdef CONFIG_X86
>               if ( opt_console_xen )
> @@ -666,16 +666,16 @@ static bool_t console_locks_busted;
>   
>   static void __putstr(const char *str)
>   {
> +    size_t len = strlen(str);
> +
>       ASSERT(spin_is_locked(&console_lock));
>   
> -    sercon_puts(str);
> -    video_puts(str);
> +    sercon_puts(str, len);
> +    video_puts(str, len);
>   
>   #ifdef CONFIG_X86
>       if ( opt_console_xen )
>       {
> -        size_t len = strlen(str);
> -
>           if ( xen_guest )
>               xen_hypercall_console_write(str, len);
>           else
> @@ -1233,6 +1233,7 @@ void debugtrace_printk(const char *fmt, ...)
>       va_list       args;
>       char         *p;
>       unsigned long flags;
> +    unsigned int nr;
>   
>       if ( debugtrace_bytes == 0 )
>           return;
> @@ -1246,12 +1247,12 @@ void debugtrace_printk(const char *fmt, ...)
>       snprintf(buf, sizeof(buf), "%u ", ++count);
>   
>       va_start(args, fmt);
> -    (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, args);
> +    nr = vscnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, args);
>       va_end(args);
>   
>       if ( debugtrace_send_to_console )
>       {
> -        serial_puts(sercon_handle, buf);
> +        serial_puts(sercon_handle, buf, nr);
>       }
>       else
>       {
> @@ -1357,7 +1358,7 @@ void panic(const char *fmt, ...)
>    * **************************************************************
>    */
>   
> -static void suspend_steal_fn(const char *str) { }
> +static void suspend_steal_fn(const char *str, unsigned int nr) { }
>   static int suspend_steal_id;
>   
>   int console_suspend(void)
> diff --git a/xen/drivers/char/consoled.c b/xen/drivers/char/consoled.c
> index 552abf5766..3e849a2557 100644
> --- a/xen/drivers/char/consoled.c
> +++ b/xen/drivers/char/consoled.c
> @@ -77,7 +77,7 @@ size_t consoled_guest_rx(void)
>   
>           if ( idx >= BUF_SZ )
>           {
> -            pv_console_puts(buf);
> +            pv_console_puts(buf, BUF_SZ);
>               idx = 0;
>           }
>       }
> @@ -85,7 +85,7 @@ size_t consoled_guest_rx(void)
>       if ( idx )
>       {
>           buf[idx] = '\0';
> -        pv_console_puts(buf);
> +        pv_console_puts(buf, idx);
>       }
>   
>       /* No need for a mem barrier because every character was already consumed */
> diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
> index 221a14c092..7498299807 100644
> --- a/xen/drivers/char/serial.c
> +++ b/xen/drivers/char/serial.c
> @@ -223,11 +223,11 @@ void serial_putc(int handle, char c)
>       spin_unlock_irqrestore(&port->tx_lock, flags);
>   }
>   
> -void serial_puts(int handle, const char *s)
> +void serial_puts(int handle, const char *s, unsigned int nr)
>   {
>       struct serial_port *port;
>       unsigned long flags;
> -    char c;
> +    unsigned int i;
>   
>       if ( handle == -1 )
>           return;
> @@ -238,8 +238,10 @@ void serial_puts(int handle, const char *s)
>   
>       spin_lock_irqsave(&port->tx_lock, flags);
>   
> -    while ( (c = *s++) != '\0' )
> +    for ( i = 0; i < nr; i++ )
>       {
> +        char c = s[i];
> +
>           if ( (c == '\n') && (handle & SERHND_COOKED) )
>               __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
>   
> diff --git a/xen/drivers/char/xen_pv_console.c b/xen/drivers/char/xen_pv_console.c
> index cc1c1d743f..5bb303d4c8 100644
> --- a/xen/drivers/char/xen_pv_console.c
> +++ b/xen/drivers/char/xen_pv_console.c
> @@ -129,13 +129,13 @@ size_t pv_console_rx(struct cpu_user_regs *regs)
>       return recv;
>   }
>   
> -static size_t pv_ring_puts(const char *buf)
> +static size_t pv_ring_puts(const char *buf, unsigned int nr)
>   {
>       XENCONS_RING_IDX cons, prod;
>       size_t sent = 0, avail;
>       bool put_r = false;
>   
> -    while ( buf[sent] != '\0' || put_r )
> +    while ( sent < nr || put_r )
>       {
>           cons = ACCESS_ONCE(cons_ring->out_cons);
>           prod = cons_ring->out_prod;
> @@ -156,7 +156,7 @@ static size_t pv_ring_puts(const char *buf)
>               continue;
>           }
>   
> -        while ( avail && (buf[sent] != '\0' || put_r) )
> +        while ( avail && (sent < nr || put_r) )
>           {
>               if ( put_r )
>               {
> @@ -185,7 +185,7 @@ static size_t pv_ring_puts(const char *buf)
>       return sent;
>   }
>   
> -void pv_console_puts(const char *buf)
> +void pv_console_puts(const char *buf, unsigned int nr)
>   {
>       unsigned long flags;
>   
> @@ -193,7 +193,7 @@ void pv_console_puts(const char *buf)
>           return;
>   
>       spin_lock_irqsave(&tx_lock, flags);
> -    pv_ring_puts(buf);
> +    pv_ring_puts(buf, nr);
>       spin_unlock_irqrestore(&tx_lock, flags);
>   }
>   
> diff --git a/xen/drivers/video/lfb.c b/xen/drivers/video/lfb.c
> index d0c8c492b0..93b6a33a41 100644
> --- a/xen/drivers/video/lfb.c
> +++ b/xen/drivers/video/lfb.c
> @@ -59,14 +59,15 @@ static void lfb_show_line(
>   }
>   
>   /* Fast mode which redraws all modified parts of a 2D text buffer. */
> -void lfb_redraw_puts(const char *s)
> +void lfb_redraw_puts(const char *s, unsigned int nr)
>   {
>       unsigned int i, min_redraw_y = lfb.ypos;
> -    char c;
>   
>       /* Paste characters into text buffer. */
> -    while ( (c = *s++) != '\0' )
> +    for ( i = 0; i < nr; i++ )
>       {
> +        char c = s[i];
> +
>           if ( (c == '\n') || (lfb.xpos >= lfb.lfbp.text_columns) )
>           {
>               if ( ++lfb.ypos >= lfb.lfbp.text_rows )
> @@ -103,13 +104,14 @@ void lfb_redraw_puts(const char *s)
>   }
>   
>   /* Slower line-based scroll mode which interacts better with dom0. */
> -void lfb_scroll_puts(const char *s)
> +void lfb_scroll_puts(const char *s, unsigned int nr)
>   {
>       unsigned int i;
> -    char c;
>   
> -    while ( (c = *s++) != '\0' )
> +    for ( i = 0; i < nr; i++ )
>       {
> +        char c = s[i];
> +
>           if ( (c == '\n') || (lfb.xpos >= lfb.lfbp.text_columns) )
>           {
>               unsigned int bytes = (lfb.lfbp.width *
> diff --git a/xen/drivers/video/lfb.h b/xen/drivers/video/lfb.h
> index ac40a66379..15599e22ef 100644
> --- a/xen/drivers/video/lfb.h
> +++ b/xen/drivers/video/lfb.h
> @@ -35,8 +35,8 @@ struct lfb_prop {
>       unsigned int text_rows;
>   };
>   
> -void lfb_redraw_puts(const char *s);
> -void lfb_scroll_puts(const char *s);
> +void lfb_redraw_puts(const char *s, unsigned int nr);
> +void lfb_scroll_puts(const char *s, unsigned int nr);
>   void lfb_carriage_return(void);
>   void lfb_free(void);
>   
> diff --git a/xen/drivers/video/vga.c b/xen/drivers/video/vga.c
> index 6a64fd9013..01f12aae42 100644
> --- a/xen/drivers/video/vga.c
> +++ b/xen/drivers/video/vga.c
> @@ -18,9 +18,9 @@ static int vgacon_keep;
>   static unsigned int xpos, ypos;
>   static unsigned char *video;
>   
> -static void vga_text_puts(const char *s);
> -static void vga_noop_puts(const char *s) {}
> -void (*video_puts)(const char *) = vga_noop_puts;
> +static void vga_text_puts(const char *s, unsigned int nr);
> +static void vga_noop_puts(const char *s, unsigned int nr) {}
> +void (*video_puts)(const char *, unsigned int nr) = vga_noop_puts;
>   
>   /*
>    * 'vga=<mode-specifier>[,keep]' where <mode-specifier> is one of:
> @@ -177,12 +177,14 @@ void __init video_endboot(void)
>       }
>   }
>   
> -static void vga_text_puts(const char *s)
> +static void vga_text_puts(const char *s, unsigned int nr)
>   {
> -    char c;
> +    unsigned int i;
>   
> -    while ( (c = *s++) != '\0' )
> +    for ( i = 0; i < nr; i++ )
>       {
> +        char c = s[i];
> +
>           if ( (c == '\n') || (xpos >= columns) )
>           {
>               if ( ++ypos >= lines )
> diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
> index b4f9463936..dafa53ba6b 100644
> --- a/xen/include/xen/console.h
> +++ b/xen/include/xen/console.h
> @@ -38,7 +38,7 @@ struct domain *console_input_domain(void);
>    * Steal output from the console. Returns +ve identifier, else -ve error.
>    * Takes the handle of the serial line to steal, and steal callback function.
>    */
> -int console_steal(int handle, void (*fn)(const char *));
> +int console_steal(int handle, void (*fn)(const char *, unsigned int nr));
>   
>   /* Give back stolen console. Takes the identifier returned by console_steal. */
>   void console_giveback(int id);
> diff --git a/xen/include/xen/early_printk.h b/xen/include/xen/early_printk.h
> index 2c3e1b3519..22f8009a5f 100644
> --- a/xen/include/xen/early_printk.h
> +++ b/xen/include/xen/early_printk.h
> @@ -5,7 +5,7 @@
>   #define __XEN_EARLY_PRINTK_H__
>   
>   #ifdef CONFIG_EARLY_PRINTK
> -void early_puts(const char *s);
> +void early_puts(const char *s, unsigned int nr);
>   #else
>   #define early_puts NULL
>   #endif
> diff --git a/xen/include/xen/pv_console.h b/xen/include/xen/pv_console.h
> index cb92539666..41144890e4 100644
> --- a/xen/include/xen/pv_console.h
> +++ b/xen/include/xen/pv_console.h
> @@ -8,7 +8,7 @@
>   void pv_console_init(void);
>   void pv_console_set_rx_handler(serial_rx_fn fn);
>   void pv_console_init_postirq(void);
> -void pv_console_puts(const char *buf);
> +void pv_console_puts(const char *buf, unsigned int nr);
>   size_t pv_console_rx(struct cpu_user_regs *regs);
>   evtchn_port_t pv_console_evtchn(void);
>   
> @@ -17,7 +17,7 @@ evtchn_port_t pv_console_evtchn(void);
>   static inline void pv_console_init(void) {}
>   static inline void pv_console_set_rx_handler(serial_rx_fn fn) { }
>   static inline void pv_console_init_postirq(void) { }
> -static inline void pv_console_puts(const char *buf) { }
> +static inline void pv_console_puts(const char *buf, unsigned int nr) { }
>   static inline size_t pv_console_rx(struct cpu_user_regs *regs) { return 0; }
>   evtchn_port_t pv_console_evtchn(void)
>   {
> diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h
> index f2994d4093..e11d6d3ebc 100644
> --- a/xen/include/xen/serial.h
> +++ b/xen/include/xen/serial.h
> @@ -114,8 +114,8 @@ int serial_parse_handle(char *conf);
>   /* Transmit a single character via the specified COM port. */
>   void serial_putc(int handle, char c);
>   
> -/* Transmit a NULL-terminated string via the specified COM port. */
> -void serial_puts(int handle, const char *s);
> +/* Transmit a string via the specified COM port. */
> +void serial_puts(int handle, const char *s, unsigned int nr);
>   
>   /*
>    * An alternative to registering a character-receive hook. This function
> diff --git a/xen/include/xen/video.h b/xen/include/xen/video.h
> index 2e897f9df5..ddd21f374d 100644
> --- a/xen/include/xen/video.h
> +++ b/xen/include/xen/video.h
> @@ -13,11 +13,11 @@
>   
>   #ifdef CONFIG_VIDEO
>   void video_init(void);
> -extern void (*video_puts)(const char *);
> +extern void (*video_puts)(const char *, unsigned int nr);
>   void video_endboot(void);
>   #else
>   #define video_init()    ((void)0)
> -#define video_puts(s)   ((void)0)
> +#define video_puts(s, nr)   ((void)0)
>   #define video_endboot() ((void)0)
>   #endif
>   
> 

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-26 23:03 [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write Julien Grall
  2019-02-27 10:25 ` Jan Beulich
  2019-02-27 10:45 ` Julien Grall
@ 2019-02-27 12:55 ` Wei Liu
  2019-02-27 18:45   ` Julien Grall
  2 siblings, 1 reply; 17+ messages in thread
From: Wei Liu @ 2019-02-27 12:55 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich, xen-devel

On Tue, Feb 26, 2019 at 11:03:51PM +0000, Julien Grall wrote:
> After upgrading Debian to Buster, I started noticing console mangling
> when using zsh. This is happenning because output sent by zsh to the
> console may contain NUL character in the middle of the buffer.
> 
> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
> However, the implementation in Xen considers NUL character is used to
> terminate the buffer and therefore will ignore anything after it.
> 
> The actual documentation of CONSOLEIO_write is pretty limited. From the
> declaration, the hypercall takes a buffer and size. So this could lead
> to think the NUL character is allowed in the middle of the buffer.
> 
> This patch updates the console API to pass the size along the buffer
> down so we can remove the reliance on buffer terminating by a NUL
> character.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> 
> ---
> 
[...]
> @@ -527,7 +527,7 @@ static inline void xen_console_write_debug_port(const char *buf, size_t len)
>  static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>  {
>      char kbuf[128];
> -    int kcount = 0;
> +    unsigned int kcount = 0;
>      struct domain *cd = current->domain;
>  
>      while ( count > 0 )
> @@ -547,8 +547,8 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>              /* Use direct console output as it could be interactive */
>              spin_lock_irq(&console_lock);
>  
> -            sercon_puts(kbuf);
> -            video_puts(kbuf);
> +            sercon_puts(kbuf, kcount);
> +            video_puts(kbuf, kcount);
>  

I think you missed the non-hwdom branch in the same function. It still
strips non-printable characters.

>  int console_suspend(void)
[...]
> diff --git a/xen/drivers/char/consoled.c b/xen/drivers/char/consoled.c
> index 552abf5766..3e849a2557 100644
> --- a/xen/drivers/char/consoled.c
> +++ b/xen/drivers/char/consoled.c
> @@ -77,7 +77,7 @@ size_t consoled_guest_rx(void)
>  
>          if ( idx >= BUF_SZ )
>          {
> -            pv_console_puts(buf);
> +            pv_console_puts(buf, BUF_SZ);
>              idx = 0;
>          }
>      }
> @@ -85,7 +85,7 @@ size_t consoled_guest_rx(void)
>      if ( idx )
>      {
>          buf[idx] = '\0';

Can this be deleted? Now that you've explicitly sized the buffer.

Wei.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-27 10:25 ` Jan Beulich
  2019-02-27 10:42   ` Julien Grall
@ 2019-02-27 12:55   ` Wei Liu
  1 sibling, 0 replies; 17+ messages in thread
From: Wei Liu @ 2019-02-27 12:55 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Julien Grall, xen-devel

On Wed, Feb 27, 2019 at 03:25:22AM -0700, Jan Beulich wrote:
> >>> On 27.02.19 at 00:03, <julien.grall@arm.com> wrote:
> > After upgrading Debian to Buster, I started noticing console mangling
> > when using zsh. This is happenning because output sent by zsh to the
> > console may contain NUL character in the middle of the buffer.
> > 
> > Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
> > However, the implementation in Xen considers NUL character is used to
> > terminate the buffer and therefore will ignore anything after it.
> > 
> > The actual documentation of CONSOLEIO_write is pretty limited. From the
> > declaration, the hypercall takes a buffer and size. So this could lead
> > to think the NUL character is allowed in the middle of the buffer.
> > 
> > This patch updates the console API to pass the size along the buffer
> > down so we can remove the reliance on buffer terminating by a NUL
> > character.
> 
> We don't need the behavior for internal producers, so I think the change
> touches way too much code. I think all you need to do is make the
> hypercall handler sense null characters, and perhaps simply invoke lower
> level handlers multiple times. Or replace them by something else (e.g. a
> blank).

I don't think replacing NULs with blank is the right thing to do. It's
not only about how human perceives the output, but also about scripting.

Wei.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-27 12:55 ` Wei Liu
@ 2019-02-27 18:45   ` Julien Grall
  2019-03-01 22:59     ` Daniel De Graaf
  0 siblings, 1 reply; 17+ messages in thread
From: Julien Grall @ 2019-02-27 18:45 UTC (permalink / raw)
  To: Wei Liu
  Cc: Stefano Stabellini, Konrad Rzeszutek Wilk, George Dunlap,
	Andrew Cooper, Ian Jackson, Tim Deegan, Jan Beulich, xen-devel,
	Daniel De Graaf

Hi Wei,

On 2/27/19 12:55 PM, Wei Liu wrote:
> On Tue, Feb 26, 2019 at 11:03:51PM +0000, Julien Grall wrote:
>> After upgrading Debian to Buster, I started noticing console mangling
>> when using zsh. This is happenning because output sent by zsh to the
>> console may contain NUL character in the middle of the buffer.
>>
>> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
>> However, the implementation in Xen considers NUL character is used to
>> terminate the buffer and therefore will ignore anything after it.
>>
>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>> declaration, the hypercall takes a buffer and size. So this could lead
>> to think the NUL character is allowed in the middle of the buffer.
>>
>> This patch updates the console API to pass the size along the buffer
>> down so we can remove the reliance on buffer terminating by a NUL
>> character.
>>
>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>>
>> ---
>>
> [...]
>> @@ -527,7 +527,7 @@ static inline void xen_console_write_debug_port(const char *buf, size_t len)
>>   static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>>   {
>>       char kbuf[128];
>> -    int kcount = 0;
>> +    unsigned int kcount = 0;
>>       struct domain *cd = current->domain;
>>   
>>       while ( count > 0 )
>> @@ -547,8 +547,8 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>>               /* Use direct console output as it could be interactive */
>>               spin_lock_irq(&console_lock);
>>   
>> -            sercon_puts(kbuf);
>> -            video_puts(kbuf);
>> +            sercon_puts(kbuf, kcount);
>> +            video_puts(kbuf, kcount);
>>   
> 
> I think you missed the non-hwdom branch in the same function. It still
> strips non-printable characters.

Good point. The non-printable characters was added by Daniel in commit 
48d50de8e0 " console: buffer and show origin of guest PV writes" without 
much explanation.

The only reason I can see is, as we buffer the guest writes, the console 
would be screwed if we split an escape sequence. Furthermore, for guest 
output, we will always append "(dX)" to the output. So I am not entirely 
sure what to do in the non-hwdom case.

Any opinions?

> 
>>   int console_suspend(void)
> [...]
>> diff --git a/xen/drivers/char/consoled.c b/xen/drivers/char/consoled.c
>> index 552abf5766..3e849a2557 100644
>> --- a/xen/drivers/char/consoled.c
>> +++ b/xen/drivers/char/consoled.c
>> @@ -77,7 +77,7 @@ size_t consoled_guest_rx(void)
>>   
>>           if ( idx >= BUF_SZ )
>>           {
>> -            pv_console_puts(buf);
>> +            pv_console_puts(buf, BUF_SZ);
>>               idx = 0;
>>           }
>>       }
>> @@ -85,7 +85,7 @@ size_t consoled_guest_rx(void)
>>       if ( idx )
>>       {
>>           buf[idx] = '\0';
> 
> Can this be deleted? Now that you've explicitly sized the buffer.

We probably can delete a few of the '\0' over the console code. I will 
have a look at it.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-27 18:45   ` Julien Grall
@ 2019-03-01 22:59     ` Daniel De Graaf
  2019-03-04 11:21       ` George Dunlap
  0 siblings, 1 reply; 17+ messages in thread
From: Daniel De Graaf @ 2019-03-01 22:59 UTC (permalink / raw)
  To: Julien Grall, Wei Liu
  Cc: Stefano Stabellini, Konrad Rzeszutek Wilk, George Dunlap,
	Andrew Cooper, Ian Jackson, Tim Deegan, Jan Beulich, xen-devel

On 2/27/19 1:45 PM, Julien Grall wrote:
> Hi Wei,
> 
> On 2/27/19 12:55 PM, Wei Liu wrote:
>> On Tue, Feb 26, 2019 at 11:03:51PM +0000, Julien Grall wrote:
>>> After upgrading Debian to Buster, I started noticing console mangling
>>> when using zsh. This is happenning because output sent by zsh to the
>>> console may contain NUL character in the middle of the buffer.
>>>
>>> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
>>> However, the implementation in Xen considers NUL character is used to
>>> terminate the buffer and therefore will ignore anything after it.
>>>
>>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>>> declaration, the hypercall takes a buffer and size. So this could lead
>>> to think the NUL character is allowed in the middle of the buffer.
>>>
>>> This patch updates the console API to pass the size along the buffer
>>> down so we can remove the reliance on buffer terminating by a NUL
>>> character.
>>>
>>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>>>
>>> ---
>>>
>> [...]
>>> @@ -527,7 +527,7 @@ static inline void xen_console_write_debug_port(const char *buf, size_t len)
>>>   static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>>>   {
>>>       char kbuf[128];
>>> -    int kcount = 0;
>>> +    unsigned int kcount = 0;
>>>       struct domain *cd = current->domain;
>>>       while ( count > 0 )
>>> @@ -547,8 +547,8 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>>>               /* Use direct console output as it could be interactive */
>>>               spin_lock_irq(&console_lock);
>>> -            sercon_puts(kbuf);
>>> -            video_puts(kbuf);
>>> +            sercon_puts(kbuf, kcount);
>>> +            video_puts(kbuf, kcount);
>>
>> I think you missed the non-hwdom branch in the same function. It still
>> strips non-printable characters.
> 
> Good point. The non-printable characters was added by Daniel in commit 48d50de8e0 " console: buffer and show origin of guest PV writes" without much explanation.

Yes, I added stripping of non-printable characters because escape sequences printed out by some guests (in particular, clear screen sequences printed out by some distro's early boot scripts) interfered with the output of other guests.  It also prevents guests from pretending to be one another or the hypervisor, if the console is being used for some kind of auditing or logging.

One thing I didn't consider that I probably should have is that isprint() in the hypervisor is not a UTF-8 aware check, so it will end up corrupting characters if your guests treat the console as having that encoding.

> The only reason I can see is, as we buffer the guest writes, the console would be screwed if we split an escape sequence. Furthermore, for guest output, we will always append "(dX)" to the output. So I am not entirely sure what to do in the non-hwdom case.
> 
> Any opinions?

This really depends on the purpose of the console in the system.  Since there's usually possible hypervisor messages in the output, it makes sense to me to treat it as a line-based log containing readable text.  However, the ability for the hardware domain to use it interactively is also important for debugging, and limiting or buffering that domain's output would interfere with that.  The current handling of the output is a compromise between these two uses.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-01 22:59     ` Daniel De Graaf
@ 2019-03-04 11:21       ` George Dunlap
  2019-03-04 11:48         ` Julien Grall
  0 siblings, 1 reply; 17+ messages in thread
From: George Dunlap @ 2019-03-04 11:21 UTC (permalink / raw)
  To: Daniel De Graaf, Julien Grall, Wei Liu
  Cc: Stefano Stabellini, Konrad Rzeszutek Wilk, George Dunlap,
	Andrew Cooper, Ian Jackson, Tim Deegan, Jan Beulich, xen-devel

On 3/1/19 10:59 PM, Daniel De Graaf wrote:
> On 2/27/19 1:45 PM, Julien Grall wrote:
>> Hi Wei,
>>
>> On 2/27/19 12:55 PM, Wei Liu wrote:
>>> On Tue, Feb 26, 2019 at 11:03:51PM +0000, Julien Grall wrote:
>>>> After upgrading Debian to Buster, I started noticing console mangling
>>>> when using zsh. This is happenning because output sent by zsh to the
>>>> console may contain NUL character in the middle of the buffer.
>>>>
>>>> Linux is sending the buffer as it is to Xen console via
>>>> CONSOLEIO_write.
>>>> However, the implementation in Xen considers NUL character is used to
>>>> terminate the buffer and therefore will ignore anything after it.

zsh is sending a NUL character to the console in the middle of the
buffer?  Why would it do that?  Is that defined behavior, or does it
just happen to work because Xen is the first console device to act
strange as a result?

There's an argument to be made that 1) zsh shouldn't be sending NUL
characters, and/or that 2) Linux should be the one 'sanitizing' input it
sends to the console.

>>>> @@ -527,7 +527,7 @@ static inline void
>>>> xen_console_write_debug_port(const char *buf, size_t len)
>>>>   static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char)
>>>> buffer, int count)
>>>>   {
>>>>       char kbuf[128];
>>>> -    int kcount = 0;
>>>> +    unsigned int kcount = 0;
>>>>       struct domain *cd = current->domain;
>>>>       while ( count > 0 )
>>>> @@ -547,8 +547,8 @@ static long
>>>> guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>>>>               /* Use direct console output as it could be
>>>> interactive */
>>>>               spin_lock_irq(&console_lock);
>>>> -            sercon_puts(kbuf);
>>>> -            video_puts(kbuf);
>>>> +            sercon_puts(kbuf, kcount);
>>>> +            video_puts(kbuf, kcount);
>>>
>>> I think you missed the non-hwdom branch in the same function. It still
>>> strips non-printable characters.
>>
>> Good point. The non-printable characters was added by Daniel in commit
>> 48d50de8e0 " console: buffer and show origin of guest PV writes"
>> without much explanation.
> 
> Yes, I added stripping of non-printable characters because escape
> sequences printed out by some guests (in particular, clear screen
> sequences printed out by some distro's early boot scripts) interfered
> with the output of other guests.  It also prevents guests from
> pretending to be one another or the hypervisor, if the console is being
> used for some kind of auditing or logging.

It sounds like it would be useful to add a comment to that effect on the
non-hwdomain path, to make sure things don't accidentally get removed.

> One thing I didn't consider that I probably should have is that
> isprint() in the hypervisor is not a UTF-8 aware check, so it will end
> up corrupting characters if your guests treat the console as having that
> encoding.
> 
>> The only reason I can see is, as we buffer the guest writes, the
>> console would be screwed if we split an escape sequence. Furthermore,
>> for guest output, we will always append "(dX)" to the output. So I am
>> not entirely sure what to do in the non-hwdom case.
>>
>> Any opinions?
> 
> This really depends on the purpose of the console in the system.  Since
> there's usually possible hypervisor messages in the output, it makes
> sense to me to treat it as a line-based log containing readable text. 
> However, the ability for the hardware domain to use it interactively is
> also important for debugging, and limiting or buffering that domain's
> output would interfere with that.  The current handling of the output is
> a compromise between these two uses.

Right; the system console is a shared resource, and the hypervisor has
to  make sure that unprivileged guests don't do anything to muck it up.
 As you say, in the general case they shouldn't be able to insert lines
or clear the screen or things like that.

If for specific setups it's required for one particular guest to have
that kind of access, we should add in an interface to grant that ability
to specific guests.

 -George

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-04 11:21       ` George Dunlap
@ 2019-03-04 11:48         ` Julien Grall
  2019-03-04 12:00           ` Ian Jackson
  0 siblings, 1 reply; 17+ messages in thread
From: Julien Grall @ 2019-03-04 11:48 UTC (permalink / raw)
  To: George Dunlap, Daniel De Graaf, Wei Liu
  Cc: Stefano Stabellini, Konrad Rzeszutek Wilk, George Dunlap,
	Andrew Cooper, Ian Jackson, Tim Deegan, Jan Beulich, xen-devel

Hi,

On 04/03/2019 11:21, George Dunlap wrote:
> On 3/1/19 10:59 PM, Daniel De Graaf wrote:
>> On 2/27/19 1:45 PM, Julien Grall wrote:
>>> Hi Wei,
>>>
>>> On 2/27/19 12:55 PM, Wei Liu wrote:
>>>> On Tue, Feb 26, 2019 at 11:03:51PM +0000, Julien Grall wrote:
>>>>> After upgrading Debian to Buster, I started noticing console mangling
>>>>> when using zsh. This is happenning because output sent by zsh to the
>>>>> console may contain NUL character in the middle of the buffer.
>>>>>
>>>>> Linux is sending the buffer as it is to Xen console via
>>>>> CONSOLEIO_write.
>>>>> However, the implementation in Xen considers NUL character is used to
>>>>> terminate the buffer and therefore will ignore anything after it.
> 
> zsh is sending a NUL character to the console in the middle of the
> buffer?  Why would it do that?  Is that defined behavior, or does it
> just happen to work because Xen is the first console device to act
> strange as a result?
I have no idea why new version of ZSH is adding '\0' in the buffer. But, to be 
honest, it does not matter to know it.

What matters is an application using the POSIX call write() is free to put a 
'\0' in the middle of the stream. It is up to the reader (i.e screen/gdb...) to 
decide how to interpret the characters.

> 
> There's an argument to be made that 1) zsh shouldn't be sending NUL
> characters, and/or that 2) Linux should be the one 'sanitizing' input it
> sends to the console.
Your arguments seems to be based on the assumption the console is only used by a 
human. Console can be used for other purpose, such as communication with an 
external debugger. So how do you decide what to sanitize?

IHMO, both Xen and Linux should just pass all the characters to the other end. 
This is inline with the semantics of the posix call write().

> 
>>>>> @@ -527,7 +527,7 @@ static inline void
>>>>> xen_console_write_debug_port(const char *buf, size_t len)
>>>>>    static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char)
>>>>> buffer, int count)
>>>>>    {
>>>>>        char kbuf[128];
>>>>> -    int kcount = 0;
>>>>> +    unsigned int kcount = 0;
>>>>>        struct domain *cd = current->domain;
>>>>>        while ( count > 0 )
>>>>> @@ -547,8 +547,8 @@ static long
>>>>> guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count)
>>>>>                /* Use direct console output as it could be
>>>>> interactive */
>>>>>                spin_lock_irq(&console_lock);
>>>>> -            sercon_puts(kbuf);
>>>>> -            video_puts(kbuf);
>>>>> +            sercon_puts(kbuf, kcount);
>>>>> +            video_puts(kbuf, kcount);
>>>>
>>>> I think you missed the non-hwdom branch in the same function. It still
>>>> strips non-printable characters.
>>>
>>> Good point. The non-printable characters was added by Daniel in commit
>>> 48d50de8e0 " console: buffer and show origin of guest PV writes"
>>> without much explanation.
>>
>> Yes, I added stripping of non-printable characters because escape
>> sequences printed out by some guests (in particular, clear screen
>> sequences printed out by some distro's early boot scripts) interfered
>> with the output of other guests.  It also prevents guests from
>> pretending to be one another or the hypervisor, if the console is being
>> used for some kind of auditing or logging.
> 
> It sounds like it would be useful to add a comment to that effect on the
> non-hwdomain path, to make sure things don't accidentally get removed.

I have a patch to document the behavior.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-04 11:48         ` Julien Grall
@ 2019-03-04 12:00           ` Ian Jackson
  0 siblings, 0 replies; 17+ messages in thread
From: Ian Jackson @ 2019-03-04 12:00 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	Andrew Cooper, Tim (Xen.org),
	George Dunlap, Jan Beulich, xen-devel, Daniel De Graaf

Julien Grall writes ("Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write"):
> On 04/03/2019 11:21, George Dunlap wrote:
> > zsh is sending a NUL character to the console in the middle of the
> > buffer?  Why would it do that?  Is that defined behavior, or does it
> > just happen to work because Xen is the first console device to act
> > strange as a result?
>
> I have no idea why new version of ZSH is adding '\0' in the
> buffer. But, to be honest, it does not matter to know it.
> 
> What matters is an application using the POSIX call write() is free
> to put a '\0' in the middle of the stream. It is up to the reader
> (i.e screen/gdb...) to decide how to interpret the characters.

Nuls are perfectly legitimate in terminal streams.  They used to be
used for padding for slow terminals, for example.  See terminfo(5)
section `Delays and Padding', or search for the pcre `\bpad'.

NB that Xen does not control the ultimate kind of terminal.  The
terminal is whatever is ultimately connected (via a series of physical
and logical links) to the dom0's console interface.

There is no bug in zsh here.

Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-02-27 10:45 ` Julien Grall
@ 2019-03-05 12:57   ` Juergen Gross
  2019-03-05 14:08     ` Julien Grall
  0 siblings, 1 reply; 17+ messages in thread
From: Juergen Gross @ 2019-03-05 12:57 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich

On 27/02/2019 11:45, Julien Grall wrote:
> (+ Juergen Gross as RM)
> 
> I forgot to CC Juergen for this.
> 
> On 2/26/19 11:03 PM, Julien Grall wrote:
>> After upgrading Debian to Buster, I started noticing console mangling
>> when using zsh. This is happenning because output sent by zsh to the
>> console may contain NUL character in the middle of the buffer.
>>
>> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
>> However, the implementation in Xen considers NUL character is used to
>> terminate the buffer and therefore will ignore anything after it.
>>
>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>> declaration, the hypercall takes a buffer and size. So this could lead
>> to think the NUL character is allowed in the middle of the buffer.
>>
>> This patch updates the console API to pass the size along the buffer
>> down so we can remove the reliance on buffer terminating by a NUL
>> character.
>>
>> Signed-off-by: Julien Grall <julien.grall@arm.com>

The risk for a regression is too high this late in the 4.12 release
process IMO.

My plan is to have only one further RC before branching off 4.12,
so please let us shift this patch to 4.13.


Juergen

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-05 12:57   ` Juergen Gross
@ 2019-03-05 14:08     ` Julien Grall
  2019-03-05 14:12       ` Juergen Gross
  0 siblings, 1 reply; 17+ messages in thread
From: Julien Grall @ 2019-03-05 14:08 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich

Hi Juergen,

On 3/5/19 12:57 PM, Juergen Gross wrote:
> On 27/02/2019 11:45, Julien Grall wrote:
>> (+ Juergen Gross as RM)
>>
>> I forgot to CC Juergen for this.
>>
>> On 2/26/19 11:03 PM, Julien Grall wrote:
>>> After upgrading Debian to Buster, I started noticing console mangling
>>> when using zsh. This is happenning because output sent by zsh to the
>>> console may contain NUL character in the middle of the buffer.
>>>
>>> Linux is sending the buffer as it is to Xen console via CONSOLEIO_write.
>>> However, the implementation in Xen considers NUL character is used to
>>> terminate the buffer and therefore will ignore anything after it.
>>>
>>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>>> declaration, the hypercall takes a buffer and size. So this could lead
>>> to think the NUL character is allowed in the middle of the buffer.
>>>
>>> This patch updates the console API to pass the size along the buffer
>>> down so we can remove the reliance on buffer terminating by a NUL
>>> character.
>>>
>>> Signed-off-by: Julien Grall <julien.grall@arm.com>
> 
> The risk for a regression is too high this late in the 4.12 release
> process IMO.

This code path is fairly well tested (console are used pretty much all 
the times). So a regression would be quickly noticed.

This patch has the advantage to allow upgrade to a newer Debian without 
loosing part of your prompt on zsh. I am not sure whether the problem is 
the same with other Distros.

> 
> My plan is to have only one further RC before branching off 4.12,
> so please let us shift this patch to 4.13.

I understand. It is possible to workaround the problem at least with 
zsh. So a release note in Xen (and maybe Debian) should do the job.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-05 14:08     ` Julien Grall
@ 2019-03-05 14:12       ` Juergen Gross
  2019-03-05 15:28         ` Julien Grall
  0 siblings, 1 reply; 17+ messages in thread
From: Juergen Gross @ 2019-03-05 14:12 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich

On 05/03/2019 15:08, Julien Grall wrote:
> Hi Juergen,
> 
> On 3/5/19 12:57 PM, Juergen Gross wrote:
>> On 27/02/2019 11:45, Julien Grall wrote:
>>> (+ Juergen Gross as RM)
>>>
>>> I forgot to CC Juergen for this.
>>>
>>> On 2/26/19 11:03 PM, Julien Grall wrote:
>>>> After upgrading Debian to Buster, I started noticing console mangling
>>>> when using zsh. This is happenning because output sent by zsh to the
>>>> console may contain NUL character in the middle of the buffer.
>>>>
>>>> Linux is sending the buffer as it is to Xen console via
>>>> CONSOLEIO_write.
>>>> However, the implementation in Xen considers NUL character is used to
>>>> terminate the buffer and therefore will ignore anything after it.
>>>>
>>>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>>>> declaration, the hypercall takes a buffer and size. So this could lead
>>>> to think the NUL character is allowed in the middle of the buffer.
>>>>
>>>> This patch updates the console API to pass the size along the buffer
>>>> down so we can remove the reliance on buffer terminating by a NUL
>>>> character.
>>>>
>>>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>>
>> The risk for a regression is too high this late in the 4.12 release
>> process IMO.
> 
> This code path is fairly well tested (console are used pretty much all
> the times). So a regression would be quickly noticed.

Only if you test all the guests out in the wild.

> This patch has the advantage to allow upgrade to a newer Debian without
> loosing part of your prompt on zsh. I am not sure whether the problem is
> the same with other Distros.
> 
>>
>> My plan is to have only one further RC before branching off 4.12,
>> so please let us shift this patch to 4.13.
> 
> I understand. It is possible to workaround the problem at least with
> zsh. So a release note in Xen (and maybe Debian) should do the job.

Could you please post the needed information for the 4.12 RN?


Juergen

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-05 14:12       ` Juergen Gross
@ 2019-03-05 15:28         ` Julien Grall
  2019-03-05 16:44           ` Juergen Gross
  0 siblings, 1 reply; 17+ messages in thread
From: Julien Grall @ 2019-03-05 15:28 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich

Hi Juergen,

On 3/5/19 2:12 PM, Juergen Gross wrote:
> On 05/03/2019 15:08, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 3/5/19 12:57 PM, Juergen Gross wrote:
>>> On 27/02/2019 11:45, Julien Grall wrote:
>>>> (+ Juergen Gross as RM)
>>>>
>>>> I forgot to CC Juergen for this.
>>>>
>>>> On 2/26/19 11:03 PM, Julien Grall wrote:
>>>>> After upgrading Debian to Buster, I started noticing console mangling
>>>>> when using zsh. This is happenning because output sent by zsh to the
>>>>> console may contain NUL character in the middle of the buffer.
>>>>>
>>>>> Linux is sending the buffer as it is to Xen console via
>>>>> CONSOLEIO_write.
>>>>> However, the implementation in Xen considers NUL character is used to
>>>>> terminate the buffer and therefore will ignore anything after it.
>>>>>
>>>>> The actual documentation of CONSOLEIO_write is pretty limited. From the
>>>>> declaration, the hypercall takes a buffer and size. So this could lead
>>>>> to think the NUL character is allowed in the middle of the buffer.
>>>>>
>>>>> This patch updates the console API to pass the size along the buffer
>>>>> down so we can remove the reliance on buffer terminating by a NUL
>>>>> character.
>>>>>
>>>>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>>>
>>> The risk for a regression is too high this late in the 4.12 release
>>> process IMO.
>>
>> This code path is fairly well tested (console are used pretty much all
>> the times). So a regression would be quickly noticed.
> 
> Only if you test all the guests out in the wild.

The buffer is bounded to 'nr'. So the worst things that can happen is 
you print more characters than you wanted. CONSOLEIO_write is using a 
semantics very similar to write() and we didn't document what happen 
when encountering a NUL character. So, I highly doubt anyone relies on 
the current behavior.

Thinking a bit more, from what Ian wrote [1], the issue maybe wider than 
zsh. So maybe we want to write a band-aid patch at least helping the 
most common case (i.e losing all characters after the first NUL character).

The band-aid patch should be contained to just the hypercall. Would that 
be more suitable for you?

> 
>> This patch has the advantage to allow upgrade to a newer Debian without
>> loosing part of your prompt on zsh. I am not sure whether the problem is
>> the same with other Distros.
>>
>>>
>>> My plan is to have only one further RC before branching off 4.12,
>>> so please let us shift this patch to 4.13.
>>
>> I understand. It is possible to workaround the problem at least with
>> zsh. So a release note in Xen (and maybe Debian) should do the job.
> 
> Could you please post the needed information for the 4.12 RN?

How about:

"
While the hypercall CONSOLEIO_write looks analogous to the POSIX call 
write, it will only print character up to the first NUL character if any 
in the buffer. This may result to loss of characters for any application 
using directly the POSIX call write.

The issue has been confirmed some zsh version (such as in Debian 
Buster). Where the prompt is mangled, this could be avoided by adding 
'setopt single_line_zle' in your .zshrc.
"

Cheers,

[1] https://lists.xen.org/archives/html/xen-devel/2019-03/msg00082.html

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-05 15:28         ` Julien Grall
@ 2019-03-05 16:44           ` Juergen Gross
  2019-03-05 16:57             ` Julien Grall
  0 siblings, 1 reply; 17+ messages in thread
From: Juergen Gross @ 2019-03-05 16:44 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich

On 05/03/2019 16:28, Julien Grall wrote:
> Hi Juergen,
> 
> On 3/5/19 2:12 PM, Juergen Gross wrote:
>> On 05/03/2019 15:08, Julien Grall wrote:
>>> Hi Juergen,
>>>
>>> On 3/5/19 12:57 PM, Juergen Gross wrote:
>>>> On 27/02/2019 11:45, Julien Grall wrote:
>>>>> (+ Juergen Gross as RM)
>>>>>
>>>>> I forgot to CC Juergen for this.
>>>>>
>>>>> On 2/26/19 11:03 PM, Julien Grall wrote:
>>>>>> After upgrading Debian to Buster, I started noticing console mangling
>>>>>> when using zsh. This is happenning because output sent by zsh to the
>>>>>> console may contain NUL character in the middle of the buffer.
>>>>>>
>>>>>> Linux is sending the buffer as it is to Xen console via
>>>>>> CONSOLEIO_write.
>>>>>> However, the implementation in Xen considers NUL character is used to
>>>>>> terminate the buffer and therefore will ignore anything after it.
>>>>>>
>>>>>> The actual documentation of CONSOLEIO_write is pretty limited.
>>>>>> From the
>>>>>> declaration, the hypercall takes a buffer and size. So this could
>>>>>> lead
>>>>>> to think the NUL character is allowed in the middle of the buffer.
>>>>>>
>>>>>> This patch updates the console API to pass the size along the buffer
>>>>>> down so we can remove the reliance on buffer terminating by a NUL
>>>>>> character.
>>>>>>
>>>>>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>>>>
>>>> The risk for a regression is too high this late in the 4.12 release
>>>> process IMO.
>>>
>>> This code path is fairly well tested (console are used pretty much all
>>> the times). So a regression would be quickly noticed.
>>
>> Only if you test all the guests out in the wild.
> 
> The buffer is bounded to 'nr'. So the worst things that can happen is
> you print more characters than you wanted. CONSOLEIO_write is using a
> semantics very similar to write() and we didn't document what happen
> when encountering a NUL character. So, I highly doubt anyone relies on
> the current behavior.
> 
> Thinking a bit more, from what Ian wrote [1], the issue maybe wider than
> zsh. So maybe we want to write a band-aid patch at least helping the
> most common case (i.e losing all characters after the first NUL character).
> 
> The band-aid patch should be contained to just the hypercall. Would that
> be more suitable for you?

My main concern is the reasoning of Daniel:

"Yes, I added stripping of non-printable characters because escape
sequences printed out by some guests (in particular, clear screen
sequences printed out by some distro's early boot scripts) interfered
with the output of other guests.  It also prevents guests from
pretending to be one another or the hypervisor, if the console is being
used for some kind of auditing or logging."

With keeping in mind that the behavior is the same since more than 5
years I'd prefer to just add the text below to the release note.

> 
>>
>>> This patch has the advantage to allow upgrade to a newer Debian without
>>> loosing part of your prompt on zsh. I am not sure whether the problem is
>>> the same with other Distros.
>>>
>>>>
>>>> My plan is to have only one further RC before branching off 4.12,
>>>> so please let us shift this patch to 4.13.
>>>
>>> I understand. It is possible to workaround the problem at least with
>>> zsh. So a release note in Xen (and maybe Debian) should do the job.
>>
>> Could you please post the needed information for the 4.12 RN?
> 
> How about:
> 
> "
> While the hypercall CONSOLEIO_write looks analogous to the POSIX call
> write, it will only print character up to the first NUL character if any
> in the buffer. This may result to loss of characters for any application
> using directly the POSIX call write.
> 
> The issue has been confirmed some zsh version (such as in Debian
> Buster). Where the prompt is mangled, this could be avoided by adding
> 'setopt single_line_zle' in your .zshrc.
> "

Sounds okay for me.

With keeping in mind that the behavior is the same since more than 5
years I'm in favor of just adding above text to the release note.


Juergen

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write
  2019-03-05 16:44           ` Juergen Gross
@ 2019-03-05 16:57             ` Julien Grall
  0 siblings, 0 replies; 17+ messages in thread
From: Julien Grall @ 2019-03-05 16:57 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Stefano Stabellini, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich

Hi Juergen,

On 3/5/19 4:44 PM, Juergen Gross wrote:
> On 05/03/2019 16:28, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 3/5/19 2:12 PM, Juergen Gross wrote:
>>> On 05/03/2019 15:08, Julien Grall wrote:
>>>> Hi Juergen,
>>>>
>>>> On 3/5/19 12:57 PM, Juergen Gross wrote:
>>>>> On 27/02/2019 11:45, Julien Grall wrote:
>>>>>> (+ Juergen Gross as RM)
>>>>>>
>>>>>> I forgot to CC Juergen for this.
>>>>>>
>>>>>> On 2/26/19 11:03 PM, Julien Grall wrote:
>>>>>>> After upgrading Debian to Buster, I started noticing console mangling
>>>>>>> when using zsh. This is happenning because output sent by zsh to the
>>>>>>> console may contain NUL character in the middle of the buffer.
>>>>>>>
>>>>>>> Linux is sending the buffer as it is to Xen console via
>>>>>>> CONSOLEIO_write.
>>>>>>> However, the implementation in Xen considers NUL character is used to
>>>>>>> terminate the buffer and therefore will ignore anything after it.
>>>>>>>
>>>>>>> The actual documentation of CONSOLEIO_write is pretty limited.
>>>>>>>  From the
>>>>>>> declaration, the hypercall takes a buffer and size. So this could
>>>>>>> lead
>>>>>>> to think the NUL character is allowed in the middle of the buffer.
>>>>>>>
>>>>>>> This patch updates the console API to pass the size along the buffer
>>>>>>> down so we can remove the reliance on buffer terminating by a NUL
>>>>>>> character.
>>>>>>>
>>>>>>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>>>>>
>>>>> The risk for a regression is too high this late in the 4.12 release
>>>>> process IMO.
>>>>
>>>> This code path is fairly well tested (console are used pretty much all
>>>> the times). So a regression would be quickly noticed.
>>>
>>> Only if you test all the guests out in the wild.
>>
>> The buffer is bounded to 'nr'. So the worst things that can happen is
>> you print more characters than you wanted. CONSOLEIO_write is using a
>> semantics very similar to write() and we didn't document what happen
>> when encountering a NUL character. So, I highly doubt anyone relies on
>> the current behavior.
>>
>> Thinking a bit more, from what Ian wrote [1], the issue maybe wider than
>> zsh. So maybe we want to write a band-aid patch at least helping the
>> most common case (i.e losing all characters after the first NUL character).
>>
>> The band-aid patch should be contained to just the hypercall. Would that
>> be more suitable for you?
> 
> My main concern is the reasoning of Daniel:
> 
> "Yes, I added stripping of non-printable characters because escape
> sequences printed out by some guests (in particular, clear screen
> sequences printed out by some distro's early boot scripts) interfered
> with the output of other guests.  It also prevents guests from
> pretending to be one another or the hypervisor, if the console is being
> used for some kind of auditing or logging."
> 
> With keeping in mind that the behavior is the same since more than 5
> years I'd prefer to just add the text below to the release note.
I am afraid you have taken Daniel's comment out of the context. His 
comment was in discussion about what should be the guest behavior with 
NUL character. I have no plan for Xen 4.12 (or any later release) to 
modify this behavior.

In the case of Dom0, we already print all the non-printable characters 
until the first NUL character (or end of the buffer). What this patch is 
doing is to avoid using NUL character as a special case.

Anyway, I am not going to insist. I will defer this to Xen 4.13.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2019-03-05 16:57 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-26 23:03 [PATCH for-4.12 RFC] xen/console: Handle NUL character in buffer sent via CONSOLEIO_write Julien Grall
2019-02-27 10:25 ` Jan Beulich
2019-02-27 10:42   ` Julien Grall
2019-02-27 12:55   ` Wei Liu
2019-02-27 10:45 ` Julien Grall
2019-03-05 12:57   ` Juergen Gross
2019-03-05 14:08     ` Julien Grall
2019-03-05 14:12       ` Juergen Gross
2019-03-05 15:28         ` Julien Grall
2019-03-05 16:44           ` Juergen Gross
2019-03-05 16:57             ` Julien Grall
2019-02-27 12:55 ` Wei Liu
2019-02-27 18:45   ` Julien Grall
2019-03-01 22:59     ` Daniel De Graaf
2019-03-04 11:21       ` George Dunlap
2019-03-04 11:48         ` Julien Grall
2019-03-04 12:00           ` Ian Jackson

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.