xref: /openbmc/linux/tools/testing/selftests/sgx/main.c (revision e2bd6bad)
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 "main.h"
21 #include "../kselftest.h"
22 
23 static const uint64_t MAGIC = 0x1122334455667788ULL;
24 vdso_sgx_enter_enclave_t eenter;
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 bool report_results(struct sgx_enclave_run *run, int ret, uint64_t result,
111 		  const char *test)
112 {
113 	bool valid = true;
114 
115 	if (ret) {
116 		printf("FAIL: %s() returned: %d\n", test, ret);
117 		valid = false;
118 	}
119 
120 	if (run->function != EEXIT) {
121 		printf("FAIL: %s() function, expected: %u, got: %u\n", test, EEXIT,
122 		       run->function);
123 		valid = false;
124 	}
125 
126 	if (result != MAGIC) {
127 		printf("FAIL: %s(), expected: 0x%lx, got: 0x%lx\n", test, MAGIC,
128 		       result);
129 		valid = false;
130 	}
131 
132 	if (run->user_data) {
133 		printf("FAIL: %s() user data, expected: 0x0, got: 0x%llx\n",
134 		       test, run->user_data);
135 		valid = false;
136 	}
137 
138 	return valid;
139 }
140 
141 static int user_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,
142 			struct sgx_enclave_run *run)
143 {
144 	run->user_data = 0;
145 	return 0;
146 }
147 
148 int main(int argc, char *argv[])
149 {
150 	struct sgx_enclave_run run;
151 	struct vdso_symtab symtab;
152 	Elf64_Sym *eenter_sym;
153 	uint64_t result = 0;
154 	struct encl encl;
155 	unsigned int i;
156 	void *addr;
157 	int ret;
158 
159 	memset(&run, 0, sizeof(run));
160 
161 	if (!encl_load("test_encl.elf", &encl)) {
162 		encl_delete(&encl);
163 		ksft_exit_skip("cannot load enclaves\n");
164 	}
165 
166 	if (!encl_measure(&encl))
167 		goto err;
168 
169 	if (!encl_build(&encl))
170 		goto err;
171 
172 	/*
173 	 * An enclave consumer only must do this.
174 	 */
175 	for (i = 0; i < encl.nr_segments; i++) {
176 		struct encl_segment *seg = &encl.segment_tbl[i];
177 
178 		addr = mmap((void *)encl.encl_base + seg->offset, seg->size,
179 			    seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0);
180 		if (addr == MAP_FAILED) {
181 			perror("mmap() segment failed");
182 			exit(KSFT_FAIL);
183 		}
184 	}
185 
186 	memset(&run, 0, sizeof(run));
187 	run.tcs = encl.encl_base;
188 
189 	/* Get vDSO base address */
190 	addr = (void *)getauxval(AT_SYSINFO_EHDR);
191 	if (!addr)
192 		goto err;
193 
194 	if (!vdso_get_symtab(addr, &symtab))
195 		goto err;
196 
197 	eenter_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
198 	if (!eenter_sym)
199 		goto err;
200 
201 	eenter = addr + eenter_sym->st_value;
202 
203 	ret = sgx_call_vdso((void *)&MAGIC, &result, 0, EENTER, NULL, NULL, &run);
204 	if (!report_results(&run, ret, result, "sgx_call_vdso"))
205 		goto err;
206 
207 
208 	/* Invoke the vDSO directly. */
209 	result = 0;
210 	ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
211 		     0, 0, &run);
212 	if (!report_results(&run, ret, result, "eenter"))
213 		goto err;
214 
215 	/* And with an exit handler. */
216 	run.user_handler = (__u64)user_handler;
217 	run.user_data = 0xdeadbeef;
218 	ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
219 		     0, 0, &run);
220 	if (!report_results(&run, ret, result, "user_handler"))
221 		goto err;
222 
223 	printf("SUCCESS\n");
224 	encl_delete(&encl);
225 	exit(KSFT_PASS);
226 
227 err:
228 	encl_delete(&encl);
229 	exit(KSFT_FAIL);
230 }
231