qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] vnc: heap-use-after-free in vnc_client_io() after vnc_d


From: Philippe Mathieu-Daudé
Subject: Re: [Qemu-devel] vnc: heap-use-after-free in vnc_client_io() after vnc_disconnect_finish()
Date: Thu, 19 Apr 2018 23:24:00 -0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0

On 04/19/2018 09:39 PM, Philippe Mathieu-Daudé wrote:
> On 04/19/2018 01:40 PM, Daniel P. Berrangé wrote:
>> On Thu, Apr 19, 2018 at 06:37:12PM +0200, Marc-André Lureau wrote:
>>> On Tue, Apr 17, 2018 at 7:52 PM, Philippe Mathieu-Daudé <address@hidden> 
>>> wrote:
>>>> running commit ce8d4082054519f2eaac39958edde502860a7fc6:
>>>>
>>>> qemu-system-mips -M malta -m 512 \
>>>>   -kernel vmlinux-3.2.0-4-4kc-malta \
>>>>   -append 'root=/dev/sda1 console=ttyS0' \
>>>>   -hda debian_wheezy_mips_standard.qcow2 \
>>>>   -redir tcp:5556::22 -serial stdio
>>>>
>>>> and connecting with "xtightvncviewer :0" I get when closing vnc:
>>>
>>> This is also true with other targets, ex:
>>> x86_64-softmmu/qemu-system-x86_64 -vnc :0
>>>
>>> Daniel, Gerd, are you looking at it? this looks like a 2.12 regression.
>>
>> I've not had toime to look at it - would be useful if someone can bisect
>> it at least if its a regression since 2.11
> 
> My worst bisect so far, anyway here we go:
> 
> 13e1d0e71e78a925848258391a6e616b6b5ae219 is the first bad commit
> commit 13e1d0e71e78a925848258391a6e616b6b5ae219
> Author: Daniel P. Berrange <address@hidden>
> Date:   Thu Feb 1 16:45:14 2018 +0000
> 
>     ui: convert VNC server to QIONetListener
> 
>     The VNC server already has the ability to listen on multiple sockets.
>     Converting it to use the QIONetListener APIs though, will reduce the
>     amount of code in the VNC server and improve the clarity of what is
>     left.
> 
>     Signed-off-by: Daniel P. Berrange <address@hidden>
>     Message-id: address@hidden
>     Signed-off-by: Gerd Hoffmann <address@hidden>
> 
> 
>>>> ==27686==ERROR: AddressSanitizer: heap-use-after-free on address
>>>> 0x63100003c814 at pc 0x55eed918362a bp 0x7ffdf5c36c80 sp 0x7ffdf5c36c78
>>>> READ of size 4 at 0x63100003c814 thread T0
>>>>     #0 0x55eed9183629 in vnc_client_io /source/qemu/ui/vnc.c:1549
>>>>     #1 0x55eed94ae26c in qio_channel_fd_source_dispatch
>>>> /source/qemu/io/channel-watch.c:84
>>>>     #2 0x7f3e181860f4 in g_main_context_dispatch
>>>> (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4c0f4)
>>>>     #3 0x55eed95b9799 in glib_pollfds_poll 
>>>> /source/qemu/util/main-loop.c:215
>>>>     #4 0x55eed95b9989 in os_host_main_loop_wait
>>>> /source/qemu/util/main-loop.c:263
>>>>     #5 0x55eed95b9b5f in main_loop_wait /source/qemu/util/main-loop.c:522
>>>>     #6 0x55eed898f7dd in main_loop /source/qemu/vl.c:1943
>>>>     #7 0x55eed89a1f0b in main /source/qemu/vl.c:4734
>>>>     #8 0x7f3dfe094a86 in __libc_start_main
>>>> (/lib/x86_64-linux-gnu/libc.so.6+0x21a86)
>>>>     #9 0x55eed8518db9 in _start
>>>> (/build/qemu/mips-softmmu/qemu-system-mips+0x14f3db9)
>>>>
>>>> 0x63100003c814 is located 20 bytes inside of 75744-byte region
>>>> [0x63100003c800,0x63100004efe0)
>>>> freed by thread T0 here:
>>>>     #0 0x7f3e18b878c8 in __interceptor_free
>>>> (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd98c8)
>>>>     #1 0x55eed9181bb0 in vnc_disconnect_finish /source/qemu/ui/vnc.c:1278
>>>>     #2 0x55eed9183225 in vnc_client_read /source/qemu/ui/vnc.c:1511
>>>>     #3 0x55eed91835a9 in vnc_client_io /source/qemu/ui/vnc.c:1541
>>>>     #4 0x55eed94ae26c in qio_channel_fd_source_dispatch
>>>> /source/qemu/io/channel-watch.c:84
>>>>     #5 0x7f3e181860f4 in g_main_context_dispatch
>>>> (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4c0f4)
>>>>
>>>> previously allocated by thread T0 here:
>>>>     #0 0x7f3e18b87df8 in calloc
>>>> (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd9df8)
>>>>     #1 0x7f3e1818b8b0 in g_malloc0
>>>> (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x518b0)
>>>>     #2 0x55eed9192aa0 in vnc_listen_io /source/qemu/ui/vnc.c:3186
>>>>     #3 0x55eed94b9fd7 in qio_net_listener_channel_func
>>>> /source/qemu/io/net-listener.c:57
>>>>     #4 0x55eed94ae26c in qio_channel_fd_source_dispatch
>>>> /source/qemu/io/channel-watch.c:84
>>>>     #5 0x7f3e181860f4 in g_main_context_dispatch
>>>> (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4c0f4)
>>>>
>>>> SUMMARY: AddressSanitizer: heap-use-after-free
>>>> /source/qemu/ui/vnc.c:1549 in vnc_client_io
>>>> Shadow bytes around the buggy address:
>>>>   0x0c627ffff8b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>>   0x0c627ffff8c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>>   0x0c627ffff8d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>>   0x0c627ffff8e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>>   0x0c627ffff8f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>> =>0x0c627ffff900: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd
>>>>   0x0c627ffff910: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
>>>>   0x0c627ffff920: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
>>>>   0x0c627ffff930: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
>>>>   0x0c627ffff940: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
>>>>   0x0c627ffff950: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
>>>>
>>>> Shadow byte legend (one shadow byte represents 8 application bytes):
>>>>   Heap left redzone:       fa
>>>>   Freed heap region:       fd
>>>> ==26606==ABORTING

Apparently this commit only _triggers_ a latent bug...

What I see is

void vnc_disconnect_finish(VncState *vs)
{
    ...
    g_free(vs);
}

So:

static int vnc_client_read(VncState *vs)
{
    ...
    ret = vnc_client_read_plain(vs);
    if (!ret) {
        if (vs->disconnecting) {
            vnc_disconnect_finish(vs); // free(vs)
            return -1;

Then:

gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED,
                       GIOCondition condition, void *opaque)
{
    VncState *vs = opaque;
    if (condition & G_IO_IN) {
        if (vnc_client_read(vs) < 0) { // vs freed
            goto end;
        }
    }
    ...
 end:
    if (vs->disconnecting) { // vs use-after-free

Which seems related to:

    commit d49b87f0d1e0520443a990fc610d0f02bc63c556
    Author: Klim Kireev <address@hidden>
    Date:   Wed Feb 7 12:48:44 2018 +0300

        vnc: fix segfault in closed connection handling

        On one of our client's node, due to trying to read from closed ioc,
        a segmentation fault occured. Corresponding backtrace:

        0  object_get_class (address@hidden)
        1  qio_channel_readv_full (ioc=0x0, iov=0x7ffe55277180 ...
        2  qio_channel_read (ioc=<optimized out> ...
        3  vnc_client_read_buf (address@hidden, ...
        4  vnc_client_read_plain (vs=0x55625f3c6000)
        5  vnc_client_read (vs=0x55625f3c6000)
        6  vnc_client_io (ioc=<optimized out>, condition=G_IO_IN, ...
        7  g_main_dispatch (context=0x556251568a50)
        8  g_main_context_dispatch (address@hidden)
        9  glib_pollfds_poll ()
        10 os_host_main_loop_wait (timeout=<optimized out>)
        11 main_loop_wait (address@hidden)
        12 main_loop () at vl.c:1909
        13 main (argc=<optimized out>, argv=<optimized out>, ...

        Having analyzed the coredump, I understood that the reason is that
        ioc_tag is reset on vnc_disconnect_start and ioc is cleaned
        in vnc_disconnect_finish. Between these two events due to some
        reasons the ioc_tag was set again and after vnc_disconnect_finish
        the handler is running with freed ioc,
        which led to the segmentation fault.

        The patch checks vs->disconnecting in places where we call
        qio_channel_add_watch and resets handler if disconnecting == TRUE
        to prevent such an occurrence.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]