x86/sev: Check for user-space IOIO pointing to kernel space
authorJoerg Roedel <jroedel@suse.de>
Mon, 16 Oct 2023 12:42:50 +0000 (14:42 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Tue, 17 Oct 2023 08:58:16 +0000 (10:58 +0200)
Check the memory operand of INS/OUTS before emulating the instruction.
The #VC exception can get raised from user-space, but the memory operand
can be manipulated to access kernel memory before the emulation actually
begins and after the exception handler has run.

  [ bp: Massage commit message. ]

Fixes: 597cfe48212a ("x86/boot/compressed/64: Setup a GHCB-based VC Exception handler")
Reported-by: Tom Dohrmann <erbse.13@gmx.de>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: <stable@kernel.org>
arch/x86/boot/compressed/sev.c
arch/x86/kernel/sev-shared.c

index afd91041ec3ed062a7ce1c68c443b7f1650dfebe..80d76aea1f7bf19864252287ac7c1a8b4c08fbcd 100644 (file)
@@ -108,6 +108,11 @@ static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t si
        return ES_OK;
 }
 
+static bool fault_in_kernel_space(unsigned long address)
+{
+       return false;
+}
+
 #undef __init
 #define __init
 
index bcd77c48be0a5aa18aaf4f81f502d02c6a9500c2..4d729686f99259e3328808dfb4ea0918712cb11e 100644 (file)
@@ -592,6 +592,23 @@ fail:
        sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
 }
 
+static enum es_result vc_insn_string_check(struct es_em_ctxt *ctxt,
+                                          unsigned long address,
+                                          bool write)
+{
+       if (user_mode(ctxt->regs) && fault_in_kernel_space(address)) {
+               ctxt->fi.vector     = X86_TRAP_PF;
+               ctxt->fi.error_code = X86_PF_USER;
+               ctxt->fi.cr2        = address;
+               if (write)
+                       ctxt->fi.error_code |= X86_PF_WRITE;
+
+               return ES_EXCEPTION;
+       }
+
+       return ES_OK;
+}
+
 static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
                                          void *src, char *buf,
                                          unsigned int data_size,
@@ -599,7 +616,12 @@ static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
                                          bool backwards)
 {
        int i, b = backwards ? -1 : 1;
-       enum es_result ret = ES_OK;
+       unsigned long address = (unsigned long)src;
+       enum es_result ret;
+
+       ret = vc_insn_string_check(ctxt, address, false);
+       if (ret != ES_OK)
+               return ret;
 
        for (i = 0; i < count; i++) {
                void *s = src + (i * data_size * b);
@@ -620,7 +642,12 @@ static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt,
                                           bool backwards)
 {
        int i, s = backwards ? -1 : 1;
-       enum es_result ret = ES_OK;
+       unsigned long address = (unsigned long)dst;
+       enum es_result ret;
+
+       ret = vc_insn_string_check(ctxt, address, true);
+       if (ret != ES_OK)
+               return ret;
 
        for (i = 0; i < count; i++) {
                void *d = dst + (i * data_size * s);