xref: /openbmc/linux/tools/testing/selftests/sgx/main.c (revision 25b892b5)
1 // SPDX-License-Identifier: GPL-2.0
2 /*  Copyright(c) 2016-20 Intel Corporation. */
3 
4 #include <elf.h>
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/ioctl.h>
14 #include <sys/mman.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <sys/auxv.h>
19 #include "defines.h"
20 #include "../kselftest_harness.h"
21 #include "main.h"
22 
23 static const uint64_t MAGIC = 0x1122334455667788ULL;
24 vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;
25 
26 struct vdso_symtab {
27 	Elf64_Sym *elf_symtab;
28 	const char *elf_symstrtab;
29 	Elf64_Word *elf_hashtab;
30 };
31 
32 static Elf64_Dyn *vdso_get_dyntab(void *addr)
33 {
34 	Elf64_Ehdr *ehdr = addr;
35 	Elf64_Phdr *phdrtab = addr + ehdr->e_phoff;
36 	int i;
37 
38 	for (i = 0; i < ehdr->e_phnum; i++)
39 		if (phdrtab[i].p_type == PT_DYNAMIC)
40 			return addr + phdrtab[i].p_offset;
41 
42 	return NULL;
43 }
44 
45 static void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag)
46 {
47 	int i;
48 
49 	for (i = 0; dyntab[i].d_tag != DT_NULL; i++)
50 		if (dyntab[i].d_tag == tag)
51 			return addr + dyntab[i].d_un.d_ptr;
52 
53 	return NULL;
54 }
55 
56 static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab)
57 {
58 	Elf64_Dyn *dyntab = vdso_get_dyntab(addr);
59 
60 	symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB);
61 	if (!symtab->elf_symtab)
62 		return false;
63 
64 	symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB);
65 	if (!symtab->elf_symstrtab)
66 		return false;
67 
68 	symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH);
69 	if (!symtab->elf_hashtab)
70 		return false;
71 
72 	return true;
73 }
74 
75 static unsigned long elf_sym_hash(const char *name)
76 {
77 	unsigned long h = 0, high;
78 
79 	while (*name) {
80 		h = (h << 4) + *name++;
81 		high = h & 0xf0000000;
82 
83 		if (high)
84 			h ^= high >> 24;
85 
86 		h &= ~high;
87 	}
88 
89 	return h;
90 }
91 
92 static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name)
93 {
94 	Elf64_Word bucketnum = symtab->elf_hashtab[0];
95 	Elf64_Word *buckettab = &symtab->elf_hashtab[2];
96 	Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum];
97 	Elf64_Sym *sym;
98 	Elf64_Word i;
99 
100 	for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF;
101 	     i = chaintab[i]) {
102 		sym = &symtab->elf_symtab[i];
103 		if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name]))
104 			return sym;
105 	}
106 
107 	return NULL;
108 }
109 
110 FIXTURE(enclave) {
111 	struct encl encl;
112 	struct sgx_enclave_run run;
113 };
114 
115 FIXTURE_SETUP(enclave)
116 {
117 	Elf64_Sym *sgx_enter_enclave_sym = NULL;
118 	struct vdso_symtab symtab;
119 	struct encl_segment *seg;
120 	char maps_line[256];
121 	FILE *maps_file;
122 	unsigned int i;
123 	void *addr;
124 
125 	if (!encl_load("test_encl.elf", &self->encl)) {
126 		encl_delete(&self->encl);
127 		ksft_exit_skip("cannot load enclaves\n");
128 	}
129 
130 	for (i = 0; i < self->encl.nr_segments; i++) {
131 		seg = &self->encl.segment_tbl[i];
132 
133 		TH_LOG("0x%016lx 0x%016lx 0x%02x", seg->offset, seg->size, seg->prot);
134 	}
135 
136 	if (!encl_measure(&self->encl))
137 		goto err;
138 
139 	if (!encl_build(&self->encl))
140 		goto err;
141 
142 	/*
143 	 * An enclave consumer only must do this.
144 	 */
145 	for (i = 0; i < self->encl.nr_segments; i++) {
146 		struct encl_segment *seg = &self->encl.segment_tbl[i];
147 
148 		addr = mmap((void *)self->encl.encl_base + seg->offset, seg->size,
149 			    seg->prot, MAP_SHARED | MAP_FIXED, self->encl.fd, 0);
150 		EXPECT_NE(addr, MAP_FAILED);
151 		if (addr == MAP_FAILED)
152 			goto err;
153 	}
154 
155 	/* Get vDSO base address */
156 	addr = (void *)getauxval(AT_SYSINFO_EHDR);
157 	if (!addr)
158 		goto err;
159 
160 	if (!vdso_get_symtab(addr, &symtab))
161 		goto err;
162 
163 	sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
164 	if (!sgx_enter_enclave_sym)
165 		goto err;
166 
167 	vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value;
168 
169 	memset(&self->run, 0, sizeof(self->run));
170 	self->run.tcs = self->encl.encl_base;
171 
172 	maps_file = fopen("/proc/self/maps", "r");
173 	if (maps_file != NULL)  {
174 		while (fgets(maps_line, sizeof(maps_line), maps_file) != NULL) {
175 			maps_line[strlen(maps_line) - 1] = '\0';
176 
177 			if (strstr(maps_line, "/dev/sgx_enclave"))
178 				TH_LOG("%s", maps_line);
179 		}
180 
181 		fclose(maps_file);
182 	}
183 
184 err:
185 	if (!sgx_enter_enclave_sym)
186 		encl_delete(&self->encl);
187 
188 	ASSERT_NE(sgx_enter_enclave_sym, NULL);
189 }
190 
191 FIXTURE_TEARDOWN(enclave)
192 {
193 	encl_delete(&self->encl);
194 }
195 
196 #define ENCL_CALL(op, run, clobbered) \
197 	({ \
198 		int ret; \
199 		if ((clobbered)) \
200 			ret = vdso_sgx_enter_enclave((unsigned long)(op), 0, 0, \
201 						     EENTER, 0, 0, (run)); \
202 		else \
203 			ret = sgx_enter_enclave((void *)(op), NULL, 0, EENTER, NULL, NULL, \
204 						(run)); \
205 		ret; \
206 	})
207 
208 #define EXPECT_EEXIT(run) \
209 	do { \
210 		EXPECT_EQ((run)->function, EEXIT); \
211 		if ((run)->function != EEXIT) \
212 			TH_LOG("0x%02x 0x%02x 0x%016llx", (run)->exception_vector, \
213 			       (run)->exception_error_code, (run)->exception_addr); \
214 	} while (0)
215 
216 TEST_F(enclave, unclobbered_vdso)
217 {
218 	struct encl_op op;
219 
220 	op.type = ENCL_OP_PUT;
221 	op.buffer = MAGIC;
222 
223 	EXPECT_EQ(ENCL_CALL(&op, &self->run, false), 0);
224 
225 	EXPECT_EEXIT(&self->run);
226 	EXPECT_EQ(self->run.user_data, 0);
227 
228 	op.type = ENCL_OP_GET;
229 	op.buffer = 0;
230 
231 	EXPECT_EQ(ENCL_CALL(&op, &self->run, false), 0);
232 
233 	EXPECT_EQ(op.buffer, MAGIC);
234 	EXPECT_EEXIT(&self->run);
235 	EXPECT_EQ(self->run.user_data, 0);
236 }
237 
238 TEST_F(enclave, clobbered_vdso)
239 {
240 	struct encl_op op;
241 
242 	op.type = ENCL_OP_PUT;
243 	op.buffer = MAGIC;
244 
245 	EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
246 
247 	EXPECT_EEXIT(&self->run);
248 	EXPECT_EQ(self->run.user_data, 0);
249 
250 	op.type = ENCL_OP_GET;
251 	op.buffer = 0;
252 
253 	EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
254 
255 	EXPECT_EQ(op.buffer, MAGIC);
256 	EXPECT_EEXIT(&self->run);
257 	EXPECT_EQ(self->run.user_data, 0);
258 }
259 
260 static int test_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,
261 			struct sgx_enclave_run *run)
262 {
263 	run->user_data = 0;
264 
265 	return 0;
266 }
267 
268 TEST_F(enclave, clobbered_vdso_and_user_function)
269 {
270 	struct encl_op op;
271 
272 	self->run.user_handler = (__u64)test_handler;
273 	self->run.user_data = 0xdeadbeef;
274 
275 	op.type = ENCL_OP_PUT;
276 	op.buffer = MAGIC;
277 
278 	EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
279 
280 	EXPECT_EEXIT(&self->run);
281 	EXPECT_EQ(self->run.user_data, 0);
282 
283 	op.type = ENCL_OP_GET;
284 	op.buffer = 0;
285 
286 	EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
287 
288 	EXPECT_EQ(op.buffer, MAGIC);
289 	EXPECT_EEXIT(&self->run);
290 	EXPECT_EQ(self->run.user_data, 0);
291 }
292 
293 TEST_HARNESS_MAIN
294