diff mbox series

[v6] Add Intel umip(User Mode Instruction Prevention) basic function tests

Message ID 20190117144444.11427-1-pengfei.xu@intel.com
State Accepted
Headers show
Series [v6] Add Intel umip(User Mode Instruction Prevention) basic function tests | expand

Commit Message

Pengfei Xu Jan. 17, 2019, 2:44 p.m. UTC
umip is a security feature present in new Intel Processors.
  Intel CPU like ICE lake or newer is required.
  When umip enabled, it prevents the execution of certain instructions
  and situation as below:
    when Current Privilege Level (CPL) is greater than 0, user space
    applications could not access to system-wide settings such as
    the global and local descriptor tables, the segment selectors to
    the current task state and the local descriptor table.
  umip is enabled by default at boot.
  umip will protect below instructions in user mode:
    * SGDT - Store Global Descriptor Table
    * SIDT - Store Interrupt Descriptor Table
    * SLDT - Store Local Descriptor Table
    * SMSW - Store Machine Status Word
    * STR  - Store Task Register
  If CPU not support umip, you still could comment cpuinfo check code
  to verify anyway.

Signed-off-by: Pengfei Xu <pengfei.xu@intel.com>
---
 runtest/secure_umip                              |   2 +
 testcases/kernel/security/umip/.gitignore        |   1 +
 testcases/kernel/security/umip/Makefile          |   7 +
 testcases/kernel/security/umip/umip_basic_test.c | 174 +++++++++++++++++++++++
 4 files changed, 184 insertions(+)
 create mode 100644 runtest/secure_umip
 create mode 100644 testcases/kernel/security/umip/.gitignore
 create mode 100644 testcases/kernel/security/umip/Makefile
 create mode 100644 testcases/kernel/security/umip/umip_basic_test.c

Comments

Cyril Hrubis Jan. 23, 2019, 11:23 a.m. UTC | #1
Hi!
Pushed with a few changes, thanks!

* added the kconfig requirement to the tst_test structure
* the whole test is now in #ifdef __x86_64__
  (otherwise the asm statements would fail to compile on other
  architectures)
* moved the runtest entry to kernel_misc
  (in order to avoid having runtest files with just one entry)
diff mbox series

Patch

diff --git a/runtest/secure_umip b/runtest/secure_umip
new file mode 100644
index 000000000..499be3273
--- /dev/null
+++ b/runtest/secure_umip
@@ -0,0 +1,2 @@ 
+#DESCRIPTION: CPU security feature UMIP test
+umip_instruction_test umip_basic_test
diff --git a/testcases/kernel/security/umip/.gitignore b/testcases/kernel/security/umip/.gitignore
new file mode 100644
index 000000000..a8bb84631
--- /dev/null
+++ b/testcases/kernel/security/umip/.gitignore
@@ -0,0 +1 @@ 
+umip_basic_test
diff --git a/testcases/kernel/security/umip/Makefile b/testcases/kernel/security/umip/Makefile
new file mode 100644
index 000000000..18896b6f2
--- /dev/null
+++ b/testcases/kernel/security/umip/Makefile
@@ -0,0 +1,7 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/security/umip/umip_basic_test.c b/testcases/kernel/security/umip/umip_basic_test.c
new file mode 100644
index 000000000..0b4a66741
--- /dev/null
+++ b/testcases/kernel/security/umip/umip_basic_test.c
@@ -0,0 +1,174 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * testcases/security/umip/umip_basic_test.c
+ * Copyright (C) 2018 Intel Corporation
+ * Author: Neri, Ricardo <ricardo.neri@intel.com>
+ *	 Pengfei, Xu   <pengfei.xu@intel.com>
+ */
+
+/*
+ * This test will check if Intel umip(User-Mode Execution Prevention) is
+ * working.
+ *
+ * Intel CPU of ICE lake or newer is required for the test
+ * kconfig requirement:CONFIG_X86_INTEL_UMIP=y
+ *
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "tst_test.h"
+#include "tst_safe_stdio.h"
+
+#define CPUINFO_FILE "/proc/cpuinfo"
+
+#define GDT_LEN 10
+#define IDT_LEN 10
+
+static struct tcase {
+	enum {
+	sgdt,
+	sidt,
+	sldt,
+	smsw,
+	str
+	} option;
+	int exp_sig;
+} tcases[] = {
+	{sgdt, SIGSEGV},
+	{sidt, SIGSEGV},
+	{sldt, SIGSEGV},
+	{smsw, SIGSEGV},
+	{str, SIGSEGV},
+};
+
+static void asm_sgdt(void)
+{
+	unsigned char val[GDT_LEN];
+
+	memset(val, 0, sizeof(val));
+	tst_res(TINFO, "TEST sgdt, sgdt result save at [%p]", val);
+	asm volatile("sgdt %0\n" : "=m" (val));
+	exit(0);
+}
+
+static void asm_sidt(void)
+{
+	unsigned char val[IDT_LEN];
+
+	memset(val, 0, sizeof(val));
+	tst_res(TINFO, "TEST sidt, sidt result save at [%p]\n", val);
+	asm volatile("sidt %0\n" : "=m" (val));
+	exit(0);
+}
+
+static void asm_sldt(void)
+{
+	unsigned long val;
+
+	tst_res(TINFO, "TEST sldt, sldt result save at [%p]\n", &val);
+	asm volatile("sldt %0\n" : "=m" (val));
+	exit(0);
+}
+
+static void asm_smsw(void)
+{
+	unsigned long val;
+
+	tst_res(TINFO, "TEST smsw, smsw result save at [%p]\n", &val);
+	asm volatile("smsw %0\n" : "=m" (val));
+	exit(0);
+}
+
+static void asm_str(void)
+{
+	unsigned long val;
+
+	tst_res(TINFO, "TEST str, str result save at [%p]\n", &val);
+	asm volatile("str %0\n" : "=m" (val));
+	exit(0);
+}
+
+static void verify_umip_instruction(unsigned int n)
+{
+	int status;
+	struct tcase *tc = &tcases[n];
+	pid_t pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		switch (tc->option) {
+		case 0:
+			asm_sgdt();
+			break;
+		case 1:
+			asm_sidt();
+			break;
+		case 2:
+			asm_sldt();
+			break;
+		case 3:
+			asm_smsw();
+			break;
+		case 4:
+			asm_str();
+			break;
+		default:
+			tst_brk(TCONF, "Invalid tcase parameter:%d",
+				tc->option);
+		}
+		exit(0);
+	}
+
+	SAFE_WAITPID(pid, &status, 0);
+
+	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
+		tst_res(TPASS, "Got SIGSEGV");
+		return;
+	}
+	tst_res(TFAIL, "Didn't receive SIGSEGV, child exited with %s",
+		tst_strstatus(status));
+}
+
+static void setup(void)
+{
+	FILE *fp;
+	int max = 2048;
+	char buf[max];
+
+	// cpuinfo should contain umip
+	fp = SAFE_FOPEN(CPUINFO_FILE, "r");
+	while (!feof(fp)) {
+		if (fgets(buf, sizeof(buf), fp) == NULL) {
+			SAFE_FCLOSE(fp);
+			tst_brk(TCONF, "cpuinfo show: cpu does not support umip");
+		}
+
+		if (!strstr(buf, "flags"))
+			continue;
+
+		if (strstr(buf, "umip")) {
+			tst_res(TINFO, "cpuinfo contain umip, cpu support umip");
+			break;
+		} else
+			continue;
+	}
+
+	SAFE_FCLOSE(fp);
+}
+
+static struct tst_test test = {
+	.min_kver = "4.1",
+	.setup = setup,
+	.tcnt = ARRAY_SIZE(tcases),
+	.forks_child = 1,
+	.test = verify_umip_instruction,
+	.needs_root = 1,
+};