hw/uefi: add pcap support

Add pcapfile property to uevi-vars-* devices, allowing to write out a
capture of the communication traffic between uefi firmware and qemu.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20260114110406.3500357-3-kraxel@redhat.com>
[PMD: Wrap long line to avoid checkpatch.pl warning]
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
Gerd Hoffmann
2025-11-26 15:25:59 +01:00
committed by Philippe Mathieu-Daudé
parent 9aac42720c
commit 41e047ad66
5 changed files with 114 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ system_ss.add(files('hardware-info.c', 'ovmf-log.c'))
uefi_vars_ss = ss.source_set()
if (config_all_devices.has_key('CONFIG_UEFI_VARS'))
uefi_vars_ss.add(files('var-service-core.c',
'var-service-pcap.c',
'var-service-json.c',
'var-service-vars.c',
'var-service-auth.c',

View File

@@ -101,6 +101,8 @@ static uint32_t uefi_vars_cmd_mm(uefi_vars_state *uv, bool dma_mode)
}
memset(uv->buffer + size, 0, uv->buf_size - size);
uefi_vars_pcap_request(uv, uv->buffer, size);
/* dispatch */
if (qemu_uuid_is_equal(&mhdr->guid, &EfiSmmVariableProtocolGuid)) {
retval = uefi_vars_mm_vars_proto(uv);
@@ -127,6 +129,8 @@ static uint32_t uefi_vars_cmd_mm(uefi_vars_state *uv, bool dma_mode)
retval = UEFI_VARS_STS_ERR_NOT_SUPPORTED;
}
uefi_vars_pcap_reply(uv, uv->buffer, sizeof(*mhdr) + mhdr->length);
/* write buffer */
if (dma_mode) {
dma_memory_write(&address_space_memory, dma,
@@ -163,6 +167,8 @@ void uefi_vars_hard_reset(uefi_vars_state *uv)
uefi_vars_clear_volatile(uv);
uefi_vars_policies_clear(uv);
uefi_vars_auth_init(uv);
uefi_vars_pcap_reset(uv);
}
static uint32_t uefi_vars_cmd(uefi_vars_state *uv, uint32_t cmd)
@@ -319,4 +325,5 @@ void uefi_vars_realize(uefi_vars_state *uv, Error **errp)
{
uefi_vars_json_init(uv, errp);
uefi_vars_json_load(uv, errp);
uefi_vars_pcap_init(uv, errp);
}

View File

@@ -0,0 +1,95 @@
/*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/pcap.h"
#include "system/dma.h"
#include "hw/uefi/var-service.h"
#define LINKTYPE_EDK2_MM 302
#define SNAPLEN (64 * 1024)
#define TYPE_RESET 0x01
#define TYPE_REQUEST 0x02
#define TYPE_REPLY 0x03
static void uefi_vars_pcap_header(FILE *fp)
{
static const struct pcap_hdr header = {
.magic_number = PCAP_MAGIC,
.version_major = PCAP_MAJOR,
.version_minor = PCAP_MINOR,
.snaplen = SNAPLEN,
.network = LINKTYPE_EDK2_MM,
};
fwrite(&header, sizeof(header), 1, fp);
fflush(fp);
}
static void uefi_vars_pcap_packet(FILE *fp, uint32_t type,
void *buffer, size_t size)
{
struct pcaprec_hdr header;
struct timeval tv;
uint32_t orig_len = size + sizeof(type);
uint32_t incl_len = MIN(orig_len, SNAPLEN);
gettimeofday(&tv, NULL);
header.ts_sec = tv.tv_sec;
header.ts_usec = tv.tv_usec;
header.incl_len = incl_len;
header.orig_len = orig_len;
fwrite(&header, sizeof(header), 1, fp);
fwrite(&type, sizeof(type), 1, fp);
if (buffer) {
fwrite(buffer, incl_len - sizeof(type), 1, fp);
}
fflush(fp);
}
void uefi_vars_pcap_init(uefi_vars_state *uv, Error **errp)
{
int fd;
if (!uv->pcapfile) {
return;
}
fd = qemu_create(uv->pcapfile,
O_WRONLY | O_TRUNC | O_BINARY,
0666, errp);
if (fd < 0) {
return;
}
uv->pcapfp = fdopen(fd, "wb");
uefi_vars_pcap_header(uv->pcapfp);
}
void uefi_vars_pcap_reset(uefi_vars_state *uv)
{
if (!uv->pcapfp) {
return;
}
uefi_vars_pcap_packet(uv->pcapfp, TYPE_RESET, NULL, 0);
}
void uefi_vars_pcap_request(uefi_vars_state *uv, void *buffer, size_t size)
{
if (!uv->pcapfp) {
return;
}
uefi_vars_pcap_packet(uv->pcapfp, TYPE_REQUEST, buffer, size);
}
void uefi_vars_pcap_reply(uefi_vars_state *uv, void *buffer, size_t size)
{
if (!uv->pcapfp) {
return;
}
uefi_vars_pcap_packet(uv->pcapfp, TYPE_REPLY, buffer, size);
}

View File

@@ -33,6 +33,7 @@ static const Property uefi_vars_sysbus_properties[] = {
DEFINE_PROP_SIZE("size", uefi_vars_sysbus_state, state.max_storage,
256 * 1024),
DEFINE_PROP_STRING("jsonfile", uefi_vars_sysbus_state, state.jsonfile),
DEFINE_PROP_STRING("pcapfile", uefi_vars_sysbus_state, state.pcapfile),
DEFINE_PROP_BOOL("force-secure-boot", uefi_vars_sysbus_state,
state.force_secure_boot, false),
DEFINE_PROP_BOOL("disable-custom-mode", uefi_vars_sysbus_state,

View File

@@ -77,6 +77,10 @@ struct uefi_vars_state {
bool force_secure_boot;
bool disable_custom_mode;
bool use_pio;
/* request + reply capture */
char *pcapfile;
FILE *pcapfp;
};
struct uefi_vars_cert {
@@ -189,4 +193,10 @@ uefi_var_policy *uefi_vars_add_policy(uefi_vars_state *uv,
variable_policy_entry *pe);
uint32_t uefi_vars_mm_check_policy_proto(uefi_vars_state *uv);
/* vars-service-pcap.c */
void uefi_vars_pcap_init(uefi_vars_state *uv, Error **errp);
void uefi_vars_pcap_reset(uefi_vars_state *uv);
void uefi_vars_pcap_request(uefi_vars_state *uv, void *buffer, size_t size);
void uefi_vars_pcap_reply(uefi_vars_state *uv, void *buffer, size_t size);
#endif /* QEMU_UEFI_VAR_SERVICE_H */