From: hshoexer Subject: SEV-ES: ensure GHCB is cleared/invalidated after use To: tech@openbsd.org Date: Thu, 27 Nov 2025 15:46:19 +0100 Hi, in SEV-ES mode, guest userland is allowed to execute the vmgexit instruction, although it has no control over the GHCB. Therefore, it is important that the GHCB does not contain a valid request after use. In all "vmgexit paths" the GHCB is cleared by ghcb_sync_in() (it calls ghcb_clear()) after returning from the hypervisor back into the guest. However, in _ghcb_mem_rw() I missed this when requesting MMIO writes from the hypervisor. The diff below corrects this. I want to keep this pattern in all vmgexit paths: ghcb_sync_out vmgexit ghcb_verify_bm ghcb_sync_in Therefore, I shuffled some code around instead of just calling vmgexit_clear() in the else branch. ok? thoughts? Take care, HJ. ----------------------------------------------------------------------- diff --git a/sys/arch/amd64/amd64/ghcb.c b/sys/arch/amd64/amd64/ghcb.c index 2b0fa809570..b6aa2840228 100644 --- a/sys/arch/amd64/amd64/ghcb.c +++ b/sys/arch/amd64/amd64/ghcb.c @@ -271,7 +271,7 @@ _ghcb_mem_rw(vaddr_t addr, int valsz, void *val, bool read) struct ghcb_sync syncout, syncin; struct ghcb_sa *ghcb; unsigned long s; - struct ghcb_extra_regs ghcb_regs; + struct ghcb_extra_regs ghcb_regs, *pregs = NULL; KASSERT(val != NULL); @@ -334,15 +334,15 @@ _ghcb_mem_rw(vaddr_t addr, int valsz, void *val, bool read) panic("invalid hypervisor response"); } - memset(&ghcb_regs, 0, sizeof(ghcb_regs)); - if (read) { + memset(&ghcb_regs, 0, sizeof(ghcb_regs)); ghcb_regs.data = val; ghcb_regs.data_sz = size; - - ghcb_sync_in(NULL, &ghcb_regs, ghcb, &syncin); + pregs = &ghcb_regs; } + ghcb_sync_in(NULL, pregs, ghcb, &syncin); + intr_restore(s); }