diff --git a/LibOS/shim/include/shim_table.h b/LibOS/shim/include/shim_table.h index 92f5788d..6c29c4fb 100644 --- a/LibOS/shim/include/shim_table.h +++ b/LibOS/shim/include/shim_table.h @@ -500,6 +500,7 @@ int shim_do_pipe2 (int * fildes, int flags); ssize_t shim_do_recvmmsg (int sockfd, struct mmsghdr * msg, size_t vlen, int flags, struct __kernel_timespec * timeout); ssize_t shim_do_sendmmsg (int sockfd, struct mmsghdr * msg, size_t vlen, int flags); +int shim_do_eventfd2(int count, int flags); /* libos call implementation */ long shim_do_sandbox_create (int flags, const char * fs_sb, diff --git a/LibOS/shim/src/fs/proc/fs.c b/LibOS/shim/src/fs/proc/fs.c index 8e3ae55d..bb24af20 100644 --- a/LibOS/shim/src/fs/proc/fs.c +++ b/LibOS/shim/src/fs/proc/fs.c @@ -48,8 +48,68 @@ extern const struct proc_dir dir_ipc_thread; extern const struct proc_fs_ops fs_meminfo; extern const struct proc_fs_ops fs_cpuinfo; +/* minimal /proc/sys/vm/overcommit_memory emulation (always returns 0) */ +static int proc_dummy_open(struct shim_handle * hdl, const char * name, int flags) { + __UNUSED(name); + + if (flags & (O_WRONLY|O_RDWR)) + return -EACCES; + + char* str = malloc(128); + if (!str) + return -ENOMEM; + + int len = snprintf(str, 128, "0"); /* always return "0" text */ + + struct shim_str_data * data = malloc(sizeof(struct shim_str_data)); + if (!data) { + free(str); + return -ENOMEM; + } + + memset(data, 0, sizeof(struct shim_str_data)); + data->str = str; + data->len = len; + hdl->type = TYPE_STR; + hdl->flags = flags & ~O_RDONLY; + hdl->acc_mode = MAY_READ; + hdl->info.str.data = data; + return 0; +} + +static int proc_dummy_mode(const char * name, mode_t * mode) { + __UNUSED(name); + *mode = 0444; + return 0; +} + +static int proc_dummy_stat(const char * name, struct stat * buf) { + __UNUSED(name); + memset(buf, 0, sizeof(struct stat)); + buf->st_dev = buf->st_ino = 1; + buf->st_mode = 0444|S_IFREG; + buf->st_uid = buf->st_gid = 0; + buf->st_size = 128; + return 0; +} + +const struct proc_fs_ops fs_dummy = { + .open = &proc_dummy_open, + .mode = &proc_dummy_mode, + .stat = &proc_dummy_stat, + }; + +const struct proc_dir dir_sys_vm = { .size = 1, .ent = { + { .name = "overcommit_memory", .fs_ops = &fs_dummy }, + }, }; + +const struct proc_dir dir_sys = { .size = 1, .ent = { + { .name = "vm", .fs_ops = &fs_dummy, .dir = &dir_sys_vm, }, + }, }; +/* END minimal /proc/sys/vm/overcommit_memory emulation (always returns 0) */ + const struct proc_dir proc_root = { - .size = 5, + .size = 6, .ent = { { .name = "self", .fs_ops = &fs_thread, .dir = &dir_thread, }, { .nm_ops = &nm_thread, .fs_ops = &fs_thread, .dir = &dir_thread, }, @@ -57,6 +117,7 @@ const struct proc_dir proc_root = { .dir = &dir_ipc_thread, }, { .name = "meminfo", .fs_ops = &fs_meminfo, }, { .name = "cpuinfo", .fs_ops = &fs_cpuinfo, }, + { .name = "sys", .fs_ops = &fs_dummy, .dir = &dir_sys, }, }, }; #define PROC_INO_BASE 1 @@ -132,6 +193,7 @@ static int proc_match_name (const char * trim_name, const char * token = trim_name, * next_token; const struct proc_ent * tmp = proc_root.ent; + const struct proc_ent * end = tmp + proc_root.size; const struct proc_ent * last = NULL; if (*token == '/') @@ -140,7 +202,7 @@ static int proc_match_name (const char * trim_name, while (token) { int tlen = token_len(token, &next_token); - for ( ; tmp->name || tmp->nm_ops ; tmp++) { + for ( ; tmp < end ; tmp++) { if (tmp->name && !memcmp(tmp->name, token, tlen)) goto found; @@ -152,10 +214,17 @@ static int proc_match_name (const char * trim_name, return -ENOENT; found: - if (!tmp->dir && next_token) + if (!next_token) { + /* found the entry, break out of the while loop */ + last = tmp; + break; + } + + if (!tmp->dir) return -ENOENT; last = tmp; + end = tmp->dir->ent + tmp->dir->size; tmp = tmp->dir->ent; token = next_token; } diff --git a/LibOS/shim/src/shim_syscalls.c b/LibOS/shim/src/shim_syscalls.c index 0c234be9..7df4833b 100644 --- a/LibOS/shim/src/shim_syscalls.c +++ b/LibOS/shim/src/shim_syscalls.c @@ -1101,7 +1101,7 @@ DEFINE_SHIM_SYSCALL (accept4, 4, shim_do_accept4, int, int, sockfd, SHIM_SYSCALL_PASSTHROUGH (signalfd4, 4, int, int, ufd, __sigset_t *, user_mask, size_t, sizemask, int, flags) -SHIM_SYSCALL_PASSTHROUGH (eventfd2, 2, int, int, count, int, flags) +DEFINE_SHIM_SYSCALL (eventfd2, 2, shim_do_eventfd2, int, int, init, int, flags) /* epoll_create1: sys/shim_epoll.c */ DEFINE_SHIM_SYSCALL (epoll_create1, 1, shim_do_epoll_create1, int, int, flags) diff --git a/LibOS/shim/src/sys/shim_ioctl.c b/LibOS/shim/src/sys/shim_ioctl.c index 793bd785..78abad99 100644 --- a/LibOS/shim/src/sys/shim_ioctl.c +++ b/LibOS/shim/src/sys/shim_ioctl.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,8 @@ #define TERM_DEFAULT_CFLAG (B38400|CS8|CREAD) #define TERM_DEFAULT_LFLAG (ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN) +static int ioctl_passthru (struct shim_handle * hdl, unsigned int cmd, unsigned long arg); + static int ioctl_termios (struct shim_handle * hdl, unsigned int cmd, unsigned long arg) { @@ -500,10 +503,333 @@ done_fioread: break; default: - ret = -ENOSYS; + ret = ioctl_passthru(hdl, cmd, arg); break; } put_handle(hdl); return ret; } + +#define DUMMY_IOCTL_PRINT _IOR('p', 0x01, struct dummy_print) +struct dummy_print { + const char * str; + unsigned long size; +}; + +/* Dmitrii Kuvaiskii: list of ioctls for North Cove FPGA driver */ +#define FPGA_MAGIC 0xB5 +#define FPGA_BASE 0x00 +#define PORT_BASE 0x40 +#define FME_BASE 0x80 + +#define FPGA_GET_API_VERSION _IO(FPGA_MAGIC, FPGA_BASE + 0) +#define FPGA_CHECK_EXTENSION _IO(FPGA_MAGIC, FPGA_BASE + 1) +#define FPGA_PORT_RESET _IO(FPGA_MAGIC, PORT_BASE + 0) +#define FPGA_PORT_GET_INFO _IO(FPGA_MAGIC, PORT_BASE + 1) +#define FPGA_PORT_GET_REGION_INFO _IO(FPGA_MAGIC, PORT_BASE + 2) +#define FPGA_PORT_DMA_MAP _IO(FPGA_MAGIC, PORT_BASE + 3) +#define FPGA_PORT_DMA_UNMAP _IO(FPGA_MAGIC, PORT_BASE + 4) +#define FPGA_PORT_UMSG_ENABLE _IO(FPGA_MAGIC, PORT_BASE + 5) +#define FPGA_PORT_UMSG_DISABLE _IO(FPGA_MAGIC, PORT_BASE + 6) +#define FPGA_PORT_UMSG_SET_MODE _IO(FPGA_MAGIC, PORT_BASE + 7) +#define FPGA_PORT_UMSG_SET_BASE_ADDR _IO(FPGA_MAGIC, PORT_BASE + 8) +#define FPGA_PORT_ERR_SET_IRQ _IO(FPGA_MAGIC, PORT_BASE + 9) +#define FPGA_PORT_UAFU_SET_IRQ _IO(FPGA_MAGIC, PORT_BASE + 10) +#define FPGA_PORT_UAFU_MMAP _IO(FPGA_MAGIC, PORT_BASE + 11) +#define FPGA_PORT_UAFU_UNMAP _IO(FPGA_MAGIC, PORT_BASE + 12) +#define FPGA_FME_PORT_PR _IO(FPGA_MAGIC, FME_BASE + 0) +#define FPGA_FME_PORT_RELEASE _IO(FPGA_MAGIC, FME_BASE + 1) +#define FPGA_FME_PORT_ASSIGN _IO(FPGA_MAGIC, FME_BASE + 2) +#define FPGA_FME_GET_INFO _IO(FPGA_MAGIC, FME_BASE + 3) +#define FPGA_FME_ERR_SET_IRQ _IO(FPGA_MAGIC, FME_BASE + 4) + +struct fpga_port_info { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 capability; /* The capability of port device */ + __u32 num_regions; /* The number of supported regions */ + __u32 num_umsgs; /* The number of allocated umsgs */ + __u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +struct fpga_port_region_info { + __u32 argsz; /* Structure length */ + __u32 flags; /* Access permission */ + __u32 index; /* Region index */ + __u32 padding; + __u64 size; /* Region size (bytes) */ + __u64 offset; /* Region offset from start of device fd */ +}; + +struct fpga_port_dma_map { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u64 user_addr; /* Process virtual address */ + __u64 length; /* Length of mapping (bytes)*/ + __u64 iova; /* IO virtual address */ +}; + +struct fpga_port_dma_unmap { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u64 iova; /* IO virtual address */ +}; + +struct fpga_port_umsg_cfg { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 hint_bitmap; /* UMSG Hint Mode Bitmap */ +}; + +struct fpga_port_umsg_base_addr { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u64 iova; /* IO virtual address */ +}; + +struct fpga_port_err_irq_set { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __s32 evtfd; /* Eventfd handler */ +}; + +struct fpga_port_uafu_irq_set { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 start; /* First irq number */ + __u32 count; /* The number of eventfd handler */ + __s32 evtfd[8]; /* Eventfd handler; assume no more than 8 for simplicity */ +}; + +struct fpga_port_uafu_mmap { + __u32 argsz; /* Structure length, ignored */ + __u32 flags; /* MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB | MAP_1G_HUGEPAGE */ + __u64 addr; /* Always zero, ignored */ + __u64 len; /* Length of DMA region to allocate in untrusted memory */ + __u64 local_addr; /* Output address of the allocated DMA region in untrusted memory */ +}; + +struct fpga_port_uafu_unmap { + __u32 argsz; /* Structure length, ignored */ + __u32 flags; /* Flags, ignored */ + __u64 addr; /* Base address of DMA region allocated in untrusted memory */ + __u64 len; /* Length of DMA region allocated in untrusted memory */ +}; + +struct fpga_fme_port_pr { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 port_id; + __u32 buffer_size; + __u64 buffer_address; /* Userspace address to the buffer for PR */ + __u64 status; /* HW error code if ioctl returns -EIO */ +}; + +struct fpga_fme_port_release { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 port_id; +}; + +struct fpga_fme_port_assign { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 port_id; +}; + +struct fpga_fme_info { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __u32 capability; /* The capability of FME device */ +}; + +struct fpga_fme_err_irq_set { + __u32 argsz; /* Structure length */ + __u32 flags; /* Zero for now */ + __s32 evtfd; /* Eventfd handler */ +}; + + +static int ioctl_passthru (struct shim_handle * hdl, unsigned int cmd, unsigned long arg) { + PAL_ARG* pal_arg = NULL; + PAL_NUM ninputs = 0, noutputs = 0; + PAL_ARG* inputs = NULL; + PAL_ARG* outputs = NULL; + + // Don't change these macros + + #define SET_ARG_TYPE(type) \ + do { \ + pal_arg = __alloca(sizeof(PAL_ARG)); \ + pal_arg->val = (PAL_PTR) arg; \ + pal_arg->size = sizeof(type); \ + pal_arg->off = 0; \ + } while (0) + + + #define SET_NOUTPUTS(num) \ + do { \ + outputs = __alloca(sizeof(PAL_ARG) * (num)); \ + } while (0) + + #define ADD_OUTPUT_SIZE(type, field, fsize) \ + do { \ + type* __a = (void *) arg; \ + outputs[noutputs].val = (PAL_PTR) __a->field; \ + outputs[noutputs].size = (fsize); \ + outputs[noutputs].off = offsetof(type, field); \ + noutputs++; \ + } while (0) + + #define SET_NINPUTS(num) \ + do { \ + inputs = __alloca(sizeof(PAL_ARG) * (num)); \ + } while (0) + + #define ADD_INPUT_SIZE(type, field, fsize) \ + do { \ + type* __a = (void *) arg; \ + inputs[ninputs].val = (PAL_PTR) __a->field; \ + inputs[ninputs].size = (fsize); \ + inputs[ninputs].off = offsetof(type, field); \ + ninputs++; \ + } while (0) + + + // List the all ioctl opcodes allowed for passthrough + switch(cmd) { + // This is an example: DUMMY_IOCTL_PRINT will print out the string + // in the argument to the kernel log. + case DUMMY_IOCTL_PRINT: { + struct dummy_print* __arg = (void *) arg; + SET_ARG_TYPE(struct dummy_print); + SET_NOUTPUTS(1); + ADD_OUTPUT_SIZE(struct dummy_print, str, __arg->size); + // Specify input size if necessary + break; + } + + // Dmitrii Kuvaiskii: list of ioctls for North Cove FPGA driver + case FPGA_GET_API_VERSION: + case FPGA_CHECK_EXTENSION: + case FPGA_PORT_RESET: + case FPGA_PORT_UMSG_ENABLE: + case FPGA_PORT_UMSG_DISABLE: + break; + + case FPGA_PORT_GET_INFO: { + struct fpga_port_info* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_info); + break; + } + + case FPGA_PORT_GET_REGION_INFO: { + struct fpga_port_region_info* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_region_info); + break; + } + + case FPGA_PORT_DMA_MAP: { + struct fpga_port_dma_map* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_dma_map); + /* TODO: This ioctl fails because user_addr is in enclave space + * not available for the kernel driver! */ + debug("ioctl(FPGA_PORT_DMA_MAP): user_addr=%p length=%lu\n", + __arg->user_addr, __arg->length); + break; + } + + case FPGA_PORT_DMA_UNMAP: { + struct fpga_port_dma_unmap* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_dma_unmap); + break; + } + + case FPGA_PORT_UMSG_SET_MODE: { + struct fpga_port_umsg_cfg* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_umsg_cfg); + break; + } + + case FPGA_PORT_UMSG_SET_BASE_ADDR: { + struct fpga_port_umsg_base_addr* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_umsg_base_addr); + break; + } + + case FPGA_PORT_ERR_SET_IRQ: { + struct fpga_port_err_irq_set* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_err_irq_set); + break; + } + + case FPGA_PORT_UAFU_SET_IRQ: { + struct fpga_port_uafu_irq_set* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_port_uafu_irq_set); + break; + } + + case FPGA_PORT_UAFU_MMAP: { + /* special case: instead of ioctl, allocate untrusted memory */ +#define PAL_ALLOC_DMAREGION 0x4000 + struct fpga_port_uafu_mmap* __arg = (void *) arg; + __arg->addr = 0x0UL; + void* ret = (void *) DkVirtualMemoryAlloc(/* addr */ (void*)__arg->addr, + /* size */ __arg->len, + /* alloc_type */ PAL_ALLOC_DMAREGION, + /* prot abused as flags */ __arg->flags); + if (!ret) { + __arg->local_addr = 0; + return -ENOMEM; + } + __arg->local_addr = (uint64_t) ret; + return 0; + } + + case FPGA_PORT_UAFU_UNMAP: { + /* special case: instead of ioctl, deallocate untrusted memory */ + struct fpga_port_uafu_unmap* __arg = (void *) arg; + DkVirtualMemoryFree((void*)__arg->addr, __arg->len); + return 0; + } + + case FPGA_FME_PORT_PR: { + struct fpga_fme_port_pr* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_fme_port_pr); + break; + } + + case FPGA_FME_PORT_RELEASE: { + struct fpga_fme_port_release* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_fme_port_release); + break; + } + + case FPGA_FME_PORT_ASSIGN: { + struct fpga_fme_port_assign* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_fme_port_assign); + break; + } + + case FPGA_FME_GET_INFO: { + struct fpga_fme_info* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_fme_info); + break; + } + + case FPGA_FME_ERR_SET_IRQ: { + struct fpga_fme_err_irq_set* __arg = (void *) arg; + SET_ARG_TYPE(struct fpga_fme_err_irq_set); + break; + } + + default: + return -ENOSYS; + } + + PAL_NATIVE_ERRNO = 0; + PAL_NUM retval = DkHostExtensionCall(hdl->pal_handle, cmd, pal_arg, noutputs, outputs, + ninputs, inputs); + return (PAL_NATIVE_ERRNO == 0) ? (int) retval : -PAL_ERRNO; +} diff --git a/LibOS/shim/src/sys/shim_mmap.c b/LibOS/shim/src/sys/shim_mmap.c index e8cc1223..440eae08 100644 --- a/LibOS/shim/src/sys/shim_mmap.c +++ b/LibOS/shim/src/sys/shim_mmap.c @@ -134,6 +134,11 @@ void * shim_do_mmap (void * addr, size_t length, int prot, int flags, int fd, return (void *) ret; } + if (ret_addr != addr) { + bkeep_munmap(addr, length, flags); + bkeep_mmap(ret_addr, length, prot, flags, hdl, offset, NULL); + } + ADD_PROFILE_OCCURENCE(mmap, length); return ret_addr; } diff --git a/LibOS/shim/src/sys/shim_open.c b/LibOS/shim/src/sys/shim_open.c index 401974c9..b3a0fe3e 100644 --- a/LibOS/shim/src/sys/shim_open.c +++ b/LibOS/shim/src/sys/shim_open.c @@ -39,6 +39,20 @@ #include #include +int eventfds[128] = {0}; +int eventfds_cnt = 0; + +int shim_do_eventfd2(int init, int flags) { + PAL_NATIVE_ERRNO = 0; + PAL_NUM retval = DkEventfdPassthrough(init, flags); + if (PAL_NATIVE_ERRNO == 0) { + /* TODO: need some lock here but don't care for now */ + assert(eventfds_cnt < 128); + eventfds[eventfds_cnt++] = (int) retval; + } + return (PAL_NATIVE_ERRNO == 0) ? (int) retval : -PAL_ERRNO; +} + int do_handle_read (struct shim_handle * hdl, void * buf, int count) { if (!(hdl->acc_mode & MAY_READ)) @@ -58,6 +72,14 @@ int do_handle_read (struct shim_handle * hdl, void * buf, int count) size_t shim_do_read (int fd, void * buf, size_t count) { + /* if this fd is eventfd, then do pass-through read */ + for (int i = 0; i < eventfds_cnt; i++) { + if (fd == eventfds[i]) { + int ret = DkReadPassthrough((PAL_NUM)fd, (PAL_PTR)buf, (PAL_NUM)count); + return ret; + } + } + if (!buf || test_user_memory(buf, count, true)) return -EFAULT; @@ -89,6 +111,14 @@ int do_handle_write (struct shim_handle * hdl, const void * buf, int count) size_t shim_do_write (int fd, const void * buf, size_t count) { + /* if this fd is eventfd, then do pass-through write */ + for (int i = 0; i < eventfds_cnt; i++) { + if (fd == eventfds[i]) { + int ret = DkWritePassthrough((PAL_NUM)fd, (PAL_PTR)buf, (PAL_NUM)count); + return ret; + } + } + if (!buf || test_user_memory((void *) buf, count, false)) return -EFAULT; @@ -103,6 +133,14 @@ size_t shim_do_write (int fd, const void * buf, size_t count) int shim_do_open (const char * file, int flags, mode_t mode) { + if (strlen(file) >= 15 && strpartcmp_static(file, "/sys/class/fpga")) { + char hardlink[128] = {'\0'}; + strcpy_static(hardlink, "/sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/", sizeof(hardlink)); + memcpy(hardlink + strlen(hardlink), file + 15, strlen(file) - 15); + file = hardlink; + debug("[FPGA DEMO] opening hardlink file: %s\n", file); + } + if (!file || test_user_string(file)) return -EFAULT; @@ -112,7 +150,6 @@ int shim_do_open (const char * file, int flags, mode_t mode) struct shim_handle * hdl = get_new_handle(); if (!hdl) return -ENOMEM; - int ret = 0; ret = open_namei(hdl, NULL, file, flags, mode, NULL); if (ret < 0) @@ -164,6 +201,18 @@ out: int shim_do_close (int fd) { + /* if this fd is eventfd, then do pass-through close */ + for (int i = 0; i < eventfds_cnt; i++) { + if (fd == eventfds[i]) { + /* TODO: need some lock here but don't care for now */ + int ret = DkClosePassthrough((PAL_NUM)fd); + for (int j = i; j < eventfds_cnt-1; j++) + eventfds[j] = eventfds[j+1]; + eventfds_cnt--; + return ret; + } + } + struct shim_handle * handle = detach_fd_handle(fd, NULL, NULL); if (!handle) return -EBADF; @@ -197,6 +246,13 @@ off_t shim_do_lseek (int fd, off_t offset, int origin) goto out; } + /* Dmitrii Kuvaiskii: special case of lseek(0, SEEK_SET) on pseudo-device */ + if ((origin == SEEK_SET) && (offset == 0) && + (hdl->info.file.type == FILE_TTY)) { + put_handle(hdl); + return 0; + } + ret = fs->fs_ops->seek(hdl, offset, origin); out: put_handle(hdl); diff --git a/LibOS/shim/src/sys/shim_poll.c b/LibOS/shim/src/sys/shim_poll.c index 9e491697..afae3a47 100644 --- a/LibOS/shim/src/sys/shim_poll.c +++ b/LibOS/shim/src/sys/shim_poll.c @@ -385,8 +385,34 @@ done_polling: return ret; } +extern int eventfds[128]; +extern int eventfds_cnt; + int shim_do_poll (struct pollfd * fds, nfds_t nfds, int timeout) { + /* if the first fd in fds is eventfd, then do pass-through poll + * (this assumes that _all_ other fds are also eventfds) */ + if (nfds > 0 && fds) { + for (int i = 0; i < eventfds_cnt; i++) { + if (fds[0].fd == eventfds[i]) { + PAL_POLLFD dkfds[nfds]; + + for (nfds_t j = 0; j < nfds; j++) { + dkfds[j].fd = (PAL_NUM)fds[j].fd; + dkfds[j].events = (PAL_NUM)fds[j].events; + dkfds[j].revents = (PAL_NUM)fds[j].revents; + } + + int ret = DkPollPassthrough((PAL_POLLFD*) &dkfds, (PAL_NUM)nfds, (PAL_NUM)timeout); + + for (nfds_t j = 0; j < nfds; j++) + fds[j].revents = (short)dkfds[j].revents; + + return ret; + } + } + } + struct shim_thread * cur = get_cur_thread(); struct poll_handle * polls = diff --git a/LibOS/shim/src/sys/shim_stat.c b/LibOS/shim/src/sys/shim_stat.c index 2fdd6712..58b94f9c 100644 --- a/LibOS/shim/src/sys/shim_stat.c +++ b/LibOS/shim/src/sys/shim_stat.c @@ -28,11 +28,18 @@ #include #include - #include int shim_do_stat (const char * file, struct stat * stat) { + if (strlen(file) >= 15 && strpartcmp_static(file, "/sys/class/fpga")) { + char hardlink[128] = {'\0'}; + strcpy_static(hardlink, "/sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/", sizeof(hardlink)); + memcpy(hardlink + strlen(hardlink), file + 15, strlen(file) - 15); + file = hardlink; + debug("[FPGA DEMO] stating hardlink file: %s\n", file); + } + if (!file || test_user_string(file)) return -EFAULT; @@ -61,6 +68,14 @@ out: int shim_do_lstat (const char * file, struct stat * stat) { + if (strlen(file) >= 15 && strpartcmp_static(file, "/sys/class/fpga")) { + char hardlink[128] = {'\0'}; + strcpy_static(hardlink, "/sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/", sizeof(hardlink)); + memcpy(hardlink + strlen(hardlink), file + 15, strlen(file) - 15); + file = hardlink; + debug("[FPGA DEMO] stating hardlink file: %s\n", file); + } + if (!file || test_user_string(file)) return -EFAULT; @@ -119,13 +134,20 @@ int shim_do_readlink (const char * file, char * buf, size_t bufsize) if (bufsize <= 0) return -EINVAL; + if (strlen(file) >= 15 && strpartcmp_static(file, "/sys/class/fpga")) { + char hardlink[128] = {'\0'}; + strcpy_static(hardlink, "/sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/", sizeof(hardlink)); + memcpy(hardlink + strlen(hardlink), file + 15, strlen(file) - 15); + memcpy(buf, hardlink, strlen(hardlink)); + return strlen(hardlink); + } + int ret; struct shim_dentry * dent = NULL; struct shim_qstr qstr = QSTR_INIT; if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent, NULL)) < 0) return ret; - ret = -EINVAL; /* The correct behavior is to return -EINVAL if file is not a symbolic link */ diff --git a/LibOS/shim/test/native/host-random-device.c b/LibOS/shim/test/native/host-random-device.c new file mode 100644 index 00000000..37ff6b04 --- /dev/null +++ b/LibOS/shim/test/native/host-random-device.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + int fd = open("/sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/intel-fpga-dev.0/device/device", O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + void* mem = mmap(NULL, 4096, PROT_READ, MAP_SHARED|MAP_FILE, + fd, 0); + + if (mem != (void*)-1) { + fprintf(stderr, "mapped /dev/host-random at %p\n", mem); + } else { + perror("mmap"); + } + + char data[16] = {'\0'}; + if (read(fd, data, 16) < 0) { + perror("file read"); + return 1; + } + fprintf(stderr, "data = %s\n", data); + return 0; +} + diff --git a/LibOS/shim/test/native/host-random-device.manifest.template b/LibOS/shim/test/native/host-random-device.manifest.template new file mode 100644 index 00000000..f41a27db --- /dev/null +++ b/LibOS/shim/test/native/host-random-device.manifest.template @@ -0,0 +1,22 @@ +loader.preload = file:$(SHIMPATH) +loader.env.LD_LIBRARY_PATH = /lib +loader.debug_type = inline + +fs.mount.lib.type = chroot +fs.mount.lib.path = /lib +fs.mount.lib.uri = file:$(LIBCDIR) + +fs.mount.bin.type = chroot +fs.mount.bin.path = /bin +fs.mount.bin.uri = file:/bin + +fs.mount.random.type = chroot +fs.mount.random.path = /sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/intel-fpga-dev.0/device/device +fs.mount.random.uri = dev:tty,/sys/devices/pci0000:00/0000:00:01.1/0000:02:00.0/fpga/intel-fpga-dev.0/device/device + +# sgx-related +sgx.trusted_files.ld = file:$(LIBCDIR)/ld-linux-x86-64.so.2 +sgx.trusted_files.libc = file:$(LIBCDIR)/libc.so.6 +sgx.trusted_files.libdl = file:$(LIBCDIR)/libdl.so.2 +sgx.trusted_files.libm = file:$(LIBCDIR)/libm.so.6 +sgx.trusted_files.libpthread = file:$(LIBCDIR)/libpthread.so.0 diff --git a/LibOS/shim/test/native/test-ioctl.c b/LibOS/shim/test/native/test-ioctl.c new file mode 100644 index 00000000..9f8ca735 --- /dev/null +++ b/LibOS/shim/test/native/test-ioctl.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ioctl-dummy-driver/dummy.h" + +int main(int argc, char **argv) +{ + int fd = open("/dev/dummy", O_RDWR); + if (fd < 0) { + perror("open"); + return 1; + } + + for (int i = 1; i < argc; i++) { + struct dummy_print arg; + arg.str = argv[i]; + arg.size = strlen(argv[i]); + + if (ioctl(fd, DUMMY_IOCTL_PRINT, &arg)) { + perror("ioctl"); + return 1; + } + + fprintf(stderr, "wrote %s to kernel\n", argv[i]); + } + + void *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE, + fd, 0); + + if (!mem) { + perror("mmap"); + return 1; + } + + fprintf(stderr, "mapped /dev/dummy at %p\n", mem); + for (int i = 0; i < 4096; i++) + if (((unsigned char *) mem)[i]) { + perror("memory read"); + return 1; + } + + return 0; +} + diff --git a/LibOS/shim/test/native/test-ioctl.manifest.template b/LibOS/shim/test/native/test-ioctl.manifest.template new file mode 100644 index 00000000..c53d63aa --- /dev/null +++ b/LibOS/shim/test/native/test-ioctl.manifest.template @@ -0,0 +1,23 @@ +loader.preload = file:$(SHIMPATH) +loader.env.LD_LIBRARY_PATH = /lib +loader.debug_type = inline + +fs.mount.lib.type = chroot +fs.mount.lib.path = /lib +fs.mount.lib.uri = file:$(LIBCDIR) + +fs.mount.bin.type = chroot +fs.mount.bin.path = /bin +fs.mount.bin.uri = file:/bin + +fs.mount.ioctl.type = chroot +fs.mount.ioctl.path = /dev/dummy +fs.mount.ioctl.uri = file:/dev/dummy + +# sgx-related +sgx.trusted_files.ld = file:$(LIBCDIR)/ld-linux-x86-64.so.2 +sgx.trusted_files.libc = file:$(LIBCDIR)/libc.so.6 +sgx.trusted_files.libdl = file:$(LIBCDIR)/libdl.so.2 +sgx.trusted_files.libm = file:$(LIBCDIR)/libm.so.6 +sgx.trusted_files.libpthread = file:$(LIBCDIR)/libpthread.so.0 +sgx.allowed_files.ioctl = file:/dev/dummy diff --git a/Pal/src/db_misc.c b/Pal/src/db_misc.c index 8ce505c7..1609d687 100644 --- a/Pal/src/db_misc.c +++ b/Pal/src/db_misc.c @@ -150,3 +150,88 @@ DkCpuIdRetrieve (PAL_IDX leaf, PAL_IDX subleaf, PAL_IDX values[4]) LEAVE_PAL_CALL_RETURN(PAL_TRUE); } + +PAL_NUM DkHostExtensionCall (PAL_HANDLE handle, PAL_NUM op, PAL_ARG* arg, PAL_NUM noutputs, PAL_ARG* outputs, + PAL_NUM ninputs, PAL_ARG* inputs) +{ + ENTER_PAL_CALL(DkHostExtensionCall); + + if (!handle) { + _DkRaiseFailure(PAL_ERROR_INVAL); + LEAVE_PAL_CALL_RETURN(0); + } + + if (UNKNOWN_HANDLE(handle)) { + _DkRaiseFailure(PAL_ERROR_BADHANDLE); + LEAVE_PAL_CALL_RETURN(0); + } + + int64_t status = _DkHostExtensionCall(handle, op, arg, noutputs, outputs, ninputs, inputs); + + if (status < 0) { + _DkRaiseFailure(-status); + status = 0; + } + + LEAVE_PAL_CALL_RETURN(status); +} + +PAL_NUM DkEventfdPassthrough(PAL_NUM initval, PAL_NUM flags) { + ENTER_PAL_CALL(DkEventfdPassthrough); + + int ret = _DkEventfdPassthrough(initval, flags); + if (ret < 0) { + _DkRaiseFailure(-ret); + ret = 0; + } + + LEAVE_PAL_CALL_RETURN(ret); +} + +PAL_NUM DkPollPassthrough(PAL_POLLFD* fds, PAL_NUM nfds, PAL_NUM timeout) { + ENTER_PAL_CALL(DkPollPassthrough); + + int ret = _DkPollPassthrough(fds, nfds, timeout); + if (ret < 0) { + _DkRaiseFailure(-ret); + ret = 0; + } + + LEAVE_PAL_CALL_RETURN(ret); +} + +PAL_NUM DkReadPassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count) { + ENTER_PAL_CALL(DkReadPassthrough); + + int ret = _DkReadPassthrough(fd, buf, count); + if (ret < 0) { + _DkRaiseFailure(-ret); + ret = 0; + } + + LEAVE_PAL_CALL_RETURN(ret); +} + +PAL_NUM DkWritePassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count) { + ENTER_PAL_CALL(DkWritePassthrough); + + int ret = _DkWritePassthrough(fd, buf, count); + if (ret < 0) { + _DkRaiseFailure(-ret); + ret = 0; + } + + LEAVE_PAL_CALL_RETURN(ret); +} + +PAL_NUM DkClosePassthrough(PAL_NUM fd) { + ENTER_PAL_CALL(DkClosePassthrough); + + int ret = _DkClosePassthrough(fd); + if (ret < 0) { + _DkRaiseFailure(-ret); + ret = 0; + } + + LEAVE_PAL_CALL_RETURN(ret); +} diff --git a/Pal/src/host/Linux-SGX/db_devices.c b/Pal/src/host/Linux-SGX/db_devices.c index bd915cad..36a8377c 100644 --- a/Pal/src/host/Linux-SGX/db_devices.c +++ b/Pal/src/host/Linux-SGX/db_devices.c @@ -65,13 +65,18 @@ static int parse_device_uri(const char ** uri, char ** type, struct handle_ops * for (p = u ; (*p) && (*p) != ',' && (*p) != '/' ; p++); - if (strpartcmp_static(u, "tty")) + /* + * For terminal devices, Graphene supports two types of URIs: + * dev:tty => Standard terminal + * dev:tty, => Local terminal devices (e.g., virtual TTY) + */ + if (strpartcmp_static(u, "tty") && (!(*p) || *p == ',')) dops = &term_ops; if (!dops) return -PAL_ERROR_NOTSUPPORT; - *uri = (*p) ? p + 1 : p; + *uri = (*p) ? p + 1 : NULL; if (type) { *type = malloc_copy(u, p - u + 1); if (!*type) @@ -96,11 +101,21 @@ static int term_attrquerybyhdl (PAL_HANDLE hdl, PAL_STREAM_ATTR * attr); /* Method to open standard terminal */ -static int open_standard_term (PAL_HANDLE * handle, const char * param, - int access) -{ - if (param) - return -PAL_ERROR_NOTIMPLEMENTED; +static int open_standard_term(PAL_HANDLE* handle, const char* path, int access) { + /* remove the "file:" prefix */ + if (path) { + const char *p; + for (p = path; (*p) && (*p) != ':'; p++); + if ((*p) == ':' && (p - path == 4) && strpartcmp_static(path, "file:")) + path = path + 5; + } + + int dev_fd = -1; + if (path) { + dev_fd = ocall_open(path, access, 0); + if (IS_ERR(dev_fd)) + return unix_to_pal_error(ERRNO(dev_fd)); + } PAL_HANDLE hdl = malloc(HANDLE_SIZE(dev)); SET_HANDLE_TYPE(hdl, dev); @@ -108,12 +123,12 @@ static int open_standard_term (PAL_HANDLE * handle, const char * param, if (!(access & PAL_ACCESS_WRONLY)) { HANDLE_HDR(hdl)->flags |= RFD(0); - hdl->dev.fd_in = 0; + hdl->dev.fd_in = dev_fd != -1 ? dev_fd : 0; } if (access & (PAL_ACCESS_WRONLY|PAL_ACCESS_RDWR)) { HANDLE_HDR(hdl)->flags |= WFD(1); - hdl->dev.fd_out = 1; + hdl->dev.fd_out = dev_fd != -1 ? dev_fd : 1; } *handle = hdl; @@ -132,24 +147,7 @@ static int term_open (PAL_HANDLE *handle, const char * type, const char * uri, !WITHIN_MASK(options, PAL_OPTION_MASK)) return -PAL_ERROR_INVAL; - const char * term = NULL; - const char * param = NULL; - - const char * tmp = uri; - while (*tmp) { - if (!term && *tmp == '/') - term = tmp + 1; - if (*tmp == ',') { - param = param + 1; - break; - } - tmp++; - } - - if (term) - return -PAL_ERROR_NOTIMPLEMENTED; - - return open_standard_term(handle, param, access); + return open_standard_term(handle, uri, access); } static int term_close (PAL_HANDLE handle) diff --git a/Pal/src/host/Linux-SGX/db_files.c b/Pal/src/host/Linux-SGX/db_files.c index 38ff123c..ed833f2f 100644 --- a/Pal/src/host/Linux-SGX/db_files.c +++ b/Pal/src/host/Linux-SGX/db_files.c @@ -196,11 +196,15 @@ static int file_map (PAL_HANDLE handle, void ** addr, int prot, * we allow mapping the file outside the enclave, if the library OS * does not request a specific address. */ - if (!mem && !stubs && !(prot & PAL_PROT_WRITECOPY)) { + if (!stubs && !(prot & PAL_PROT_WRITECOPY)) { + mem = NULL; ret = ocall_map_untrusted(handle->file.fd, offset, size, HOST_PROT(prot), &mem); - if (!IS_ERR(ret)) + if (!IS_ERR(ret)) { + SGX_DBG(DBG_I, "file:%s is mapped outside the enclave\n", + handle->file.realpath); *addr = mem; + } return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : ret; } diff --git a/Pal/src/host/Linux-SGX/db_memory.c b/Pal/src/host/Linux-SGX/db_memory.c index 8fb5f93d..7ca7c8a6 100644 --- a/Pal/src/host/Linux-SGX/db_memory.c +++ b/Pal/src/host/Linux-SGX/db_memory.c @@ -65,11 +65,22 @@ bool _DkCheckMemoryMappable (const void * addr, size_t size) int _DkVirtualMemoryAlloc (void ** paddr, uint64_t size, int alloc_type, int prot) { +#if 0 if (!WITHIN_MASK(prot, PAL_PROT_MASK)) return -PAL_ERROR_INVAL; +#endif void * addr = *paddr, * mem; + /* special case: alloc in untrusted memory for DMA with FPGA; + * note that we abuse prot argument as flags and also abuse offset */ + if (alloc_type & PAL_ALLOC_DMAREGION) { + int ret = ocall_map_untrusted(/*fd=*/-1, /*offset=*/prot, size, PROT_READ|PROT_WRITE, paddr); + if (IS_ERR(ret)) + return -PAL_ERROR_INVAL; + return 0; + } + if ((alloc_type & PAL_ALLOC_INTERNAL) && addr) return -PAL_ERROR_INVAL; diff --git a/Pal/src/host/Linux-SGX/db_misc.c b/Pal/src/host/Linux-SGX/db_misc.c index a638ff41..15ea52ac 100644 --- a/Pal/src/host/Linux-SGX/db_misc.c +++ b/Pal/src/host/Linux-SGX/db_misc.c @@ -180,3 +180,54 @@ int _DkCpuIdRetrieve (unsigned int leaf, unsigned int subleaf, add_cpuid_to_cache(leaf, subleaf, values); return 0; } + +int64_t _DkHostExtensionCall (PAL_HANDLE handle, PAL_NUM op, PAL_ARG* arg, int noutputs, PAL_ARG* outputs, + int ninputs, PAL_ARG* inputs) { + // The handle needs to have at least one fd + if (!(HANDLE_HDR(handle)->flags & (RFD(0)|WFD(0)))) + return -PAL_ERROR_BADHANDLE; + + uint64_t retval = 0; + int ret = ocall_ioctl(handle->generic.fds[0], op, arg, noutputs, outputs, + ninputs, inputs, &retval); + return (ret < 0) ? ret : retval; +} + + +int _DkEventfdPassthrough(PAL_NUM initval, PAL_NUM flags) { + int ret = ocall_eventfd_passthrough(initval, flags); + return ret; +} + +int _DkPollPassthrough(PAL_POLLFD* fds, PAL_NUM nfds, PAL_NUM timeout) { + int64_t ocalltimeout = (int64_t)timeout; + struct pollfd ocallfds[nfds]; + + for (PAL_NUM i = 0; i < nfds; i++) { + ocallfds[i].fd = (int)fds[i].fd; + ocallfds[i].events = (short)fds[i].events; + ocallfds[i].revents = (short)fds[i].revents; + } + + int ret = ocall_poll((struct pollfd*) &ocallfds, (int)nfds, &ocalltimeout); + + for (PAL_NUM i = 0; i < nfds; i++) + fds[i].revents = (PAL_NUM)ocallfds[i].revents; + + return ret; +} + +int _DkReadPassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count) { + int ret = ocall_read((int)fd, (void*)buf, (unsigned int)count); + return ret; +} + +int _DkWritePassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count) { + int ret = ocall_write((int)fd, (const void*)buf, (unsigned int)count); + return ret; +} + +int _DkClosePassthrough(PAL_NUM fd) { + int ret = ocall_close((int)fd); + return ret; +} diff --git a/Pal/src/host/Linux-SGX/db_rtld.c b/Pal/src/host/Linux-SGX/db_rtld.c index 19828339..7f0707d4 100644 --- a/Pal/src/host/Linux-SGX/db_rtld.c +++ b/Pal/src/host/Linux-SGX/db_rtld.c @@ -158,8 +158,8 @@ void setup_pal_map (struct link_map * pal_map) char buffer[BUFFER_LENGTH]; snprintf(buffer, BUFFER_LENGTH, - "add-symbol-file %s 0x%p -readnow -s .rodata 0x%p " - "-s .dynamic 0x%p -s .data 0x%p -s .bss 0x%p", + "add-symbol-file %s %p -readnow -s .rodata %p " + "-s .dynamic %p -s .data %p -s .bss %p", pal_map->l_name, §ion_text, §ion_rodata, §ion_dynamic, §ion_data, §ion_bss); diff --git a/Pal/src/host/Linux-SGX/enclave_ocalls.c b/Pal/src/host/Linux-SGX/enclave_ocalls.c index f4c97079..618fb21f 100644 --- a/Pal/src/host/Linux-SGX/enclave_ocalls.c +++ b/Pal/src/host/Linux-SGX/enclave_ocalls.c @@ -1104,3 +1104,86 @@ int ocall_load_debug(const char * command) sgx_reset_ustack(); return retval; } + +int ocall_ioctl (int fd, uint64_t op, PAL_ARG* arg, int noutputs, PAL_ARG* outputs, + int ninputs, PAL_ARG* inputs, uint64_t* retval) { + int status = 0; + + ms_ocall_ioctl_t* ms; + ms = sgx_alloc_on_ustack(sizeof(*ms)); + if (!ms) { + sgx_reset_ustack(); + return -EPERM; + } + + ms->ms_fd = fd; + ms->ms_op = op; + ms->ms_arg = NULL; + if (arg) { + /* some ioctls have the third argument arg, perform deep copy to ustack */ + ms->ms_arg = sgx_copy_to_ustack(arg->val, arg->size); + if (!ms->ms_arg) { + sgx_reset_ustack(); + return -EPERM; + } + + for (int i = 0; i < noutputs; i++) { + void* newptr = sgx_copy_to_ustack(outputs[i].val, outputs[i].size); + if (!newptr) { + sgx_reset_ustack(); + return -EPERM; + } + *(void**) (((uintptr_t) ms->ms_arg) + outputs[i].off) = newptr; + } + } + + status = sgx_ocall(OCALL_IOCTL, ms); + if (!status) { + *retval = ms->ms_retval; + + if (arg) { + /* some ioctls have the third argument arg, perform deep copy from ustack */ + if (!sgx_copy_to_enclave(arg->val, arg->size, ms->ms_arg, arg->size)) { + sgx_reset_ustack(); + return -EPERM; + } + + for (int i = 0; i < noutputs; i++) { + *(void**) (((uintptr_t) arg->val) + outputs[i].off) = outputs[i].val; + } + + for (int i = 0; i < ninputs; i++) { + void* newptr = *(void**) (((uintptr_t) ms->ms_arg) + inputs[i].off); + if (!sgx_copy_to_enclave(inputs[i].val, inputs[i].size, newptr, inputs[i].size)) { + sgx_reset_ustack(); + return -EPERM; + } + assert(*(void**) (((uintptr_t) arg->val) + inputs[i].off) == inputs[i].val); + } + } + } + + sgx_reset_ustack(); + return status; +} + + +int ocall_eventfd_passthrough (unsigned int initval, int flags) +{ + int retval = 0; + ms_ocall_eventfd_passthrough_t * ms; + + ms = sgx_alloc_on_ustack(sizeof(*ms)); + if (!ms) { + sgx_reset_ustack(); + return -EPERM; + } + + ms->ms_initval = initval; + ms->ms_flags = flags; + + retval = sgx_ocall(OCALL_EVENTFD_PASSTHROUGH, ms); + + sgx_reset_ustack(); + return retval; +} diff --git a/Pal/src/host/Linux-SGX/enclave_ocalls.h b/Pal/src/host/Linux-SGX/enclave_ocalls.h index 0fff4902..599d57c6 100644 --- a/Pal/src/host/Linux-SGX/enclave_ocalls.h +++ b/Pal/src/host/Linux-SGX/enclave_ocalls.h @@ -100,3 +100,8 @@ int ocall_rename (const char * oldpath, const char * newpath); int ocall_delete (const char * pathname); int ocall_load_debug (const char * command); + +int ocall_ioctl (int fd, uint64_t op, PAL_ARG* arg, int noutputs, PAL_ARG* outputs, + int ninputs, PAL_ARG* inputs, uint64_t* retval); + +int ocall_eventfd_passthrough (unsigned int initval, int flags); diff --git a/Pal/src/host/Linux-SGX/ocall_types.h b/Pal/src/host/Linux-SGX/ocall_types.h index 5c3f9522..a1c2b274 100644 --- a/Pal/src/host/Linux-SGX/ocall_types.h +++ b/Pal/src/host/Linux-SGX/ocall_types.h @@ -53,6 +53,8 @@ enum { OCALL_RENAME, OCALL_DELETE, OCALL_LOAD_DEBUG, + OCALL_IOCTL, + OCALL_EVENTFD_PASSTHROUGH, OCALL_NR, }; @@ -262,4 +264,16 @@ typedef struct { unsigned int ms_tid; } ms_ocall_schedule_t; +typedef struct { + int ms_fd; + uint64_t ms_op; + void* ms_arg; + uint64_t ms_retval; +} ms_ocall_ioctl_t; + +typedef struct { + unsigned int ms_initval; + int ms_flags; +} ms_ocall_eventfd_passthrough_t; + #pragma pack(pop) diff --git a/Pal/src/host/Linux-SGX/pal.map b/Pal/src/host/Linux-SGX/pal.map index c41e4722..a66263c7 100644 --- a/Pal/src/host/Linux-SGX/pal.map +++ b/Pal/src/host/Linux-SGX/pal.map @@ -42,6 +42,13 @@ PAL { DkSegmentRegister; # set segment register DkMemoryAvailableQuota; DkCpuIdRetrieve; # retrieve CPUID + DkHostExtensionCall; + + DkEventfdPassthrough; + DkPollPassthrough; + DkReadPassthrough; + DkWritePassthrough; + DkClosePassthrough; # Debugging ABIs pal_printf; pal_snprintf; DkDebugAttachBinary; DkDebugDetachBinary; diff --git a/Pal/src/host/Linux-SGX/sgx_enclave.c b/Pal/src/host/Linux-SGX/sgx_enclave.c index fb2b6326..01d327a8 100644 --- a/Pal/src/host/Linux-SGX/sgx_enclave.c +++ b/Pal/src/host/Linux-SGX/sgx_enclave.c @@ -58,10 +58,23 @@ static int sgx_ocall_map_untrusted(void * pms) ms_ocall_map_untrusted_t * ms = (ms_ocall_map_untrusted_t *) pms; void * addr; ODEBUG(OCALL_MAP_UNTRUSTED, ms); - addr = (void *) INLINE_SYSCALL(mmap, 6, NULL, ms->ms_size, - ms->ms_prot, - MAP_FILE|MAP_SHARED, - ms->ms_fd, ms->ms_offset); + + if (ms->ms_fd == -1) { + /* special case: alloc in untrusted memory for DMA with FPGA; + * note that we abuse ms_offset as flags */ + addr = (void *) INLINE_SYSCALL(mmap, 6, NULL, ms->ms_size, + ms->ms_prot, + /* flags */ (int)ms->ms_offset, + /* fd is ignored*/ -1, + /* offset is ignored */ 0); + + } else { + addr = (void *) INLINE_SYSCALL(mmap, 6, NULL, ms->ms_size, + ms->ms_prot, + MAP_FILE|MAP_SHARED, + ms->ms_fd, ms->ms_offset); + } + if (IS_ERR_P(addr)) return -ERRNO_P(addr); @@ -657,6 +670,36 @@ static int sgx_ocall_load_debug(void * pms) return 0; } +static int sgx_ocall_ioctl (void * pms) +{ + ms_ocall_ioctl_t * ms = (ms_ocall_ioctl_t *) pms; + int64_t retval; + ODEBUG(OCALL_IOCTL, ms); + + retval = INLINE_SYSCALL(ioctl, 3, ms->ms_fd, ms->ms_op, ms->ms_arg); + + if (IS_ERR(retval)) { + return unix_to_pal_error(ERRNO(retval)); + } else { + ms->ms_retval = retval; + return 0; + } +} + +static int sgx_ocall_eventfd_passthrough (void * pms) +{ + ms_ocall_eventfd_passthrough_t * ms = (ms_ocall_eventfd_passthrough_t *) pms; + int64_t retval; + ODEBUG(OCALL_EVENTFD_PASSTHROUGH, ms); + + retval = INLINE_SYSCALL(eventfd2, 2, ms->ms_initval, ms->ms_flags); + + if (IS_ERR(retval)) + return unix_to_pal_error(ERRNO(retval)); + return retval; +} + + sgx_ocall_fn_t ocall_table[OCALL_NR] = { [OCALL_EXIT] = sgx_ocall_exit, [OCALL_PRINT_STRING] = sgx_ocall_print_string, @@ -695,6 +738,9 @@ sgx_ocall_fn_t ocall_table[OCALL_NR] = { [OCALL_RENAME] = sgx_ocall_rename, [OCALL_DELETE] = sgx_ocall_delete, [OCALL_LOAD_DEBUG] = sgx_ocall_load_debug, + [OCALL_IOCTL] = sgx_ocall_ioctl, + + [OCALL_EVENTFD_PASSTHROUGH] = sgx_ocall_eventfd_passthrough }; #define EDEBUG(code, ms) do {} while (0) diff --git a/Pal/src/host/Linux/db_devices.c b/Pal/src/host/Linux/db_devices.c index e3ec2f22..2bd2f0db 100644 --- a/Pal/src/host/Linux/db_devices.c +++ b/Pal/src/host/Linux/db_devices.c @@ -65,13 +65,18 @@ static int parse_device_uri(const char** uri, char** type, struct handle_ops** o for (p = u; (*p) && (*p) != ',' && (*p) != '/'; p++) ; - if (strpartcmp_static(u, "tty")) + /* + * For terminal devices, Graphene supports two types of URIs: + * dev:tty => Standard terminal + * dev:tty, => Local terminal devices (e.g., virtual TTY) + */ + if (strpartcmp_static(u, "tty") && (!(*p) || *p == ',')) dops = &term_ops; if (!dops) return -PAL_ERROR_NOTSUPPORT; - *uri = (*p) ? p + 1 : p; + *uri = (*p) ? p + 1 : NULL; if (type) { *type = malloc_copy(u, p - u + 1); if (!*type) @@ -91,9 +96,13 @@ static int term_attrquery(const char* type, const char* uri, PAL_STREAM_ATTR* at static int term_attrquerybyhdl(PAL_HANDLE hdl, PAL_STREAM_ATTR* attr); /* Method to open standard terminal */ -static int open_standard_term(PAL_HANDLE* handle, const char* param, int access) { - if (param) - return -PAL_ERROR_NOTIMPLEMENTED; +static int open_standard_term(PAL_HANDLE* handle, const char* path, int access) { + int dev_fd = -1; + if (path) { + dev_fd = INLINE_SYSCALL(open, 3, path, access, 0); + if (IS_ERR(dev_fd)) + return unix_to_pal_error(ERRNO(dev_fd)); + } PAL_HANDLE hdl = malloc(HANDLE_SIZE(dev)); SET_HANDLE_TYPE(hdl, dev); @@ -101,12 +110,12 @@ static int open_standard_term(PAL_HANDLE* handle, const char* param, int access) if (!(access & PAL_ACCESS_WRONLY)) { HANDLE_HDR(hdl)->flags |= RFD(0); - hdl->dev.fd_in = 0; + hdl->dev.fd_in = dev_fd != -1 ? dev_fd : 0; } if (access & (PAL_ACCESS_WRONLY | PAL_ACCESS_RDWR)) { HANDLE_HDR(hdl)->flags |= WFD(1); - hdl->dev.fd_out = 1; + hdl->dev.fd_out = dev_fd != -1 ? dev_fd : 1; } *handle = hdl; @@ -124,24 +133,7 @@ static int term_open(PAL_HANDLE* handle, const char* type, const char* uri, int !WITHIN_MASK(options, PAL_OPTION_MASK)) return -PAL_ERROR_INVAL; - const char* term = NULL; - const char* param = NULL; - - const char* tmp = uri; - while (*tmp) { - if (!term && *tmp == '/') - term = tmp + 1; - if (*tmp == ',') { - param = param + 1; - break; - } - tmp++; - } - - if (term) - return -PAL_ERROR_NOTIMPLEMENTED; - - return open_standard_term(handle, param, access); + return open_standard_term(handle, uri, access); } static int term_close(PAL_HANDLE handle) { diff --git a/Pal/src/host/Linux/db_misc.c b/Pal/src/host/Linux/db_misc.c index 547fbd89..3afcf700 100644 --- a/Pal/src/host/Linux/db_misc.c +++ b/Pal/src/host/Linux/db_misc.c @@ -241,3 +241,18 @@ int _DkCpuIdRetrieve (unsigned int leaf, unsigned int subleaf, cpuid(leaf, subleaf, values); return 0; } + +int64_t _DkHostExtensionCall (PAL_HANDLE handle, PAL_NUM op, PAL_ARG* arg, int noutputs, PAL_ARG* outputs, + int ninputs, PAL_ARG* inputs) +{ + // The handle needs to have at least one fd + if (!(HANDLE_HDR(handle)->flags & (RFD(0)|WFD(0)))) + return -PAL_ERROR_BADHANDLE; + + int64_t ret = INLINE_SYSCALL(ioctl, 3, handle->generic.fds[0], op, arg->val); + + if (IS_ERR(ret)) + return -PAL_ERROR_DENIED; + + return ret; +} diff --git a/Pal/src/host/Linux/pal.map b/Pal/src/host/Linux/pal.map index 1ce4b9bf..08a4a14d 100644 --- a/Pal/src/host/Linux/pal.map +++ b/Pal/src/host/Linux/pal.map @@ -39,6 +39,7 @@ PAL { DkStreamChangeName; DkStreamAttributesSetByHandle; DkMemoryAvailableQuota; + DkHostExtensionCall; # Debugging ABIs pal_printf; DkDebugAttachBinary; DkDebugDetachBinary; diff --git a/Pal/src/pal.h b/Pal/src/pal.h index c2a242e9..066f800d 100644 --- a/Pal/src/pal.h +++ b/Pal/src/pal.h @@ -205,6 +205,7 @@ PAL_CONTROL * pal_control_addr (void); #ifdef IN_PAL #define PAL_ALLOC_INTERNAL 0x8000 +#define PAL_ALLOC_DMAREGION 0x4000 /* alloc in untrusted memory for DMA with FPGA */ #endif /* Memory Protection Flags */ @@ -522,6 +523,27 @@ PAL_NUM DkMemoryAvailableQuota (void); PAL_BOL DkCpuIdRetrieve (PAL_IDX leaf, PAL_IDX subleaf, PAL_IDX values[4]); +typedef struct { + PAL_PTR val; + PAL_NUM size, off; +} PAL_ARG; + +PAL_NUM +DkHostExtensionCall (PAL_HANDLE handle, PAL_NUM op, PAL_ARG* arg, PAL_NUM noutputs, PAL_ARG* outputs, + PAL_NUM ninputs, PAL_ARG* inputs); + +typedef struct { + PAL_NUM fd; + PAL_NUM events; + PAL_NUM revents; +} PAL_POLLFD; + +PAL_NUM DkEventfdPassthrough(PAL_NUM initval, PAL_NUM flags); +PAL_NUM DkPollPassthrough(PAL_POLLFD* fds, PAL_NUM nfds, PAL_NUM timeout); +PAL_NUM DkReadPassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count); +PAL_NUM DkWritePassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count); +PAL_NUM DkClosePassthrough(PAL_NUM fd); + #ifdef __GNUC__ # define symbol_version_default(real, name, version) \ __asm__ (".symver " #real "," #name "@@" #version "\n") diff --git a/Pal/src/pal_internal.h b/Pal/src/pal_internal.h index 5ffd37be..82e46061 100644 --- a/Pal/src/pal_internal.h +++ b/Pal/src/pal_internal.h @@ -356,6 +356,14 @@ int _DkPhysicalMemoryCommit (PAL_HANDLE channel, int entries, int _DkPhysicalMemoryMap (PAL_HANDLE channel, int entries, PAL_PTR * addrs, PAL_NUM * sizes, PAL_FLG * prots); int _DkCpuIdRetrieve (unsigned int leaf, unsigned int subleaf, unsigned int values[4]); +int64_t _DkHostExtensionCall (PAL_HANDLE handle, PAL_NUM op, PAL_ARG* arg, int noutputs, PAL_ARG* outputs, + int ninputs, PAL_ARG* inputs); + +int _DkEventfdPassthrough(PAL_NUM initval, PAL_NUM flags); +int _DkPollPassthrough(PAL_POLLFD* fds, PAL_NUM nfds, PAL_NUM timeout); +int _DkReadPassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count); +int _DkWritePassthrough(PAL_NUM fd, PAL_PTR buf, PAL_NUM count); +int _DkClosePassthrough(PAL_NUM fd); #define INIT_FAIL(exitcode, reason) \ do { \ diff --git a/README.md b/README.md index bfde678f..760545d0 100644 --- a/README.md +++ b/README.md @@ -71,39 +71,6 @@ To build Graphene library OS with debug symbols, run "make DEBUG=1" instead of To build with "-Werror", run "make WERROR=1". -### 2.1. BUILD WITH KERNEL-LEVEL SANDBOXING (OPTIONAL) - -__** Note: this step is optional. **__ - -__** Note: for building with Intel:registered: SGX support, skip this step, go to section 2.2 **__ - -__** Disclaimer: this feature is experimental and may contain bugs. Please do - no use in production system before further assessment.__ - -To enable sandboxing, a customized Linux kernel is needed. Note that -this feature is optional and completely unnecessary for running on SGX. -To build the Graphene Linux kernel, do the following steps: - - cd Pal/linux-3.19 - make menuconfig - make - make install - (Add Graphene kernel as a boot option by commands like "update-grub") - (reboot and choose the Graphene kernel) - -Please note that the building process may pause before building the Linux -kernel, because it requires you to provide a sensible configuration file -(.config). The Graphene kernel requires the following options to be enabled -in the configuration: - - - CONFIG_GRAPHENE=y - - CONFIG_GRAPHENE_BULK_IPC=y - - CONFIG_GRAPHENE_ISOLATE=y - -For more details about the building and installation, see the Graphene github -Wiki page: . - - ### 2.2 BUILD WITH INTEL:registered: SGX SUPPORT #### 2.1.1 Prerequisites @@ -126,8 +93,14 @@ files) and the signatures, to the SGX-enabled hosts. The Intel SGX Linux SDK is required for running Graphene Library OS. Download and install from the official Intel github repositories: - - - - + - (SGX SDK) + - (SGX Driver) + * Order of steps would be: (Important: Select branch sgx2. Master branch is deprecated) + 1. Build & Install SGX driver (Follow instructions in : https://github.com/intel/linux-sgx-driver) + 2. Build & Install SGX SDK & SGX PSW Package + 3. Test the Intel(R) SGX SDK Package with the Code Samples + Note: This section "Test the Intel(R) SGX SDK Package with the Code Samples" actually is written in middle, but requires the PSW, SGX SDK, SGX driver to be installed before running' + A Linux driver must be installed before running Graphene Library OS in enclaves. Simply run the following command to build the driver: @@ -151,10 +124,28 @@ To build with debug symbols, run the command: Using "make SGX=1" in the test or regression directory will automatically generate the enclave signatures (.sig files). +Note: +1. Before running make SGX=1. LD_LIBRARY_PATH must be unset. + $ unset LD_LIBRARY_PATH +2. For the very first time: Make will ask for Install directory of SGX driver. Provide the path to the SGX driver checked out and build earlier in 2.2 + + #### 2.1.3 Run Built-in Examples in Graphene-SGX +Following items need to be run again everytime when the system is re-booted. An init script can be created if required. + +1. Load Graphene-SGX driver + In /Pal/src/host/Linux-SGX/sgx-driver + $ ./load.sh +2. Start SGX AESMD service + sudo service aesmd start +3. Set Minimum V.A mmap to 0 +sudo sysctl vm.mmap_min_addr=0 + + There are a few built-in examples under LibOS/shim/test/. The "native" folder includes a rich set of C programs and "apps" folder includes a few tested applications, such as GCC, Python, and Apache. + (1) Build and run a Hello World program with Graphene on SGX - go to LibOS/shim/test/native, build the enclaves via command: @@ -182,13 +173,28 @@ There are a few built-in examples under LibOS/shim/test/. The "native" folder in SGX=1 ./python.manifest.sgx scripts/helloworld.py -#### 2.1.3 Including Application Test Cases +#### 2.1.4 Including Application Test Cases To add the application test cases, issue the following command from the root of the source tree: git submodule update --init -- LibOS/shim/test/apps/ +#### 2.1.5 OpenVINO FPGA + + +Note: The Apps folder contains an example of OpenVINO-FPGA +Follow the Readme in the OpenVINO-FPGA to build and run the App. + +Following are the list of changes to support OpenVINO-FPGA in the Graphene source code: +1. IOCTL support for Graphene-SGX +2. Eventfd/poll support for Graphene-SGX +3. DMA memory allocation outside SGX memory +4. Additional workarounds for symlinks, lseek etc. +5. Mapping device file objects + +This features were added relative to Graphene source code in Aug '18. New commits might already fix the missing features mentioned above + ## 3. HOW TO RUN AN APPLICATION IN GRAPHENE? Graphene library OS uses PAL (libpal.so) as a loader to bootstrap an