Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 "defines.h"
19#include "main.h"
20#include "../kselftest.h"
21
22static const uint64_t MAGIC = 0x1122334455667788ULL;
23vdso_sgx_enter_enclave_t eenter;
24
25struct vdso_symtab {
26 Elf64_Sym *elf_symtab;
27 const char *elf_symstrtab;
28 Elf64_Word *elf_hashtab;
29};
30
31static void *vdso_get_base_addr(char *envp[])
32{
33 Elf64_auxv_t *auxv;
34 int i;
35
36 for (i = 0; envp[i]; i++)
37 ;
38
39 auxv = (Elf64_auxv_t *)&envp[i + 1];
40
41 for (i = 0; auxv[i].a_type != AT_NULL; i++) {
42 if (auxv[i].a_type == AT_SYSINFO_EHDR)
43 return (void *)auxv[i].a_un.a_val;
44 }
45
46 return NULL;
47}
48
49static Elf64_Dyn *vdso_get_dyntab(void *addr)
50{
51 Elf64_Ehdr *ehdr = addr;
52 Elf64_Phdr *phdrtab = addr + ehdr->e_phoff;
53 int i;
54
55 for (i = 0; i < ehdr->e_phnum; i++)
56 if (phdrtab[i].p_type == PT_DYNAMIC)
57 return addr + phdrtab[i].p_offset;
58
59 return NULL;
60}
61
62static void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag)
63{
64 int i;
65
66 for (i = 0; dyntab[i].d_tag != DT_NULL; i++)
67 if (dyntab[i].d_tag == tag)
68 return addr + dyntab[i].d_un.d_ptr;
69
70 return NULL;
71}
72
73static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab)
74{
75 Elf64_Dyn *dyntab = vdso_get_dyntab(addr);
76
77 symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB);
78 if (!symtab->elf_symtab)
79 return false;
80
81 symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB);
82 if (!symtab->elf_symstrtab)
83 return false;
84
85 symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH);
86 if (!symtab->elf_hashtab)
87 return false;
88
89 return true;
90}
91
92static unsigned long elf_sym_hash(const char *name)
93{
94 unsigned long h = 0, high;
95
96 while (*name) {
97 h = (h << 4) + *name++;
98 high = h & 0xf0000000;
99
100 if (high)
101 h ^= high >> 24;
102
103 h &= ~high;
104 }
105
106 return h;
107}
108
109static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name)
110{
111 Elf64_Word bucketnum = symtab->elf_hashtab[0];
112 Elf64_Word *buckettab = &symtab->elf_hashtab[2];
113 Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum];
114 Elf64_Sym *sym;
115 Elf64_Word i;
116
117 for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF;
118 i = chaintab[i]) {
119 sym = &symtab->elf_symtab[i];
120 if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name]))
121 return sym;
122 }
123
124 return NULL;
125}
126
127bool report_results(struct sgx_enclave_run *run, int ret, uint64_t result,
128 const char *test)
129{
130 bool valid = true;
131
132 if (ret) {
133 printf("FAIL: %s() returned: %d\n", test, ret);
134 valid = false;
135 }
136
137 if (run->function != EEXIT) {
138 printf("FAIL: %s() function, expected: %u, got: %u\n", test, EEXIT,
139 run->function);
140 valid = false;
141 }
142
143 if (result != MAGIC) {
144 printf("FAIL: %s(), expected: 0x%lx, got: 0x%lx\n", test, MAGIC,
145 result);
146 valid = false;
147 }
148
149 if (run->user_data) {
150 printf("FAIL: %s() user data, expected: 0x0, got: 0x%llx\n",
151 test, run->user_data);
152 valid = false;
153 }
154
155 return valid;
156}
157
158static int user_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,
159 struct sgx_enclave_run *run)
160{
161 run->user_data = 0;
162 return 0;
163}
164
165int main(int argc, char *argv[], char *envp[])
166{
167 struct sgx_enclave_run run;
168 struct vdso_symtab symtab;
169 Elf64_Sym *eenter_sym;
170 uint64_t result = 0;
171 struct encl encl;
172 unsigned int i;
173 void *addr;
174 int ret;
175
176 memset(&run, 0, sizeof(run));
177
178 if (!encl_load("test_encl.elf", &encl)) {
179 encl_delete(&encl);
180 ksft_exit_skip("cannot load enclaves\n");
181 }
182
183 if (!encl_measure(&encl))
184 goto err;
185
186 if (!encl_build(&encl))
187 goto err;
188
189 /*
190 * An enclave consumer only must do this.
191 */
192 for (i = 0; i < encl.nr_segments; i++) {
193 struct encl_segment *seg = &encl.segment_tbl[i];
194
195 addr = mmap((void *)encl.encl_base + seg->offset, seg->size,
196 seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0);
197 if (addr == MAP_FAILED) {
198 fprintf(stderr, "mmap() failed, errno=%d.\n", errno);
199 exit(KSFT_FAIL);
200 }
201 }
202
203 memset(&run, 0, sizeof(run));
204 run.tcs = encl.encl_base;
205
206 addr = vdso_get_base_addr(envp);
207 if (!addr)
208 goto err;
209
210 if (!vdso_get_symtab(addr, &symtab))
211 goto err;
212
213 eenter_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
214 if (!eenter_sym)
215 goto err;
216
217 eenter = addr + eenter_sym->st_value;
218
219 ret = sgx_call_vdso((void *)&MAGIC, &result, 0, EENTER, NULL, NULL, &run);
220 if (!report_results(&run, ret, result, "sgx_call_vdso"))
221 goto err;
222
223
224 /* Invoke the vDSO directly. */
225 result = 0;
226 ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
227 0, 0, &run);
228 if (!report_results(&run, ret, result, "eenter"))
229 goto err;
230
231 /* And with an exit handler. */
232 run.user_handler = (__u64)user_handler;
233 run.user_data = 0xdeadbeef;
234 ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
235 0, 0, &run);
236 if (!report_results(&run, ret, result, "user_handler"))
237 goto err;
238
239 printf("SUCCESS\n");
240 encl_delete(&encl);
241 exit(KSFT_PASS);
242
243err:
244 encl_delete(&encl);
245 exit(KSFT_FAIL);
246}