From: Mike Larkin Subject: Re: SEV-ES guest: In vctrap() only allow CPUID from userspace To: tech@openbsd.org Date: Wed, 2 Jul 2025 11:46:38 -0700 On Tue, Jul 01, 2025 at 10:36:33AM +0200, Hans-Jörg Höxer wrote: > Hi, > > this diff restricts #VC trap handling. > > Take care, > HJ. > see below > ----------- > commit bbf8ca5bfcd41771b0ecac3597bf033a603a54c3 > Author: Hans-Joerg Hoexer > Date: Thu Mar 20 17:17:31 2025 +0100 > > SEV-ES guest: In vctrap() only allow CPUID also from userspace > > CPUID is the only instruction we allow to raise a #VC exception also > from user space. All other instructions are limited to raise #VC > from kernel space only. > > With respect to rdmsr/wrmsr this is an additional safe-guard, as > these two instructions will raise a #GP anyway when the CPL is > greater than 0. > > With respect to in/out userland can be allowed to access IO ports. > Howerver, for now we do not want to support this. > > diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c > index f68cb2c90d5..9c532846c41 100644 > --- a/sys/arch/amd64/amd64/trap.c > +++ b/sys/arch/amd64/amd64/trap.c > @@ -97,7 +97,7 @@ > > int upageflttrap(struct trapframe *, uint64_t); > int kpageflttrap(struct trapframe *, uint64_t); > -int vctrap(struct trapframe *); > +int vctrap(struct trapframe *, int); > void kerntrap(struct trapframe *); > void usertrap(struct trapframe *); > void ast(struct trapframe *); > @@ -302,7 +302,7 @@ kpageflttrap(struct trapframe *frame, uint64_t cr2) > } > > int > -vctrap(struct trapframe *frame) > +vctrap(struct trapframe *frame, int user) > { > uint64_t sw_exitcode, sw_exitinfo1, sw_exitinfo2; > uint8_t *rip = (uint8_t *)(frame->tf_rip); > @@ -340,6 +340,8 @@ vctrap(struct trapframe *frame) > frame->tf_rip += 2; > break; > case SVM_VMEXIT_MSR: { > + if (user) > + return 0; /* not allowed from userspace */ > if (*rip == 0x0f && *(rip + 1) == 0x30) { > /* WRMSR */ > ghcb_sync_val(GHCB_RAX, GHCB_SZ32, &syncout); > @@ -357,6 +359,8 @@ vctrap(struct trapframe *frame) > break; > } > case SVM_VMEXIT_IOIO: { > + if (user) > + return 0; /* not allowed from userspace */ Does this not break cases that use the IOPB for port access from usermode? > switch (*rip) { > case 0x66: { > switch (*(rip + 1)) { > @@ -505,7 +509,7 @@ kerntrap(struct trapframe *frame) > #endif /* NISA > 0 */ > > case T_VC: > - if (vctrap(frame)) > + if (vctrap(frame, 0)) > return; > goto we_re_toast; > } > @@ -588,9 +592,11 @@ usertrap(struct trapframe *frame) > : ILL_BADSTK; > break; > case T_VC: > - vctrap(frame); > - goto out; > - > + if (vctrap(frame, 1)) > + goto out; > + sig = SIGILL; > + code = ILL_PRVOPC; > + break; > case T_PAGEFLT: /* page fault */ > if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p), > "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", > diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S > index 59823862c18..4181ab216d0 100644 > --- a/sys/arch/amd64/amd64/vector.S > +++ b/sys/arch/amd64/amd64/vector.S > @@ -553,6 +553,7 @@ IDTVEC(vctrap_early) > TRAP_ENTRY_KERN /* early #VC has to be in kernel mode */ > cld > movq %rsp, %rdi > + movq $0x0, %rsi > call vctrap > movq $0,-8(%rsp) > INTRFASTEXIT