• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (C) 2018 Intel Corporation
5  * Author: Neri, Ricardo <ricardo.neri@intel.com>
6  *	 Pengfei, Xu   <pengfei.xu@intel.com>
7  */
8 
9 /*
10  * This test will check if Intel umip(User-Mode Execution Prevention) is
11  * working.
12  *
13  * Intel CPU of ICE lake or newer is required for the test
14  * kconfig requirement:CONFIG_X86_INTEL_UMIP=y
15  */
16 
17 #define _GNU_SOURCE
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/wait.h>
23 #include <signal.h>
24 
25 #include "tst_test.h"
26 #include "tst_safe_stdio.h"
27 
28 #define CPUINFO_FILE "/proc/cpuinfo"
29 
30 #define GDT_LEN 10
31 #define IDT_LEN 10
32 
33 #ifdef __x86_64__
34 
asm_sgdt(void)35 static void asm_sgdt(void)
36 {
37 	unsigned char val[GDT_LEN];
38 
39 	memset(val, 0, sizeof(val));
40 	tst_res(TINFO, "TEST sgdt, sgdt result save at [%p]", val);
41 	asm volatile("sgdt %0\n" : "=m" (val));
42 	exit(0);
43 }
44 
asm_sidt(void)45 static void asm_sidt(void)
46 {
47 	unsigned char val[IDT_LEN];
48 
49 	memset(val, 0, sizeof(val));
50 	tst_res(TINFO, "TEST sidt, sidt result save at [%p]", val);
51 	asm volatile("sidt %0\n" : "=m" (val));
52 	exit(0);
53 }
54 
asm_sldt(void)55 static void asm_sldt(void)
56 {
57 	unsigned long val;
58 
59 	tst_res(TINFO, "TEST sldt, sldt result save at [%p]", &val);
60 	asm volatile("sldt %0\n" : "=m" (val));
61 	exit(0);
62 }
63 
asm_smsw(void)64 static void asm_smsw(void)
65 {
66 	unsigned long val;
67 
68 	tst_res(TINFO, "TEST smsw, smsw result save at [%p]", &val);
69 	asm volatile("smsw %0\n" : "=m" (val));
70 	exit(0);
71 }
72 
asm_str(void)73 static void asm_str(void)
74 {
75 	unsigned long val;
76 
77 	tst_res(TINFO, "TEST str, str result save at [%p]", &val);
78 	asm volatile("str %0\n" : "=m" (val));
79 	exit(0);
80 }
81 
verify_umip_instruction(unsigned int n)82 static void verify_umip_instruction(unsigned int n)
83 {
84 	int status;
85 	pid_t pid;
86 
87 	pid = SAFE_FORK();
88 	if (pid == 0) {
89 		tst_no_corefile(0);
90 
91 		switch (n) {
92 		case 0:
93 			asm_sgdt();
94 			break;
95 		case 1:
96 			asm_sidt();
97 			break;
98 		case 2:
99 			asm_sldt();
100 			break;
101 		case 3:
102 			asm_smsw();
103 			break;
104 		case 4:
105 			asm_str();
106 			break;
107 		default:
108 			tst_brk(TBROK, "Invalid tcase parameter: %d", n);
109 		}
110 		exit(0);
111 	}
112 
113 	SAFE_WAITPID(pid, &status, 0);
114 
115 	switch (n) {
116 	case 0:
117 	case 1:
118 	case 3:
119 		/* after linux kernel v5.4 mainline, 64bit SGDT SIDT SMSW will return
120 		   dummy value and not trigger SIGSEGV due to kernel code change */
121 		if ((tst_kvercmp(5, 4, 0)) >= 0) {
122 			tst_res(TINFO, "Linux kernel version is v5.4 or after than v5.4");
123 			if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
124 				tst_res(TFAIL, "Got SIGSEGV");
125 				return;
126 			}
127 			tst_res(TPASS, "Didn't receive SIGSEGV, child exited with %s",
128 				tst_strstatus(status));
129 			return;
130 		} else
131 			tst_res(TINFO, "Linux kernel version is before than v5.4");
132 	}
133 
134 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
135 		tst_res(TPASS, "Got SIGSEGV");
136 		return;
137 	}
138 	tst_res(TFAIL, "Didn't receive SIGSEGV, child exited with %s",
139 		tst_strstatus(status));
140 }
141 
setup(void)142 static void setup(void)
143 {
144 	FILE *fp;
145 	char buf[2048];
146 
147 	fp = SAFE_FOPEN(CPUINFO_FILE, "r");
148 	while (!feof(fp)) {
149 		if (fgets(buf, sizeof(buf), fp) == NULL) {
150 			SAFE_FCLOSE(fp);
151 			tst_brk(TCONF, "cpuinfo show: cpu does not support umip");
152 		}
153 
154 		if (!strstr(buf, "flags"))
155 			continue;
156 
157 		if (strstr(buf, "umip")) {
158 			tst_res(TINFO, "cpuinfo contains umip, CPU supports umip");
159 			break;
160 		} else
161 			continue;
162 	}
163 
164 	SAFE_FCLOSE(fp);
165 }
166 
167 static struct tst_test test = {
168 	.min_kver = "4.1",
169 	.setup = setup,
170 	.tcnt = 5,
171 	.forks_child = 1,
172 	.test = verify_umip_instruction,
173 	.needs_kconfigs = (const char *[]){
174 		"CONFIG_X86_INTEL_UMIP=y",
175 		NULL
176 	},
177 	.needs_root = 1,
178 };
179 
180 #else
181 
182 TST_TEST_TCONF("Tests needs x86_64 CPU");
183 
184 #endif /* __x86_64__ */
185