Index | Thread | Search

From:
Mike Larkin <mlarkin@nested.page>
Subject:
Re: SEV-ES: ensure GHCB is cleared/invalidated after use
To:
tech@openbsd.org
Date:
Sun, 30 Nov 2025 11:10:47 -0800

Download raw body.

Thread
On Thu, Nov 27, 2025 at 03:46:19PM +0100, hshoexer wrote:
> 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?
>

good catch. ok mlarkin.

> 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);
>  }
>
>