xref: /aosp_15_r20/external/ltp/testcases/kernel/security/umip/umip_basic_test.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (C) 2018 Intel Corporation
5  * Author: Neri, Ricardo <[email protected]>
6  *	 Pengfei, Xu   <[email protected]>
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 		break;
133 	case 2:
134 	case 4:
135 		/* after Linux kernel v5.10 mainline, SLDT and STR will return
136 		   dummy value and not trigger SIGSEGV due to kernel code change */
137 		if ((tst_kvercmp(5, 10, 0)) >= 0) {
138 			tst_res(TINFO, "Linux kernel version is v5.10 or higher");
139 			if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
140 				tst_res(TFAIL, "Got SIGSEGV");
141 				return;
142 			}
143 			tst_res(TPASS, "Didn't receive SIGSEGV, child exited with %s",
144 				tst_strstatus(status));
145 			return;
146 		} else
147 			tst_res(TINFO, "Linux kernel version is earlier than v5.10");
148 		break;
149 	}
150 
151 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
152 		tst_res(TPASS, "Got SIGSEGV");
153 		return;
154 	}
155 	tst_res(TFAIL, "Didn't receive SIGSEGV, child exited with %s",
156 		tst_strstatus(status));
157 }
158 
setup(void)159 static void setup(void)
160 {
161 	FILE *fp;
162 	char buf[2048];
163 
164 	fp = SAFE_FOPEN(CPUINFO_FILE, "r");
165 	while (!feof(fp)) {
166 		if (fgets(buf, sizeof(buf), fp) == NULL) {
167 			SAFE_FCLOSE(fp);
168 			tst_brk(TCONF, "cpuinfo show: cpu does not support umip");
169 		}
170 
171 		if (!strstr(buf, "flags"))
172 			continue;
173 
174 		if (strstr(buf, "umip")) {
175 			tst_res(TINFO, "cpuinfo contains umip, CPU supports umip");
176 			break;
177 		} else
178 			continue;
179 	}
180 
181 	SAFE_FCLOSE(fp);
182 }
183 
184 static struct tst_test test = {
185 	.min_kver = "4.1",
186 	.setup = setup,
187 	.tcnt = 5,
188 	.forks_child = 1,
189 	.test = verify_umip_instruction,
190 	.needs_kconfigs = (const char *[]){
191 		"CONFIG_X86_INTEL_UMIP=y | CONFIG_X86_UMIP=y",
192 		NULL
193 	},
194 	.needs_root = 1,
195 };
196 
197 #else
198 
199 TST_TEST_TCONF("Tests needs x86_64 CPU");
200 
201 #endif /* __x86_64__ */
202