1// SPDX-License-Identifier: GPL-2.0
2/* Copyright(c) 2016-20 Intel Corporation. */
3
4#include <cpuid.h>
5#include <elf.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdint.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14#include <sys/ioctl.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <sys/time.h>
18#include <sys/types.h>
19#include <sys/auxv.h>
20#include "defines.h"
21#include "../kselftest_harness.h"
22#include "main.h"
23
24static const uint64_t MAGIC = 0x1122334455667788ULL;
25static const uint64_t MAGIC2 = 0x8877665544332211ULL;
26vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;
27
28/*
29 * Security Information (SECINFO) data structure needed by a few SGX
30 * instructions (eg. ENCLU[EACCEPT] and ENCLU[EMODPE]) holds meta-data
31 * about an enclave page. &enum sgx_secinfo_page_state specifies the
32 * secinfo flags used for page state.
33 */
34enum sgx_secinfo_page_state {
35 SGX_SECINFO_PENDING = (1 << 3),
36 SGX_SECINFO_MODIFIED = (1 << 4),
37 SGX_SECINFO_PR = (1 << 5),
38};
39
40struct vdso_symtab {
41 Elf64_Sym *elf_symtab;
42 const char *elf_symstrtab;
43 Elf64_Word *elf_hashtab;
44};
45
46static Elf64_Dyn *vdso_get_dyntab(void *addr)
47{
48 Elf64_Ehdr *ehdr = addr;
49 Elf64_Phdr *phdrtab = addr + ehdr->e_phoff;
50 int i;
51
52 for (i = 0; i < ehdr->e_phnum; i++)
53 if (phdrtab[i].p_type == PT_DYNAMIC)
54 return addr + phdrtab[i].p_offset;
55
56 return NULL;
57}
58
59static void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag)
60{
61 int i;
62
63 for (i = 0; dyntab[i].d_tag != DT_NULL; i++)
64 if (dyntab[i].d_tag == tag)
65 return addr + dyntab[i].d_un.d_ptr;
66
67 return NULL;
68}
69
70static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab)
71{
72 Elf64_Dyn *dyntab = vdso_get_dyntab(addr);
73
74 symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB);
75 if (!symtab->elf_symtab)
76 return false;
77
78 symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB);
79 if (!symtab->elf_symstrtab)
80 return false;
81
82 symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH);
83 if (!symtab->elf_hashtab)
84 return false;
85
86 return true;
87}
88
89static inline int sgx2_supported(void)
90{
91 unsigned int eax, ebx, ecx, edx;
92
93 __cpuid_count(SGX_CPUID, 0x0, eax, ebx, ecx, edx);
94
95 return eax & 0x2;
96}
97
98static unsigned long elf_sym_hash(const char *name)
99{
100 unsigned long h = 0, high;
101
102 while (*name) {
103 h = (h << 4) + *name++;
104 high = h & 0xf0000000;
105
106 if (high)
107 h ^= high >> 24;
108
109 h &= ~high;
110 }
111
112 return h;
113}
114
115static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name)
116{
117 Elf64_Word bucketnum = symtab->elf_hashtab[0];
118 Elf64_Word *buckettab = &symtab->elf_hashtab[2];
119 Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum];
120 Elf64_Sym *sym;
121 Elf64_Word i;
122
123 for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF;
124 i = chaintab[i]) {
125 sym = &symtab->elf_symtab[i];
126 if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name]))
127 return sym;
128 }
129
130 return NULL;
131}
132
133/*
134 * Return the offset in the enclave where the TCS segment can be found.
135 * The first RW segment loaded is the TCS.
136 */
137static off_t encl_get_tcs_offset(struct encl *encl)
138{
139 int i;
140
141 for (i = 0; i < encl->nr_segments; i++) {
142 struct encl_segment *seg = &encl->segment_tbl[i];
143
144 if (i == 0 && seg->prot == (PROT_READ | PROT_WRITE))
145 return seg->offset;
146 }
147
148 return -1;
149}
150
151/*
152 * Return the offset in the enclave where the data segment can be found.
153 * The first RW segment loaded is the TCS, skip that to get info on the
154 * data segment.
155 */
156static off_t encl_get_data_offset(struct encl *encl)
157{
158 int i;
159
160 for (i = 1; i < encl->nr_segments; i++) {
161 struct encl_segment *seg = &encl->segment_tbl[i];
162
163 if (seg->prot == (PROT_READ | PROT_WRITE))
164 return seg->offset;
165 }
166
167 return -1;
168}
169
170FIXTURE(enclave) {
171 struct encl encl;
172 struct sgx_enclave_run run;
173};
174
175static bool setup_test_encl(unsigned long heap_size, struct encl *encl,
176 struct __test_metadata *_metadata)
177{
178 Elf64_Sym *sgx_enter_enclave_sym = NULL;
179 struct vdso_symtab symtab;
180 struct encl_segment *seg;
181 char maps_line[256];
182 FILE *maps_file;
183 unsigned int i;
184 void *addr;
185
186 if (!encl_load(path: "test_encl.elf", encl, heap_size)) {
187 encl_delete(ctx: encl);
188 TH_LOG("Failed to load the test enclave.");
189 return false;
190 }
191
192 if (!encl_measure(encl))
193 goto err;
194
195 if (!encl_build(encl))
196 goto err;
197
198 /*
199 * An enclave consumer only must do this.
200 */
201 for (i = 0; i < encl->nr_segments; i++) {
202 struct encl_segment *seg = &encl->segment_tbl[i];
203
204 addr = mmap((void *)encl->encl_base + seg->offset, seg->size,
205 seg->prot, MAP_SHARED | MAP_FIXED, encl->fd, 0);
206 EXPECT_NE(addr, MAP_FAILED);
207 if (addr == MAP_FAILED)
208 goto err;
209 }
210
211 /* Get vDSO base address */
212 addr = (void *)getauxval(AT_SYSINFO_EHDR);
213 if (!addr)
214 goto err;
215
216 if (!vdso_get_symtab(addr, symtab: &symtab))
217 goto err;
218
219 sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
220 if (!sgx_enter_enclave_sym)
221 goto err;
222
223 vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value;
224
225 return true;
226
227err:
228 for (i = 0; i < encl->nr_segments; i++) {
229 seg = &encl->segment_tbl[i];
230
231 TH_LOG("0x%016lx 0x%016lx 0x%02x", seg->offset, seg->size, seg->prot);
232 }
233
234 maps_file = fopen("/proc/self/maps", "r");
235 if (maps_file != NULL) {
236 while (fgets(maps_line, sizeof(maps_line), maps_file) != NULL) {
237 maps_line[strlen(maps_line) - 1] = '\0';
238
239 if (strstr(maps_line, "/dev/sgx_enclave"))
240 TH_LOG("%s", maps_line);
241 }
242
243 fclose(maps_file);
244 }
245
246 TH_LOG("Failed to initialize the test enclave.");
247
248 encl_delete(ctx: encl);
249
250 return false;
251}
252
253FIXTURE_SETUP(enclave)
254{
255}
256
257FIXTURE_TEARDOWN(enclave)
258{
259 encl_delete(ctx: &self->encl);
260}
261
262#define ENCL_CALL(op, run, clobbered) \
263 ({ \
264 int ret; \
265 if ((clobbered)) \
266 ret = vdso_sgx_enter_enclave((unsigned long)(op), 0, 0, \
267 EENTER, 0, 0, (run)); \
268 else \
269 ret = sgx_enter_enclave((void *)(op), NULL, 0, EENTER, NULL, NULL, \
270 (run)); \
271 ret; \
272 })
273
274#define EXPECT_EEXIT(run) \
275 do { \
276 EXPECT_EQ((run)->function, EEXIT); \
277 if ((run)->function != EEXIT) \
278 TH_LOG("0x%02x 0x%02x 0x%016llx", (run)->exception_vector, \
279 (run)->exception_error_code, (run)->exception_addr); \
280 } while (0)
281
282TEST_F(enclave, unclobbered_vdso)
283{
284 struct encl_op_get_from_buf get_op;
285 struct encl_op_put_to_buf put_op;
286
287 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
288
289 memset(&self->run, 0, sizeof(self->run));
290 self->run.tcs = self->encl.encl_base;
291
292 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;
293 put_op.value = MAGIC;
294
295 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0);
296
297 EXPECT_EEXIT(&self->run);
298 EXPECT_EQ(self->run.user_data, 0);
299
300 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;
301 get_op.value = 0;
302
303 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0);
304
305 EXPECT_EQ(get_op.value, MAGIC);
306 EXPECT_EEXIT(&self->run);
307 EXPECT_EQ(self->run.user_data, 0);
308}
309
310/*
311 * A section metric is concatenated in a way that @low bits 12-31 define the
312 * bits 12-31 of the metric and @high bits 0-19 define the bits 32-51 of the
313 * metric.
314 */
315static unsigned long sgx_calc_section_metric(unsigned int low,
316 unsigned int high)
317{
318 return (low & GENMASK_ULL(31, 12)) +
319 ((high & GENMASK_ULL(19, 0)) << 32);
320}
321
322/*
323 * Sum total available physical SGX memory across all EPC sections
324 *
325 * Return: total available physical SGX memory available on system
326 */
327static unsigned long get_total_epc_mem(void)
328{
329 unsigned int eax, ebx, ecx, edx;
330 unsigned long total_size = 0;
331 unsigned int type;
332 int section = 0;
333
334 while (true) {
335 __cpuid_count(SGX_CPUID, section + SGX_CPUID_EPC, eax, ebx, ecx, edx);
336
337 type = eax & SGX_CPUID_EPC_MASK;
338 if (type == SGX_CPUID_EPC_INVALID)
339 break;
340
341 if (type != SGX_CPUID_EPC_SECTION)
342 break;
343
344 total_size += sgx_calc_section_metric(low: ecx, high: edx);
345
346 section++;
347 }
348
349 return total_size;
350}
351
352TEST_F(enclave, unclobbered_vdso_oversubscribed)
353{
354 struct encl_op_get_from_buf get_op;
355 struct encl_op_put_to_buf put_op;
356 unsigned long total_mem;
357
358 total_mem = get_total_epc_mem();
359 ASSERT_NE(total_mem, 0);
360 ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata));
361
362 memset(&self->run, 0, sizeof(self->run));
363 self->run.tcs = self->encl.encl_base;
364
365 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;
366 put_op.value = MAGIC;
367
368 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0);
369
370 EXPECT_EEXIT(&self->run);
371 EXPECT_EQ(self->run.user_data, 0);
372
373 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;
374 get_op.value = 0;
375
376 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0);
377
378 EXPECT_EQ(get_op.value, MAGIC);
379 EXPECT_EEXIT(&self->run);
380 EXPECT_EQ(self->run.user_data, 0);
381}
382
383TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900)
384{
385 struct sgx_enclave_remove_pages remove_ioc;
386 struct sgx_enclave_modify_types modt_ioc;
387 struct encl_op_get_from_buf get_op;
388 struct encl_op_eaccept eaccept_op;
389 struct encl_op_put_to_buf put_op;
390 struct encl_segment *heap;
391 unsigned long total_mem;
392 int ret, errno_save;
393 unsigned long addr;
394 unsigned long i;
395
396 /*
397 * Create enclave with additional heap that is as big as all
398 * available physical SGX memory.
399 */
400 total_mem = get_total_epc_mem();
401 ASSERT_NE(total_mem, 0);
402 TH_LOG("Creating an enclave with %lu bytes heap may take a while ...",
403 total_mem);
404 ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata));
405
406 /*
407 * Hardware (SGX2) and kernel support is needed for this test. Start
408 * with check that test has a chance of succeeding.
409 */
410 memset(&modt_ioc, 0, sizeof(modt_ioc));
411 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
412
413 if (ret == -1) {
414 if (errno == ENOTTY)
415 SKIP(return,
416 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
417 else if (errno == ENODEV)
418 SKIP(return, "System does not support SGX2");
419 }
420
421 /*
422 * Invalid parameters were provided during sanity check,
423 * expect command to fail.
424 */
425 EXPECT_EQ(ret, -1);
426
427 /* SGX2 is supported by kernel and hardware, test can proceed. */
428 memset(&self->run, 0, sizeof(self->run));
429 self->run.tcs = self->encl.encl_base;
430
431 heap = &self->encl.segment_tbl[self->encl.nr_segments - 1];
432
433 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;
434 put_op.value = MAGIC;
435
436 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0);
437
438 EXPECT_EEXIT(&self->run);
439 EXPECT_EQ(self->run.user_data, 0);
440
441 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;
442 get_op.value = 0;
443
444 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0);
445
446 EXPECT_EQ(get_op.value, MAGIC);
447 EXPECT_EEXIT(&self->run);
448 EXPECT_EQ(self->run.user_data, 0);
449
450 /* Trim entire heap. */
451 memset(&modt_ioc, 0, sizeof(modt_ioc));
452
453 modt_ioc.offset = heap->offset;
454 modt_ioc.length = heap->size;
455 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;
456
457 TH_LOG("Changing type of %zd bytes to trimmed may take a while ...",
458 heap->size);
459 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
460 errno_save = ret == -1 ? errno : 0;
461
462 EXPECT_EQ(ret, 0);
463 EXPECT_EQ(errno_save, 0);
464 EXPECT_EQ(modt_ioc.result, 0);
465 EXPECT_EQ(modt_ioc.count, heap->size);
466
467 /* EACCEPT all removed pages. */
468 addr = self->encl.encl_base + heap->offset;
469
470 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;
471 eaccept_op.header.type = ENCL_OP_EACCEPT;
472
473 TH_LOG("Entering enclave to run EACCEPT for each page of %zd bytes may take a while ...",
474 heap->size);
475 for (i = 0; i < heap->size; i += 4096) {
476 eaccept_op.epc_addr = addr + i;
477 eaccept_op.ret = 0;
478
479 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
480
481 EXPECT_EQ(self->run.exception_vector, 0);
482 EXPECT_EQ(self->run.exception_error_code, 0);
483 EXPECT_EQ(self->run.exception_addr, 0);
484 ASSERT_EQ(eaccept_op.ret, 0);
485 ASSERT_EQ(self->run.function, EEXIT);
486 }
487
488 /* Complete page removal. */
489 memset(&remove_ioc, 0, sizeof(remove_ioc));
490
491 remove_ioc.offset = heap->offset;
492 remove_ioc.length = heap->size;
493
494 TH_LOG("Removing %zd bytes from enclave may take a while ...",
495 heap->size);
496 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);
497 errno_save = ret == -1 ? errno : 0;
498
499 EXPECT_EQ(ret, 0);
500 EXPECT_EQ(errno_save, 0);
501 EXPECT_EQ(remove_ioc.count, heap->size);
502}
503
504TEST_F(enclave, clobbered_vdso)
505{
506 struct encl_op_get_from_buf get_op;
507 struct encl_op_put_to_buf put_op;
508
509 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
510
511 memset(&self->run, 0, sizeof(self->run));
512 self->run.tcs = self->encl.encl_base;
513
514 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;
515 put_op.value = MAGIC;
516
517 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, true), 0);
518
519 EXPECT_EEXIT(&self->run);
520 EXPECT_EQ(self->run.user_data, 0);
521
522 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;
523 get_op.value = 0;
524
525 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, true), 0);
526
527 EXPECT_EQ(get_op.value, MAGIC);
528 EXPECT_EEXIT(&self->run);
529 EXPECT_EQ(self->run.user_data, 0);
530}
531
532static int test_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,
533 struct sgx_enclave_run *run)
534{
535 run->user_data = 0;
536
537 return 0;
538}
539
540TEST_F(enclave, clobbered_vdso_and_user_function)
541{
542 struct encl_op_get_from_buf get_op;
543 struct encl_op_put_to_buf put_op;
544
545 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
546
547 memset(&self->run, 0, sizeof(self->run));
548 self->run.tcs = self->encl.encl_base;
549
550 self->run.user_handler = (__u64)test_handler;
551 self->run.user_data = 0xdeadbeef;
552
553 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;
554 put_op.value = MAGIC;
555
556 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, true), 0);
557
558 EXPECT_EEXIT(&self->run);
559 EXPECT_EQ(self->run.user_data, 0);
560
561 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;
562 get_op.value = 0;
563
564 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, true), 0);
565
566 EXPECT_EQ(get_op.value, MAGIC);
567 EXPECT_EEXIT(&self->run);
568 EXPECT_EQ(self->run.user_data, 0);
569}
570
571/*
572 * Sanity check that it is possible to enter either of the two hardcoded TCS
573 */
574TEST_F(enclave, tcs_entry)
575{
576 struct encl_op_header op;
577
578 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
579
580 memset(&self->run, 0, sizeof(self->run));
581 self->run.tcs = self->encl.encl_base;
582
583 op.type = ENCL_OP_NOP;
584
585 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
586
587 EXPECT_EEXIT(&self->run);
588 EXPECT_EQ(self->run.exception_vector, 0);
589 EXPECT_EQ(self->run.exception_error_code, 0);
590 EXPECT_EQ(self->run.exception_addr, 0);
591
592 /* Move to the next TCS. */
593 self->run.tcs = self->encl.encl_base + PAGE_SIZE;
594
595 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
596
597 EXPECT_EEXIT(&self->run);
598 EXPECT_EQ(self->run.exception_vector, 0);
599 EXPECT_EQ(self->run.exception_error_code, 0);
600 EXPECT_EQ(self->run.exception_addr, 0);
601}
602
603/*
604 * Second page of .data segment is used to test changing PTE permissions.
605 * This spans the local encl_buffer within the test enclave.
606 *
607 * 1) Start with a sanity check: a value is written to the target page within
608 * the enclave and read back to ensure target page can be written to.
609 * 2) Change PTE permissions (RW -> RO) of target page within enclave.
610 * 3) Repeat (1) - this time expecting a regular #PF communicated via the
611 * vDSO.
612 * 4) Change PTE permissions of target page within enclave back to be RW.
613 * 5) Repeat (1) by resuming enclave, now expected to be possible to write to
614 * and read from target page within enclave.
615 */
616TEST_F(enclave, pte_permissions)
617{
618 struct encl_op_get_from_addr get_addr_op;
619 struct encl_op_put_to_addr put_addr_op;
620 unsigned long data_start;
621 int ret;
622
623 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
624
625 memset(&self->run, 0, sizeof(self->run));
626 self->run.tcs = self->encl.encl_base;
627
628 data_start = self->encl.encl_base +
629 encl_get_data_offset(encl: &self->encl) +
630 PAGE_SIZE;
631
632 /*
633 * Sanity check to ensure it is possible to write to page that will
634 * have its permissions manipulated.
635 */
636
637 /* Write MAGIC to page */
638 put_addr_op.value = MAGIC;
639 put_addr_op.addr = data_start;
640 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
641
642 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
643
644 EXPECT_EEXIT(&self->run);
645 EXPECT_EQ(self->run.exception_vector, 0);
646 EXPECT_EQ(self->run.exception_error_code, 0);
647 EXPECT_EQ(self->run.exception_addr, 0);
648
649 /*
650 * Read memory that was just written to, confirming that it is the
651 * value previously written (MAGIC).
652 */
653 get_addr_op.value = 0;
654 get_addr_op.addr = data_start;
655 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
656
657 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
658
659 EXPECT_EQ(get_addr_op.value, MAGIC);
660 EXPECT_EEXIT(&self->run);
661 EXPECT_EQ(self->run.exception_vector, 0);
662 EXPECT_EQ(self->run.exception_error_code, 0);
663 EXPECT_EQ(self->run.exception_addr, 0);
664
665 /* Change PTE permissions of target page within the enclave */
666 ret = mprotect((void *)data_start, PAGE_SIZE, PROT_READ);
667 if (ret)
668 perror("mprotect");
669
670 /*
671 * PTE permissions of target page changed to read-only, EPCM
672 * permissions unchanged (EPCM permissions are RW), attempt to
673 * write to the page, expecting a regular #PF.
674 */
675
676 put_addr_op.value = MAGIC2;
677
678 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
679
680 EXPECT_EQ(self->run.exception_vector, 14);
681 EXPECT_EQ(self->run.exception_error_code, 0x7);
682 EXPECT_EQ(self->run.exception_addr, data_start);
683
684 self->run.exception_vector = 0;
685 self->run.exception_error_code = 0;
686 self->run.exception_addr = 0;
687
688 /*
689 * Change PTE permissions back to enable enclave to write to the
690 * target page and resume enclave - do not expect any exceptions this
691 * time.
692 */
693 ret = mprotect((void *)data_start, PAGE_SIZE, PROT_READ | PROT_WRITE);
694 if (ret)
695 perror("mprotect");
696
697 EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0,
698 0, ERESUME, 0, 0, &self->run),
699 0);
700
701 EXPECT_EEXIT(&self->run);
702 EXPECT_EQ(self->run.exception_vector, 0);
703 EXPECT_EQ(self->run.exception_error_code, 0);
704 EXPECT_EQ(self->run.exception_addr, 0);
705
706 get_addr_op.value = 0;
707
708 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
709
710 EXPECT_EQ(get_addr_op.value, MAGIC2);
711 EXPECT_EEXIT(&self->run);
712 EXPECT_EQ(self->run.exception_vector, 0);
713 EXPECT_EQ(self->run.exception_error_code, 0);
714 EXPECT_EQ(self->run.exception_addr, 0);
715}
716
717/*
718 * Modifying permissions of TCS page should not be possible.
719 */
720TEST_F(enclave, tcs_permissions)
721{
722 struct sgx_enclave_restrict_permissions ioc;
723 int ret, errno_save;
724
725 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
726
727 memset(&self->run, 0, sizeof(self->run));
728 self->run.tcs = self->encl.encl_base;
729
730 memset(&ioc, 0, sizeof(ioc));
731
732 /*
733 * Ensure kernel supports needed ioctl() and system supports needed
734 * commands.
735 */
736
737 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc);
738 errno_save = ret == -1 ? errno : 0;
739
740 /*
741 * Invalid parameters were provided during sanity check,
742 * expect command to fail.
743 */
744 ASSERT_EQ(ret, -1);
745
746 /* ret == -1 */
747 if (errno_save == ENOTTY)
748 SKIP(return,
749 "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()");
750 else if (errno_save == ENODEV)
751 SKIP(return, "System does not support SGX2");
752
753 /*
754 * Attempt to make TCS page read-only. This is not allowed and
755 * should be prevented by the kernel.
756 */
757 ioc.offset = encl_get_tcs_offset(encl: &self->encl);
758 ioc.length = PAGE_SIZE;
759 ioc.permissions = SGX_SECINFO_R;
760
761 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc);
762 errno_save = ret == -1 ? errno : 0;
763
764 EXPECT_EQ(ret, -1);
765 EXPECT_EQ(errno_save, EINVAL);
766 EXPECT_EQ(ioc.result, 0);
767 EXPECT_EQ(ioc.count, 0);
768}
769
770/*
771 * Enclave page permission test.
772 *
773 * Modify and restore enclave page's EPCM (enclave) permissions from
774 * outside enclave (ENCLS[EMODPR] via kernel) as well as from within
775 * enclave (via ENCLU[EMODPE]). Check for page fault if
776 * VMA allows access but EPCM permissions do not.
777 */
778TEST_F(enclave, epcm_permissions)
779{
780 struct sgx_enclave_restrict_permissions restrict_ioc;
781 struct encl_op_get_from_addr get_addr_op;
782 struct encl_op_put_to_addr put_addr_op;
783 struct encl_op_eaccept eaccept_op;
784 struct encl_op_emodpe emodpe_op;
785 unsigned long data_start;
786 int ret, errno_save;
787
788 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
789
790 memset(&self->run, 0, sizeof(self->run));
791 self->run.tcs = self->encl.encl_base;
792
793 /*
794 * Ensure kernel supports needed ioctl() and system supports needed
795 * commands.
796 */
797 memset(&restrict_ioc, 0, sizeof(restrict_ioc));
798
799 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS,
800 &restrict_ioc);
801 errno_save = ret == -1 ? errno : 0;
802
803 /*
804 * Invalid parameters were provided during sanity check,
805 * expect command to fail.
806 */
807 ASSERT_EQ(ret, -1);
808
809 /* ret == -1 */
810 if (errno_save == ENOTTY)
811 SKIP(return,
812 "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()");
813 else if (errno_save == ENODEV)
814 SKIP(return, "System does not support SGX2");
815
816 /*
817 * Page that will have its permissions changed is the second data
818 * page in the .data segment. This forms part of the local encl_buffer
819 * within the enclave.
820 *
821 * At start of test @data_start should have EPCM as well as PTE and
822 * VMA permissions of RW.
823 */
824
825 data_start = self->encl.encl_base +
826 encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
827
828 /*
829 * Sanity check that page at @data_start is writable before making
830 * any changes to page permissions.
831 *
832 * Start by writing MAGIC to test page.
833 */
834 put_addr_op.value = MAGIC;
835 put_addr_op.addr = data_start;
836 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
837
838 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
839
840 EXPECT_EEXIT(&self->run);
841 EXPECT_EQ(self->run.exception_vector, 0);
842 EXPECT_EQ(self->run.exception_error_code, 0);
843 EXPECT_EQ(self->run.exception_addr, 0);
844
845 /*
846 * Read memory that was just written to, confirming that
847 * page is writable.
848 */
849 get_addr_op.value = 0;
850 get_addr_op.addr = data_start;
851 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
852
853 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
854
855 EXPECT_EQ(get_addr_op.value, MAGIC);
856 EXPECT_EEXIT(&self->run);
857 EXPECT_EQ(self->run.exception_vector, 0);
858 EXPECT_EQ(self->run.exception_error_code, 0);
859 EXPECT_EQ(self->run.exception_addr, 0);
860
861 /*
862 * Change EPCM permissions to read-only. Kernel still considers
863 * the page writable.
864 */
865 memset(&restrict_ioc, 0, sizeof(restrict_ioc));
866
867 restrict_ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
868 restrict_ioc.length = PAGE_SIZE;
869 restrict_ioc.permissions = SGX_SECINFO_R;
870
871 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS,
872 &restrict_ioc);
873 errno_save = ret == -1 ? errno : 0;
874
875 EXPECT_EQ(ret, 0);
876 EXPECT_EQ(errno_save, 0);
877 EXPECT_EQ(restrict_ioc.result, 0);
878 EXPECT_EQ(restrict_ioc.count, 4096);
879
880 /*
881 * EPCM permissions changed from kernel, need to EACCEPT from enclave.
882 */
883 eaccept_op.epc_addr = data_start;
884 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_REG | SGX_SECINFO_PR;
885 eaccept_op.ret = 0;
886 eaccept_op.header.type = ENCL_OP_EACCEPT;
887
888 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
889
890 EXPECT_EEXIT(&self->run);
891 EXPECT_EQ(self->run.exception_vector, 0);
892 EXPECT_EQ(self->run.exception_error_code, 0);
893 EXPECT_EQ(self->run.exception_addr, 0);
894 EXPECT_EQ(eaccept_op.ret, 0);
895
896 /*
897 * EPCM permissions of page is now read-only, expect #PF
898 * on EPCM when attempting to write to page from within enclave.
899 */
900 put_addr_op.value = MAGIC2;
901
902 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
903
904 EXPECT_EQ(self->run.function, ERESUME);
905 EXPECT_EQ(self->run.exception_vector, 14);
906 EXPECT_EQ(self->run.exception_error_code, 0x8007);
907 EXPECT_EQ(self->run.exception_addr, data_start);
908
909 self->run.exception_vector = 0;
910 self->run.exception_error_code = 0;
911 self->run.exception_addr = 0;
912
913 /*
914 * Received AEX but cannot return to enclave at same entrypoint,
915 * need different TCS from where EPCM permission can be made writable
916 * again.
917 */
918 self->run.tcs = self->encl.encl_base + PAGE_SIZE;
919
920 /*
921 * Enter enclave at new TCS to change EPCM permissions to be
922 * writable again and thus fix the page fault that triggered the
923 * AEX.
924 */
925
926 emodpe_op.epc_addr = data_start;
927 emodpe_op.flags = SGX_SECINFO_R | SGX_SECINFO_W;
928 emodpe_op.header.type = ENCL_OP_EMODPE;
929
930 EXPECT_EQ(ENCL_CALL(&emodpe_op, &self->run, true), 0);
931
932 EXPECT_EEXIT(&self->run);
933 EXPECT_EQ(self->run.exception_vector, 0);
934 EXPECT_EQ(self->run.exception_error_code, 0);
935 EXPECT_EQ(self->run.exception_addr, 0);
936
937 /*
938 * Attempt to return to main TCS to resume execution at faulting
939 * instruction, PTE should continue to allow writing to the page.
940 */
941 self->run.tcs = self->encl.encl_base;
942
943 /*
944 * Wrong page permissions that caused original fault has
945 * now been fixed via EPCM permissions.
946 * Resume execution in main TCS to re-attempt the memory access.
947 */
948 self->run.tcs = self->encl.encl_base;
949
950 EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0,
951 ERESUME, 0, 0,
952 &self->run),
953 0);
954
955 EXPECT_EEXIT(&self->run);
956 EXPECT_EQ(self->run.exception_vector, 0);
957 EXPECT_EQ(self->run.exception_error_code, 0);
958 EXPECT_EQ(self->run.exception_addr, 0);
959
960 get_addr_op.value = 0;
961
962 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
963
964 EXPECT_EQ(get_addr_op.value, MAGIC2);
965 EXPECT_EEXIT(&self->run);
966 EXPECT_EQ(self->run.user_data, 0);
967 EXPECT_EQ(self->run.exception_vector, 0);
968 EXPECT_EQ(self->run.exception_error_code, 0);
969 EXPECT_EQ(self->run.exception_addr, 0);
970}
971
972/*
973 * Test the addition of pages to an initialized enclave via writing to
974 * a page belonging to the enclave's address space but was not added
975 * during enclave creation.
976 */
977TEST_F(enclave, augment)
978{
979 struct encl_op_get_from_addr get_addr_op;
980 struct encl_op_put_to_addr put_addr_op;
981 struct encl_op_eaccept eaccept_op;
982 size_t total_size = 0;
983 void *addr;
984 int i;
985
986 if (!sgx2_supported())
987 SKIP(return, "SGX2 not supported");
988
989 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
990
991 memset(&self->run, 0, sizeof(self->run));
992 self->run.tcs = self->encl.encl_base;
993
994 for (i = 0; i < self->encl.nr_segments; i++) {
995 struct encl_segment *seg = &self->encl.segment_tbl[i];
996
997 total_size += seg->size;
998 }
999
1000 /*
1001 * Actual enclave size is expected to be larger than the loaded
1002 * test enclave since enclave size must be a power of 2 in bytes
1003 * and test_encl does not consume it all.
1004 */
1005 EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size);
1006
1007 /*
1008 * Create memory mapping for the page that will be added. New
1009 * memory mapping is for one page right after all existing
1010 * mappings.
1011 * Kernel will allow new mapping using any permissions if it
1012 * falls into the enclave's address range but not backed
1013 * by existing enclave pages.
1014 */
1015 addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE,
1016 PROT_READ | PROT_WRITE | PROT_EXEC,
1017 MAP_SHARED | MAP_FIXED, self->encl.fd, 0);
1018 EXPECT_NE(addr, MAP_FAILED);
1019
1020 self->run.exception_vector = 0;
1021 self->run.exception_error_code = 0;
1022 self->run.exception_addr = 0;
1023
1024 /*
1025 * Attempt to write to the new page from within enclave.
1026 * Expected to fail since page is not (yet) part of the enclave.
1027 * The first #PF will trigger the addition of the page to the
1028 * enclave, but since the new page needs an EACCEPT from within the
1029 * enclave before it can be used it would not be possible
1030 * to successfully return to the failing instruction. This is the
1031 * cause of the second #PF captured here having the SGX bit set,
1032 * it is from hardware preventing the page from being used.
1033 */
1034 put_addr_op.value = MAGIC;
1035 put_addr_op.addr = (unsigned long)addr;
1036 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1037
1038 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1039
1040 EXPECT_EQ(self->run.function, ERESUME);
1041 EXPECT_EQ(self->run.exception_vector, 14);
1042 EXPECT_EQ(self->run.exception_addr, (unsigned long)addr);
1043
1044 if (self->run.exception_error_code == 0x6) {
1045 munmap(addr, PAGE_SIZE);
1046 SKIP(return, "Kernel does not support adding pages to initialized enclave");
1047 }
1048
1049 EXPECT_EQ(self->run.exception_error_code, 0x8007);
1050
1051 self->run.exception_vector = 0;
1052 self->run.exception_error_code = 0;
1053 self->run.exception_addr = 0;
1054
1055 /* Handle AEX by running EACCEPT from new entry point. */
1056 self->run.tcs = self->encl.encl_base + PAGE_SIZE;
1057
1058 eaccept_op.epc_addr = self->encl.encl_base + total_size;
1059 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;
1060 eaccept_op.ret = 0;
1061 eaccept_op.header.type = ENCL_OP_EACCEPT;
1062
1063 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1064
1065 EXPECT_EEXIT(&self->run);
1066 EXPECT_EQ(self->run.exception_vector, 0);
1067 EXPECT_EQ(self->run.exception_error_code, 0);
1068 EXPECT_EQ(self->run.exception_addr, 0);
1069 EXPECT_EQ(eaccept_op.ret, 0);
1070
1071 /* Can now return to main TCS to resume execution. */
1072 self->run.tcs = self->encl.encl_base;
1073
1074 EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0,
1075 ERESUME, 0, 0,
1076 &self->run),
1077 0);
1078
1079 EXPECT_EEXIT(&self->run);
1080 EXPECT_EQ(self->run.exception_vector, 0);
1081 EXPECT_EQ(self->run.exception_error_code, 0);
1082 EXPECT_EQ(self->run.exception_addr, 0);
1083
1084 /*
1085 * Read memory from newly added page that was just written to,
1086 * confirming that data previously written (MAGIC) is present.
1087 */
1088 get_addr_op.value = 0;
1089 get_addr_op.addr = (unsigned long)addr;
1090 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1091
1092 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1093
1094 EXPECT_EQ(get_addr_op.value, MAGIC);
1095 EXPECT_EEXIT(&self->run);
1096 EXPECT_EQ(self->run.exception_vector, 0);
1097 EXPECT_EQ(self->run.exception_error_code, 0);
1098 EXPECT_EQ(self->run.exception_addr, 0);
1099
1100 munmap(addr, PAGE_SIZE);
1101}
1102
1103/*
1104 * Test for the addition of pages to an initialized enclave via a
1105 * pre-emptive run of EACCEPT on page to be added.
1106 */
1107TEST_F(enclave, augment_via_eaccept)
1108{
1109 struct encl_op_get_from_addr get_addr_op;
1110 struct encl_op_put_to_addr put_addr_op;
1111 struct encl_op_eaccept eaccept_op;
1112 size_t total_size = 0;
1113 void *addr;
1114 int i;
1115
1116 if (!sgx2_supported())
1117 SKIP(return, "SGX2 not supported");
1118
1119 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1120
1121 memset(&self->run, 0, sizeof(self->run));
1122 self->run.tcs = self->encl.encl_base;
1123
1124 for (i = 0; i < self->encl.nr_segments; i++) {
1125 struct encl_segment *seg = &self->encl.segment_tbl[i];
1126
1127 total_size += seg->size;
1128 }
1129
1130 /*
1131 * Actual enclave size is expected to be larger than the loaded
1132 * test enclave since enclave size must be a power of 2 in bytes while
1133 * test_encl does not consume it all.
1134 */
1135 EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size);
1136
1137 /*
1138 * mmap() a page at end of existing enclave to be used for dynamic
1139 * EPC page.
1140 *
1141 * Kernel will allow new mapping using any permissions if it
1142 * falls into the enclave's address range but not backed
1143 * by existing enclave pages.
1144 */
1145
1146 addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE,
1147 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED,
1148 self->encl.fd, 0);
1149 EXPECT_NE(addr, MAP_FAILED);
1150
1151 self->run.exception_vector = 0;
1152 self->run.exception_error_code = 0;
1153 self->run.exception_addr = 0;
1154
1155 /*
1156 * Run EACCEPT on new page to trigger the #PF->EAUG->EACCEPT(again
1157 * without a #PF). All should be transparent to userspace.
1158 */
1159 eaccept_op.epc_addr = self->encl.encl_base + total_size;
1160 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;
1161 eaccept_op.ret = 0;
1162 eaccept_op.header.type = ENCL_OP_EACCEPT;
1163
1164 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1165
1166 if (self->run.exception_vector == 14 &&
1167 self->run.exception_error_code == 4 &&
1168 self->run.exception_addr == self->encl.encl_base + total_size) {
1169 munmap(addr, PAGE_SIZE);
1170 SKIP(return, "Kernel does not support adding pages to initialized enclave");
1171 }
1172
1173 EXPECT_EEXIT(&self->run);
1174 EXPECT_EQ(self->run.exception_vector, 0);
1175 EXPECT_EQ(self->run.exception_error_code, 0);
1176 EXPECT_EQ(self->run.exception_addr, 0);
1177 EXPECT_EQ(eaccept_op.ret, 0);
1178
1179 /*
1180 * New page should be accessible from within enclave - attempt to
1181 * write to it.
1182 */
1183 put_addr_op.value = MAGIC;
1184 put_addr_op.addr = (unsigned long)addr;
1185 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1186
1187 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1188
1189 EXPECT_EEXIT(&self->run);
1190 EXPECT_EQ(self->run.exception_vector, 0);
1191 EXPECT_EQ(self->run.exception_error_code, 0);
1192 EXPECT_EQ(self->run.exception_addr, 0);
1193
1194 /*
1195 * Read memory from newly added page that was just written to,
1196 * confirming that data previously written (MAGIC) is present.
1197 */
1198 get_addr_op.value = 0;
1199 get_addr_op.addr = (unsigned long)addr;
1200 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1201
1202 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1203
1204 EXPECT_EQ(get_addr_op.value, MAGIC);
1205 EXPECT_EEXIT(&self->run);
1206 EXPECT_EQ(self->run.exception_vector, 0);
1207 EXPECT_EQ(self->run.exception_error_code, 0);
1208 EXPECT_EQ(self->run.exception_addr, 0);
1209
1210 munmap(addr, PAGE_SIZE);
1211}
1212
1213/*
1214 * SGX2 page type modification test in two phases:
1215 * Phase 1:
1216 * Create a new TCS, consisting out of three new pages (stack page with regular
1217 * page type, SSA page with regular page type, and TCS page with TCS page
1218 * type) in an initialized enclave and run a simple workload within it.
1219 * Phase 2:
1220 * Remove the three pages added in phase 1, add a new regular page at the
1221 * same address that previously hosted the TCS page and verify that it can
1222 * be modified.
1223 */
1224TEST_F(enclave, tcs_create)
1225{
1226 struct encl_op_init_tcs_page init_tcs_page_op;
1227 struct sgx_enclave_remove_pages remove_ioc;
1228 struct encl_op_get_from_addr get_addr_op;
1229 struct sgx_enclave_modify_types modt_ioc;
1230 struct encl_op_put_to_addr put_addr_op;
1231 struct encl_op_get_from_buf get_buf_op;
1232 struct encl_op_put_to_buf put_buf_op;
1233 void *addr, *tcs, *stack_end, *ssa;
1234 struct encl_op_eaccept eaccept_op;
1235 size_t total_size = 0;
1236 uint64_t val_64;
1237 int errno_save;
1238 int ret, i;
1239
1240 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl,
1241 _metadata));
1242
1243 memset(&self->run, 0, sizeof(self->run));
1244 self->run.tcs = self->encl.encl_base;
1245
1246 /*
1247 * Hardware (SGX2) and kernel support is needed for this test. Start
1248 * with check that test has a chance of succeeding.
1249 */
1250 memset(&modt_ioc, 0, sizeof(modt_ioc));
1251 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1252
1253 if (ret == -1) {
1254 if (errno == ENOTTY)
1255 SKIP(return,
1256 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1257 else if (errno == ENODEV)
1258 SKIP(return, "System does not support SGX2");
1259 }
1260
1261 /*
1262 * Invalid parameters were provided during sanity check,
1263 * expect command to fail.
1264 */
1265 EXPECT_EQ(ret, -1);
1266
1267 /*
1268 * Add three regular pages via EAUG: one will be the TCS stack, one
1269 * will be the TCS SSA, and one will be the new TCS. The stack and
1270 * SSA will remain as regular pages, the TCS page will need its
1271 * type changed after populated with needed data.
1272 */
1273 for (i = 0; i < self->encl.nr_segments; i++) {
1274 struct encl_segment *seg = &self->encl.segment_tbl[i];
1275
1276 total_size += seg->size;
1277 }
1278
1279 /*
1280 * Actual enclave size is expected to be larger than the loaded
1281 * test enclave since enclave size must be a power of 2 in bytes while
1282 * test_encl does not consume it all.
1283 */
1284 EXPECT_LT(total_size + 3 * PAGE_SIZE, self->encl.encl_size);
1285
1286 /*
1287 * mmap() three pages at end of existing enclave to be used for the
1288 * three new pages.
1289 */
1290 addr = mmap((void *)self->encl.encl_base + total_size, 3 * PAGE_SIZE,
1291 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
1292 self->encl.fd, 0);
1293 EXPECT_NE(addr, MAP_FAILED);
1294
1295 self->run.exception_vector = 0;
1296 self->run.exception_error_code = 0;
1297 self->run.exception_addr = 0;
1298
1299 stack_end = (void *)self->encl.encl_base + total_size;
1300 tcs = (void *)self->encl.encl_base + total_size + PAGE_SIZE;
1301 ssa = (void *)self->encl.encl_base + total_size + 2 * PAGE_SIZE;
1302
1303 /*
1304 * Run EACCEPT on each new page to trigger the
1305 * EACCEPT->(#PF)->EAUG->EACCEPT(again without a #PF) flow.
1306 */
1307
1308 eaccept_op.epc_addr = (unsigned long)stack_end;
1309 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;
1310 eaccept_op.ret = 0;
1311 eaccept_op.header.type = ENCL_OP_EACCEPT;
1312
1313 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1314
1315 if (self->run.exception_vector == 14 &&
1316 self->run.exception_error_code == 4 &&
1317 self->run.exception_addr == (unsigned long)stack_end) {
1318 munmap(addr, 3 * PAGE_SIZE);
1319 SKIP(return, "Kernel does not support adding pages to initialized enclave");
1320 }
1321
1322 EXPECT_EEXIT(&self->run);
1323 EXPECT_EQ(self->run.exception_vector, 0);
1324 EXPECT_EQ(self->run.exception_error_code, 0);
1325 EXPECT_EQ(self->run.exception_addr, 0);
1326 EXPECT_EQ(eaccept_op.ret, 0);
1327
1328 eaccept_op.epc_addr = (unsigned long)ssa;
1329
1330 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1331
1332 EXPECT_EEXIT(&self->run);
1333 EXPECT_EQ(self->run.exception_vector, 0);
1334 EXPECT_EQ(self->run.exception_error_code, 0);
1335 EXPECT_EQ(self->run.exception_addr, 0);
1336 EXPECT_EQ(eaccept_op.ret, 0);
1337
1338 eaccept_op.epc_addr = (unsigned long)tcs;
1339
1340 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1341
1342 EXPECT_EEXIT(&self->run);
1343 EXPECT_EQ(self->run.exception_vector, 0);
1344 EXPECT_EQ(self->run.exception_error_code, 0);
1345 EXPECT_EQ(self->run.exception_addr, 0);
1346 EXPECT_EQ(eaccept_op.ret, 0);
1347
1348 /*
1349 * Three new pages added to enclave. Now populate the TCS page with
1350 * needed data. This should be done from within enclave. Provide
1351 * the function that will do the actual data population with needed
1352 * data.
1353 */
1354
1355 /*
1356 * New TCS will use the "encl_dyn_entry" entrypoint that expects
1357 * stack to begin in page before TCS page.
1358 */
1359 val_64 = encl_get_entry(encl: &self->encl, symbol: "encl_dyn_entry");
1360 EXPECT_NE(val_64, 0);
1361
1362 init_tcs_page_op.tcs_page = (unsigned long)tcs;
1363 init_tcs_page_op.ssa = (unsigned long)total_size + 2 * PAGE_SIZE;
1364 init_tcs_page_op.entry = val_64;
1365 init_tcs_page_op.header.type = ENCL_OP_INIT_TCS_PAGE;
1366
1367 EXPECT_EQ(ENCL_CALL(&init_tcs_page_op, &self->run, true), 0);
1368
1369 EXPECT_EEXIT(&self->run);
1370 EXPECT_EQ(self->run.exception_vector, 0);
1371 EXPECT_EQ(self->run.exception_error_code, 0);
1372 EXPECT_EQ(self->run.exception_addr, 0);
1373
1374 /* Change TCS page type to TCS. */
1375 memset(&modt_ioc, 0, sizeof(modt_ioc));
1376
1377 modt_ioc.offset = total_size + PAGE_SIZE;
1378 modt_ioc.length = PAGE_SIZE;
1379 modt_ioc.page_type = SGX_PAGE_TYPE_TCS;
1380
1381 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1382 errno_save = ret == -1 ? errno : 0;
1383
1384 EXPECT_EQ(ret, 0);
1385 EXPECT_EQ(errno_save, 0);
1386 EXPECT_EQ(modt_ioc.result, 0);
1387 EXPECT_EQ(modt_ioc.count, 4096);
1388
1389 /* EACCEPT new TCS page from enclave. */
1390 eaccept_op.epc_addr = (unsigned long)tcs;
1391 eaccept_op.flags = SGX_SECINFO_TCS | SGX_SECINFO_MODIFIED;
1392 eaccept_op.ret = 0;
1393 eaccept_op.header.type = ENCL_OP_EACCEPT;
1394
1395 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1396
1397 EXPECT_EEXIT(&self->run);
1398 EXPECT_EQ(self->run.exception_vector, 0);
1399 EXPECT_EQ(self->run.exception_error_code, 0);
1400 EXPECT_EQ(self->run.exception_addr, 0);
1401 EXPECT_EQ(eaccept_op.ret, 0);
1402
1403 /* Run workload from new TCS. */
1404 self->run.tcs = (unsigned long)tcs;
1405
1406 /*
1407 * Simple workload to write to data buffer and read value back.
1408 */
1409 put_buf_op.header.type = ENCL_OP_PUT_TO_BUFFER;
1410 put_buf_op.value = MAGIC;
1411
1412 EXPECT_EQ(ENCL_CALL(&put_buf_op, &self->run, true), 0);
1413
1414 EXPECT_EEXIT(&self->run);
1415 EXPECT_EQ(self->run.exception_vector, 0);
1416 EXPECT_EQ(self->run.exception_error_code, 0);
1417 EXPECT_EQ(self->run.exception_addr, 0);
1418
1419 get_buf_op.header.type = ENCL_OP_GET_FROM_BUFFER;
1420 get_buf_op.value = 0;
1421
1422 EXPECT_EQ(ENCL_CALL(&get_buf_op, &self->run, true), 0);
1423
1424 EXPECT_EQ(get_buf_op.value, MAGIC);
1425 EXPECT_EEXIT(&self->run);
1426 EXPECT_EQ(self->run.exception_vector, 0);
1427 EXPECT_EQ(self->run.exception_error_code, 0);
1428 EXPECT_EQ(self->run.exception_addr, 0);
1429
1430 /*
1431 * Phase 2 of test:
1432 * Remove pages associated with new TCS, create a regular page
1433 * where TCS page used to be and verify it can be used as a regular
1434 * page.
1435 */
1436
1437 /* Start page removal by requesting change of page type to PT_TRIM. */
1438 memset(&modt_ioc, 0, sizeof(modt_ioc));
1439
1440 modt_ioc.offset = total_size;
1441 modt_ioc.length = 3 * PAGE_SIZE;
1442 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;
1443
1444 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1445 errno_save = ret == -1 ? errno : 0;
1446
1447 EXPECT_EQ(ret, 0);
1448 EXPECT_EQ(errno_save, 0);
1449 EXPECT_EQ(modt_ioc.result, 0);
1450 EXPECT_EQ(modt_ioc.count, 3 * PAGE_SIZE);
1451
1452 /*
1453 * Enter enclave via TCS #1 and approve page removal by sending
1454 * EACCEPT for each of three removed pages.
1455 */
1456 self->run.tcs = self->encl.encl_base;
1457
1458 eaccept_op.epc_addr = (unsigned long)stack_end;
1459 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;
1460 eaccept_op.ret = 0;
1461 eaccept_op.header.type = ENCL_OP_EACCEPT;
1462
1463 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1464
1465 EXPECT_EEXIT(&self->run);
1466 EXPECT_EQ(self->run.exception_vector, 0);
1467 EXPECT_EQ(self->run.exception_error_code, 0);
1468 EXPECT_EQ(self->run.exception_addr, 0);
1469 EXPECT_EQ(eaccept_op.ret, 0);
1470
1471 eaccept_op.epc_addr = (unsigned long)tcs;
1472 eaccept_op.ret = 0;
1473
1474 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1475
1476 EXPECT_EEXIT(&self->run);
1477 EXPECT_EQ(self->run.exception_vector, 0);
1478 EXPECT_EQ(self->run.exception_error_code, 0);
1479 EXPECT_EQ(self->run.exception_addr, 0);
1480 EXPECT_EQ(eaccept_op.ret, 0);
1481
1482 eaccept_op.epc_addr = (unsigned long)ssa;
1483 eaccept_op.ret = 0;
1484
1485 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1486
1487 EXPECT_EEXIT(&self->run);
1488 EXPECT_EQ(self->run.exception_vector, 0);
1489 EXPECT_EQ(self->run.exception_error_code, 0);
1490 EXPECT_EQ(self->run.exception_addr, 0);
1491 EXPECT_EQ(eaccept_op.ret, 0);
1492
1493 /* Send final ioctl() to complete page removal. */
1494 memset(&remove_ioc, 0, sizeof(remove_ioc));
1495
1496 remove_ioc.offset = total_size;
1497 remove_ioc.length = 3 * PAGE_SIZE;
1498
1499 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);
1500 errno_save = ret == -1 ? errno : 0;
1501
1502 EXPECT_EQ(ret, 0);
1503 EXPECT_EQ(errno_save, 0);
1504 EXPECT_EQ(remove_ioc.count, 3 * PAGE_SIZE);
1505
1506 /*
1507 * Enter enclave via TCS #1 and access location where TCS #3 was to
1508 * trigger dynamic add of regular page at that location.
1509 */
1510 eaccept_op.epc_addr = (unsigned long)tcs;
1511 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;
1512 eaccept_op.ret = 0;
1513 eaccept_op.header.type = ENCL_OP_EACCEPT;
1514
1515 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1516
1517 EXPECT_EEXIT(&self->run);
1518 EXPECT_EQ(self->run.exception_vector, 0);
1519 EXPECT_EQ(self->run.exception_error_code, 0);
1520 EXPECT_EQ(self->run.exception_addr, 0);
1521 EXPECT_EQ(eaccept_op.ret, 0);
1522
1523 /*
1524 * New page should be accessible from within enclave - write to it.
1525 */
1526 put_addr_op.value = MAGIC;
1527 put_addr_op.addr = (unsigned long)tcs;
1528 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1529
1530 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1531
1532 EXPECT_EEXIT(&self->run);
1533 EXPECT_EQ(self->run.exception_vector, 0);
1534 EXPECT_EQ(self->run.exception_error_code, 0);
1535 EXPECT_EQ(self->run.exception_addr, 0);
1536
1537 /*
1538 * Read memory from newly added page that was just written to,
1539 * confirming that data previously written (MAGIC) is present.
1540 */
1541 get_addr_op.value = 0;
1542 get_addr_op.addr = (unsigned long)tcs;
1543 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1544
1545 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1546
1547 EXPECT_EQ(get_addr_op.value, MAGIC);
1548 EXPECT_EEXIT(&self->run);
1549 EXPECT_EQ(self->run.exception_vector, 0);
1550 EXPECT_EQ(self->run.exception_error_code, 0);
1551 EXPECT_EQ(self->run.exception_addr, 0);
1552
1553 munmap(addr, 3 * PAGE_SIZE);
1554}
1555
1556/*
1557 * Ensure sane behavior if user requests page removal, does not run
1558 * EACCEPT from within enclave but still attempts to finalize page removal
1559 * with the SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl(). The latter should fail
1560 * because the removal was not EACCEPTed from within the enclave.
1561 */
1562TEST_F(enclave, remove_added_page_no_eaccept)
1563{
1564 struct sgx_enclave_remove_pages remove_ioc;
1565 struct encl_op_get_from_addr get_addr_op;
1566 struct sgx_enclave_modify_types modt_ioc;
1567 struct encl_op_put_to_addr put_addr_op;
1568 unsigned long data_start;
1569 int ret, errno_save;
1570
1571 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1572
1573 memset(&self->run, 0, sizeof(self->run));
1574 self->run.tcs = self->encl.encl_base;
1575
1576 /*
1577 * Hardware (SGX2) and kernel support is needed for this test. Start
1578 * with check that test has a chance of succeeding.
1579 */
1580 memset(&modt_ioc, 0, sizeof(modt_ioc));
1581 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1582
1583 if (ret == -1) {
1584 if (errno == ENOTTY)
1585 SKIP(return,
1586 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1587 else if (errno == ENODEV)
1588 SKIP(return, "System does not support SGX2");
1589 }
1590
1591 /*
1592 * Invalid parameters were provided during sanity check,
1593 * expect command to fail.
1594 */
1595 EXPECT_EQ(ret, -1);
1596
1597 /*
1598 * Page that will be removed is the second data page in the .data
1599 * segment. This forms part of the local encl_buffer within the
1600 * enclave.
1601 */
1602 data_start = self->encl.encl_base +
1603 encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1604
1605 /*
1606 * Sanity check that page at @data_start is writable before
1607 * removing it.
1608 *
1609 * Start by writing MAGIC to test page.
1610 */
1611 put_addr_op.value = MAGIC;
1612 put_addr_op.addr = data_start;
1613 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1614
1615 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1616
1617 EXPECT_EEXIT(&self->run);
1618 EXPECT_EQ(self->run.exception_vector, 0);
1619 EXPECT_EQ(self->run.exception_error_code, 0);
1620 EXPECT_EQ(self->run.exception_addr, 0);
1621
1622 /*
1623 * Read memory that was just written to, confirming that data
1624 * previously written (MAGIC) is present.
1625 */
1626 get_addr_op.value = 0;
1627 get_addr_op.addr = data_start;
1628 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1629
1630 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1631
1632 EXPECT_EQ(get_addr_op.value, MAGIC);
1633 EXPECT_EEXIT(&self->run);
1634 EXPECT_EQ(self->run.exception_vector, 0);
1635 EXPECT_EQ(self->run.exception_error_code, 0);
1636 EXPECT_EQ(self->run.exception_addr, 0);
1637
1638 /* Start page removal by requesting change of page type to PT_TRIM */
1639 memset(&modt_ioc, 0, sizeof(modt_ioc));
1640
1641 modt_ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1642 modt_ioc.length = PAGE_SIZE;
1643 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;
1644
1645 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1646 errno_save = ret == -1 ? errno : 0;
1647
1648 EXPECT_EQ(ret, 0);
1649 EXPECT_EQ(errno_save, 0);
1650 EXPECT_EQ(modt_ioc.result, 0);
1651 EXPECT_EQ(modt_ioc.count, 4096);
1652
1653 /* Skip EACCEPT */
1654
1655 /* Send final ioctl() to complete page removal */
1656 memset(&remove_ioc, 0, sizeof(remove_ioc));
1657
1658 remove_ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1659 remove_ioc.length = PAGE_SIZE;
1660
1661 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);
1662 errno_save = ret == -1 ? errno : 0;
1663
1664 /* Operation not permitted since EACCEPT was omitted. */
1665 EXPECT_EQ(ret, -1);
1666 EXPECT_EQ(errno_save, EPERM);
1667 EXPECT_EQ(remove_ioc.count, 0);
1668}
1669
1670/*
1671 * Request enclave page removal but instead of correctly following with
1672 * EACCEPT a read attempt to page is made from within the enclave.
1673 */
1674TEST_F(enclave, remove_added_page_invalid_access)
1675{
1676 struct encl_op_get_from_addr get_addr_op;
1677 struct encl_op_put_to_addr put_addr_op;
1678 struct sgx_enclave_modify_types ioc;
1679 unsigned long data_start;
1680 int ret, errno_save;
1681
1682 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1683
1684 memset(&self->run, 0, sizeof(self->run));
1685 self->run.tcs = self->encl.encl_base;
1686
1687 /*
1688 * Hardware (SGX2) and kernel support is needed for this test. Start
1689 * with check that test has a chance of succeeding.
1690 */
1691 memset(&ioc, 0, sizeof(ioc));
1692 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1693
1694 if (ret == -1) {
1695 if (errno == ENOTTY)
1696 SKIP(return,
1697 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1698 else if (errno == ENODEV)
1699 SKIP(return, "System does not support SGX2");
1700 }
1701
1702 /*
1703 * Invalid parameters were provided during sanity check,
1704 * expect command to fail.
1705 */
1706 EXPECT_EQ(ret, -1);
1707
1708 /*
1709 * Page that will be removed is the second data page in the .data
1710 * segment. This forms part of the local encl_buffer within the
1711 * enclave.
1712 */
1713 data_start = self->encl.encl_base +
1714 encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1715
1716 /*
1717 * Sanity check that page at @data_start is writable before
1718 * removing it.
1719 *
1720 * Start by writing MAGIC to test page.
1721 */
1722 put_addr_op.value = MAGIC;
1723 put_addr_op.addr = data_start;
1724 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1725
1726 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1727
1728 EXPECT_EEXIT(&self->run);
1729 EXPECT_EQ(self->run.exception_vector, 0);
1730 EXPECT_EQ(self->run.exception_error_code, 0);
1731 EXPECT_EQ(self->run.exception_addr, 0);
1732
1733 /*
1734 * Read memory that was just written to, confirming that data
1735 * previously written (MAGIC) is present.
1736 */
1737 get_addr_op.value = 0;
1738 get_addr_op.addr = data_start;
1739 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1740
1741 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1742
1743 EXPECT_EQ(get_addr_op.value, MAGIC);
1744 EXPECT_EEXIT(&self->run);
1745 EXPECT_EQ(self->run.exception_vector, 0);
1746 EXPECT_EQ(self->run.exception_error_code, 0);
1747 EXPECT_EQ(self->run.exception_addr, 0);
1748
1749 /* Start page removal by requesting change of page type to PT_TRIM. */
1750 memset(&ioc, 0, sizeof(ioc));
1751
1752 ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1753 ioc.length = PAGE_SIZE;
1754 ioc.page_type = SGX_PAGE_TYPE_TRIM;
1755
1756 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1757 errno_save = ret == -1 ? errno : 0;
1758
1759 EXPECT_EQ(ret, 0);
1760 EXPECT_EQ(errno_save, 0);
1761 EXPECT_EQ(ioc.result, 0);
1762 EXPECT_EQ(ioc.count, 4096);
1763
1764 /*
1765 * Read from page that was just removed.
1766 */
1767 get_addr_op.value = 0;
1768
1769 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1770
1771 /*
1772 * From kernel perspective the page is present but according to SGX the
1773 * page should not be accessible so a #PF with SGX bit set is
1774 * expected.
1775 */
1776
1777 EXPECT_EQ(self->run.function, ERESUME);
1778 EXPECT_EQ(self->run.exception_vector, 14);
1779 EXPECT_EQ(self->run.exception_error_code, 0x8005);
1780 EXPECT_EQ(self->run.exception_addr, data_start);
1781}
1782
1783/*
1784 * Request enclave page removal and correctly follow with
1785 * EACCEPT but do not follow with removal ioctl() but instead a read attempt
1786 * to removed page is made from within the enclave.
1787 */
1788TEST_F(enclave, remove_added_page_invalid_access_after_eaccept)
1789{
1790 struct encl_op_get_from_addr get_addr_op;
1791 struct encl_op_put_to_addr put_addr_op;
1792 struct sgx_enclave_modify_types ioc;
1793 struct encl_op_eaccept eaccept_op;
1794 unsigned long data_start;
1795 int ret, errno_save;
1796
1797 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1798
1799 memset(&self->run, 0, sizeof(self->run));
1800 self->run.tcs = self->encl.encl_base;
1801
1802 /*
1803 * Hardware (SGX2) and kernel support is needed for this test. Start
1804 * with check that test has a chance of succeeding.
1805 */
1806 memset(&ioc, 0, sizeof(ioc));
1807 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1808
1809 if (ret == -1) {
1810 if (errno == ENOTTY)
1811 SKIP(return,
1812 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1813 else if (errno == ENODEV)
1814 SKIP(return, "System does not support SGX2");
1815 }
1816
1817 /*
1818 * Invalid parameters were provided during sanity check,
1819 * expect command to fail.
1820 */
1821 EXPECT_EQ(ret, -1);
1822
1823 /*
1824 * Page that will be removed is the second data page in the .data
1825 * segment. This forms part of the local encl_buffer within the
1826 * enclave.
1827 */
1828 data_start = self->encl.encl_base +
1829 encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1830
1831 /*
1832 * Sanity check that page at @data_start is writable before
1833 * removing it.
1834 *
1835 * Start by writing MAGIC to test page.
1836 */
1837 put_addr_op.value = MAGIC;
1838 put_addr_op.addr = data_start;
1839 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1840
1841 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1842
1843 EXPECT_EEXIT(&self->run);
1844 EXPECT_EQ(self->run.exception_vector, 0);
1845 EXPECT_EQ(self->run.exception_error_code, 0);
1846 EXPECT_EQ(self->run.exception_addr, 0);
1847
1848 /*
1849 * Read memory that was just written to, confirming that data
1850 * previously written (MAGIC) is present.
1851 */
1852 get_addr_op.value = 0;
1853 get_addr_op.addr = data_start;
1854 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1855
1856 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1857
1858 EXPECT_EQ(get_addr_op.value, MAGIC);
1859 EXPECT_EEXIT(&self->run);
1860 EXPECT_EQ(self->run.exception_vector, 0);
1861 EXPECT_EQ(self->run.exception_error_code, 0);
1862 EXPECT_EQ(self->run.exception_addr, 0);
1863
1864 /* Start page removal by requesting change of page type to PT_TRIM. */
1865 memset(&ioc, 0, sizeof(ioc));
1866
1867 ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1868 ioc.length = PAGE_SIZE;
1869 ioc.page_type = SGX_PAGE_TYPE_TRIM;
1870
1871 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1872 errno_save = ret == -1 ? errno : 0;
1873
1874 EXPECT_EQ(ret, 0);
1875 EXPECT_EQ(errno_save, 0);
1876 EXPECT_EQ(ioc.result, 0);
1877 EXPECT_EQ(ioc.count, 4096);
1878
1879 eaccept_op.epc_addr = (unsigned long)data_start;
1880 eaccept_op.ret = 0;
1881 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;
1882 eaccept_op.header.type = ENCL_OP_EACCEPT;
1883
1884 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1885
1886 EXPECT_EEXIT(&self->run);
1887 EXPECT_EQ(self->run.exception_vector, 0);
1888 EXPECT_EQ(self->run.exception_error_code, 0);
1889 EXPECT_EQ(self->run.exception_addr, 0);
1890 EXPECT_EQ(eaccept_op.ret, 0);
1891
1892 /* Skip ioctl() to remove page. */
1893
1894 /*
1895 * Read from page that was just removed.
1896 */
1897 get_addr_op.value = 0;
1898
1899 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1900
1901 /*
1902 * From kernel perspective the page is present but according to SGX the
1903 * page should not be accessible so a #PF with SGX bit set is
1904 * expected.
1905 */
1906
1907 EXPECT_EQ(self->run.function, ERESUME);
1908 EXPECT_EQ(self->run.exception_vector, 14);
1909 EXPECT_EQ(self->run.exception_error_code, 0x8005);
1910 EXPECT_EQ(self->run.exception_addr, data_start);
1911}
1912
1913TEST_F(enclave, remove_untouched_page)
1914{
1915 struct sgx_enclave_remove_pages remove_ioc;
1916 struct sgx_enclave_modify_types modt_ioc;
1917 struct encl_op_eaccept eaccept_op;
1918 unsigned long data_start;
1919 int ret, errno_save;
1920
1921 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1922
1923 /*
1924 * Hardware (SGX2) and kernel support is needed for this test. Start
1925 * with check that test has a chance of succeeding.
1926 */
1927 memset(&modt_ioc, 0, sizeof(modt_ioc));
1928 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1929
1930 if (ret == -1) {
1931 if (errno == ENOTTY)
1932 SKIP(return,
1933 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1934 else if (errno == ENODEV)
1935 SKIP(return, "System does not support SGX2");
1936 }
1937
1938 /*
1939 * Invalid parameters were provided during sanity check,
1940 * expect command to fail.
1941 */
1942 EXPECT_EQ(ret, -1);
1943
1944 /* SGX2 is supported by kernel and hardware, test can proceed. */
1945 memset(&self->run, 0, sizeof(self->run));
1946 self->run.tcs = self->encl.encl_base;
1947
1948 data_start = self->encl.encl_base +
1949 encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1950
1951 memset(&modt_ioc, 0, sizeof(modt_ioc));
1952
1953 modt_ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1954 modt_ioc.length = PAGE_SIZE;
1955 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;
1956 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
1957 errno_save = ret == -1 ? errno : 0;
1958
1959 EXPECT_EQ(ret, 0);
1960 EXPECT_EQ(errno_save, 0);
1961 EXPECT_EQ(modt_ioc.result, 0);
1962 EXPECT_EQ(modt_ioc.count, 4096);
1963
1964 /*
1965 * Enter enclave via TCS #1 and approve page removal by sending
1966 * EACCEPT for removed page.
1967 */
1968
1969 eaccept_op.epc_addr = data_start;
1970 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;
1971 eaccept_op.ret = 0;
1972 eaccept_op.header.type = ENCL_OP_EACCEPT;
1973
1974 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1975 EXPECT_EEXIT(&self->run);
1976 EXPECT_EQ(self->run.exception_vector, 0);
1977 EXPECT_EQ(self->run.exception_error_code, 0);
1978 EXPECT_EQ(self->run.exception_addr, 0);
1979 EXPECT_EQ(eaccept_op.ret, 0);
1980
1981 memset(&remove_ioc, 0, sizeof(remove_ioc));
1982
1983 remove_ioc.offset = encl_get_data_offset(encl: &self->encl) + PAGE_SIZE;
1984 remove_ioc.length = PAGE_SIZE;
1985 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);
1986 errno_save = ret == -1 ? errno : 0;
1987
1988 EXPECT_EQ(ret, 0);
1989 EXPECT_EQ(errno_save, 0);
1990 EXPECT_EQ(remove_ioc.count, 4096);
1991}
1992
1993TEST_HARNESS_MAIN
1994

source code of linux/tools/testing/selftests/sgx/main.c