1*acc4229cSAndra Paraschiv // SPDX-License-Identifier: GPL-2.0 2*acc4229cSAndra Paraschiv /* 3*acc4229cSAndra Paraschiv * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4*acc4229cSAndra Paraschiv */ 5*acc4229cSAndra Paraschiv 6*acc4229cSAndra Paraschiv /** 7*acc4229cSAndra Paraschiv * DOC: Sample flow of using the ioctl interface provided by the Nitro Enclaves (NE) 8*acc4229cSAndra Paraschiv * kernel driver. 9*acc4229cSAndra Paraschiv * 10*acc4229cSAndra Paraschiv * Usage 11*acc4229cSAndra Paraschiv * ----- 12*acc4229cSAndra Paraschiv * 13*acc4229cSAndra Paraschiv * Load the nitro_enclaves module, setting also the enclave CPU pool. The 14*acc4229cSAndra Paraschiv * enclave CPUs need to be full cores from the same NUMA node. CPU 0 and its 15*acc4229cSAndra Paraschiv * siblings have to remain available for the primary / parent VM, so they 16*acc4229cSAndra Paraschiv * cannot be included in the enclave CPU pool. 17*acc4229cSAndra Paraschiv * 18*acc4229cSAndra Paraschiv * See the cpu list section from the kernel documentation. 19*acc4229cSAndra Paraschiv * https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html#cpu-lists 20*acc4229cSAndra Paraschiv * 21*acc4229cSAndra Paraschiv * insmod drivers/virt/nitro_enclaves/nitro_enclaves.ko 22*acc4229cSAndra Paraschiv * lsmod 23*acc4229cSAndra Paraschiv * 24*acc4229cSAndra Paraschiv * The CPU pool can be set at runtime, after the kernel module is loaded. 25*acc4229cSAndra Paraschiv * 26*acc4229cSAndra Paraschiv * echo <cpu-list> > /sys/module/nitro_enclaves/parameters/ne_cpus 27*acc4229cSAndra Paraschiv * 28*acc4229cSAndra Paraschiv * NUMA and CPU siblings information can be found using: 29*acc4229cSAndra Paraschiv * 30*acc4229cSAndra Paraschiv * lscpu 31*acc4229cSAndra Paraschiv * /proc/cpuinfo 32*acc4229cSAndra Paraschiv * 33*acc4229cSAndra Paraschiv * Check the online / offline CPU list. The CPUs from the pool should be 34*acc4229cSAndra Paraschiv * offlined. 35*acc4229cSAndra Paraschiv * 36*acc4229cSAndra Paraschiv * lscpu 37*acc4229cSAndra Paraschiv * 38*acc4229cSAndra Paraschiv * Check dmesg for any warnings / errors through the NE driver lifetime / usage. 39*acc4229cSAndra Paraschiv * The NE logs contain the "nitro_enclaves" or "pci 0000:00:02.0" pattern. 40*acc4229cSAndra Paraschiv * 41*acc4229cSAndra Paraschiv * dmesg 42*acc4229cSAndra Paraschiv * 43*acc4229cSAndra Paraschiv * Setup hugetlbfs huge pages. The memory needs to be from the same NUMA node as 44*acc4229cSAndra Paraschiv * the enclave CPUs. 45*acc4229cSAndra Paraschiv * 46*acc4229cSAndra Paraschiv * https://www.kernel.org/doc/html/latest/admin-guide/mm/hugetlbpage.html 47*acc4229cSAndra Paraschiv * 48*acc4229cSAndra Paraschiv * By default, the allocation of hugetlb pages are distributed on all possible 49*acc4229cSAndra Paraschiv * NUMA nodes. Use the following configuration files to set the number of huge 50*acc4229cSAndra Paraschiv * pages from a NUMA node: 51*acc4229cSAndra Paraschiv * 52*acc4229cSAndra Paraschiv * /sys/devices/system/node/node<X>/hugepages/hugepages-2048kB/nr_hugepages 53*acc4229cSAndra Paraschiv * /sys/devices/system/node/node<X>/hugepages/hugepages-1048576kB/nr_hugepages 54*acc4229cSAndra Paraschiv * 55*acc4229cSAndra Paraschiv * or, if not on a system with multiple NUMA nodes, can also set the number 56*acc4229cSAndra Paraschiv * of 2 MiB / 1 GiB huge pages using 57*acc4229cSAndra Paraschiv * 58*acc4229cSAndra Paraschiv * /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages 59*acc4229cSAndra Paraschiv * /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages 60*acc4229cSAndra Paraschiv * 61*acc4229cSAndra Paraschiv * In this example 256 hugepages of 2 MiB are used. 62*acc4229cSAndra Paraschiv * 63*acc4229cSAndra Paraschiv * Build and run the NE sample. 64*acc4229cSAndra Paraschiv * 65*acc4229cSAndra Paraschiv * make -C samples/nitro_enclaves clean 66*acc4229cSAndra Paraschiv * make -C samples/nitro_enclaves 67*acc4229cSAndra Paraschiv * ./samples/nitro_enclaves/ne_ioctl_sample <path_to_enclave_image> 68*acc4229cSAndra Paraschiv * 69*acc4229cSAndra Paraschiv * Unload the nitro_enclaves module. 70*acc4229cSAndra Paraschiv * 71*acc4229cSAndra Paraschiv * rmmod nitro_enclaves 72*acc4229cSAndra Paraschiv * lsmod 73*acc4229cSAndra Paraschiv */ 74*acc4229cSAndra Paraschiv 75*acc4229cSAndra Paraschiv #include <stdio.h> 76*acc4229cSAndra Paraschiv #include <stdlib.h> 77*acc4229cSAndra Paraschiv #include <errno.h> 78*acc4229cSAndra Paraschiv #include <fcntl.h> 79*acc4229cSAndra Paraschiv #include <limits.h> 80*acc4229cSAndra Paraschiv #include <poll.h> 81*acc4229cSAndra Paraschiv #include <pthread.h> 82*acc4229cSAndra Paraschiv #include <string.h> 83*acc4229cSAndra Paraschiv #include <sys/eventfd.h> 84*acc4229cSAndra Paraschiv #include <sys/ioctl.h> 85*acc4229cSAndra Paraschiv #include <sys/mman.h> 86*acc4229cSAndra Paraschiv #include <sys/socket.h> 87*acc4229cSAndra Paraschiv #include <sys/stat.h> 88*acc4229cSAndra Paraschiv #include <sys/types.h> 89*acc4229cSAndra Paraschiv #include <unistd.h> 90*acc4229cSAndra Paraschiv 91*acc4229cSAndra Paraschiv #include <linux/mman.h> 92*acc4229cSAndra Paraschiv #include <linux/nitro_enclaves.h> 93*acc4229cSAndra Paraschiv #include <linux/vm_sockets.h> 94*acc4229cSAndra Paraschiv 95*acc4229cSAndra Paraschiv /** 96*acc4229cSAndra Paraschiv * NE_DEV_NAME - Nitro Enclaves (NE) misc device that provides the ioctl interface. 97*acc4229cSAndra Paraschiv */ 98*acc4229cSAndra Paraschiv #define NE_DEV_NAME "/dev/nitro_enclaves" 99*acc4229cSAndra Paraschiv 100*acc4229cSAndra Paraschiv /** 101*acc4229cSAndra Paraschiv * NE_POLL_WAIT_TIME - Timeout in seconds for each poll event. 102*acc4229cSAndra Paraschiv */ 103*acc4229cSAndra Paraschiv #define NE_POLL_WAIT_TIME (60) 104*acc4229cSAndra Paraschiv /** 105*acc4229cSAndra Paraschiv * NE_POLL_WAIT_TIME_MS - Timeout in milliseconds for each poll event. 106*acc4229cSAndra Paraschiv */ 107*acc4229cSAndra Paraschiv #define NE_POLL_WAIT_TIME_MS (NE_POLL_WAIT_TIME * 1000) 108*acc4229cSAndra Paraschiv 109*acc4229cSAndra Paraschiv /** 110*acc4229cSAndra Paraschiv * NE_SLEEP_TIME - Amount of time in seconds for the process to keep the enclave alive. 111*acc4229cSAndra Paraschiv */ 112*acc4229cSAndra Paraschiv #define NE_SLEEP_TIME (300) 113*acc4229cSAndra Paraschiv 114*acc4229cSAndra Paraschiv /** 115*acc4229cSAndra Paraschiv * NE_DEFAULT_NR_VCPUS - Default number of vCPUs set for an enclave. 116*acc4229cSAndra Paraschiv */ 117*acc4229cSAndra Paraschiv #define NE_DEFAULT_NR_VCPUS (2) 118*acc4229cSAndra Paraschiv 119*acc4229cSAndra Paraschiv /** 120*acc4229cSAndra Paraschiv * NE_MIN_MEM_REGION_SIZE - Minimum size of a memory region - 2 MiB. 121*acc4229cSAndra Paraschiv */ 122*acc4229cSAndra Paraschiv #define NE_MIN_MEM_REGION_SIZE (2 * 1024 * 1024) 123*acc4229cSAndra Paraschiv 124*acc4229cSAndra Paraschiv /** 125*acc4229cSAndra Paraschiv * NE_DEFAULT_NR_MEM_REGIONS - Default number of memory regions of 2 MiB set for 126*acc4229cSAndra Paraschiv * an enclave. 127*acc4229cSAndra Paraschiv */ 128*acc4229cSAndra Paraschiv #define NE_DEFAULT_NR_MEM_REGIONS (256) 129*acc4229cSAndra Paraschiv 130*acc4229cSAndra Paraschiv /** 131*acc4229cSAndra Paraschiv * NE_IMAGE_LOAD_HEARTBEAT_CID - Vsock CID for enclave image loading heartbeat logic. 132*acc4229cSAndra Paraschiv */ 133*acc4229cSAndra Paraschiv #define NE_IMAGE_LOAD_HEARTBEAT_CID (3) 134*acc4229cSAndra Paraschiv /** 135*acc4229cSAndra Paraschiv * NE_IMAGE_LOAD_HEARTBEAT_PORT - Vsock port for enclave image loading heartbeat logic. 136*acc4229cSAndra Paraschiv */ 137*acc4229cSAndra Paraschiv #define NE_IMAGE_LOAD_HEARTBEAT_PORT (9000) 138*acc4229cSAndra Paraschiv /** 139*acc4229cSAndra Paraschiv * NE_IMAGE_LOAD_HEARTBEAT_VALUE - Heartbeat value for enclave image loading. 140*acc4229cSAndra Paraschiv */ 141*acc4229cSAndra Paraschiv #define NE_IMAGE_LOAD_HEARTBEAT_VALUE (0xb7) 142*acc4229cSAndra Paraschiv 143*acc4229cSAndra Paraschiv /** 144*acc4229cSAndra Paraschiv * struct ne_user_mem_region - User space memory region set for an enclave. 145*acc4229cSAndra Paraschiv * @userspace_addr: Address of the user space memory region. 146*acc4229cSAndra Paraschiv * @memory_size: Size of the user space memory region. 147*acc4229cSAndra Paraschiv */ 148*acc4229cSAndra Paraschiv struct ne_user_mem_region { 149*acc4229cSAndra Paraschiv void *userspace_addr; 150*acc4229cSAndra Paraschiv size_t memory_size; 151*acc4229cSAndra Paraschiv }; 152*acc4229cSAndra Paraschiv 153*acc4229cSAndra Paraschiv /** 154*acc4229cSAndra Paraschiv * ne_create_vm() - Create a slot for the enclave VM. 155*acc4229cSAndra Paraschiv * @ne_dev_fd: The file descriptor of the NE misc device. 156*acc4229cSAndra Paraschiv * @slot_uid: The generated slot uid for the enclave. 157*acc4229cSAndra Paraschiv * @enclave_fd : The generated file descriptor for the enclave. 158*acc4229cSAndra Paraschiv * 159*acc4229cSAndra Paraschiv * Context: Process context. 160*acc4229cSAndra Paraschiv * Return: 161*acc4229cSAndra Paraschiv * * 0 on success. 162*acc4229cSAndra Paraschiv * * Negative return value on failure. 163*acc4229cSAndra Paraschiv */ 164*acc4229cSAndra Paraschiv static int ne_create_vm(int ne_dev_fd, unsigned long *slot_uid, int *enclave_fd) 165*acc4229cSAndra Paraschiv { 166*acc4229cSAndra Paraschiv int rc = -EINVAL; 167*acc4229cSAndra Paraschiv *enclave_fd = ioctl(ne_dev_fd, NE_CREATE_VM, slot_uid); 168*acc4229cSAndra Paraschiv 169*acc4229cSAndra Paraschiv if (*enclave_fd < 0) { 170*acc4229cSAndra Paraschiv rc = *enclave_fd; 171*acc4229cSAndra Paraschiv switch (errno) { 172*acc4229cSAndra Paraschiv case NE_ERR_NO_CPUS_AVAIL_IN_POOL: { 173*acc4229cSAndra Paraschiv printf("Error in create VM, no CPUs available in the NE CPU pool\n"); 174*acc4229cSAndra Paraschiv 175*acc4229cSAndra Paraschiv break; 176*acc4229cSAndra Paraschiv } 177*acc4229cSAndra Paraschiv 178*acc4229cSAndra Paraschiv default: 179*acc4229cSAndra Paraschiv printf("Error in create VM [%m]\n"); 180*acc4229cSAndra Paraschiv } 181*acc4229cSAndra Paraschiv 182*acc4229cSAndra Paraschiv return rc; 183*acc4229cSAndra Paraschiv } 184*acc4229cSAndra Paraschiv 185*acc4229cSAndra Paraschiv return 0; 186*acc4229cSAndra Paraschiv } 187*acc4229cSAndra Paraschiv 188*acc4229cSAndra Paraschiv 189*acc4229cSAndra Paraschiv /** 190*acc4229cSAndra Paraschiv * ne_poll_enclave_fd() - Thread function for polling the enclave fd. 191*acc4229cSAndra Paraschiv * @data: Argument provided for the polling function. 192*acc4229cSAndra Paraschiv * 193*acc4229cSAndra Paraschiv * Context: Process context. 194*acc4229cSAndra Paraschiv * Return: 195*acc4229cSAndra Paraschiv * * NULL on success / failure. 196*acc4229cSAndra Paraschiv */ 197*acc4229cSAndra Paraschiv void *ne_poll_enclave_fd(void *data) 198*acc4229cSAndra Paraschiv { 199*acc4229cSAndra Paraschiv int enclave_fd = *(int *)data; 200*acc4229cSAndra Paraschiv struct pollfd fds[1] = {}; 201*acc4229cSAndra Paraschiv int i = 0; 202*acc4229cSAndra Paraschiv int rc = -EINVAL; 203*acc4229cSAndra Paraschiv 204*acc4229cSAndra Paraschiv printf("Running from poll thread, enclave fd %d\n", enclave_fd); 205*acc4229cSAndra Paraschiv 206*acc4229cSAndra Paraschiv fds[0].fd = enclave_fd; 207*acc4229cSAndra Paraschiv fds[0].events = POLLIN | POLLERR | POLLHUP; 208*acc4229cSAndra Paraschiv 209*acc4229cSAndra Paraschiv /* Keep on polling until the current process is terminated. */ 210*acc4229cSAndra Paraschiv while (1) { 211*acc4229cSAndra Paraschiv printf("[iter %d] Polling ...\n", i); 212*acc4229cSAndra Paraschiv 213*acc4229cSAndra Paraschiv rc = poll(fds, 1, NE_POLL_WAIT_TIME_MS); 214*acc4229cSAndra Paraschiv if (rc < 0) { 215*acc4229cSAndra Paraschiv printf("Error in poll [%m]\n"); 216*acc4229cSAndra Paraschiv 217*acc4229cSAndra Paraschiv return NULL; 218*acc4229cSAndra Paraschiv } 219*acc4229cSAndra Paraschiv 220*acc4229cSAndra Paraschiv i++; 221*acc4229cSAndra Paraschiv 222*acc4229cSAndra Paraschiv if (!rc) { 223*acc4229cSAndra Paraschiv printf("Poll: %d seconds elapsed\n", 224*acc4229cSAndra Paraschiv i * NE_POLL_WAIT_TIME); 225*acc4229cSAndra Paraschiv 226*acc4229cSAndra Paraschiv continue; 227*acc4229cSAndra Paraschiv } 228*acc4229cSAndra Paraschiv 229*acc4229cSAndra Paraschiv printf("Poll received value 0x%x\n", fds[0].revents); 230*acc4229cSAndra Paraschiv 231*acc4229cSAndra Paraschiv if (fds[0].revents & POLLHUP) { 232*acc4229cSAndra Paraschiv printf("Received POLLHUP\n"); 233*acc4229cSAndra Paraschiv 234*acc4229cSAndra Paraschiv return NULL; 235*acc4229cSAndra Paraschiv } 236*acc4229cSAndra Paraschiv 237*acc4229cSAndra Paraschiv if (fds[0].revents & POLLNVAL) { 238*acc4229cSAndra Paraschiv printf("Received POLLNVAL\n"); 239*acc4229cSAndra Paraschiv 240*acc4229cSAndra Paraschiv return NULL; 241*acc4229cSAndra Paraschiv } 242*acc4229cSAndra Paraschiv } 243*acc4229cSAndra Paraschiv 244*acc4229cSAndra Paraschiv return NULL; 245*acc4229cSAndra Paraschiv } 246*acc4229cSAndra Paraschiv 247*acc4229cSAndra Paraschiv /** 248*acc4229cSAndra Paraschiv * ne_alloc_user_mem_region() - Allocate a user space memory region for an enclave. 249*acc4229cSAndra Paraschiv * @ne_user_mem_region: User space memory region allocated using hugetlbfs. 250*acc4229cSAndra Paraschiv * 251*acc4229cSAndra Paraschiv * Context: Process context. 252*acc4229cSAndra Paraschiv * Return: 253*acc4229cSAndra Paraschiv * * 0 on success. 254*acc4229cSAndra Paraschiv * * Negative return value on failure. 255*acc4229cSAndra Paraschiv */ 256*acc4229cSAndra Paraschiv static int ne_alloc_user_mem_region(struct ne_user_mem_region *ne_user_mem_region) 257*acc4229cSAndra Paraschiv { 258*acc4229cSAndra Paraschiv /** 259*acc4229cSAndra Paraschiv * Check available hugetlb encodings for different huge page sizes in 260*acc4229cSAndra Paraschiv * include/uapi/linux/mman.h. 261*acc4229cSAndra Paraschiv */ 262*acc4229cSAndra Paraschiv ne_user_mem_region->userspace_addr = mmap(NULL, ne_user_mem_region->memory_size, 263*acc4229cSAndra Paraschiv PROT_READ | PROT_WRITE, 264*acc4229cSAndra Paraschiv MAP_PRIVATE | MAP_ANONYMOUS | 265*acc4229cSAndra Paraschiv MAP_HUGETLB | MAP_HUGE_2MB, -1, 0); 266*acc4229cSAndra Paraschiv if (ne_user_mem_region->userspace_addr == MAP_FAILED) { 267*acc4229cSAndra Paraschiv printf("Error in mmap memory [%m]\n"); 268*acc4229cSAndra Paraschiv 269*acc4229cSAndra Paraschiv return -1; 270*acc4229cSAndra Paraschiv } 271*acc4229cSAndra Paraschiv 272*acc4229cSAndra Paraschiv return 0; 273*acc4229cSAndra Paraschiv } 274*acc4229cSAndra Paraschiv 275*acc4229cSAndra Paraschiv /** 276*acc4229cSAndra Paraschiv * ne_load_enclave_image() - Place the enclave image in the enclave memory. 277*acc4229cSAndra Paraschiv * @enclave_fd : The file descriptor associated with the enclave. 278*acc4229cSAndra Paraschiv * @ne_user_mem_regions: User space memory regions allocated for the enclave. 279*acc4229cSAndra Paraschiv * @enclave_image_path : The file path of the enclave image. 280*acc4229cSAndra Paraschiv * 281*acc4229cSAndra Paraschiv * Context: Process context. 282*acc4229cSAndra Paraschiv * Return: 283*acc4229cSAndra Paraschiv * * 0 on success. 284*acc4229cSAndra Paraschiv * * Negative return value on failure. 285*acc4229cSAndra Paraschiv */ 286*acc4229cSAndra Paraschiv static int ne_load_enclave_image(int enclave_fd, struct ne_user_mem_region ne_user_mem_regions[], 287*acc4229cSAndra Paraschiv char *enclave_image_path) 288*acc4229cSAndra Paraschiv { 289*acc4229cSAndra Paraschiv unsigned char *enclave_image = NULL; 290*acc4229cSAndra Paraschiv int enclave_image_fd = -1; 291*acc4229cSAndra Paraschiv size_t enclave_image_size = 0; 292*acc4229cSAndra Paraschiv size_t enclave_memory_size = 0; 293*acc4229cSAndra Paraschiv unsigned long i = 0; 294*acc4229cSAndra Paraschiv size_t image_written_bytes = 0; 295*acc4229cSAndra Paraschiv struct ne_image_load_info image_load_info = { 296*acc4229cSAndra Paraschiv .flags = NE_EIF_IMAGE, 297*acc4229cSAndra Paraschiv }; 298*acc4229cSAndra Paraschiv struct stat image_stat_buf = {}; 299*acc4229cSAndra Paraschiv int rc = -EINVAL; 300*acc4229cSAndra Paraschiv size_t temp_image_offset = 0; 301*acc4229cSAndra Paraschiv 302*acc4229cSAndra Paraschiv for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) 303*acc4229cSAndra Paraschiv enclave_memory_size += ne_user_mem_regions[i].memory_size; 304*acc4229cSAndra Paraschiv 305*acc4229cSAndra Paraschiv rc = stat(enclave_image_path, &image_stat_buf); 306*acc4229cSAndra Paraschiv if (rc < 0) { 307*acc4229cSAndra Paraschiv printf("Error in get image stat info [%m]\n"); 308*acc4229cSAndra Paraschiv 309*acc4229cSAndra Paraschiv return rc; 310*acc4229cSAndra Paraschiv } 311*acc4229cSAndra Paraschiv 312*acc4229cSAndra Paraschiv enclave_image_size = image_stat_buf.st_size; 313*acc4229cSAndra Paraschiv 314*acc4229cSAndra Paraschiv if (enclave_memory_size < enclave_image_size) { 315*acc4229cSAndra Paraschiv printf("The enclave memory is smaller than the enclave image size\n"); 316*acc4229cSAndra Paraschiv 317*acc4229cSAndra Paraschiv return -ENOMEM; 318*acc4229cSAndra Paraschiv } 319*acc4229cSAndra Paraschiv 320*acc4229cSAndra Paraschiv rc = ioctl(enclave_fd, NE_GET_IMAGE_LOAD_INFO, &image_load_info); 321*acc4229cSAndra Paraschiv if (rc < 0) { 322*acc4229cSAndra Paraschiv switch (errno) { 323*acc4229cSAndra Paraschiv case NE_ERR_NOT_IN_INIT_STATE: { 324*acc4229cSAndra Paraschiv printf("Error in get image load info, enclave not in init state\n"); 325*acc4229cSAndra Paraschiv 326*acc4229cSAndra Paraschiv break; 327*acc4229cSAndra Paraschiv } 328*acc4229cSAndra Paraschiv 329*acc4229cSAndra Paraschiv case NE_ERR_INVALID_FLAG_VALUE: { 330*acc4229cSAndra Paraschiv printf("Error in get image load info, provided invalid flag\n"); 331*acc4229cSAndra Paraschiv 332*acc4229cSAndra Paraschiv break; 333*acc4229cSAndra Paraschiv } 334*acc4229cSAndra Paraschiv 335*acc4229cSAndra Paraschiv default: 336*acc4229cSAndra Paraschiv printf("Error in get image load info [%m]\n"); 337*acc4229cSAndra Paraschiv } 338*acc4229cSAndra Paraschiv 339*acc4229cSAndra Paraschiv return rc; 340*acc4229cSAndra Paraschiv } 341*acc4229cSAndra Paraschiv 342*acc4229cSAndra Paraschiv printf("Enclave image offset in enclave memory is %lld\n", 343*acc4229cSAndra Paraschiv image_load_info.memory_offset); 344*acc4229cSAndra Paraschiv 345*acc4229cSAndra Paraschiv enclave_image_fd = open(enclave_image_path, O_RDONLY); 346*acc4229cSAndra Paraschiv if (enclave_image_fd < 0) { 347*acc4229cSAndra Paraschiv printf("Error in open enclave image file [%m]\n"); 348*acc4229cSAndra Paraschiv 349*acc4229cSAndra Paraschiv return enclave_image_fd; 350*acc4229cSAndra Paraschiv } 351*acc4229cSAndra Paraschiv 352*acc4229cSAndra Paraschiv enclave_image = mmap(NULL, enclave_image_size, PROT_READ, 353*acc4229cSAndra Paraschiv MAP_PRIVATE, enclave_image_fd, 0); 354*acc4229cSAndra Paraschiv if (enclave_image == MAP_FAILED) { 355*acc4229cSAndra Paraschiv printf("Error in mmap enclave image [%m]\n"); 356*acc4229cSAndra Paraschiv 357*acc4229cSAndra Paraschiv return -1; 358*acc4229cSAndra Paraschiv } 359*acc4229cSAndra Paraschiv 360*acc4229cSAndra Paraschiv temp_image_offset = image_load_info.memory_offset; 361*acc4229cSAndra Paraschiv 362*acc4229cSAndra Paraschiv for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) { 363*acc4229cSAndra Paraschiv size_t bytes_to_write = 0; 364*acc4229cSAndra Paraschiv size_t memory_offset = 0; 365*acc4229cSAndra Paraschiv size_t memory_size = ne_user_mem_regions[i].memory_size; 366*acc4229cSAndra Paraschiv size_t remaining_bytes = 0; 367*acc4229cSAndra Paraschiv void *userspace_addr = ne_user_mem_regions[i].userspace_addr; 368*acc4229cSAndra Paraschiv 369*acc4229cSAndra Paraschiv if (temp_image_offset >= memory_size) { 370*acc4229cSAndra Paraschiv temp_image_offset -= memory_size; 371*acc4229cSAndra Paraschiv 372*acc4229cSAndra Paraschiv continue; 373*acc4229cSAndra Paraschiv } else if (temp_image_offset != 0) { 374*acc4229cSAndra Paraschiv memory_offset = temp_image_offset; 375*acc4229cSAndra Paraschiv memory_size -= temp_image_offset; 376*acc4229cSAndra Paraschiv temp_image_offset = 0; 377*acc4229cSAndra Paraschiv } 378*acc4229cSAndra Paraschiv 379*acc4229cSAndra Paraschiv remaining_bytes = enclave_image_size - image_written_bytes; 380*acc4229cSAndra Paraschiv bytes_to_write = memory_size < remaining_bytes ? 381*acc4229cSAndra Paraschiv memory_size : remaining_bytes; 382*acc4229cSAndra Paraschiv 383*acc4229cSAndra Paraschiv memcpy(userspace_addr + memory_offset, 384*acc4229cSAndra Paraschiv enclave_image + image_written_bytes, bytes_to_write); 385*acc4229cSAndra Paraschiv 386*acc4229cSAndra Paraschiv image_written_bytes += bytes_to_write; 387*acc4229cSAndra Paraschiv 388*acc4229cSAndra Paraschiv if (image_written_bytes == enclave_image_size) 389*acc4229cSAndra Paraschiv break; 390*acc4229cSAndra Paraschiv } 391*acc4229cSAndra Paraschiv 392*acc4229cSAndra Paraschiv munmap(enclave_image, enclave_image_size); 393*acc4229cSAndra Paraschiv 394*acc4229cSAndra Paraschiv close(enclave_image_fd); 395*acc4229cSAndra Paraschiv 396*acc4229cSAndra Paraschiv return 0; 397*acc4229cSAndra Paraschiv } 398*acc4229cSAndra Paraschiv 399*acc4229cSAndra Paraschiv /** 400*acc4229cSAndra Paraschiv * ne_set_user_mem_region() - Set a user space memory region for the given enclave. 401*acc4229cSAndra Paraschiv * @enclave_fd : The file descriptor associated with the enclave. 402*acc4229cSAndra Paraschiv * @ne_user_mem_region : User space memory region to be set for the enclave. 403*acc4229cSAndra Paraschiv * 404*acc4229cSAndra Paraschiv * Context: Process context. 405*acc4229cSAndra Paraschiv * Return: 406*acc4229cSAndra Paraschiv * * 0 on success. 407*acc4229cSAndra Paraschiv * * Negative return value on failure. 408*acc4229cSAndra Paraschiv */ 409*acc4229cSAndra Paraschiv static int ne_set_user_mem_region(int enclave_fd, struct ne_user_mem_region ne_user_mem_region) 410*acc4229cSAndra Paraschiv { 411*acc4229cSAndra Paraschiv struct ne_user_memory_region mem_region = { 412*acc4229cSAndra Paraschiv .flags = NE_DEFAULT_MEMORY_REGION, 413*acc4229cSAndra Paraschiv .memory_size = ne_user_mem_region.memory_size, 414*acc4229cSAndra Paraschiv .userspace_addr = (__u64)ne_user_mem_region.userspace_addr, 415*acc4229cSAndra Paraschiv }; 416*acc4229cSAndra Paraschiv int rc = -EINVAL; 417*acc4229cSAndra Paraschiv 418*acc4229cSAndra Paraschiv rc = ioctl(enclave_fd, NE_SET_USER_MEMORY_REGION, &mem_region); 419*acc4229cSAndra Paraschiv if (rc < 0) { 420*acc4229cSAndra Paraschiv switch (errno) { 421*acc4229cSAndra Paraschiv case NE_ERR_NOT_IN_INIT_STATE: { 422*acc4229cSAndra Paraschiv printf("Error in set user memory region, enclave not in init state\n"); 423*acc4229cSAndra Paraschiv 424*acc4229cSAndra Paraschiv break; 425*acc4229cSAndra Paraschiv } 426*acc4229cSAndra Paraschiv 427*acc4229cSAndra Paraschiv case NE_ERR_INVALID_MEM_REGION_SIZE: { 428*acc4229cSAndra Paraschiv printf("Error in set user memory region, mem size not multiple of 2 MiB\n"); 429*acc4229cSAndra Paraschiv 430*acc4229cSAndra Paraschiv break; 431*acc4229cSAndra Paraschiv } 432*acc4229cSAndra Paraschiv 433*acc4229cSAndra Paraschiv case NE_ERR_INVALID_MEM_REGION_ADDR: { 434*acc4229cSAndra Paraschiv printf("Error in set user memory region, invalid user space address\n"); 435*acc4229cSAndra Paraschiv 436*acc4229cSAndra Paraschiv break; 437*acc4229cSAndra Paraschiv } 438*acc4229cSAndra Paraschiv 439*acc4229cSAndra Paraschiv case NE_ERR_UNALIGNED_MEM_REGION_ADDR: { 440*acc4229cSAndra Paraschiv printf("Error in set user memory region, unaligned user space address\n"); 441*acc4229cSAndra Paraschiv 442*acc4229cSAndra Paraschiv break; 443*acc4229cSAndra Paraschiv } 444*acc4229cSAndra Paraschiv 445*acc4229cSAndra Paraschiv case NE_ERR_MEM_REGION_ALREADY_USED: { 446*acc4229cSAndra Paraschiv printf("Error in set user memory region, memory region already used\n"); 447*acc4229cSAndra Paraschiv 448*acc4229cSAndra Paraschiv break; 449*acc4229cSAndra Paraschiv } 450*acc4229cSAndra Paraschiv 451*acc4229cSAndra Paraschiv case NE_ERR_MEM_NOT_HUGE_PAGE: { 452*acc4229cSAndra Paraschiv printf("Error in set user memory region, not backed by huge pages\n"); 453*acc4229cSAndra Paraschiv 454*acc4229cSAndra Paraschiv break; 455*acc4229cSAndra Paraschiv } 456*acc4229cSAndra Paraschiv 457*acc4229cSAndra Paraschiv case NE_ERR_MEM_DIFFERENT_NUMA_NODE: { 458*acc4229cSAndra Paraschiv printf("Error in set user memory region, different NUMA node than CPUs\n"); 459*acc4229cSAndra Paraschiv 460*acc4229cSAndra Paraschiv break; 461*acc4229cSAndra Paraschiv } 462*acc4229cSAndra Paraschiv 463*acc4229cSAndra Paraschiv case NE_ERR_MEM_MAX_REGIONS: { 464*acc4229cSAndra Paraschiv printf("Error in set user memory region, max memory regions reached\n"); 465*acc4229cSAndra Paraschiv 466*acc4229cSAndra Paraschiv break; 467*acc4229cSAndra Paraschiv } 468*acc4229cSAndra Paraschiv 469*acc4229cSAndra Paraschiv case NE_ERR_INVALID_PAGE_SIZE: { 470*acc4229cSAndra Paraschiv printf("Error in set user memory region, has page not multiple of 2 MiB\n"); 471*acc4229cSAndra Paraschiv 472*acc4229cSAndra Paraschiv break; 473*acc4229cSAndra Paraschiv } 474*acc4229cSAndra Paraschiv 475*acc4229cSAndra Paraschiv case NE_ERR_INVALID_FLAG_VALUE: { 476*acc4229cSAndra Paraschiv printf("Error in set user memory region, provided invalid flag\n"); 477*acc4229cSAndra Paraschiv 478*acc4229cSAndra Paraschiv break; 479*acc4229cSAndra Paraschiv } 480*acc4229cSAndra Paraschiv 481*acc4229cSAndra Paraschiv default: 482*acc4229cSAndra Paraschiv printf("Error in set user memory region [%m]\n"); 483*acc4229cSAndra Paraschiv } 484*acc4229cSAndra Paraschiv 485*acc4229cSAndra Paraschiv return rc; 486*acc4229cSAndra Paraschiv } 487*acc4229cSAndra Paraschiv 488*acc4229cSAndra Paraschiv return 0; 489*acc4229cSAndra Paraschiv } 490*acc4229cSAndra Paraschiv 491*acc4229cSAndra Paraschiv /** 492*acc4229cSAndra Paraschiv * ne_free_mem_regions() - Unmap all the user space memory regions that were set 493*acc4229cSAndra Paraschiv * aside for the enclave. 494*acc4229cSAndra Paraschiv * @ne_user_mem_regions: The user space memory regions associated with an enclave. 495*acc4229cSAndra Paraschiv * 496*acc4229cSAndra Paraschiv * Context: Process context. 497*acc4229cSAndra Paraschiv */ 498*acc4229cSAndra Paraschiv static void ne_free_mem_regions(struct ne_user_mem_region ne_user_mem_regions[]) 499*acc4229cSAndra Paraschiv { 500*acc4229cSAndra Paraschiv unsigned int i = 0; 501*acc4229cSAndra Paraschiv 502*acc4229cSAndra Paraschiv for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) 503*acc4229cSAndra Paraschiv munmap(ne_user_mem_regions[i].userspace_addr, 504*acc4229cSAndra Paraschiv ne_user_mem_regions[i].memory_size); 505*acc4229cSAndra Paraschiv } 506*acc4229cSAndra Paraschiv 507*acc4229cSAndra Paraschiv /** 508*acc4229cSAndra Paraschiv * ne_add_vcpu() - Add a vCPU to the given enclave. 509*acc4229cSAndra Paraschiv * @enclave_fd : The file descriptor associated with the enclave. 510*acc4229cSAndra Paraschiv * @vcpu_id: vCPU id to be set for the enclave, either provided or 511*acc4229cSAndra Paraschiv * auto-generated (if provided vCPU id is 0). 512*acc4229cSAndra Paraschiv * 513*acc4229cSAndra Paraschiv * Context: Process context. 514*acc4229cSAndra Paraschiv * Return: 515*acc4229cSAndra Paraschiv * * 0 on success. 516*acc4229cSAndra Paraschiv * * Negative return value on failure. 517*acc4229cSAndra Paraschiv */ 518*acc4229cSAndra Paraschiv static int ne_add_vcpu(int enclave_fd, unsigned int *vcpu_id) 519*acc4229cSAndra Paraschiv { 520*acc4229cSAndra Paraschiv int rc = -EINVAL; 521*acc4229cSAndra Paraschiv 522*acc4229cSAndra Paraschiv rc = ioctl(enclave_fd, NE_ADD_VCPU, vcpu_id); 523*acc4229cSAndra Paraschiv if (rc < 0) { 524*acc4229cSAndra Paraschiv switch (errno) { 525*acc4229cSAndra Paraschiv case NE_ERR_NO_CPUS_AVAIL_IN_POOL: { 526*acc4229cSAndra Paraschiv printf("Error in add vcpu, no CPUs available in the NE CPU pool\n"); 527*acc4229cSAndra Paraschiv 528*acc4229cSAndra Paraschiv break; 529*acc4229cSAndra Paraschiv } 530*acc4229cSAndra Paraschiv 531*acc4229cSAndra Paraschiv case NE_ERR_VCPU_ALREADY_USED: { 532*acc4229cSAndra Paraschiv printf("Error in add vcpu, the provided vCPU is already used\n"); 533*acc4229cSAndra Paraschiv 534*acc4229cSAndra Paraschiv break; 535*acc4229cSAndra Paraschiv } 536*acc4229cSAndra Paraschiv 537*acc4229cSAndra Paraschiv case NE_ERR_VCPU_NOT_IN_CPU_POOL: { 538*acc4229cSAndra Paraschiv printf("Error in add vcpu, the provided vCPU is not in the NE CPU pool\n"); 539*acc4229cSAndra Paraschiv 540*acc4229cSAndra Paraschiv break; 541*acc4229cSAndra Paraschiv } 542*acc4229cSAndra Paraschiv 543*acc4229cSAndra Paraschiv case NE_ERR_VCPU_INVALID_CPU_CORE: { 544*acc4229cSAndra Paraschiv printf("Error in add vcpu, the core id of the provided vCPU is invalid\n"); 545*acc4229cSAndra Paraschiv 546*acc4229cSAndra Paraschiv break; 547*acc4229cSAndra Paraschiv } 548*acc4229cSAndra Paraschiv 549*acc4229cSAndra Paraschiv case NE_ERR_NOT_IN_INIT_STATE: { 550*acc4229cSAndra Paraschiv printf("Error in add vcpu, enclave not in init state\n"); 551*acc4229cSAndra Paraschiv 552*acc4229cSAndra Paraschiv break; 553*acc4229cSAndra Paraschiv } 554*acc4229cSAndra Paraschiv 555*acc4229cSAndra Paraschiv case NE_ERR_INVALID_VCPU: { 556*acc4229cSAndra Paraschiv printf("Error in add vcpu, the provided vCPU is out of avail CPUs range\n"); 557*acc4229cSAndra Paraschiv 558*acc4229cSAndra Paraschiv break; 559*acc4229cSAndra Paraschiv } 560*acc4229cSAndra Paraschiv 561*acc4229cSAndra Paraschiv default: 562*acc4229cSAndra Paraschiv printf("Error in add vcpu [%m]\n"); 563*acc4229cSAndra Paraschiv 564*acc4229cSAndra Paraschiv } 565*acc4229cSAndra Paraschiv return rc; 566*acc4229cSAndra Paraschiv } 567*acc4229cSAndra Paraschiv 568*acc4229cSAndra Paraschiv return 0; 569*acc4229cSAndra Paraschiv } 570*acc4229cSAndra Paraschiv 571*acc4229cSAndra Paraschiv /** 572*acc4229cSAndra Paraschiv * ne_start_enclave() - Start the given enclave. 573*acc4229cSAndra Paraschiv * @enclave_fd : The file descriptor associated with the enclave. 574*acc4229cSAndra Paraschiv * @enclave_start_info : Enclave metadata used for starting e.g. vsock CID. 575*acc4229cSAndra Paraschiv * 576*acc4229cSAndra Paraschiv * Context: Process context. 577*acc4229cSAndra Paraschiv * Return: 578*acc4229cSAndra Paraschiv * * 0 on success. 579*acc4229cSAndra Paraschiv * * Negative return value on failure. 580*acc4229cSAndra Paraschiv */ 581*acc4229cSAndra Paraschiv static int ne_start_enclave(int enclave_fd, struct ne_enclave_start_info *enclave_start_info) 582*acc4229cSAndra Paraschiv { 583*acc4229cSAndra Paraschiv int rc = -EINVAL; 584*acc4229cSAndra Paraschiv 585*acc4229cSAndra Paraschiv rc = ioctl(enclave_fd, NE_START_ENCLAVE, enclave_start_info); 586*acc4229cSAndra Paraschiv if (rc < 0) { 587*acc4229cSAndra Paraschiv switch (errno) { 588*acc4229cSAndra Paraschiv case NE_ERR_NOT_IN_INIT_STATE: { 589*acc4229cSAndra Paraschiv printf("Error in start enclave, enclave not in init state\n"); 590*acc4229cSAndra Paraschiv 591*acc4229cSAndra Paraschiv break; 592*acc4229cSAndra Paraschiv } 593*acc4229cSAndra Paraschiv 594*acc4229cSAndra Paraschiv case NE_ERR_NO_MEM_REGIONS_ADDED: { 595*acc4229cSAndra Paraschiv printf("Error in start enclave, no memory regions have been added\n"); 596*acc4229cSAndra Paraschiv 597*acc4229cSAndra Paraschiv break; 598*acc4229cSAndra Paraschiv } 599*acc4229cSAndra Paraschiv 600*acc4229cSAndra Paraschiv case NE_ERR_NO_VCPUS_ADDED: { 601*acc4229cSAndra Paraschiv printf("Error in start enclave, no vCPUs have been added\n"); 602*acc4229cSAndra Paraschiv 603*acc4229cSAndra Paraschiv break; 604*acc4229cSAndra Paraschiv } 605*acc4229cSAndra Paraschiv 606*acc4229cSAndra Paraschiv case NE_ERR_FULL_CORES_NOT_USED: { 607*acc4229cSAndra Paraschiv printf("Error in start enclave, enclave has no full cores set\n"); 608*acc4229cSAndra Paraschiv 609*acc4229cSAndra Paraschiv break; 610*acc4229cSAndra Paraschiv } 611*acc4229cSAndra Paraschiv 612*acc4229cSAndra Paraschiv case NE_ERR_ENCLAVE_MEM_MIN_SIZE: { 613*acc4229cSAndra Paraschiv printf("Error in start enclave, enclave memory is less than min size\n"); 614*acc4229cSAndra Paraschiv 615*acc4229cSAndra Paraschiv break; 616*acc4229cSAndra Paraschiv } 617*acc4229cSAndra Paraschiv 618*acc4229cSAndra Paraschiv case NE_ERR_INVALID_FLAG_VALUE: { 619*acc4229cSAndra Paraschiv printf("Error in start enclave, provided invalid flag\n"); 620*acc4229cSAndra Paraschiv 621*acc4229cSAndra Paraschiv break; 622*acc4229cSAndra Paraschiv } 623*acc4229cSAndra Paraschiv 624*acc4229cSAndra Paraschiv case NE_ERR_INVALID_ENCLAVE_CID: { 625*acc4229cSAndra Paraschiv printf("Error in start enclave, provided invalid enclave CID\n"); 626*acc4229cSAndra Paraschiv 627*acc4229cSAndra Paraschiv break; 628*acc4229cSAndra Paraschiv } 629*acc4229cSAndra Paraschiv 630*acc4229cSAndra Paraschiv default: 631*acc4229cSAndra Paraschiv printf("Error in start enclave [%m]\n"); 632*acc4229cSAndra Paraschiv } 633*acc4229cSAndra Paraschiv 634*acc4229cSAndra Paraschiv return rc; 635*acc4229cSAndra Paraschiv } 636*acc4229cSAndra Paraschiv 637*acc4229cSAndra Paraschiv return 0; 638*acc4229cSAndra Paraschiv } 639*acc4229cSAndra Paraschiv 640*acc4229cSAndra Paraschiv /** 641*acc4229cSAndra Paraschiv * ne_start_enclave_check_booted() - Start the enclave and wait for a hearbeat 642*acc4229cSAndra Paraschiv * from it, on a newly created vsock channel, 643*acc4229cSAndra Paraschiv * to check it has booted. 644*acc4229cSAndra Paraschiv * @enclave_fd : The file descriptor associated with the enclave. 645*acc4229cSAndra Paraschiv * 646*acc4229cSAndra Paraschiv * Context: Process context. 647*acc4229cSAndra Paraschiv * Return: 648*acc4229cSAndra Paraschiv * * 0 on success. 649*acc4229cSAndra Paraschiv * * Negative return value on failure. 650*acc4229cSAndra Paraschiv */ 651*acc4229cSAndra Paraschiv static int ne_start_enclave_check_booted(int enclave_fd) 652*acc4229cSAndra Paraschiv { 653*acc4229cSAndra Paraschiv struct sockaddr_vm client_vsock_addr = {}; 654*acc4229cSAndra Paraschiv int client_vsock_fd = -1; 655*acc4229cSAndra Paraschiv socklen_t client_vsock_len = sizeof(client_vsock_addr); 656*acc4229cSAndra Paraschiv struct ne_enclave_start_info enclave_start_info = {}; 657*acc4229cSAndra Paraschiv struct pollfd fds[1] = {}; 658*acc4229cSAndra Paraschiv int rc = -EINVAL; 659*acc4229cSAndra Paraschiv unsigned char recv_buf = 0; 660*acc4229cSAndra Paraschiv struct sockaddr_vm server_vsock_addr = { 661*acc4229cSAndra Paraschiv .svm_family = AF_VSOCK, 662*acc4229cSAndra Paraschiv .svm_cid = NE_IMAGE_LOAD_HEARTBEAT_CID, 663*acc4229cSAndra Paraschiv .svm_port = NE_IMAGE_LOAD_HEARTBEAT_PORT, 664*acc4229cSAndra Paraschiv }; 665*acc4229cSAndra Paraschiv int server_vsock_fd = -1; 666*acc4229cSAndra Paraschiv 667*acc4229cSAndra Paraschiv server_vsock_fd = socket(AF_VSOCK, SOCK_STREAM, 0); 668*acc4229cSAndra Paraschiv if (server_vsock_fd < 0) { 669*acc4229cSAndra Paraschiv rc = server_vsock_fd; 670*acc4229cSAndra Paraschiv 671*acc4229cSAndra Paraschiv printf("Error in socket [%m]\n"); 672*acc4229cSAndra Paraschiv 673*acc4229cSAndra Paraschiv return rc; 674*acc4229cSAndra Paraschiv } 675*acc4229cSAndra Paraschiv 676*acc4229cSAndra Paraschiv rc = bind(server_vsock_fd, (struct sockaddr *)&server_vsock_addr, 677*acc4229cSAndra Paraschiv sizeof(server_vsock_addr)); 678*acc4229cSAndra Paraschiv if (rc < 0) { 679*acc4229cSAndra Paraschiv printf("Error in bind [%m]\n"); 680*acc4229cSAndra Paraschiv 681*acc4229cSAndra Paraschiv goto out; 682*acc4229cSAndra Paraschiv } 683*acc4229cSAndra Paraschiv 684*acc4229cSAndra Paraschiv rc = listen(server_vsock_fd, 1); 685*acc4229cSAndra Paraschiv if (rc < 0) { 686*acc4229cSAndra Paraschiv printf("Error in listen [%m]\n"); 687*acc4229cSAndra Paraschiv 688*acc4229cSAndra Paraschiv goto out; 689*acc4229cSAndra Paraschiv } 690*acc4229cSAndra Paraschiv 691*acc4229cSAndra Paraschiv rc = ne_start_enclave(enclave_fd, &enclave_start_info); 692*acc4229cSAndra Paraschiv if (rc < 0) 693*acc4229cSAndra Paraschiv goto out; 694*acc4229cSAndra Paraschiv 695*acc4229cSAndra Paraschiv printf("Enclave started, CID %llu\n", enclave_start_info.enclave_cid); 696*acc4229cSAndra Paraschiv 697*acc4229cSAndra Paraschiv fds[0].fd = server_vsock_fd; 698*acc4229cSAndra Paraschiv fds[0].events = POLLIN; 699*acc4229cSAndra Paraschiv 700*acc4229cSAndra Paraschiv rc = poll(fds, 1, NE_POLL_WAIT_TIME_MS); 701*acc4229cSAndra Paraschiv if (rc < 0) { 702*acc4229cSAndra Paraschiv printf("Error in poll [%m]\n"); 703*acc4229cSAndra Paraschiv 704*acc4229cSAndra Paraschiv goto out; 705*acc4229cSAndra Paraschiv } 706*acc4229cSAndra Paraschiv 707*acc4229cSAndra Paraschiv if (!rc) { 708*acc4229cSAndra Paraschiv printf("Poll timeout, %d seconds elapsed\n", NE_POLL_WAIT_TIME); 709*acc4229cSAndra Paraschiv 710*acc4229cSAndra Paraschiv rc = -ETIMEDOUT; 711*acc4229cSAndra Paraschiv 712*acc4229cSAndra Paraschiv goto out; 713*acc4229cSAndra Paraschiv } 714*acc4229cSAndra Paraschiv 715*acc4229cSAndra Paraschiv if ((fds[0].revents & POLLIN) == 0) { 716*acc4229cSAndra Paraschiv printf("Poll received value %d\n", fds[0].revents); 717*acc4229cSAndra Paraschiv 718*acc4229cSAndra Paraschiv rc = -EINVAL; 719*acc4229cSAndra Paraschiv 720*acc4229cSAndra Paraschiv goto out; 721*acc4229cSAndra Paraschiv } 722*acc4229cSAndra Paraschiv 723*acc4229cSAndra Paraschiv rc = accept(server_vsock_fd, (struct sockaddr *)&client_vsock_addr, 724*acc4229cSAndra Paraschiv &client_vsock_len); 725*acc4229cSAndra Paraschiv if (rc < 0) { 726*acc4229cSAndra Paraschiv printf("Error in accept [%m]\n"); 727*acc4229cSAndra Paraschiv 728*acc4229cSAndra Paraschiv goto out; 729*acc4229cSAndra Paraschiv } 730*acc4229cSAndra Paraschiv 731*acc4229cSAndra Paraschiv client_vsock_fd = rc; 732*acc4229cSAndra Paraschiv 733*acc4229cSAndra Paraschiv /* 734*acc4229cSAndra Paraschiv * Read the heartbeat value that the init process in the enclave sends 735*acc4229cSAndra Paraschiv * after vsock connect. 736*acc4229cSAndra Paraschiv */ 737*acc4229cSAndra Paraschiv rc = read(client_vsock_fd, &recv_buf, sizeof(recv_buf)); 738*acc4229cSAndra Paraschiv if (rc < 0) { 739*acc4229cSAndra Paraschiv printf("Error in read [%m]\n"); 740*acc4229cSAndra Paraschiv 741*acc4229cSAndra Paraschiv goto out; 742*acc4229cSAndra Paraschiv } 743*acc4229cSAndra Paraschiv 744*acc4229cSAndra Paraschiv if (rc != sizeof(recv_buf) || recv_buf != NE_IMAGE_LOAD_HEARTBEAT_VALUE) { 745*acc4229cSAndra Paraschiv printf("Read %d instead of %d\n", recv_buf, 746*acc4229cSAndra Paraschiv NE_IMAGE_LOAD_HEARTBEAT_VALUE); 747*acc4229cSAndra Paraschiv 748*acc4229cSAndra Paraschiv goto out; 749*acc4229cSAndra Paraschiv } 750*acc4229cSAndra Paraschiv 751*acc4229cSAndra Paraschiv /* Write the heartbeat value back. */ 752*acc4229cSAndra Paraschiv rc = write(client_vsock_fd, &recv_buf, sizeof(recv_buf)); 753*acc4229cSAndra Paraschiv if (rc < 0) { 754*acc4229cSAndra Paraschiv printf("Error in write [%m]\n"); 755*acc4229cSAndra Paraschiv 756*acc4229cSAndra Paraschiv goto out; 757*acc4229cSAndra Paraschiv } 758*acc4229cSAndra Paraschiv 759*acc4229cSAndra Paraschiv rc = 0; 760*acc4229cSAndra Paraschiv 761*acc4229cSAndra Paraschiv out: 762*acc4229cSAndra Paraschiv close(server_vsock_fd); 763*acc4229cSAndra Paraschiv 764*acc4229cSAndra Paraschiv return rc; 765*acc4229cSAndra Paraschiv } 766*acc4229cSAndra Paraschiv 767*acc4229cSAndra Paraschiv int main(int argc, char *argv[]) 768*acc4229cSAndra Paraschiv { 769*acc4229cSAndra Paraschiv int enclave_fd = -1; 770*acc4229cSAndra Paraschiv unsigned int i = 0; 771*acc4229cSAndra Paraschiv int ne_dev_fd = -1; 772*acc4229cSAndra Paraschiv struct ne_user_mem_region ne_user_mem_regions[NE_DEFAULT_NR_MEM_REGIONS] = {}; 773*acc4229cSAndra Paraschiv unsigned int ne_vcpus[NE_DEFAULT_NR_VCPUS] = {}; 774*acc4229cSAndra Paraschiv int rc = -EINVAL; 775*acc4229cSAndra Paraschiv pthread_t thread_id = 0; 776*acc4229cSAndra Paraschiv unsigned long slot_uid = 0; 777*acc4229cSAndra Paraschiv 778*acc4229cSAndra Paraschiv if (argc != 2) { 779*acc4229cSAndra Paraschiv printf("Usage: %s <path_to_enclave_image>\n", argv[0]); 780*acc4229cSAndra Paraschiv 781*acc4229cSAndra Paraschiv exit(EXIT_FAILURE); 782*acc4229cSAndra Paraschiv } 783*acc4229cSAndra Paraschiv 784*acc4229cSAndra Paraschiv if (strlen(argv[1]) >= PATH_MAX) { 785*acc4229cSAndra Paraschiv printf("The size of the path to enclave image is higher than max path\n"); 786*acc4229cSAndra Paraschiv 787*acc4229cSAndra Paraschiv exit(EXIT_FAILURE); 788*acc4229cSAndra Paraschiv } 789*acc4229cSAndra Paraschiv 790*acc4229cSAndra Paraschiv ne_dev_fd = open(NE_DEV_NAME, O_RDWR | O_CLOEXEC); 791*acc4229cSAndra Paraschiv if (ne_dev_fd < 0) { 792*acc4229cSAndra Paraschiv printf("Error in open NE device [%m]\n"); 793*acc4229cSAndra Paraschiv 794*acc4229cSAndra Paraschiv exit(EXIT_FAILURE); 795*acc4229cSAndra Paraschiv } 796*acc4229cSAndra Paraschiv 797*acc4229cSAndra Paraschiv printf("Creating enclave slot ...\n"); 798*acc4229cSAndra Paraschiv 799*acc4229cSAndra Paraschiv rc = ne_create_vm(ne_dev_fd, &slot_uid, &enclave_fd); 800*acc4229cSAndra Paraschiv 801*acc4229cSAndra Paraschiv close(ne_dev_fd); 802*acc4229cSAndra Paraschiv 803*acc4229cSAndra Paraschiv if (rc < 0) 804*acc4229cSAndra Paraschiv exit(EXIT_FAILURE); 805*acc4229cSAndra Paraschiv 806*acc4229cSAndra Paraschiv printf("Enclave fd %d\n", enclave_fd); 807*acc4229cSAndra Paraschiv 808*acc4229cSAndra Paraschiv rc = pthread_create(&thread_id, NULL, ne_poll_enclave_fd, (void *)&enclave_fd); 809*acc4229cSAndra Paraschiv if (rc < 0) { 810*acc4229cSAndra Paraschiv printf("Error in thread create [%m]\n"); 811*acc4229cSAndra Paraschiv 812*acc4229cSAndra Paraschiv close(enclave_fd); 813*acc4229cSAndra Paraschiv 814*acc4229cSAndra Paraschiv exit(EXIT_FAILURE); 815*acc4229cSAndra Paraschiv } 816*acc4229cSAndra Paraschiv 817*acc4229cSAndra Paraschiv for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) { 818*acc4229cSAndra Paraschiv ne_user_mem_regions[i].memory_size = NE_MIN_MEM_REGION_SIZE; 819*acc4229cSAndra Paraschiv 820*acc4229cSAndra Paraschiv rc = ne_alloc_user_mem_region(&ne_user_mem_regions[i]); 821*acc4229cSAndra Paraschiv if (rc < 0) { 822*acc4229cSAndra Paraschiv printf("Error in alloc userspace memory region, iter %d\n", i); 823*acc4229cSAndra Paraschiv 824*acc4229cSAndra Paraschiv goto release_enclave_fd; 825*acc4229cSAndra Paraschiv } 826*acc4229cSAndra Paraschiv } 827*acc4229cSAndra Paraschiv 828*acc4229cSAndra Paraschiv rc = ne_load_enclave_image(enclave_fd, ne_user_mem_regions, argv[1]); 829*acc4229cSAndra Paraschiv if (rc < 0) 830*acc4229cSAndra Paraschiv goto release_enclave_fd; 831*acc4229cSAndra Paraschiv 832*acc4229cSAndra Paraschiv for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) { 833*acc4229cSAndra Paraschiv rc = ne_set_user_mem_region(enclave_fd, ne_user_mem_regions[i]); 834*acc4229cSAndra Paraschiv if (rc < 0) { 835*acc4229cSAndra Paraschiv printf("Error in set memory region, iter %d\n", i); 836*acc4229cSAndra Paraschiv 837*acc4229cSAndra Paraschiv goto release_enclave_fd; 838*acc4229cSAndra Paraschiv } 839*acc4229cSAndra Paraschiv } 840*acc4229cSAndra Paraschiv 841*acc4229cSAndra Paraschiv printf("Enclave memory regions were added\n"); 842*acc4229cSAndra Paraschiv 843*acc4229cSAndra Paraschiv for (i = 0; i < NE_DEFAULT_NR_VCPUS; i++) { 844*acc4229cSAndra Paraschiv /* 845*acc4229cSAndra Paraschiv * The vCPU is chosen from the enclave vCPU pool, if the value 846*acc4229cSAndra Paraschiv * of the vcpu_id is 0. 847*acc4229cSAndra Paraschiv */ 848*acc4229cSAndra Paraschiv ne_vcpus[i] = 0; 849*acc4229cSAndra Paraschiv rc = ne_add_vcpu(enclave_fd, &ne_vcpus[i]); 850*acc4229cSAndra Paraschiv if (rc < 0) { 851*acc4229cSAndra Paraschiv printf("Error in add vcpu, iter %d\n", i); 852*acc4229cSAndra Paraschiv 853*acc4229cSAndra Paraschiv goto release_enclave_fd; 854*acc4229cSAndra Paraschiv } 855*acc4229cSAndra Paraschiv 856*acc4229cSAndra Paraschiv printf("Added vCPU %d to the enclave\n", ne_vcpus[i]); 857*acc4229cSAndra Paraschiv } 858*acc4229cSAndra Paraschiv 859*acc4229cSAndra Paraschiv printf("Enclave vCPUs were added\n"); 860*acc4229cSAndra Paraschiv 861*acc4229cSAndra Paraschiv rc = ne_start_enclave_check_booted(enclave_fd); 862*acc4229cSAndra Paraschiv if (rc < 0) { 863*acc4229cSAndra Paraschiv printf("Error in the enclave start / image loading heartbeat logic [rc=%d]\n", rc); 864*acc4229cSAndra Paraschiv 865*acc4229cSAndra Paraschiv goto release_enclave_fd; 866*acc4229cSAndra Paraschiv } 867*acc4229cSAndra Paraschiv 868*acc4229cSAndra Paraschiv printf("Entering sleep for %d seconds ...\n", NE_SLEEP_TIME); 869*acc4229cSAndra Paraschiv 870*acc4229cSAndra Paraschiv sleep(NE_SLEEP_TIME); 871*acc4229cSAndra Paraschiv 872*acc4229cSAndra Paraschiv close(enclave_fd); 873*acc4229cSAndra Paraschiv 874*acc4229cSAndra Paraschiv ne_free_mem_regions(ne_user_mem_regions); 875*acc4229cSAndra Paraschiv 876*acc4229cSAndra Paraschiv exit(EXIT_SUCCESS); 877*acc4229cSAndra Paraschiv 878*acc4229cSAndra Paraschiv release_enclave_fd: 879*acc4229cSAndra Paraschiv close(enclave_fd); 880*acc4229cSAndra Paraschiv ne_free_mem_regions(ne_user_mem_regions); 881*acc4229cSAndra Paraschiv 882*acc4229cSAndra Paraschiv exit(EXIT_FAILURE); 883*acc4229cSAndra Paraschiv } 884