diff mbox

[XTF,v3] Functional: Add a UMIP test

Message ID 20170815031820.20234-1-boqun.feng@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Boqun Feng Aug. 15, 2017, 3:18 a.m. UTC
Add a "umip" test for the User-Model Instruction Prevention. The test
simply tries to run sgdt/sidt/sldt/str/smsw in guest user-mode with
CR4_UMIP = 1.

Signed-off-by: Boqun Feng (Intel) <boqun.feng@gmail.com>
---
v1 --> v2:
	* add a new write_cr4_safe()
	* use %pe for exception print
	* refactor the code based on Andrew's guide and advice
v2 --> v3:
	* add test_insns() to simplify test_main() logic
	* make write_cr4_safe() return 0 for success.
	* add UMIP activation test even if !cpu_has_umip

Test results:

* With UMIP patch:
** boot with hvm_fep: SUCCESS
** boot without hvm_fep: SKIP

* Without UMIP patch:
** boot with hvm_fep: SKIP
** boot without hvm_fep: SKIP

(illed implementation)
* With UMIP cpuid exposed but hvm_cr4_guest_valid_bits() didn't include X86_CR4_UMIP:
** boot with hvm_fep: FAILURE, due to "Fail: Unable to activate UMIP.."
** boot without hvm_fep: FAILURE, due to "Fail: Unable to activate UMIP.."

* With UMIP cpuid not exposed but hvm_cr4_guest_valid_bits() included X86_CR4_UMIP:
** boot with hvm_fep: FAILURE, due to "UMIP unsupported, but setting CR4 succeeded"
** boot without hvm_fep: FAILURE, due to "UMIP unsupported, but setting CR4 succeeded"

 arch/x86/include/arch/lib.h |  13 +++
 docs/all-tests.dox          |   2 +
 tests/umip/Makefile         |   9 ++
 tests/umip/main.c           | 214 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 238 insertions(+)
 create mode 100644 tests/umip/Makefile
 create mode 100644 tests/umip/main.c

Comments

Andrew Cooper Aug. 15, 2017, 10:28 a.m. UTC | #1
On 15/08/17 04:18, Boqun Feng (Intel) wrote:
> Add a "umip" test for the User-Model Instruction Prevention. The test
> simply tries to run sgdt/sidt/sldt/str/smsw in guest user-mode with
> CR4_UMIP = 1.
>
> Signed-off-by: Boqun Feng (Intel) <boqun.feng@gmail.com>

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

It turns out there were some tabs lurking, which I fixed up.  I also
tweaked the documentation a little.

This test will now find its way automatically into OSSTest.

Out of interest (and I can't recall if I've asked this yet; if so, sorry
for being forgetful), which processor line is UMIP going to be available in?

~Andrew
Yu Zhang Aug. 15, 2017, 11:36 a.m. UTC | #2
On 8/15/2017 6:28 PM, Andrew Cooper wrote:
> On 15/08/17 04:18, Boqun Feng (Intel) wrote:
>> Add a "umip" test for the User-Model Instruction Prevention. The test
>> simply tries to run sgdt/sidt/sldt/str/smsw in guest user-mode with
>> CR4_UMIP = 1.
>>
>> Signed-off-by: Boqun Feng (Intel) <boqun.feng@gmail.com>
> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
>
> It turns out there were some tabs lurking, which I fixed up.  I also
> tweaked the documentation a little.
>
> This test will now find its way automatically into OSSTest.
>
> Out of interest (and I can't recall if I've asked this yet; if so, sorry
> for being forgetful), which processor line is UMIP going to be available in?
I guess should be in icelake. :-)

Yu
diff mbox

Patch

diff --git a/arch/x86/include/arch/lib.h b/arch/x86/include/arch/lib.h
index f608af9996f0..82eb7da600c4 100644
--- a/arch/x86/include/arch/lib.h
+++ b/arch/x86/include/arch/lib.h
@@ -340,6 +340,19 @@  static inline void write_cr4(unsigned long cr4)
     asm volatile ("mov %0, %%cr4" :: "r" (cr4));
 }
 
+static inline bool write_cr4_safe(unsigned long cr4)
+{
+    exinfo_t fault = 0;
+
+    asm volatile ("1: mov %1, %%cr4; 2:"
+                  _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi)
+                  : "+D" (fault)
+                  : "r" (cr4),
+                    "X" (ex_record_fault_edi));
+
+    return fault;
+}
+
 static inline void write_cr8(unsigned long cr8)
 {
     asm volatile ("mov %0, %%cr8" :: "r" (cr8));
diff --git a/docs/all-tests.dox b/docs/all-tests.dox
index c1b163a926cb..ef011007cf68 100644
--- a/docs/all-tests.dox
+++ b/docs/all-tests.dox
@@ -111,4 +111,6 @@  guest breakout.
 @section index-in-development In Development
 
 @subpage test-vvmx - Nested VT-x tests.
+
+@subpage test-umip - User-Mode Instruction Prevention
 */
diff --git a/tests/umip/Makefile b/tests/umip/Makefile
new file mode 100644
index 000000000000..0248c8b247a0
--- /dev/null
+++ b/tests/umip/Makefile
@@ -0,0 +1,9 @@ 
+include $(ROOT)/build/common.mk
+
+NAME      := umip
+CATEGORY  := functional
+TEST-ENVS := hvm32 hvm64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/umip/main.c b/tests/umip/main.c
new file mode 100644
index 000000000000..76764c8b38f4
--- /dev/null
+++ b/tests/umip/main.c
@@ -0,0 +1,214 @@ 
+/**
+ * @file tests/umip/main.c
+ * @ref test-umip
+ *
+ * @page test-umip umip
+ *
+ * @todo Docs for test-umip
+ *
+ * @see tests/umip/main.c
+ */
+#include <xtf.h>
+#include <arch/exinfo.h>
+#include <arch/processor.h>
+
+const char test_title[] = "User-Mode Instruction Prevention Test";
+bool test_wants_user_mappings = true;
+
+static unsigned long stub_sgdt(unsigned long force)
+{
+    exinfo_t fault = 0;
+    desc_ptr tmp;
+
+    asm volatile("test %[fep], %[fep];"
+                 "jz 1f;"
+                 _ASM_XEN_FEP
+                 "1: sgdt %[tmp]; 2:"
+                _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi)
+		: "+D" (fault), [tmp] "=m" (tmp)
+                : [fep] "q" (force),
+                  "X" (ex_record_fault_edi));
+
+    return fault;
+}
+static unsigned long stub_sidt(unsigned long force)
+{
+    exinfo_t fault = 0;
+    desc_ptr tmp;
+
+    asm volatile("test %[fep], %[fep];"
+                 "jz 1f;"
+                 _ASM_XEN_FEP
+                 "1: sidt %[tmp]; 2:"
+                 _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi)
+		 : "+D" (fault), [tmp] "=m" (tmp)
+                 : [fep] "q" (force),
+                  "X" (ex_record_fault_edi));
+
+    return fault;
+}
+
+static unsigned long stub_sldt(unsigned long force)
+{
+    exinfo_t fault = 0;
+    unsigned int tmp;
+
+    asm volatile("test %[fep], %[fep];"
+                 "jz 1f;"
+                 _ASM_XEN_FEP
+                 "1: sldt %[tmp]; 2:"
+                 _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi)
+                 : "+D" (fault), [tmp] "=r" (tmp)
+                 : [fep] "q" (force),
+                  "X" (ex_record_fault_edi));
+
+    return fault;
+}
+
+static unsigned long stub_str(unsigned long force)
+{
+    exinfo_t fault = 0;
+    unsigned int tmp;
+
+    asm volatile("test %[fep], %[fep];"
+                 "jz 1f;"
+                 _ASM_XEN_FEP
+                 "1: str %[tmp]; 2:"
+                 _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi)
+                 : "+D" (fault), [tmp] "=r" (tmp)
+                 : [fep] "q" (force),
+                  "X" (ex_record_fault_edi));
+
+    return fault;
+}
+
+static unsigned long stub_smsw(unsigned long force)
+{
+    exinfo_t fault = 0;
+    unsigned int tmp;
+
+    asm volatile("test %[fep], %[fep];"
+                 "jz 1f;"
+                 _ASM_XEN_FEP
+                 "1: smsw %[tmp]; 2:"
+                 _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi)
+                 : "+D" (fault), [tmp] "=r" (tmp)
+                 : [fep] "q" (force),
+                  "X" (ex_record_fault_edi));
+
+    return fault;
+}
+
+static const struct stub {
+    unsigned long (*fn)(unsigned long);
+    const char *name;
+} stubs[] = {
+    { stub_sgdt, "SGDT" },
+    { stub_sidt, "SIDT" },
+    { stub_sldt, "SLDT" },
+    { stub_str,  "STR" },
+    { stub_smsw, "SMSW" },
+};
+
+static void test_insns(bool umip_active, bool force)
+{
+    unsigned int i;
+    bool user;
+
+    for ( user = false; ; user = true )
+    {
+        exinfo_t exp = user && umip_active ? EXINFO_SYM(GP, 0) : 0;
+
+        for ( i = 0; i < ARRAY_SIZE(stubs); i++)
+        {
+            const struct stub *s = &stubs[i];
+            exinfo_t ret;
+
+            ret = user ? exec_user_param(s->fn, force) : s->fn(force);
+
+            /*
+             * Tolerate the instruction emulator not understanding these
+             * instructions in older releases of Xen.
+             */
+
+            if ( force && ret == EXINFO_SYM(UD, 0) )
+            {
+                static bool once;
+
+                if ( !once )
+                {
+                    xtf_skip("Skip: Emulator doesn't implement %s\n", s->name);
+                    once = true;
+                }
+
+                continue;
+            }
+
+            if ( ret != exp )
+                xtf_failure("Fail: %s %s\n"
+                            "  expected %pe\n"
+                            "       got %pe\n",
+                            user ? "user" : "supervisor", s->name,
+                            _p(exp), _p(ret));
+        }
+
+        if ( user )
+            break;
+    }
+}
+
+static void test_umip(bool umip_active)
+{
+    test_insns(umip_active, false);
+
+    if ( xtf_has_fep )
+        test_insns(umip_active, true);
+}
+
+void test_main(void)
+{
+    if ( !xtf_has_fep )
+        xtf_skip("FEP support not detected - some tests will be skipped\n");
+
+    test_umip(false);
+
+    if ( !cpu_has_umip )
+    {
+        xtf_skip("UMIP is not supported, skip the rest of test\n");
+
+        if ( !write_cr4_safe(read_cr4() | X86_CR4_UMIP) )
+            xtf_failure("UMIP unsupported, but setting CR4 bit succeeded\n");
+
+        return;
+    }
+
+    /* activate UMIP */
+    if ( write_cr4_safe(read_cr4() | X86_CR4_UMIP) )
+    {
+        xtf_failure("Fail: Unable to activate UMIP\n");
+        return;
+    }
+
+    test_umip(true);
+
+    /* deactivate UMIP */
+    if ( write_cr4_safe(read_cr4() & ~X86_CR4_UMIP) )
+    {
+        xtf_failure("Fail: Unable to deactivate UMIP\n");
+        return;
+    }
+
+    test_umip(false);
+
+    xtf_success(NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */