<feed xmlns='http://www.w3.org/2005/Atom'>
<title>qemu/qemu.git/io/channel-websock.c, branch master</title>
<subtitle>QEMU main repository</subtitle>
<id>https://git.landau.one/pub/scm/virt/qemu/qemu.git/atom?h=master</id>
<link rel='self' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/'/>
<updated>2026-09-07T10:31:03+00:00</updated>
<entry>
<title>io/channel-websock: do not lose QIO_CHANNEL_ERR_BLOCK while reading</title>
<updated>2026-09-07T10:31:03+00:00</updated>
<author>
<name>Denis V. Lunev</name>
<email>den@openvz.org</email>
</author>
<published>2026-08-31T10:01:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=7a72a4652a7955db579d2b9244a09edbf7b0529b'/>
<id>urn:sha1:7a72a4652a7955db579d2b9244a09edbf7b0529b</id>
<content type='text'>
qio_channel_websock_handshake_read() folds every negative return from
qio_channel_read() into -1. QIO_CHANNEL_ERR_BLOCK leaves errp unset, so
qio_channel_websock_handshake_io() then hands a NULL Error to
error_get_pretty() and QEMU dies.

The master channel is non-blocking and, for a wss:// client, is a TLS
channel. A G_IO_IN wakeup carrying only part of a TLS record makes
gnutls report EAGAIN, which is all it takes to reach this before the
client has authenticated.

ERR_BLOCK here means the headers are not complete yet, which is what a
0 return already tells the caller. Report it that way and keep waiting.
The watch is level triggered, so an incomplete record sitting in the
socket spins the main loop until the rest of it arrives. That is
bounded by the round trip and is what every reader layered over TLS
already does.

Fixes: 2d1d0e70cf3e ("io: add QIOChannelWebsock class")
Fixes: CVE-2026-84788
Cc: qemu-stable@nongnu.org
Cc: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
Cc: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Reviewed-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
Reviewed-by: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Signed-off-by: Denis V. Lunev &lt;den@openvz.org&gt;
Signed-off-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
</content>
</entry>
<entry>
<title>io/channel-websock: handle a blocked write during the handshake</title>
<updated>2026-09-07T10:31:03+00:00</updated>
<author>
<name>Denis V. Lunev</name>
<email>den@openvz.org</email>
</author>
<published>2026-08-31T10:01:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=2295deb48898f2c466d0a5013cdd35a9d836b1cb'/>
<id>urn:sha1:2295deb48898f2c466d0a5013cdd35a9d836b1cb</id>
<content type='text'>
qio_channel_websock_handshake_send() treats every negative return from
qio_channel_write() as fatal and passes err to error_get_pretty().
QIO_CHANNEL_ERR_BLOCK is negative but leaves err NULL, so a socket
which cannot take the response immediately crashes QEMU before the
client has authenticated.

Keep the G_IO_OUT watch armed and retry instead.

Fixes: 2d1d0e70cf3e ("io: add QIOChannelWebsock class")
Fixes: CVE-2026-84788
Cc: qemu-stable@nongnu.org
Cc: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
Cc: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Reviewed-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
Reviewed-by: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Signed-off-by: Denis V. Lunev &lt;den@openvz.org&gt;
Signed-off-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
</content>
</entry>
<entry>
<title>io/channel-websock: send an HTTP 400 when the greeting has no space</title>
<updated>2026-09-07T10:31:03+00:00</updated>
<author>
<name>Denis V. Lunev</name>
<email>den@openvz.org</email>
</author>
<published>2026-08-31T10:01:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=cd71c2f40a53a569911310aceb21cef55c349d38'/>
<id>urn:sha1:cd71c2f40a53a569911310aceb21cef55c349d38</id>
<content type='text'>
qio_channel_websock_extract_headers() returns 0 without queueing a
response when the request line contains no space, unlike every sibling
check which jumps to bad_request. encoutput stays empty, yet
qio_channel_websock_handshake_read() still reports success and the
caller arms a G_IO_OUT watch to flush nothing.

Flushing that empty buffer is where QEMU crashes. Any client can
trigger it before authentication on a VNC websocket port:

  printf 'stats\r\nx\r\n\r\n' | nc $host $port

Fixes: 07e95cd529af ("io: fully parse &amp; validate HTTP headers for websocket protocol handshake")
Fixes: f69a8bde2935 ("io: send proper HTTP response for websocket errors")
Fixes: CVE-2026-84788
Cc: qemu-stable@nongnu.org
Cc: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
Cc: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Reviewed-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
Reviewed-by: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Signed-off-by: Denis V. Lunev &lt;den@openvz.org&gt;
Signed-off-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
</content>
</entry>
<entry>
<title>io: use g_clear_handle_id() for GSource cleanup</title>
<updated>2026-05-06T14:10:46+00:00</updated>
<author>
<name>Philippe Mathieu-Daudé</name>
<email>philmd@linaro.org</email>
</author>
<published>2026-04-08T09:52:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=11a64a4b7c5460dd7ff94b8bedadb636e3338473'/>
<id>urn:sha1:11a64a4b7c5460dd7ff94b8bedadb636e3338473</id>
<content type='text'>
Use g_clear_handle_id() instead of g_source_remove() with
manual ID checking and zeroing.

This simplifies the code and ensures consistent handling of
GSource IDs, since g_clear_handle_id() checks for a non-zero
ID before calling the cleanup function and zeros it afterwards.

No functional change intended.

Mechanical change using the following Coccinelle spatch script:

  @@
  expression TAG;
  @@
  -    if (TAG &gt; 0) {
  +    if (TAG) {
           g_source_remove(TAG);
           &lt;... when != TAG
           TAG = 0;
           ...&gt;
       }

  @@
  expression TAG;
  @@
  -    g_source_remove(TAG);
  -    TAG = 0;
  +    g_clear_handle_id(&amp;TAG, g_source_remove);

  @@
  expression TAG;
  @@
  -    if (TAG) {
           g_clear_handle_id(&amp;TAG, g_source_remove);
  -    }

Inspired-by: Matthew Penney &lt;matt@matthewpenney.net&gt;
Signed-off-by: Philippe Mathieu-Daudé &lt;philmd@linaro.org&gt;
Reviewed-by: Matthew Penney &lt;matt@matthewpenney.net&gt;
Message-Id: &lt;20260408100605.66795-3-philmd@linaro.org&gt;
</content>
</entry>
<entry>
<title>io: Clear dangling GLib event source tag</title>
<updated>2026-05-06T14:10:46+00:00</updated>
<author>
<name>Philippe Mathieu-Daudé</name>
<email>philmd@linaro.org</email>
</author>
<published>2026-04-08T09:50:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=f378a25b1646d33922af75aa7ea059b2123cfb13'/>
<id>urn:sha1:f378a25b1646d33922af75aa7ea059b2123cfb13</id>
<content type='text'>
Following commit 34aad589019 ("hw/char/virtio-console: clear
dangling GLib event source tag"), prevent stale tags from
being reused by clearing dangling GLib event source tag during
the cleanup phase (finalize, unrealize).

Inspired-by: Matthew Penney &lt;matt@matthewpenney.net&gt;
Signed-off-by: Philippe Mathieu-Daudé &lt;philmd@linaro.org&gt;
Reviewed-by: Matthew Penney &lt;matt@matthewpenney.net&gt;
Message-Id: &lt;20260408100605.66795-2-philmd@linaro.org&gt;
</content>
</entry>
<entry>
<title>io: Use glib2 instead of strcasecmp/strncasecmp</title>
<updated>2026-04-23T10:27:27+00:00</updated>
<author>
<name>Kostiantyn Kostiuk</name>
<email>kkostiuk@redhat.com</email>
</author>
<published>2026-03-27T13:43:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=b25ab2e77388001e60217128e404fe8f9fa051eb'/>
<id>urn:sha1:b25ab2e77388001e60217128e404fe8f9fa051eb</id>
<content type='text'>
This is a change in semantics. g_ascii_strcasecmp() doesn't honour
locale but strcasecmp() does. But this is OK for at least one reason:
 (1) QEMU always runs with the C locale so there's not an actual
     behaviour change here
 (2) we want the comparison data in HTTP header and it should be a plain
     ASCII one, not to do weird things with "I" in Turkish locales,
     so g_ascii_strcasecmp() is better as it's explicit about that

Signed-off-by: Kostiantyn Kostiuk &lt;kkostiuk@redhat.com&gt;
Reviewed-by: Peter Maydell &lt;peter.maydell@linaro.org&gt;
Link: https://lore.kernel.org/r/20260327134401.270186-5-kkostiuk@redhat.com
Signed-off-by: Paolo Bonzini &lt;pbonzini@redhat.com&gt;
</content>
</entry>
<entry>
<title>io: fix cleanup for websock I/O source data on cancellation</title>
<updated>2026-03-05T17:40:24+00:00</updated>
<author>
<name>Daniel P. Berrangé</name>
<email>berrange@redhat.com</email>
</author>
<published>2026-01-06T13:45:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=9545c059f77e3f814fcbaba83203572ea655c50e'/>
<id>urn:sha1:9545c059f77e3f814fcbaba83203572ea655c50e</id>
<content type='text'>
The websock code will create a GSource for tracking completion of the
handshake process, passing a QIOTask which is freed by the callback
when it completes, which means when a source is cancelled, nothing is
free'ing the task.

Switch to provide a data free callback to the GSource, which ensures
the QIOTask is always freed even when the main event callback never
fires.

Fixes: https://gitlab.com/qemu-project/qemu/-/issues/3114
Signed-off-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
</content>
</entry>
<entry>
<title>io: separate freeing of tasks from marking them as complete</title>
<updated>2026-03-03T10:22:46+00:00</updated>
<author>
<name>Daniel P. Berrangé</name>
<email>berrange@redhat.com</email>
</author>
<published>2026-01-06T16:08:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=163cd0ae1182e67509b271f244a73dfd938337b9'/>
<id>urn:sha1:163cd0ae1182e67509b271f244a73dfd938337b9</id>
<content type='text'>
The original design of QIOTask was intended to simplify lifecycle
management by automatically freeing it when the task was marked as
complete. This overlooked the fact that when a QIOTask is used in
combination with a GSource, there may be times when the source
callback is never invoked. This is typically when a GSource is
released before any I/O event arrives. In such cases it is not
desirable to mark a QIOTask as complete, but it still needs to be
freed. To satisfy this, the task must be released manually.

Reviewed-by: Marc-André Lureau &lt;marcandre.lureau@redhat.com&gt;
Signed-off-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
</content>
</entry>
<entry>
<title>error: error_free(NULL) is safe, drop unnecessary conditionals</title>
<updated>2026-01-07T10:26:56+00:00</updated>
<author>
<name>Markus Armbruster</name>
<email>armbru@redhat.com</email>
</author>
<published>2025-11-19T13:08:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=a4cda041072e7c6241878260644082781cd1e733'/>
<id>urn:sha1:a4cda041072e7c6241878260644082781cd1e733</id>
<content type='text'>
Signed-off-by: Markus Armbruster &lt;armbru@redhat.com&gt;
Message-ID: &lt;20251119130855.105479-5-armbru@redhat.com&gt;
Reviewed-by: Richard Henderson &lt;richard.henderson@linaro.org&gt;
Reviewed-by: Vladimir Sementsov-Ogievskiy &lt;vsementsov@yandex-team.ru&gt;
Reviewed-by: Peter Xu &lt;peterx@redhat.com&gt;
Reviewed-by: Zhao Liu &lt;zhao1.liu@intel.com&gt;
</content>
</entry>
<entry>
<title>io: fix use after free in websocket handshake code</title>
<updated>2025-10-24T12:04:31+00:00</updated>
<author>
<name>Daniel P. Berrangé</name>
<email>berrange@redhat.com</email>
</author>
<published>2025-09-30T11:03:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/virt/qemu/qemu.git/commit/?id=b7a1f2ca45c7865b9e98e02ae605a65fc9458ae9'/>
<id>urn:sha1:b7a1f2ca45c7865b9e98e02ae605a65fc9458ae9</id>
<content type='text'>
If the QIOChannelWebsock object is freed while it is waiting to
complete a handshake, a GSource is leaked. This can lead to the
callback firing later on and triggering a use-after-free in the
use of the channel. This was observed in the VNC server with the
following trace from valgrind:

==2523108== Invalid read of size 4
==2523108==    at 0x4054A24: vnc_disconnect_start (vnc.c:1296)
==2523108==    by 0x4054A24: vnc_client_error (vnc.c:1392)
==2523108==    by 0x4068A09: vncws_handshake_done (vnc-ws.c:105)
==2523108==    by 0x44863B4: qio_task_complete (task.c:197)
==2523108==    by 0x448343D: qio_channel_websock_handshake_io (channel-websock.c:588)
==2523108==    by 0x6EDB862: UnknownInlinedFun (gmain.c:3398)
==2523108==    by 0x6EDB862: g_main_context_dispatch_unlocked.lto_priv.0 (gmain.c:4249)
==2523108==    by 0x6EDBAE4: g_main_context_dispatch (gmain.c:4237)
==2523108==    by 0x45EC79F: glib_pollfds_poll (main-loop.c:287)
==2523108==    by 0x45EC79F: os_host_main_loop_wait (main-loop.c:310)
==2523108==    by 0x45EC79F: main_loop_wait (main-loop.c:589)
==2523108==    by 0x423A56D: qemu_main_loop (runstate.c:835)
==2523108==    by 0x454F300: qemu_default_main (main.c:37)
==2523108==    by 0x73D6574: (below main) (libc_start_call_main.h:58)
==2523108==  Address 0x57a6e0dc is 28 bytes inside a block of size 103,608 free'd
==2523108==    at 0x5F2FE43: free (vg_replace_malloc.c:989)
==2523108==    by 0x6EDC444: g_free (gmem.c:208)
==2523108==    by 0x4053F23: vnc_update_client (vnc.c:1153)
==2523108==    by 0x4053F23: vnc_refresh (vnc.c:3225)
==2523108==    by 0x4042881: dpy_refresh (console.c:880)
==2523108==    by 0x4042881: gui_update (console.c:90)
==2523108==    by 0x45EFA1B: timerlist_run_timers.part.0 (qemu-timer.c:562)
==2523108==    by 0x45EFC8F: timerlist_run_timers (qemu-timer.c:495)
==2523108==    by 0x45EFC8F: qemu_clock_run_timers (qemu-timer.c:576)
==2523108==    by 0x45EFC8F: qemu_clock_run_all_timers (qemu-timer.c:663)
==2523108==    by 0x45EC765: main_loop_wait (main-loop.c:600)
==2523108==    by 0x423A56D: qemu_main_loop (runstate.c:835)
==2523108==    by 0x454F300: qemu_default_main (main.c:37)
==2523108==    by 0x73D6574: (below main) (libc_start_call_main.h:58)
==2523108==  Block was alloc'd at
==2523108==    at 0x5F343F3: calloc (vg_replace_malloc.c:1675)
==2523108==    by 0x6EE2F81: g_malloc0 (gmem.c:133)
==2523108==    by 0x4057DA3: vnc_connect (vnc.c:3245)
==2523108==    by 0x448591B: qio_net_listener_channel_func (net-listener.c:54)
==2523108==    by 0x6EDB862: UnknownInlinedFun (gmain.c:3398)
==2523108==    by 0x6EDB862: g_main_context_dispatch_unlocked.lto_priv.0 (gmain.c:4249)
==2523108==    by 0x6EDBAE4: g_main_context_dispatch (gmain.c:4237)
==2523108==    by 0x45EC79F: glib_pollfds_poll (main-loop.c:287)
==2523108==    by 0x45EC79F: os_host_main_loop_wait (main-loop.c:310)
==2523108==    by 0x45EC79F: main_loop_wait (main-loop.c:589)
==2523108==    by 0x423A56D: qemu_main_loop (runstate.c:835)
==2523108==    by 0x454F300: qemu_default_main (main.c:37)
==2523108==    by 0x73D6574: (below main) (libc_start_call_main.h:58)
==2523108==

The above can be reproduced by launching QEMU with

  $ qemu-system-x86_64 -vnc localhost:0,websocket=5700

and then repeatedly running:

  for i in {1..100}; do
     (echo -n "GET / HTTP/1.1" &amp;&amp; sleep 0.05) | nc -w 1 localhost 5700 &amp;
  done

CVE-2025-11234
Reported-by: Grant Millar | Cylo &lt;rid@cylo.io&gt;
Reviewed-by: Eric Blake &lt;eblake@redhat.com&gt;
Signed-off-by: Daniel P. Berrangé &lt;berrange@redhat.com&gt;
</content>
</entry>
</feed>
