Index | Thread | Search

From:
Hans-Jörg Höxer <hshoexer@genua.de>
Subject:
SEV-ES guest: In vctrap() only allow CPUID from userspace
To:
<tech@openbsd.org>
Date:
Tue, 1 Jul 2025 10:36:33 +0200

Download raw body.

Thread
Hi,

this diff restricts #VC trap handling.

Take care,
HJ.

-----------
commit bbf8ca5bfcd41771b0ecac3597bf033a603a54c3
Author: Hans-Joerg Hoexer <hshoexer@genua.de>
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 */
 		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