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
vdso_get_dyntab(void * addr)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
vdso_get_dyn(void * addr,Elf64_Dyn * dyntab,Elf64_Sxword tag)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
vdso_get_symtab(void * addr,struct vdso_symtab * symtab)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
elf_sym_hash(const char * name)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
vdso_symtab_get(struct vdso_symtab * symtab,const char * name)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
report_results(struct sgx_enclave_run * run,int ret,uint64_t result,const char * test)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
user_handler(long rdi,long rsi,long rdx,long ursp,long r8,long r9,struct sgx_enclave_run * run)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
main(int argc,char * argv[])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