|
@@ -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;
|