Skip to content

Commit

Permalink
selftests/x86: Add tests for User-Mode Instruction Prevention
Browse files Browse the repository at this point in the history
Certain user space programs that run on virtual-8086 mode may utilize
instructions protected by the User-Mode Instruction Prevention (UMIP)
security feature present in new Intel processors: SGDT, SIDT and SMSW. In
such a case, a general protection fault is issued if UMIP is enabled. When
such a fault happens, the kernel traps it and emulates the results of
these instructions with dummy values. The purpose of this new
test is to verify whether the impacted instructions can be executed
without causing such #GP. If no #GP exceptions occur, we expect to exit
virtual-8086 mode from INT3.

The instructions protected by UMIP are executed in representative use
cases:

 a) displacement-only memory addressing
 b) register-indirect memory addressing
 c) results stored directly in operands

Unfortunately, it is not possible to check the results against a set of
expected values because no emulation will occur in systems that do not
have the UMIP feature. Instead, results are printed for verification. A
simple verification is done to ensure that results of all tests are
identical.

Signed-off-by: Ricardo Neri <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Chen Yucong <[email protected]>
Cc: Chris Metcalf <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Denys Vlasenko <[email protected]>
Cc: Fenghua Yu <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Huang Rui <[email protected]>
Cc: Jiri Slaby <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Josh Poimboeuf <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Michael S. Tsirkin <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Paul Gortmaker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ravi V. Shankar <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/1509935277-22138-12-git-send-email-ricardo.neri-calderon@linux.intel.com
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
ricardon authored and Ingo Molnar committed Nov 8, 2017
1 parent 6fc9dc8 commit 9390afe
Showing 1 changed file with 72 additions and 1 deletion.
73 changes: 72 additions & 1 deletion tools/testing/selftests/x86/entry_from_vm86.c
Original file line number Diff line number Diff line change
@@ -95,6 +95,22 @@ asm (
"int3\n\t"
"vmcode_int80:\n\t"
"int $0x80\n\t"
"vmcode_umip:\n\t"
/* addressing via displacements */
"smsw (2052)\n\t"
"sidt (2054)\n\t"
"sgdt (2060)\n\t"
/* addressing via registers */
"mov $2066, %bx\n\t"
"smsw (%bx)\n\t"
"mov $2068, %bx\n\t"
"sidt (%bx)\n\t"
"mov $2074, %bx\n\t"
"sgdt (%bx)\n\t"
/* register operands, only for smsw */
"smsw %ax\n\t"
"mov %ax, (2080)\n\t"
"int3\n\t"
".size vmcode, . - vmcode\n\t"
"end_vmcode:\n\t"
".code32\n\t"
@@ -103,7 +119,7 @@ asm (

extern unsigned char vmcode[], end_vmcode[];
extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[],
vmcode_sti[], vmcode_int3[], vmcode_int80[];
vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[];

/* Returns false if the test was skipped. */
static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
@@ -160,6 +176,58 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
return true;
}

void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem)
{
struct table_desc {
unsigned short limit;
unsigned long base;
} __attribute__((packed));

/* Initialize variables with arbitrary values */
struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 };
struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae };
struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 };
struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 };
unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737;

/* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */
do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests");

/* Results from displacement-only addressing */
msw1 = *(unsigned short *)(test_mem + 2052);
memcpy(&idt1, test_mem + 2054, sizeof(idt1));
memcpy(&gdt1, test_mem + 2060, sizeof(gdt1));

/* Results from register-indirect addressing */
msw2 = *(unsigned short *)(test_mem + 2066);
memcpy(&idt2, test_mem + 2068, sizeof(idt2));
memcpy(&gdt2, test_mem + 2074, sizeof(gdt2));

/* Results when using register operands */
msw3 = *(unsigned short *)(test_mem + 2080);

printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1);
printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n",
idt1.limit, idt1.base);
printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n",
gdt1.limit, gdt1.base);

if (msw1 != msw2 || msw1 != msw3)
printf("[FAIL]\tAll the results of SMSW should be the same.\n");
else
printf("[PASS]\tAll the results from SMSW are identical.\n");

if (memcmp(&gdt1, &gdt2, sizeof(gdt1)))
printf("[FAIL]\tAll the results of SGDT should be the same.\n");
else
printf("[PASS]\tAll the results from SGDT are identical.\n");

if (memcmp(&idt1, &idt2, sizeof(idt1)))
printf("[FAIL]\tAll the results of SIDT should be the same.\n");
else
printf("[PASS]\tAll the results from SIDT are identical.\n");
}

int main(void)
{
struct vm86plus_struct v86;
@@ -218,6 +286,9 @@ int main(void)
v86.regs.eax = (unsigned int)-1;
do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80");

/* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */
do_umip_tests(&v86, addr);

/* Execute a null pointer */
v86.regs.cs = 0;
v86.regs.ss = 0;

0 comments on commit 9390afe

Please sign in to comment.