Skip to content

Commit b9cb9c4

Browse files
joergroedelbp3tk0v
authored andcommitted
x86/sev: Check IOBM for IOIO exceptions from user-space
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]>
1 parent a37cd2a commit b9cb9c4

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
#define __init
108113

arch/x86/kernel/sev-shared.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,9 @@ static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt,
656656
static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
657657
{
658658
struct insn *insn = &ctxt->insn;
659+
size_t size;
660+
u64 port;
661+
659662
*exitinfo = 0;
660663

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

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

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

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

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

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

706709
default:
707710
return ES_DECODE_FAILED;
708711
}
709712

713+
*exitinfo |= port << 16;
714+
710715
switch (insn->opcode.bytes[0]) {
711716
case 0x6c:
712717
case 0x6e:
@@ -716,12 +721,15 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
716721
case 0xee:
717722
/* Single byte opcodes */
718723
*exitinfo |= IOIO_DATA_8;
724+
size = 1;
719725
break;
720726
default:
721727
/* Length determined by instruction parsing */
722728
*exitinfo |= (insn->opnd_bytes == 2) ? IOIO_DATA_16
723729
: IOIO_DATA_32;
730+
size = (insn->opnd_bytes == 2) ? 2 : 4;
724731
}
732+
725733
switch (insn->addr_bytes) {
726734
case 2:
727735
*exitinfo |= IOIO_ADDR_16;
@@ -737,7 +745,7 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
737745
if (insn_has_rep_prefix(insn))
738746
*exitinfo |= IOIO_REP;
739747

740-
return ES_OK;
748+
return vc_ioio_check(ctxt, (u16)port, size);
741749
}
742750

743751
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
@@ -524,6 +524,33 @@ static enum es_result vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt
524524
return ES_OK;
525525
}
526526

527+
static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size)
528+
{
529+
BUG_ON(size > 4);
530+
531+
if (user_mode(ctxt->regs)) {
532+
struct thread_struct *t = &current->thread;
533+
struct io_bitmap *iobm = t->io_bitmap;
534+
size_t idx;
535+
536+
if (!iobm)
537+
goto fault;
538+
539+
for (idx = port; idx < port + size; ++idx) {
540+
if (test_bit(idx, iobm->bitmap))
541+
goto fault;
542+
}
543+
}
544+
545+
return ES_OK;
546+
547+
fault:
548+
ctxt->fi.vector = X86_TRAP_GP;
549+
ctxt->fi.error_code = 0;
550+
551+
return ES_EXCEPTION;
552+
}
553+
527554
/* Include code shared with pre-decompression boot stage */
528555
#include "sev-shared.c"
529556

0 commit comments

Comments
 (0)