1
2
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
23static const uint64_t MAGIC = 0x1122334455667788ULL;
24vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;
25
26struct vdso_symtab {
27 Elf64_Sym *elf_symtab;
28 const char *elf_symstrtab;
29 Elf64_Word *elf_hashtab;
30};
31
32static 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
45static 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
56static 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
75static 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
92static 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
110FIXTURE(enclave) {
111 struct encl encl;
112 struct sgx_enclave_run run;
113};
114
115FIXTURE_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
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
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
184err:
185 if (!sgx_enter_enclave_sym)
186 encl_delete(&self->encl);
187
188 ASSERT_NE(sgx_enter_enclave_sym, NULL);
189}
190
191FIXTURE_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
216TEST_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
238TEST_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
260static 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
268TEST_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
293TEST_HARNESS_MAIN
294