From f757d9d90d19b914d4023663bfc4da73bbbf007e Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Mon, 11 Aug 2025 12:11:24 +0200 Subject: [PATCH 1/4] hw/uefi: clear uefi-vars buffer in uefi_vars_write callback When the guest writes to register UEFI_VARS_REG_BUFFER_SIZE, the .write callback `uefi_vars_write` is invoked. The function allocates a heap buffer without zeroing the memory, leaving the buffer filled with residual data from prior allocations. When the guest later reads from register UEFI_VARS_REG_PIO_BUFFER_TRANSFER, the .read callback `uefi_vars_read` returns leftover metadata or other sensitive process memory from the previously allocated buffer, leading to an information disclosure vulnerability. Fixes: CVE-2025-8860 Fixes: 90ca4e03c27d ("hw/uefi: add var-service-core.c") Reported-by: ZDI Suggested-by: Gerd Hoffmann Signed-off-by: Mauro Matteo Cascella Message-ID: <20250811101128.17661-1-mcascell@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/uefi/var-service-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/uefi/var-service-core.c b/hw/uefi/var-service-core.c index feec5a5958..6ab8df091a 100644 --- a/hw/uefi/var-service-core.c +++ b/hw/uefi/var-service-core.c @@ -259,8 +259,8 @@ static void uefi_vars_write(void *opaque, hwaddr addr, uint64_t val, unsigned si uv->buf_size = val; g_free(uv->buffer); g_free(uv->pio_xfer_buffer); - uv->buffer = g_malloc(uv->buf_size); - uv->pio_xfer_buffer = g_malloc(uv->buf_size); + uv->buffer = g_malloc0(uv->buf_size); + uv->pio_xfer_buffer = g_malloc0(uv->buf_size); break; case UEFI_VARS_REG_DMA_BUFFER_ADDR_LO: uv->buf_addr_lo = val; From 88e5a28d5aabb57f44c1805fbba0a458023f5106 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 11 Aug 2025 15:01:08 +0200 Subject: [PATCH 2/4] hw/uefi: return success for notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set status to SUCCESS for ready-to-boot and exit-boot-services notification calls. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Message-ID: <20250811130110.820958-2-kraxel@redhat.com> --- hw/uefi/var-service-vars.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/uefi/var-service-vars.c b/hw/uefi/var-service-vars.c index 37d05b71cf..cbeccdbd26 100644 --- a/hw/uefi/var-service-vars.c +++ b/hw/uefi/var-service-vars.c @@ -702,12 +702,14 @@ uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv) case SMM_VARIABLE_FUNCTION_READY_TO_BOOT: trace_uefi_event("ready-to-boot"); uv->ready_to_boot = true; + mvar->status = EFI_SUCCESS; length = 0; break; case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE: trace_uefi_event("exit-boot-service"); uv->exit_boot_service = true; + mvar->status = EFI_SUCCESS; length = 0; break; From fc8ee8fe58ad410f27fca64e4ad212c5a3eabe00 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 11 Aug 2025 15:01:09 +0200 Subject: [PATCH 3/4] hw/uefi: check access for first variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When listing variables (via get-next-variable-name) only the names of variables which can be accessed will be returned. That check was missing for the first variable though. Add it. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Message-ID: <20250811130110.820958-3-kraxel@redhat.com> --- hw/uefi/var-service-vars.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/uefi/var-service-vars.c b/hw/uefi/var-service-vars.c index cbeccdbd26..8533533ea5 100644 --- a/hw/uefi/var-service-vars.c +++ b/hw/uefi/var-service-vars.c @@ -357,6 +357,9 @@ uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr, if (uefi_strlen(name, nv->name_size) == 0) { /* empty string -> first */ var = QTAILQ_FIRST(&uv->variables); + while (var && !check_access(uv, var)) { + var = QTAILQ_NEXT(var, next); + } if (!var) { return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND); } From 040237436f423253f3397547aa78d449394dfbca Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 11 Aug 2025 15:01:10 +0200 Subject: [PATCH 4/4] hw/uefi: open json file in binary mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes file length discrepancies due to line ending conversions on windows hosts. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3058 Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Message-ID: <20250811130110.820958-4-kraxel@redhat.com> --- hw/uefi/var-service-json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c index ad3462cd15..f5f1556833 100644 --- a/hw/uefi/var-service-json.c +++ b/hw/uefi/var-service-json.c @@ -172,7 +172,7 @@ static GString *uefi_vars_to_json(uefi_vars_state *uv) void uefi_vars_json_init(uefi_vars_state *uv, Error **errp) { if (uv->jsonfile) { - uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR, 0666, errp); + uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR | O_BINARY, 0666, errp); } }