qemu/hw/display
Laszlo Ersek e12abe5a7d hw/display/ramfb: plug slight guest-triggerable leak on mode setting
The fw_cfg DMA write callback in ramfb prepares a new display surface in
QEMU; this new surface is put to use ("swapped in") upon the next display
update. At that time, the old surface (if any) is released.

If the guest triggers the fw_cfg DMA write callback at least twice between
two adjacent display updates, then the second callback (and further such
callbacks) will leak the previously prepared (but not yet swapped in)
display surface.

The issue can be shown by:

(1) starting QEMU with "-trace displaysurface_free", and

(2) running the following program in the guest UEFI shell:

> #include <Library/ShellCEntryLib.h>           // ShellAppMain()
> #include <Library/UefiBootServicesTableLib.h> // gBS
> #include <Protocol/GraphicsOutput.h>          // EFI_GRAPHICS_OUTPUT_PROTOCOL
>
> INTN
> EFIAPI
> ShellAppMain (
>   IN UINTN   Argc,
>   IN CHAR16  **Argv
>   )
> {
>   EFI_STATUS                    Status;
>   VOID                          *Interface;
>   EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop;
>   UINT32                        Mode;
>
>   Status = gBS->LocateProtocol (
>                   &gEfiGraphicsOutputProtocolGuid,
>                   NULL,
>                   &Interface
>                   );
>   if (EFI_ERROR (Status)) {
>     return 1;
>   }
>
>   Gop = Interface;
>
>   Mode = 1;
>   for ( ; ;) {
>     Status = Gop->SetMode (Gop, Mode);
>     if (EFI_ERROR (Status)) {
>       break;
>     }
>
>     Mode = 1 - Mode;
>   }
>
>   return 1;
> }

The symptom is then that:

- only one trace message appears periodically,

- the time between adjacent messages keeps increasing -- implying that
  some list structure (containing the leaked resources) keeps growing,

- the "surface" pointer is ever different.

> 18566@1695127471.449586:displaysurface_free surface=0x7f2fcc09a7c0
> 18566@1695127471.529559:displaysurface_free surface=0x7f2fcc9dac10
> 18566@1695127471.659812:displaysurface_free surface=0x7f2fcc441dd0
> 18566@1695127471.839669:displaysurface_free surface=0x7f2fcc0363d0
> 18566@1695127472.069674:displaysurface_free surface=0x7f2fcc413a80
> 18566@1695127472.349580:displaysurface_free surface=0x7f2fcc09cd00
> 18566@1695127472.679783:displaysurface_free surface=0x7f2fcc1395f0
> 18566@1695127473.059848:displaysurface_free surface=0x7f2fcc1cae50
> 18566@1695127473.489724:displaysurface_free surface=0x7f2fcc42fc50
> 18566@1695127473.969791:displaysurface_free surface=0x7f2fcc45dcc0
> 18566@1695127474.499708:displaysurface_free surface=0x7f2fcc70b9d0
> 18566@1695127475.079769:displaysurface_free surface=0x7f2fcc82acc0
> 18566@1695127475.709941:displaysurface_free surface=0x7f2fcc369c00
> 18566@1695127476.389619:displaysurface_free surface=0x7f2fcc32b910
> 18566@1695127477.119772:displaysurface_free surface=0x7f2fcc0d5a20
> 18566@1695127477.899517:displaysurface_free surface=0x7f2fcc086c40
> 18566@1695127478.729962:displaysurface_free surface=0x7f2fccc72020
> 18566@1695127479.609839:displaysurface_free surface=0x7f2fcc185160
> 18566@1695127480.539688:displaysurface_free surface=0x7f2fcc23a7e0
> 18566@1695127481.519759:displaysurface_free surface=0x7f2fcc3ec870
> 18566@1695127482.549930:displaysurface_free surface=0x7f2fcc634960
> 18566@1695127483.629661:displaysurface_free surface=0x7f2fcc26b140
> 18566@1695127484.759987:displaysurface_free surface=0x7f2fcc321700
> 18566@1695127485.940289:displaysurface_free surface=0x7f2fccaad100

We figured this wasn't a CVE-worthy problem, as only small amounts of
memory were leaked (the framebuffer itself is mapped from guest RAM, QEMU
only allocates administrative structures), plus libvirt restricts QEMU
memory footprint anyway, thus the guest can only DoS itself.

Plug the leak, by releasing the last prepared (not yet swapped in) display
surface, if any, in the fw_cfg DMA write callback.

Regarding the "reproducer", with the fix in place, the log is flooded with
trace messages (one per fw_cfg write), *and* the trace message alternates
between just two "surface" pointer values (i.e., nothing is leaked, the
allocator flip-flops between two objects in effect).

This issue appears to date back to the introducion of ramfb (995b30179b,
"hw/display: add ramfb, a simple boot framebuffer living in guest ram",
2018-06-18).

Cc: Gerd Hoffmann <kraxel@redhat.com> (maintainer:ramfb)
Cc: qemu-stable@nongnu.org
Fixes: 995b30179b
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20230919131955.27223-1-lersek@redhat.com>
(cherry picked from commit e0288a7784)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2023-10-05 08:44:37 +03:00
..
acpi-vga-stub.c acpi: pc: vga: use AcpiDevAmlIf interface to build VGA device descriptors 2022-11-07 14:00:29 -05:00
acpi-vga.c acpi: pc: vga: use AcpiDevAmlIf interface to build VGA device descriptors 2022-11-07 14:00:29 -05:00
artist.c artist: set memory region owners for buffers to the artist device 2022-06-26 18:40:28 +01:00
ati_2d.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
ati_dbg.c ati-vga: Add dummy MEM_SDRAM_MODE_REG 2020-06-30 22:54:24 +02:00
ati_int.h Use OBJECT_DECLARE_SIMPLE_TYPE when possible 2020-09-18 14:12:32 -04:00
ati_regs.h ati-vga: Add dummy MEM_SDRAM_MODE_REG 2020-06-30 22:54:24 +02:00
ati.c hw/display: Allow vga_common_init() to return errors 2022-03-18 10:15:57 +01:00
bcm2835_fb.c hw/display/bcm2835_fb: Fix framebuffer allocation address 2022-07-26 14:09:44 +01:00
blizzard.c hw/display: fix tab indentation 2022-11-08 10:23:32 +01:00
bochs-display.c Use OBJECT_DECLARE_SIMPLE_TYPE when possible 2020-09-18 14:12:32 -04:00
cg3.c Remove qemu-common.h include from most units 2022-04-06 14:31:55 +02:00
cirrus_vga_internal.h hw/display/cirrus_vga: Move "isa-cirrus-vga" device into a separate file 2018-10-15 09:57:33 +02:00
cirrus_vga_isa.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
cirrus_vga_rop2.h cirrus: fix PUTPIXEL macro 2017-03-27 12:14:45 +02:00
cirrus_vga_rop.h cirrus: fix off-by-one in cirrus_bitblt_rop_bkwd_transp_*_16 2017-03-17 10:23:44 +01:00
cirrus_vga.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
dpcd.c hw/display/dpcd: Convert debug printf()s to trace events 2020-05-28 11:38:57 +02:00
edid-generate.c edid: Fix clock of Detailed Timing Descriptor 2022-03-04 11:31:46 +01:00
edid-region.c Include exec/memory.h slightly less 2019-08-16 13:31:52 +02:00
exynos4210_fimd.c hw/display/exynos4210_fimd: Fix potential NULL pointer dereference 2020-11-02 16:52:17 +00:00
framebuffer.c Include hw/hw.h exactly where needed 2019-08-16 13:31:52 +02:00
framebuffer.h
g364fb.c g364fb: add VMStateDescription for G364SysBusState 2021-07-02 17:35:08 +02:00
i2c-ddc.c Mark remaining global TypeInfo instances as const 2022-02-21 13:30:20 +00:00
jazz_led.c Use OBJECT_DECLARE_SIMPLE_TYPE when possible 2020-09-18 14:12:32 -04:00
Kconfig hw/display: Rename VGA_ISA_MM -> VGA_MMIO 2022-01-13 10:58:54 +01:00
macfb.c macfb: set initial value of mode control registers in macfb_common_realize() 2022-03-09 09:29:10 +00:00
meson.build acpi: pc: vga: use AcpiDevAmlIf interface to build VGA device descriptors 2022-11-07 14:00:29 -05:00
next-fb.c hw/display/next-fb: Fix comment typo 2022-12-03 22:07:07 +01:00
omap_dss.c hw/display: fix tab indentation 2022-11-08 10:23:32 +01:00
omap_lcdc.c hw/display/omap_lcdc: Delete unnecessary macro 2021-03-06 13:30:38 +00:00
pl110_template.h Replace config-time define HOST_WORDS_BIGENDIAN 2022-04-06 10:50:37 +02:00
pl110.c hw/display/pl110: Remove use of BITS from pl110_template.h 2021-03-14 13:14:55 +00:00
pxa2xx_lcd.c hw/display: fix tab indentation 2022-11-08 10:23:32 +01:00
qxl-logger.c hw/display/qxl: Pass requested buffer size to qxl_phys2virt() 2022-11-29 18:15:26 -05:00
qxl-render.c hw/display/qxl: Pass requested buffer size to qxl_phys2virt() 2022-11-29 18:15:26 -05:00
qxl.c qxl: don't assert() if device isn't yet initialized 2023-09-11 10:53:51 +03:00
qxl.h hw/display/qxl: Avoid buffer overrun in qxl_phys2virt (CVE-2022-4144) 2022-11-29 18:15:26 -05:00
ramfb-standalone.c Use DECLARE_*CHECKER* macros 2020-09-09 09:27:09 -04:00
ramfb.c hw/display/ramfb: plug slight guest-triggerable leak on mode setting 2023-10-05 08:44:37 +03:00
sii9022.c hw/i2c: add asynchronous send 2022-06-30 09:21:14 +02:00
sm501.c hw/i2c: Rename i2c_set_slave_address() -> i2c_slave_set_address() 2021-07-08 14:15:01 -05:00
ssd0303.c hw/i2c: add asynchronous send 2022-06-30 09:21:14 +02:00
ssd0323.c hw/ssi: Rename SSI 'slave' as 'peripheral' 2020-12-10 12:15:03 -05:00
tc6393xb.c Use g_new() & friends where that makes obvious sense 2022-03-21 15:44:44 +01:00
tcx.c Remove qemu-common.h include from most units 2022-04-06 14:31:55 +02:00
trace-events hw/display/vmware_vga: do not discard screen updates 2022-04-22 11:47:08 +02:00
trace.h trace: switch position of headers to what Meson requires 2020-08-21 06:18:24 -04:00
vga_int.h display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
vga_regs.h hw/display: fix tab indentation 2022-11-08 10:23:32 +01:00
vga-access.h vga: move access helpers to separate include file 2019-09-19 10:37:46 +02:00
vga-helpers.h vga: move access helpers to separate include file 2019-09-19 10:37:46 +02:00
vga-isa.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
vga-mmio.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
vga-pci.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
vga.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
vhost-user-gpu-pci.c modules: introduces module_kconfig directive 2022-06-06 09:26:53 +02:00
vhost-user-gpu.c vhost-user: Call qemu_socketpair() instead of socketpair() 2022-09-29 14:38:05 +04:00
vhost-user-vga.c modules: introduces module_kconfig directive 2022-06-06 09:26:53 +02:00
virtio-gpu-base.c virtio-gpu: Respect UI refresh rate for EDID 2022-06-14 10:34:37 +02:00
virtio-gpu-gl.c modules: introduces module_kconfig directive 2022-06-06 09:26:53 +02:00
virtio-gpu-pci-gl.c modules: introduces module_kconfig directive 2022-06-06 09:26:53 +02:00
virtio-gpu-pci.c modules: introduces module_kconfig directive 2022-06-06 09:26:53 +02:00
virtio-gpu-udmabuf-stubs.c virtio-gpu: splitting one extended mode guest fb into n-scanouts 2021-11-05 12:29:19 +01:00
virtio-gpu-udmabuf.c Remove qemu-common.h include from most units 2022-04-06 14:31:55 +02:00
virtio-gpu-virgl.c virtio-gpu: use VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP 2021-12-21 10:50:21 +04:00
virtio-gpu.c hw: replace most qemu_bh_new calls with qemu_bh_new_guarded 2023-09-11 10:53:50 +03:00
virtio-vga-gl.c modules: introduces module_kconfig directive 2022-06-06 09:26:53 +02:00
virtio-vga.c ui/console: Do not return a value with ui_info 2022-06-14 10:34:37 +02:00
virtio-vga.h qom: Remove module_obj_name parameter from OBJECT_DECLARE* macros 2020-09-18 14:12:32 -04:00
vmware_vga.c display: include dependencies explicitly 2022-11-10 10:17:18 -05:00
xenfb.c hw/display: fix tab indentation 2022-11-08 10:23:32 +01:00
xlnx_dp.c xlnx_dp: drop unsupported AUXCommand in xlnx_dp_aux_set_command 2022-08-08 11:40:06 +02:00