Skip to content

Commit c90c4a4

Browse files
committed
x86/sev: Check IOBM for IOIO exceptions from user-space
jira VULN-6719 cve CVE-2023-46813 commit-author Joerg Roedel <[email protected]> commit b9cb9c4 Check the IO permission bitmap (if present) before emulating IOIO #VC exceptions for user-space. These permissions are checked by hardware already before the #VC is raised, but due to the VC-handler decoding race it needs to be checked again in software. Fixes: 25189d0 ("x86/sev-es: Add support for handling IOIO exceptions") Reported-by: Tom Dohrmann <[email protected]> Signed-off-by: Joerg Roedel <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Tested-by: Tom Dohrmann <[email protected]> Cc: <[email protected]> (cherry picked from commit b9cb9c4) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent 3e1baae commit c90c4a4

File tree

3 files changed

+47
-7
lines changed

3 files changed

+47
-7
lines changed

arch/x86/boot/compressed/sev.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
103103
return ES_OK;
104104
}
105105

106+
static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size)
107+
{
108+
return ES_OK;
109+
}
110+
106111
#undef __init
107112
#undef __pa
108113
#define __init

arch/x86/kernel/sev-shared.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt,
653653
static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
654654
{
655655
struct insn *insn = &ctxt->insn;
656+
size_t size;
657+
u64 port;
658+
656659
*exitinfo = 0;
657660

658661
switch (insn->opcode.bytes[0]) {
@@ -661,49 +664,51 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
661664
case 0x6d:
662665
*exitinfo |= IOIO_TYPE_INS;
663666
*exitinfo |= IOIO_SEG_ES;
664-
*exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
667+
port = ctxt->regs->dx & 0xffff;
665668
break;
666669

667670
/* OUTS opcodes */
668671
case 0x6e:
669672
case 0x6f:
670673
*exitinfo |= IOIO_TYPE_OUTS;
671674
*exitinfo |= IOIO_SEG_DS;
672-
*exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
675+
port = ctxt->regs->dx & 0xffff;
673676
break;
674677

675678
/* IN immediate opcodes */
676679
case 0xe4:
677680
case 0xe5:
678681
*exitinfo |= IOIO_TYPE_IN;
679-
*exitinfo |= (u8)insn->immediate.value << 16;
682+
port = (u8)insn->immediate.value & 0xffff;
680683
break;
681684

682685
/* OUT immediate opcodes */
683686
case 0xe6:
684687
case 0xe7:
685688
*exitinfo |= IOIO_TYPE_OUT;
686-
*exitinfo |= (u8)insn->immediate.value << 16;
689+
port = (u8)insn->immediate.value & 0xffff;
687690
break;
688691

689692
/* IN register opcodes */
690693
case 0xec:
691694
case 0xed:
692695
*exitinfo |= IOIO_TYPE_IN;
693-
*exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
696+
port = ctxt->regs->dx & 0xffff;
694697
break;
695698

696699
/* OUT register opcodes */
697700
case 0xee:
698701
case 0xef:
699702
*exitinfo |= IOIO_TYPE_OUT;
700-
*exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
703+
port = ctxt->regs->dx & 0xffff;
701704
break;
702705

703706
default:
704707
return ES_DECODE_FAILED;
705708
}
706709

710+
*exitinfo |= port << 16;
711+
707712
switch (insn->opcode.bytes[0]) {
708713
case 0x6c:
709714
case 0x6e:
@@ -713,12 +718,15 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
713718
case 0xee:
714719
/* Single byte opcodes */
715720
*exitinfo |= IOIO_DATA_8;
721+
size = 1;
716722
break;
717723
default:
718724
/* Length determined by instruction parsing */
719725
*exitinfo |= (insn->opnd_bytes == 2) ? IOIO_DATA_16
720726
: IOIO_DATA_32;
727+
size = (insn->opnd_bytes == 2) ? 2 : 4;
721728
}
729+
722730
switch (insn->addr_bytes) {
723731
case 2:
724732
*exitinfo |= IOIO_ADDR_16;
@@ -734,7 +742,7 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
734742
if (insn_has_rep_prefix(insn))
735743
*exitinfo |= IOIO_REP;
736744

737-
return ES_OK;
745+
return vc_ioio_check(ctxt, (u16)port, size);
738746
}
739747

740748
static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)

arch/x86/kernel/sev.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,33 @@ static enum es_result vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt
493493
return ES_OK;
494494
}
495495

496+
static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size)
497+
{
498+
BUG_ON(size > 4);
499+
500+
if (user_mode(ctxt->regs)) {
501+
struct thread_struct *t = &current->thread;
502+
struct io_bitmap *iobm = t->io_bitmap;
503+
size_t idx;
504+
505+
if (!iobm)
506+
goto fault;
507+
508+
for (idx = port; idx < port + size; ++idx) {
509+
if (test_bit(idx, iobm->bitmap))
510+
goto fault;
511+
}
512+
}
513+
514+
return ES_OK;
515+
516+
fault:
517+
ctxt->fi.vector = X86_TRAP_GP;
518+
ctxt->fi.error_code = 0;
519+
520+
return ES_EXCEPTION;
521+
}
522+
496523
/* Include code shared with pre-decompression boot stage */
497524
#include "sev-shared.c"
498525

0 commit comments

Comments
 (0)