aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Neri <ricardo.neri-calderon@linux.intel.com>2017-11-05 21:27:56 -0500
committerIngo Molnar <mingo@kernel.org>2017-11-08 05:16:24 -0500
commit9390afebe1d3f5a0be18b1afdd0ce09d67cebf9e (patch)
treeb4b84c03161a39e9859155af27d1302aca096aef
parent6fc9dc81bff0ea461db534e2672acfdaf76f3e4e (diff)
selftests/x86: Add tests for User-Mode Instruction Prevention
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 <ricardo.neri-calderon@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Borislav Petkov <bp@suse.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Chen Yucong <slaoub@gmail.com> Cc: Chris Metcalf <cmetcalf@mellanox.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Huang Rui <ray.huang@amd.com> Cc: Jiri Slaby <jslaby@suse.cz> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi V. Shankar <ravi.v.shankar@intel.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Tony Luck <tony.luck@intel.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: ricardo.neri@intel.com Link: http://lkml.kernel.org/r/1509935277-22138-12-git-send-email-ricardo.neri-calderon@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/testing/selftests/x86/entry_from_vm86.c73
1 files changed, 72 insertions, 1 deletions
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c
index d075ea0e5ca1..f7d9ceac7e06 100644
--- a/tools/testing/selftests/x86/entry_from_vm86.c
+++ b/tools/testing/selftests/x86/entry_from_vm86.c
@@ -95,6 +95,22 @@ asm (
95 "int3\n\t" 95 "int3\n\t"
96 "vmcode_int80:\n\t" 96 "vmcode_int80:\n\t"
97 "int $0x80\n\t" 97 "int $0x80\n\t"
98 "vmcode_umip:\n\t"
99 /* addressing via displacements */
100 "smsw (2052)\n\t"
101 "sidt (2054)\n\t"
102 "sgdt (2060)\n\t"
103 /* addressing via registers */
104 "mov $2066, %bx\n\t"
105 "smsw (%bx)\n\t"
106 "mov $2068, %bx\n\t"
107 "sidt (%bx)\n\t"
108 "mov $2074, %bx\n\t"
109 "sgdt (%bx)\n\t"
110 /* register operands, only for smsw */
111 "smsw %ax\n\t"
112 "mov %ax, (2080)\n\t"
113 "int3\n\t"
98 ".size vmcode, . - vmcode\n\t" 114 ".size vmcode, . - vmcode\n\t"
99 "end_vmcode:\n\t" 115 "end_vmcode:\n\t"
100 ".code32\n\t" 116 ".code32\n\t"
@@ -103,7 +119,7 @@ asm (
103 119
104extern unsigned char vmcode[], end_vmcode[]; 120extern unsigned char vmcode[], end_vmcode[];
105extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], 121extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[],
106 vmcode_sti[], vmcode_int3[], vmcode_int80[]; 122 vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[];
107 123
108/* Returns false if the test was skipped. */ 124/* Returns false if the test was skipped. */
109static bool do_test(struct vm86plus_struct *v86, unsigned long eip, 125static 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,
160 return true; 176 return true;
161} 177}
162 178
179void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem)
180{
181 struct table_desc {
182 unsigned short limit;
183 unsigned long base;
184 } __attribute__((packed));
185
186 /* Initialize variables with arbitrary values */
187 struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 };
188 struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae };
189 struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 };
190 struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 };
191 unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737;
192
193 /* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */
194 do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests");
195
196 /* Results from displacement-only addressing */
197 msw1 = *(unsigned short *)(test_mem + 2052);
198 memcpy(&idt1, test_mem + 2054, sizeof(idt1));
199 memcpy(&gdt1, test_mem + 2060, sizeof(gdt1));
200
201 /* Results from register-indirect addressing */
202 msw2 = *(unsigned short *)(test_mem + 2066);
203 memcpy(&idt2, test_mem + 2068, sizeof(idt2));
204 memcpy(&gdt2, test_mem + 2074, sizeof(gdt2));
205
206 /* Results when using register operands */
207 msw3 = *(unsigned short *)(test_mem + 2080);
208
209 printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1);
210 printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n",
211 idt1.limit, idt1.base);
212 printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n",
213 gdt1.limit, gdt1.base);
214
215 if (msw1 != msw2 || msw1 != msw3)
216 printf("[FAIL]\tAll the results of SMSW should be the same.\n");
217 else
218 printf("[PASS]\tAll the results from SMSW are identical.\n");
219
220 if (memcmp(&gdt1, &gdt2, sizeof(gdt1)))
221 printf("[FAIL]\tAll the results of SGDT should be the same.\n");
222 else
223 printf("[PASS]\tAll the results from SGDT are identical.\n");
224
225 if (memcmp(&idt1, &idt2, sizeof(idt1)))
226 printf("[FAIL]\tAll the results of SIDT should be the same.\n");
227 else
228 printf("[PASS]\tAll the results from SIDT are identical.\n");
229}
230
163int main(void) 231int main(void)
164{ 232{
165 struct vm86plus_struct v86; 233 struct vm86plus_struct v86;
@@ -218,6 +286,9 @@ int main(void)
218 v86.regs.eax = (unsigned int)-1; 286 v86.regs.eax = (unsigned int)-1;
219 do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80"); 287 do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80");
220 288
289 /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */
290 do_umip_tests(&v86, addr);
291
221 /* Execute a null pointer */ 292 /* Execute a null pointer */
222 v86.regs.cs = 0; 293 v86.regs.cs = 0;
223 v86.regs.ss = 0; 294 v86.regs.ss = 0;