diff --git a/LibOS/shim/include/shim_checkpoint.h b/LibOS/shim/include/shim_checkpoint.h index df8e21b8..e96c756f 100644 --- a/LibOS/shim/include/shim_checkpoint.h +++ b/LibOS/shim/include/shim_checkpoint.h @@ -85,7 +85,7 @@ struct shim_mem_entry { void* addr; size_t size; void** paddr; - int prot; + int prot; /*< Combination of PAL_PROT_* flags */ void* data; }; diff --git a/LibOS/shim/include/shim_flags_conv.h b/LibOS/shim/include/shim_flags_conv.h new file mode 100644 index 00000000..ed135ffe --- /dev/null +++ b/LibOS/shim/include/shim_flags_conv.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2020 Invisible Things Lab + Michał Kowalczyk + This file is part of Graphene Library OS. + Graphene Library OS is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + Graphene Library OS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* + * This file defines conversions between Linux syscall flags and PAL API flags. + * + * For Linux-based PALs there is pal_flag_conv.h in Linux-common, mirroring those conversions. + */ + +#ifndef SHIM_FLAGS_CONV_H +#define SHIM_FLAGS_CONV_H + +#include +#include +#include + +#include "assert.h" +#include "pal.h" + +static inline int LINUX_PROT_TO_PAL(int prot, int map_flags) { + assert(WITHIN_MASK(prot, PROT_READ | PROT_WRITE | PROT_EXEC)); + return (prot & PROT_READ ? PAL_PROT_READ : 0) | + (prot & PROT_WRITE ? PAL_PROT_WRITE : 0) | + (prot & PROT_EXEC ? PAL_PROT_EXEC : 0) | + (map_flags & MAP_PRIVATE ? PAL_PROT_WRITECOPY : 0); +} + +static inline int LINUX_OPEN_FLAGS_TO_PAL_ACCESS(int access) { + return (access & O_RDONLY ? PAL_ACCESS_RDONLY : 0) | + (access & O_WRONLY ? PAL_ACCESS_WRONLY : 0) | + (access & O_RDWR ? PAL_ACCESS_RDWR : 0) | + (access & O_APPEND ? PAL_ACCESS_APPEND : 0); +} + +static inline int LINUX_OPEN_FLAGS_TO_PAL_CREATE(int flags) { + if (WITHIN_MASK(O_CREAT | O_EXCL, flags)) + return PAL_CREATE_ALWAYS; + if (flags & O_CREAT) + return PAL_CREATE_TRY; + return 0; +} + +static inline int LINUX_OPEN_FLAGS_TO_PAL_OPTIONS(int flags) { + return (flags & O_CLOEXEC ? PAL_OPTION_CLOEXEC : 0) | + (flags & O_NONBLOCK ? PAL_OPTION_NONBLOCK : 0); +} + +#endif /* SHIM_FLAGS_CONV_H */ diff --git a/LibOS/shim/include/shim_handle.h b/LibOS/shim/include/shim_handle.h index a1fa5a15..f932896b 100644 --- a/LibOS/shim/include/shim_handle.h +++ b/LibOS/shim/include/shim_handle.h @@ -350,7 +350,7 @@ struct shim_handle { struct shim_dir_handle dir_info; - int flags; + int flags; /* Linux' O_* flags */ int acc_mode; IDTYPE owner; struct shim_lock lock; diff --git a/LibOS/shim/include/shim_vma.h b/LibOS/shim/include/shim_vma.h index db60af7e..e83d4744 100644 --- a/LibOS/shim/include/shim_vma.h +++ b/LibOS/shim/include/shim_vma.h @@ -80,22 +80,6 @@ static inline void free_vma_val_array(struct shim_vma_val* vmas, size_t count) { #define NEED_MIGRATE_MEMORY(vma) \ (((vma)->flags & VMA_TAINTED || !(vma)->file) && !((vma)->flags & VMA_UNMAPPED)) -static inline PAL_FLG PAL_PROT(int prot, int flags) { - PAL_FLG pal_prot = 0; - - if (prot & PROT_READ) - pal_prot |= PAL_PROT_READ; - if (prot & PROT_WRITE) - pal_prot |= PAL_PROT_WRITE; - if (prot & PROT_EXEC) - pal_prot |= PAL_PROT_EXEC; - - if (flags & MAP_PRIVATE) - pal_prot |= PAL_PROT_WRITECOPY; - - return pal_prot; -} - int init_vma(void); /* Bookkeeping mmap() system call */ diff --git a/LibOS/shim/src/bookkeep/shim_vma.c b/LibOS/shim/src/bookkeep/shim_vma.c index 2bc6e063..11489bb6 100644 --- a/LibOS/shim/src/bookkeep/shim_vma.c +++ b/LibOS/shim/src/bookkeep/shim_vma.c @@ -20,20 +20,20 @@ * This file contains code to maintain bookkeeping of VMAs in library OS. */ -#include -#include -#include -#include -#include -#include - -#include -#include - #include #include #include +#include "list.h" +#include "pal.h" +#include "shim_checkpoint.h" +#include "shim_flags_conv.h" +#include "shim_fs.h" +#include "shim_handle.h" +#include "shim_internal.h" +#include "shim_thread.h" +#include "shim_vma.h" + /* * Internal bookkeeping for VMAs (virtual memory areas). This data * structure can only be accessed in this source file, with vma_list_lock @@ -1080,7 +1080,7 @@ BEGIN_CP_FUNC(vma) struct shim_vma_val * vma = (struct shim_vma_val *) obj; struct shim_vma_val * new_vma = NULL; - PAL_FLG pal_prot = PAL_PROT(vma->prot, 0); + PAL_FLG pal_prot = LINUX_PROT_TO_PAL(vma->prot, /*map_flags=*/0); ptr_t off = GET_FROM_CP_MAP(obj); @@ -1187,11 +1187,9 @@ BEGIN_RS_FUNC(vma) } if (need_mapped < vma->addr + vma->length) { - int pal_alloc_type = 0; - int pal_prot = vma->prot; - if (DkVirtualMemoryAlloc(need_mapped, - vma->addr + vma->length - need_mapped, - pal_alloc_type, pal_prot)) { + if (DkVirtualMemoryAlloc(need_mapped, vma->addr + vma->length - need_mapped, + /*alloc_type=*/0, + LINUX_PROT_TO_PAL(vma->prot, /*map_flags=*/0))) { need_mapped += vma->length; } } diff --git a/LibOS/shim/src/elf/shim_rtld.c b/LibOS/shim/src/elf/shim_rtld.c index 3f84a2d5..88d688b4 100644 --- a/LibOS/shim/src/elf/shim_rtld.c +++ b/LibOS/shim/src/elf/shim_rtld.c @@ -26,18 +26,19 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "elf.h" #include "ldsodefs.h" +#include "shim_checkpoint.h" +#include "shim_flags_conv.h" +#include "shim_fs.h" +#include "shim_handle.h" +#include "shim_internal.h" +#include "shim_table.h" +#include "shim_thread.h" +#include "shim_utils.h" +#include "shim_vdso.h" +#include "shim_vma.h" #ifndef DT_THISPROCNUM #define DT_THISPROCNUM 0 @@ -199,7 +200,8 @@ static int protect_page(struct link_map* l, void* addr, size_t size) { void* start = ALLOC_ALIGN_DOWN_PTR(addr); void* end = ALLOC_ALIGN_UP_PTR(addr + size); - if (!DkVirtualMemoryProtect(start, end - start, PAL_PROT_READ | PAL_PROT_WRITE | prot)) + if (!DkVirtualMemoryProtect(start, end - start, + PAL_PROT_READ | PAL_PROT_WRITE | LINUX_PROT_TO_PAL(prot, /*map_flags=*/0))) return -PAL_ERRNO; if (!c) @@ -237,7 +239,8 @@ static int reprotect_map(struct link_map* l) { t = next; l->textrels = t; - if (c && !DkVirtualMemoryProtect((void*)start, end - start, prot)) { + if (c && !DkVirtualMemoryProtect((void*)start, end - start, + LINUX_PROT_TO_PAL(prot, /*map_flags=*/0))) { ret = -PAL_ERRNO; break; } @@ -613,13 +616,14 @@ do_remap: if ((c->prot & PROT_WRITE) == 0) { /* Dag nab it. */ if (!DkVirtualMemoryProtect((caddr_t)ALLOC_ALIGN_DOWN(zero), g_pal_alloc_align, - c->prot | PAL_PROT_WRITE)) { + LINUX_PROT_TO_PAL(c->prot, /*map_flags=*/0) + | PAL_PROT_WRITE)) { errstring = "cannot change memory protections"; goto call_lose; } memset((void*)zero, '\0', zeropage - zero); if (!DkVirtualMemoryProtect((caddr_t)ALLOC_ALIGN_DOWN(zero), g_pal_alloc_align, - c->prot)) { + LINUX_PROT_TO_PAL(c->prot, /*map_flags=*/0))) { errstring = "cannot change memory protections"; goto call_lose; } @@ -632,7 +636,8 @@ do_remap: if (type != OBJECT_MAPPED && type != OBJECT_INTERNAL && type != OBJECT_USER && type != OBJECT_VDSO) { PAL_PTR mapat = - DkVirtualMemoryAlloc((void*)zeropage, zeroend - zeropage, 0, c->prot); + DkVirtualMemoryAlloc((void*)zeropage, zeroend - zeropage, /*alloc_type=*/0, + LINUX_PROT_TO_PAL(c->prot, /*map_flags=*/0)); if (!mapat) { errstring = "cannot map zero-fill pages"; goto call_lose; @@ -1431,8 +1436,8 @@ static int vdso_map_init(void) { return -ENOMEM; assert(addr == ALLOC_ALIGN_UP_PTR(addr)); - void* ret_addr = (void*)DkVirtualMemoryAlloc(addr, ALLOC_ALIGN_UP(vdso_so_size), 0, - PAL_PROT_READ | PAL_PROT_WRITE); + void* ret_addr = (void*)DkVirtualMemoryAlloc(addr, ALLOC_ALIGN_UP(vdso_so_size), + /*alloc_type=*/0, PAL_PROT_READ | PAL_PROT_WRITE); if (!ret_addr) return -PAL_ERRNO; assert(addr == ret_addr); diff --git a/LibOS/shim/src/fs/chroot/fs.c b/LibOS/shim/src/fs/chroot/fs.c index 60eb1e19..bd0eaa8e 100644 --- a/LibOS/shim/src/fs/chroot/fs.c +++ b/LibOS/shim/src/fs/chroot/fs.c @@ -20,25 +20,24 @@ * This file contains codes for implementation of 'chroot' filesystem. */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include +// FIXME: Sorting these includes causes a bunch of "error: ‘S_IFREG’ undeclared" errors. +#include "shim_flags_conv.h" +#include "shim_internal.h" +#include "shim_thread.h" +#include "shim_handle.h" +#include "shim_vma.h" +#include "shim_fs.h" +#include "shim_utils.h" +#include "pal.h" +#include "pal_error.h" #include #include -#include #include +#include +#include +#include +#include #define URI_MAX_SIZE STR_SIZE @@ -382,11 +381,8 @@ static int chroot_lookup (struct shim_dentry * dent) return query_dentry(dent, NULL, NULL, NULL); } -static int __chroot_open (struct shim_dentry * dent, - const char * uri, int flags, mode_t mode, - struct shim_handle * hdl, - struct shim_file_data * data) -{ +static int __chroot_open(struct shim_dentry* dent, const char* uri, int flags, mode_t mode, + struct shim_handle* hdl, struct shim_file_data* data) { int ret = 0; if (!uri) { @@ -394,13 +390,12 @@ static int __chroot_open (struct shim_dentry * dent, } int version = atomic_read(&data->version); - int oldmode = flags & O_ACCMODE; + int oldmode = LINUX_OPEN_FLAGS_TO_PAL_ACCESS(flags); int accmode = oldmode; - int creat = flags & PAL_CREATE_MASK; - int option = flags & PAL_OPTION_MASK; + int create = LINUX_OPEN_FLAGS_TO_PAL_CREATE(flags); + int options = LINUX_OPEN_FLAGS_TO_PAL_OPTIONS(flags); - if ((data->type == FILE_REGULAR || data->type == FILE_UNKNOWN) - && accmode == O_WRONLY) + if ((data->type == FILE_REGULAR || data->type == FILE_UNKNOWN) && accmode == O_WRONLY) accmode = O_RDWR; PAL_HANDLE palhdl; @@ -408,12 +403,11 @@ static int __chroot_open (struct shim_dentry * dent, if (hdl && hdl->pal_handle) { palhdl = hdl->pal_handle; } else { - palhdl = DkStreamOpen(uri, accmode, mode, creat, option); + palhdl = DkStreamOpen(uri, accmode, mode, create, options); if (!palhdl) { - if (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED && - accmode != oldmode) - palhdl = DkStreamOpen(uri, oldmode, mode, creat, option); + if (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED && accmode != oldmode) + palhdl = DkStreamOpen(uri, oldmode, mode, create, options); if (!palhdl) return -PAL_ERRNO; @@ -421,7 +415,7 @@ static int __chroot_open (struct shim_dentry * dent, /* If DENTRY_LISTED is set on the parent dentry, list_directory_dentry() will not update * dent's ino, so ino will be actively updated here. */ - if (creat) + if (create) chroot_update_ino(dent); } @@ -445,11 +439,9 @@ static int __chroot_open (struct shim_dentry * dent, return ret; } -static int chroot_open (struct shim_handle * hdl, struct shim_dentry * dent, - int flags) -{ +static int chroot_open(struct shim_handle* hdl, struct shim_dentry* dent, int flags) { int ret = 0; - struct shim_file_data * data; + struct shim_file_data* data; if ((ret = try_create_data(dent, NULL, 0, &data)) < 0) return ret; @@ -529,7 +521,7 @@ static int chroot_mkdir (struct shim_dentry * dir, struct shim_dentry * dent, return ret; } - ret = __chroot_open(dent, NULL, O_CREAT|O_EXCL, mode, NULL, data); + ret = __chroot_open(dent, NULL, O_CREAT | O_EXCL, mode, NULL, data); /* Increment the parent's link count */ struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir); @@ -726,7 +718,7 @@ static int chroot_mmap (struct shim_handle * hdl, void ** addr, size_t size, if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0) return ret; - int pal_prot = PAL_PROT(prot, flags); + int pal_prot = LINUX_PROT_TO_PAL(prot, flags); #if MAP_FILE == 0 if (flags & MAP_ANONYMOUS) diff --git a/LibOS/shim/src/shim_checkpoint.c b/LibOS/shim/src/shim_checkpoint.c index 97d777d0..407b64f4 100644 --- a/LibOS/shim/src/shim_checkpoint.c +++ b/LibOS/shim/src/shim_checkpoint.c @@ -605,8 +605,7 @@ static void * cp_alloc (struct shim_cp_store * store, void * addr, size_t size) bkeep_munmap(addr + size, reserve_size, CP_VMA_FLAGS); } - addr = (void *) DkVirtualMemoryAlloc(addr, size, 0, - PAL_PROT_READ|PAL_PROT_WRITE); + addr = (void*)DkVirtualMemoryAlloc(addr, size, 0, PAL_PROT_READ | PAL_PROT_WRITE); if (!addr) bkeep_munmap(addr, size, CP_VMA_FLAGS); @@ -863,9 +862,7 @@ int do_migration (struct newproc_cp_header * hdr, void ** cpptr) debug("checkpoint mapped at %p-%p\n", base, base + size); - PAL_FLG pal_prot = PAL_PROT_READ|PAL_PROT_WRITE; - - PAL_PTR mapped = DkVirtualMemoryAlloc(mapaddr, mapsize, 0, pal_prot); + PAL_PTR mapped = DkVirtualMemoryAlloc(mapaddr, mapsize, 0, PAL_PROT_READ | PAL_PROT_WRITE); if (!mapped) return -PAL_ERRNO; diff --git a/LibOS/shim/src/shim_init.c b/LibOS/shim/src/shim_init.c index 13a42962..ecb2d96b 100644 --- a/LibOS/shim/src/shim_init.c +++ b/LibOS/shim/src/shim_init.c @@ -207,9 +207,7 @@ void * allocate_stack (size_t size, size_t protect_size, bool user) if (!stack) return NULL; - stack = (void *) - DkVirtualMemoryAlloc(stack, size + protect_size, - 0, PAL_PROT_NONE); + stack = (void*)DkVirtualMemoryAlloc(stack, size + protect_size, 0, PAL_PROT_NONE); } else { stack = system_malloc(size + protect_size); } diff --git a/LibOS/shim/src/sys/shim_brk.c b/LibOS/shim/src/sys/shim_brk.c index 045e4a13..20e79c2d 100644 --- a/LibOS/shim/src/sys/shim_brk.c +++ b/LibOS/shim/src/sys/shim_brk.c @@ -140,8 +140,8 @@ int init_brk_region(void* brk_region, size_t data_segment_size) { void* end_brk_region = NULL; /* Allocate the whole brk region */ - void* ret = - (void*)DkVirtualMemoryAlloc(brk_region, brk_max_size, 0, PAL_PROT_READ | PAL_PROT_WRITE); + void* ret = (void*)DkVirtualMemoryAlloc(brk_region, brk_max_size, /*alloc_type=*/0, + PAL_PROT_READ | PAL_PROT_WRITE); /* Checking if the PAL call succeeds. */ if (!ret) { @@ -286,7 +286,8 @@ BEGIN_RS_FUNC(brk) { if (ret < 0) return ret; - void* ptr = DkVirtualMemoryAlloc(alloc_addr, alloc_size, 0, PAL_PROT_READ | PAL_PROT_WRITE); + void* ptr = DkVirtualMemoryAlloc(alloc_addr, alloc_size, /*alloc_type=*/0, + PAL_PROT_READ | PAL_PROT_WRITE); __UNUSED(ptr); assert(ptr == alloc_addr); debug("brk reserved area: %p - %p\n", alloc_addr, alloc_addr + alloc_size); diff --git a/LibOS/shim/src/sys/shim_fs.c b/LibOS/shim/src/sys/shim_fs.c index 15a719bd..374312e9 100644 --- a/LibOS/shim/src/sys/shim_fs.c +++ b/LibOS/shim/src/sys/shim_fs.c @@ -195,6 +195,9 @@ int shim_do_chmod(const char* path, mode_t mode) { struct shim_dentry* dent = NULL; int ret = 0; + /* This isn't documented, but that's what Linux does. */ + mode &= 07777; + if (test_user_string(path)) return -EFAULT; @@ -221,6 +224,9 @@ int shim_do_fchmodat(int dfd, const char* filename, mode_t mode) { if (test_user_string(filename)) return -EFAULT; + /* This isn't documented, but that's what Linux does. */ + mode &= 07777; + struct shim_dentry* dir = NULL; struct shim_dentry* dent = NULL; int ret = 0; @@ -251,6 +257,9 @@ int shim_do_fchmod(int fd, mode_t mode) { if (!hdl) return -EBADF; + /* This isn't documented, but that's what Linux does. */ + mode &= 07777; + struct shim_dentry* dent = hdl->dentry; int ret = 0; diff --git a/LibOS/shim/src/sys/shim_mmap.c b/LibOS/shim/src/sys/shim_mmap.c index 5a32b3a1..762a481d 100644 --- a/LibOS/shim/src/sys/shim_mmap.c +++ b/LibOS/shim/src/sys/shim_mmap.c @@ -21,16 +21,18 @@ */ #include -#include -#include -#include -#include -#include -#include -#include #include #include +#include "pal.h" +#include "pal_error.h" +#include "shim_flags_conv.h" +#include "shim_fs.h" +#include "shim_handle.h" +#include "shim_internal.h" +#include "shim_table.h" +#include "shim_vma.h" + void* shim_do_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { struct shim_handle* hdl = NULL; long ret = 0; @@ -116,7 +118,8 @@ void* shim_do_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t /* addr needs to be kept for bkeep_munmap() below */ void* ret_addr = addr; if (!hdl) { - ret_addr = (void*)DkVirtualMemoryAlloc(ret_addr, length, pal_alloc_type, PAL_PROT(prot, 0)); + ret_addr = (void*)DkVirtualMemoryAlloc(ret_addr, length, pal_alloc_type, + LINUX_PROT_TO_PAL(prot, /*map_flags=*/0)); if (!ret_addr) { if (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED) @@ -125,7 +128,7 @@ void* shim_do_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t ret = -PAL_ERRNO; } } else { - ret = hdl->fs->fs_ops->mmap(hdl, &ret_addr, length, PAL_PROT(prot, flags), flags, offset); + ret = hdl->fs->fs_ops->mmap(hdl, &ret_addr, length, prot, flags, offset); } if (hdl) @@ -153,7 +156,7 @@ int shim_do_mprotect(void* addr, size_t length, int prot) { if (bkeep_mprotect(addr, length, prot, 0) < 0) return -EPERM; - if (!DkVirtualMemoryProtect(addr, length, prot)) + if (!DkVirtualMemoryProtect(addr, length, LINUX_PROT_TO_PAL(prot, /*map_flags=*/0))) return -PAL_ERRNO; return 0; diff --git a/LibOS/shim/src/sys/shim_open.c b/LibOS/shim/src/sys/shim_open.c index a2d912f3..451b1e3a 100644 --- a/LibOS/shim/src/sys/shim_open.c +++ b/LibOS/shim/src/sys/shim_open.c @@ -114,6 +114,14 @@ int shim_do_open (const char * file, int flags, mode_t mode) if (file[0] == '\0') return -EINVAL; + if (!(flags & O_CREAT)) { + /* `mode` should be ignored if O_CREAT is not specified, according to man */ + mode = 0; + } else { + /* This isn't documented, but that's what Linux does. */ + mode &= 07777; + } + struct shim_handle * hdl = get_new_handle(); if (!hdl) return -ENOMEM; @@ -139,6 +147,14 @@ int shim_do_openat (int dfd, const char * filename, int flags, int mode) if (!filename || test_user_string(filename)) return -EFAULT; + if (!(flags & O_CREAT)) { + /* `mode` should be ignored if O_CREAT is not specified, according to man */ + mode = 0; + } else { + /* This isn't documented, but that's what Linux does. */ + mode &= 07777; + } + struct shim_dentry * dir = NULL; int ret = 0; diff --git a/LibOS/shim/src/sys/shim_pipe.c b/LibOS/shim/src/sys/shim_pipe.c index 00a54c7b..7b0f17b7 100644 --- a/LibOS/shim/src/sys/shim_pipe.c +++ b/LibOS/shim/src/sys/shim_pipe.c @@ -22,13 +22,15 @@ #include #include -#include -#include -#include -#include -#include -#include -#include + +#include "pal.h" +#include "pal_error.h" +#include "shim_flags_conv.h" +#include "shim_fs.h" +#include "shim_handle.h" +#include "shim_internal.h" +#include "shim_table.h" +#include "shim_utils.h" static int create_pipes(PAL_HANDLE* srv, PAL_HANDLE* cli, int flags, char* name, struct shim_qstr* qstr) { @@ -39,13 +41,18 @@ static int create_pipes(PAL_HANDLE* srv, PAL_HANDLE* cli, int flags, char* name, PAL_HANDLE hdl1 = NULL; /* one pipe end (accepted connect from hdl2) */ PAL_HANDLE hdl2 = NULL; /* other pipe end (connects to hdl0 and talks to hdl1) */ + if (flags & O_DIRECT) { + debug("create_pipes(): tried to create O_DIRECT pipe, which is not supported.\n"); + flags &= ~O_DIRECT; + } + if ((ret = create_pipe(name, uri, PIPE_URI_SIZE, &hdl0, qstr, /*use_vmid_for_name=*/false)) < 0) { debug("pipe creation failure\n"); return ret; } - if (!(hdl2 = DkStreamOpen(uri, 0, 0, 0, flags & O_NONBLOCK))) { + if (!(hdl2 = DkStreamOpen(uri, 0, 0, 0, LINUX_OPEN_FLAGS_TO_PAL_OPTIONS(flags)))) { ret = -PAL_ERRNO; debug("pipe connection failure\n"); goto out; diff --git a/LibOS/shim/src/sys/shim_socket.c b/LibOS/shim/src/sys/shim_socket.c index 50082702..9f8f4ffd 100644 --- a/LibOS/shim/src/sys/shim_socket.c +++ b/LibOS/shim/src/sys/shim_socket.c @@ -31,13 +31,13 @@ #include "hex.h" #include "pal.h" #include "pal_error.h" - -#include -#include -#include -#include -#include -#include +#include "shim_checkpoint.h" +#include "shim_flags_conv.h" +#include "shim_fs.h" +#include "shim_handle.h" +#include "shim_internal.h" +#include "shim_table.h" +#include "shim_utils.h" /* * User-settable options (used with setsockopt). @@ -533,7 +533,8 @@ int shim_do_bind(int sockfd, struct sockaddr* addr, socklen_t addrlen) { create_flags &= ~PAL_CREATE_DUALSTACK; } - PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&hdl->uri), 0, 0, create_flags, hdl->flags & O_NONBLOCK); + PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&hdl->uri), 0, 0, create_flags, + hdl->flags & O_NONBLOCK ? PAL_OPTION_NONBLOCK : 0); if (!pal_hdl) { ret = (PAL_NATIVE_ERRNO == PAL_ERROR_STREAMEXIST) ? -EADDRINUSE : -PAL_ERRNO; @@ -802,7 +803,8 @@ int shim_do_connect(int sockfd, struct sockaddr* addr, int addrlen) { if ((ret = create_socket_uri(hdl)) < 0) goto out; - PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&hdl->uri), 0, 0, 0, hdl->flags & O_NONBLOCK); + PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&hdl->uri), 0, 0, 0, + hdl->flags & O_NONBLOCK ? PAL_OPTION_NONBLOCK : 0); if (!pal_hdl) { ret = (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED) ? -ECONNREFUSED : -PAL_ERRNO; @@ -1061,7 +1063,8 @@ static ssize_t do_sendmsg(int fd, struct iovec* bufs, int nbufs, int flags, } if (sock->sock_state == SOCK_CREATED && !pal_hdl) { - pal_hdl = DkStreamOpen(URI_PREFIX_UDP, 0, 0, 0, hdl->flags & O_NONBLOCK); + pal_hdl = DkStreamOpen(URI_PREFIX_UDP, 0, 0, 0, + hdl->flags & O_NONBLOCK ? PAL_OPTION_NONBLOCK : 0); if (!pal_hdl) { ret = -PAL_ERRNO; goto out_locked; diff --git a/LibOS/shim/test/regression/test_libos.py b/LibOS/shim/test/regression/test_libos.py index d89489f5..509bc30d 100644 --- a/LibOS/shim/test/regression/test_libos.py +++ b/LibOS/shim/test/regression/test_libos.py @@ -2,6 +2,7 @@ import os import unittest +import shutil import subprocess from regression import ( @@ -240,6 +241,9 @@ class TC_30_Syscall(RegressionTestCase): self.assertIn('fstat returned the fd type as S_IFDIR', stdout) def test_020_getdents(self): + if os.path.exists("root"): + shutil.rmtree("root") + # This doesn't catch extraneous entries, but should be fine # until the LTP test can be run (need symlink support) @@ -261,6 +265,8 @@ class TC_30_Syscall(RegressionTestCase): self.assertIn('getdents64: dir3 [0x4]', stdout) def test_021_getdents_large_dir(self): + if os.path.exists("tmp/large_dir"): + shutil.rmtree("tmp/large_dir") stdout, _ = self.run_binary(['large_dir_read', 'tmp/large_dir', '3000']) self.assertIn('Success!', stdout) diff --git a/Pal/include/host/Linux-common/pal_flags_conv.h b/Pal/include/host/Linux-common/pal_flags_conv.h new file mode 100644 index 00000000..f47addeb --- /dev/null +++ b/Pal/include/host/Linux-common/pal_flags_conv.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2020 Invisible Things Lab + Michał Kowalczyk + This file is part of Graphene Library OS. + Graphene Library OS is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + Graphene Library OS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* + * This file defines conversions between various PAL API flags and the flags used by Linux syscalls. + * + * The counterpart of this file is shim_flag_conv.h in LibOS. + */ + +#ifndef PAL_FLAGS_CONV_H +#define PAL_FLAGS_CONV_H + +#undef __GLIBC__ +#include +#include +#include +#include + +#include "assert.h" +#include "pal.h" + +static inline int PAL_MEM_FLAGS_TO_LINUX(int alloc_type, int prot) { + assert(WITHIN_MASK(alloc_type, PAL_ALLOC_MASK)); + assert(WITHIN_MASK(prot, PAL_PROT_MASK)); + + return (alloc_type & PAL_ALLOC_RESERVE ? MAP_NORESERVE | MAP_UNINITIALIZED : 0) | + (prot & PAL_PROT_WRITECOPY ? MAP_PRIVATE : MAP_SHARED); +} + +static inline int PAL_PROT_TO_LINUX(int prot) { + assert(WITHIN_MASK(prot, PAL_PROT_MASK)); + return (prot & PAL_PROT_READ ? PROT_READ : 0) | + (prot & PAL_PROT_WRITE ? PROT_WRITE : 0) | + (prot & PAL_PROT_EXEC ? PROT_EXEC : 0); +} + +static inline int PAL_ACCESS_TO_LINUX_OPEN(int access) { + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + return (access & PAL_ACCESS_RDONLY ? O_RDONLY : 0) | + (access & PAL_ACCESS_WRONLY ? O_WRONLY : 0) | + (access & PAL_ACCESS_RDWR ? O_RDWR : 0) | + (access & PAL_ACCESS_APPEND ? O_APPEND : 0); +} + +static inline int PAL_CREATE_TO_LINUX_OPEN(int create) { + assert(create == 0 || create == PAL_CREATE_TRY || create == PAL_CREATE_ALWAYS); + return (create & PAL_CREATE_TRY ? O_CREAT : 0) | + (create & PAL_CREATE_ALWAYS ? O_CREAT | O_EXCL : 0); +} + +static inline int PAL_OPTION_TO_LINUX_OPEN(int options) { + assert(WITHIN_MASK(options, PAL_OPTION_CLOEXEC | PAL_OPTION_NONBLOCK)); + return (options & PAL_OPTION_CLOEXEC ? O_CLOEXEC : 0) | + (options & PAL_OPTION_NONBLOCK ? O_NONBLOCK : 0); +} + +#endif /* PAL_FLAGS_CONV_H */ diff --git a/Pal/include/pal/pal.h b/Pal/include/pal/pal.h index c5a539d2..fd0d7256 100644 --- a/Pal/include/pal/pal.h +++ b/Pal/include/pal/pal.h @@ -352,8 +352,10 @@ PAL_CONTROL * pal_control_addr (void); /*! Memory Allocation Flags */ enum PAL_ALLOC { - PAL_ALLOC_RESERVE = 0x0001, /*!< Only reserve the memory */ - PAL_ALLOC_INTERNAL = 0x8000, /*!< Allocate for PAL (valid only if #IN_PAL) */ + PAL_ALLOC_RESERVE = 0x1, /*!< Only reserve the memory */ + PAL_ALLOC_INTERNAL = 0x2, /*!< Allocate for PAL (valid only if #IN_PAL) */ + + PAL_ALLOC_MASK = 0x3, }; /*! Memory Protection Flags */ @@ -447,44 +449,49 @@ DkProcessExit(PAL_NUM exitCode); /*! Stream Access Flags */ enum PAL_ACCESS { - PAL_ACCESS_RDONLY = 00, - PAL_ACCESS_WRONLY = 01, - PAL_ACCESS_RDWR = 02, - PAL_ACCESS_APPEND = 04, - PAL_ACCESS_MASK = 07, + PAL_ACCESS_RDONLY = 0, + PAL_ACCESS_WRONLY = 1, + PAL_ACCESS_RDWR = 2, + PAL_ACCESS_APPEND = 4, + PAL_ACCESS_MASK = 7, }; /*! Stream Sharing Flags */ +// FIXME: These flags currently must correspond 1-1 to Linux flags, which is totally unportable. +// They should be redesigned when we'll be rewriting the filesystem layer. enum PAL_SHARE { - PAL_SHARE_GLOBAL_X = 01, - PAL_SHARE_GLOBAL_W = 02, - PAL_SHARE_GLOBAL_R = 04, - PAL_SHARE_GROUP_X = 010, - PAL_SHARE_GROUP_W = 020, - PAL_SHARE_GROUP_R = 040, - PAL_SHARE_OWNER_X = 0100, - PAL_SHARE_OWNER_W = 0200, - PAL_SHARE_OWNER_R = 0400, - PAL_SHARE_MASK = 0777, + PAL_SHARE_GLOBAL_X = 01, + PAL_SHARE_GLOBAL_W = 02, + PAL_SHARE_GLOBAL_R = 04, + PAL_SHARE_GROUP_X = 010, + PAL_SHARE_GROUP_W = 020, + PAL_SHARE_GROUP_R = 040, + PAL_SHARE_OWNER_X = 0100, + PAL_SHARE_OWNER_W = 0200, + PAL_SHARE_OWNER_R = 0400, + PAL_SHARE_STICKY = 01000, + PAL_SHARE_SET_GID = 02000, + PAL_SHARE_SET_UID = 04000, + + PAL_SHARE_MASK = 07777, }; /*! Stream Create Flags */ enum PAL_CREATE { - PAL_CREATE_TRY = 0100, /*!< Create file if file not exist (O_CREAT) */ - PAL_CREATE_ALWAYS = 0200, /*!< Create file and fail if file already exist - (O_CREAT|O_EXCL) */ - PAL_CREATE_DUALSTACK = 0400, /*!< Create dual-stack socket (opposite of IPV6_V6ONLY) */ + PAL_CREATE_TRY = 1, /*!< Create file if file does not exist */ + PAL_CREATE_ALWAYS = 2, /*!< Create file and fail if file already exists */ + PAL_CREATE_DUALSTACK = 4, /*!< Create dual-stack socket (opposite of IPV6_V6ONLY) */ - PAL_CREATE_MASK = 0700, + PAL_CREATE_MASK = 7, }; /*! Stream Option Flags */ enum PAL_OPTION { - PAL_OPTION_CLOEXEC = 01000, - PAL_OPTION_EFD_SEMAPHORE = 02000, /*!< specific to `eventfd` syscall */ - PAL_OPTION_NONBLOCK = 04000, + PAL_OPTION_CLOEXEC = 1, + PAL_OPTION_EFD_SEMAPHORE = 2, /*!< specific to `eventfd` syscall */ + PAL_OPTION_NONBLOCK = 4, - PAL_OPTION_MASK = 07000, + PAL_OPTION_MASK = 7, }; @@ -551,8 +558,8 @@ PAL_NUM DkStreamWrite(PAL_HANDLE handle, PAL_NUM offset, PAL_NUM count, PAL_PTR buffer, PAL_STR dest); enum PAL_DELETE { - PAL_DELETE_RD = 01, /*!< shut down the read side only */ - PAL_DELETE_WR = 02, /*!< shut down the write side only */ + PAL_DELETE_RD = 1, /*!< shut down the read side only */ + PAL_DELETE_WR = 2, /*!< shut down the write side only */ }; /*! @@ -560,8 +567,7 @@ enum PAL_DELETE { * * \param access which side to shut down (#PAL_DELETE), or both if 0 is given. */ -void -DkStreamDelete(PAL_HANDLE handle, PAL_FLG access); +void DkStreamDelete(PAL_HANDLE handle, PAL_FLG access); /*! * \brief Map a file to a virtual memory address in the current process. diff --git a/Pal/regression/File.c b/Pal/regression/File.c index 3ddaa0ef..b227def8 100644 --- a/Pal/regression/File.c +++ b/Pal/regression/File.c @@ -103,13 +103,13 @@ int main(int argc, char** argv, char** envp) { PAL_HANDLE file4 = DkStreamOpen("file:file_nonexist.tmp", PAL_ACCESS_RDWR, - PAL_SHARE_OWNER_R | PAL_SHARE_OWNER_W, PAL_CREATE_TRY | PAL_CREATE_ALWAYS, 0); + PAL_SHARE_OWNER_R | PAL_SHARE_OWNER_W, PAL_CREATE_ALWAYS, 0); if (file4) pal_printf("File Creation Test 1 OK\n"); PAL_HANDLE file5 = DkStreamOpen("file:file_nonexist.tmp", PAL_ACCESS_RDWR, - PAL_SHARE_OWNER_R | PAL_SHARE_OWNER_W, PAL_CREATE_TRY | PAL_CREATE_ALWAYS, 0); + PAL_SHARE_OWNER_R | PAL_SHARE_OWNER_W, PAL_CREATE_ALWAYS, 0); if (file5) { DkObjectClose(file5); } else { @@ -125,7 +125,7 @@ int main(int argc, char** argv, char** envp) { file6 = DkStreamOpen("file:file_nonexist_disallowed.tmp", PAL_ACCESS_RDWR, - PAL_SHARE_OWNER_R | PAL_SHARE_OWNER_W, PAL_CREATE_TRY | PAL_CREATE_ALWAYS, 0); + PAL_SHARE_OWNER_R | PAL_SHARE_OWNER_W, PAL_CREATE_ALWAYS, 0); if (!file6) { pal_printf("File Creation Test 4 OK\n"); } else { diff --git a/Pal/src/db_memory.c b/Pal/src/db_memory.c index d48364ec..9277b1a2 100644 --- a/Pal/src/db_memory.c +++ b/Pal/src/db_memory.c @@ -27,8 +27,7 @@ #include "pal_error.h" #include "pal_internal.h" -PAL_PTR -DkVirtualMemoryAlloc(PAL_PTR addr, PAL_NUM size, PAL_FLG alloc_type, PAL_FLG prot) { +PAL_PTR DkVirtualMemoryAlloc(PAL_PTR addr, PAL_NUM size, PAL_FLG alloc_type, PAL_FLG prot) { ENTER_PAL_CALL(DkVirtualMemoryAlloc); void* map_addr = (void*)addr; diff --git a/Pal/src/db_streams.c b/Pal/src/db_streams.c index a0f4bf17..5839a05b 100644 --- a/Pal/src/db_streams.c +++ b/Pal/src/db_streams.c @@ -157,6 +157,11 @@ int _DkStreamOpen(PAL_HANDLE* handle, const char* uri, int access, int share, in struct handle_ops* ops = NULL; char* type = NULL; + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); + int ret = parse_stream_uri(&uri, &type, &ops); if (ret < 0) return ret; @@ -169,13 +174,17 @@ int _DkStreamOpen(PAL_HANDLE* handle, const char* uri, int access, int share, in /* PAL call DkStreamOpen: Open stream based on uri, as given access/share/ create/options flags. DkStreamOpen return a PAL_HANDLE to access the - stream, or return NULL. Error code is notified. */ -PAL_HANDLE -DkStreamOpen(PAL_STR uri, PAL_FLG access, PAL_FLG share, PAL_FLG create, PAL_FLG options) { + stream, or return NULL. Error code is notified. + + FIXME: Currently `share` must match 1-1 to Linux open() `mode` argument. This isn't really + portable and will cause problems when implementing other PALs. + */ +PAL_HANDLE DkStreamOpen(PAL_STR uri, PAL_FLG access, PAL_FLG share, PAL_FLG create, + PAL_FLG options) { ENTER_PAL_CALL(DkStreamOpen); PAL_HANDLE handle = NULL; - int ret = _DkStreamOpen(&handle, uri, access, share, create, options); + int ret = _DkStreamOpen(&handle, uri, access, share, create, options); if (ret < 0) { _DkRaiseFailure(-ret); @@ -221,6 +230,8 @@ DkStreamWaitForClient(PAL_HANDLE handle) { the stream. For example, file will be deleted, socket witll be disconnected, etc */ int _DkStreamDelete(PAL_HANDLE handle, int access) { + assert(access == 0 || access == PAL_DELETE_RD || access == PAL_DELETE_WR); + const struct handle_ops* ops = HANDLE_OPS(handle); if (!ops) @@ -371,8 +382,7 @@ int _DkStreamAttributesQuery(const char* uri, PAL_STREAM_ATTR* attr) { /* PAL call DkStreamAttributeQuery: query attribute of a stream by its URI, attr is memory given by user space. Return the pointer of attr if succeeded, or NULL if failed. Error code is notified */ -PAL_BOL -DkStreamAttributesQuery(PAL_STR uri, PAL_STREAM_ATTR* attr) { +PAL_BOL DkStreamAttributesQuery(PAL_STR uri, PAL_STREAM_ATTR* attr) { ENTER_PAL_CALL(DkStreamAttributesQuery); if (!uri || !attr) { @@ -410,8 +420,7 @@ int _DkStreamAttributesQueryByHandle(PAL_HANDLE hdl, PAL_STREAM_ATTR* attr) { /* PAL call DkStreamAttributesQueryByHandle: Query attribute of a stream by its handle, attr is memory given by user space. Return the pointer of attr if succeeded, or NULL if failed. Error code is notified */ -PAL_BOL -DkStreamAttributesQueryByHandle(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) { +PAL_BOL DkStreamAttributesQueryByHandle(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) { ENTER_PAL_CALL(DkStreamAttributesQueryByHandle); if (!handle || !attr) { @@ -432,8 +441,7 @@ DkStreamAttributesQueryByHandle(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) { /* PAL call DkStreamAttributesSetByHandle: Set attribute of a stream by its handle, attr is memory given by user space. Return the pointer of attr if succeeded, or NULL if failed. Error code is notified */ -PAL_BOL -DkStreamAttributesSetByHandle(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) { +PAL_BOL DkStreamAttributesSetByHandle(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) { ENTER_PAL_CALL(DkStreamAttributesSetByHandle); if (!handle || !attr) { @@ -507,6 +515,8 @@ int _DkStreamMap(PAL_HANDLE handle, void** paddr, int prot, uint64_t offset, uin void* addr = *paddr; int ret; + assert(WITHIN_MASK(prot, PAL_PROT_MASK)); + const struct handle_ops* ops = HANDLE_OPS(handle); if (!ops) @@ -526,8 +536,7 @@ int _DkStreamMap(PAL_HANDLE handle, void** paddr, int prot, uint64_t offset, uin space. prot/offset/size are the protection, offset and size of the memory mapping. Return the address if succeeded or NULL if failed. Error code is notified. */ -PAL_PTR -DkStreamMap(PAL_HANDLE handle, PAL_PTR addr, PAL_FLG prot, PAL_NUM offset, PAL_NUM size) { +PAL_PTR DkStreamMap(PAL_HANDLE handle, PAL_PTR addr, PAL_FLG prot, PAL_NUM offset, PAL_NUM size) { ENTER_PAL_CALL(DkStreamMap); void* map_addr = (void*)addr; @@ -598,8 +607,7 @@ int64_t _DkStreamSetLength(PAL_HANDLE handle, uint64_t length) { /* PAL call DkStreamSetLength: Truncate the stream at certain length. Return the length if succeeded or 0 if failed. Error code is notified. */ -PAL_NUM -DkStreamSetLength(PAL_HANDLE handle, PAL_NUM length) { +PAL_NUM DkStreamSetLength(PAL_HANDLE handle, PAL_NUM length) { PAL_NUM rv = 0; ENTER_PAL_CALL(DkStreamSetLength); diff --git a/Pal/src/host/Linux-SGX/db_devices.c b/Pal/src/host/Linux-SGX/db_devices.c index 74af24bd..8dced5b3 100644 --- a/Pal/src/host/Linux-SGX/db_devices.c +++ b/Pal/src/host/Linux-SGX/db_devices.c @@ -115,11 +115,16 @@ static int open_standard_term(PAL_HANDLE* handle, const char* param, int access) /* 'open' operation for terminal stream */ static int term_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share, int create, int options) { - if (strcmp_static(type, "tty")) - return -PAL_ERROR_INVAL; + __UNUSED(share); + __UNUSED(create); + __UNUSED(options); - if (!WITHIN_MASK(share, PAL_SHARE_MASK) || !WITHIN_MASK(create, PAL_CREATE_MASK) || - !WITHIN_MASK(options, PAL_OPTION_MASK)) + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); + + if (strcmp_static(type, "tty")) return -PAL_ERROR_INVAL; const char* term = NULL; diff --git a/Pal/src/host/Linux-SGX/db_files.c b/Pal/src/host/Linux-SGX/db_files.c index e9a87c31..c1ec34a2 100644 --- a/Pal/src/host/Linux-SGX/db_files.c +++ b/Pal/src/host/Linux-SGX/db_files.c @@ -29,6 +29,7 @@ #include "pal_debug.h" #include "pal_defs.h" #include "pal_error.h" +#include "pal_flags_conv.h" #include "pal_internal.h" #include "pal_linux.h" #include "pal_linux_defs.h" @@ -48,7 +49,10 @@ static int file_open(PAL_HANDLE* handle, const char* type, const char* uri, int if (strcmp_static(type, URI_TYPE_FILE)) return -PAL_ERROR_INVAL; /* try to do the real open */ - int fd = ocall_open(uri, access | create | options, share); + int fd = ocall_open(uri, PAL_ACCESS_TO_LINUX_OPEN(access) | + PAL_CREATE_TO_LINUX_OPEN(create) | + PAL_OPTION_TO_LINUX_OPEN(options), + share); if (IS_ERR(fd)) return unix_to_pal_error(ERRNO(fd)); @@ -184,7 +188,7 @@ static int file_map(PAL_HANDLE handle, void** addr, int prot, uint64_t offset, u * does not request a specific address. */ if (!mem && !stubs && !(prot & PAL_PROT_WRITECOPY)) { - ret = ocall_mmap_untrusted(handle->file.fd, offset, size, HOST_PROT(prot), &mem); + ret = ocall_mmap_untrusted(handle->file.fd, offset, size, PAL_PROT_TO_LINUX(prot), &mem); if (!IS_ERR(ret)) *addr = mem; return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : ret; @@ -394,13 +398,19 @@ static int dir_open(PAL_HANDLE* handle, const char* type, const char* uri, int a int ret; - if (create & PAL_CREATE_TRY) { + if (create & PAL_CREATE_TRY || create & PAL_CREATE_ALWAYS) { ret = ocall_mkdir(uri, share); - if (IS_ERR(ret) && ERRNO(ret) == EEXIST && create & PAL_CREATE_ALWAYS) - return -PAL_ERROR_STREAMEXIST; + + if (IS_ERR(ret)) { + if (ERRNO(ret) == EEXIST && create & PAL_CREATE_ALWAYS) + return -PAL_ERROR_STREAMEXIST; + if (ERRNO(ret) != EEXIST) + return unix_to_pal_error(ERRNO(ret)); + assert(ERRNO(ret) == EEXIST && create & PAL_CREATE_TRY); + } } - ret = ocall_open(uri, O_DIRECTORY | options, 0); + ret = ocall_open(uri, O_DIRECTORY | PAL_OPTION_TO_LINUX_OPEN(options), 0); if (IS_ERR(ret)) return unix_to_pal_error(ERRNO(ret)); diff --git a/Pal/src/host/Linux-SGX/db_memory.c b/Pal/src/host/Linux-SGX/db_memory.c index b6e2fb6a..8d951594 100644 --- a/Pal/src/host/Linux-SGX/db_memory.c +++ b/Pal/src/host/Linux-SGX/db_memory.c @@ -26,6 +26,7 @@ #include "pal_debug.h" #include "pal_defs.h" #include "pal_error.h" +#include "pal_flags_conv.h" #include "pal_internal.h" #include "pal_linux.h" #include "pal_linux_defs.h" @@ -47,7 +48,12 @@ bool _DkCheckMemoryMappable(const void* addr, size_t size) { } int _DkVirtualMemoryAlloc(void** paddr, uint64_t size, int alloc_type, int prot) { - if (!size || !WITHIN_MASK(prot, PAL_PROT_MASK)) + __UNUSED(prot); + + assert(WITHIN_MASK(alloc_type, PAL_ALLOC_MASK)); + assert(WITHIN_MASK(prot, PAL_PROT_MASK)); + + if (!size) return -PAL_ERROR_INVAL; void* addr = *paddr; @@ -85,6 +91,8 @@ int _DkVirtualMemoryProtect(void* addr, uint64_t size, int prot) { __UNUSED(size); __UNUSED(prot); + assert(WITHIN_MASK(prot, PAL_PROT_MASK)); + static struct atomic_int at_cnt = {.counter = 0}; if (atomic_cmpxchg(&at_cnt, 0, 1) == 0) SGX_DBG(DBG_M, "[Warning] DkVirtualMemoryProtect is unimplemented in Linux-SGX PAL"); diff --git a/Pal/src/host/Linux-SGX/db_sockets.c b/Pal/src/host/Linux-SGX/db_sockets.c index 750a8e85..973b5a80 100644 --- a/Pal/src/host/Linux-SGX/db_sockets.c +++ b/Pal/src/host/Linux-SGX/db_sockets.c @@ -436,9 +436,13 @@ static int tcp_connect(PAL_HANDLE* handle, char* uri, int options) { /* 'open' operation of tcp stream */ static int tcp_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share, int create, int options) { - if (!WITHIN_MASK(access, PAL_ACCESS_MASK) || !WITHIN_MASK(share, PAL_SHARE_MASK) || - !WITHIN_MASK(create, PAL_CREATE_MASK) || !WITHIN_MASK(options, PAL_OPTION_MASK)) - return -PAL_ERROR_INVAL; + __UNUSED(access); + __UNUSED(share); + + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); int uri_len = strlen(uri) + 1; @@ -589,9 +593,13 @@ static int udp_connect(PAL_HANDLE* handle, char* uri, int create, int options) { static int udp_open(PAL_HANDLE* hdl, const char* type, const char* uri, int access, int share, int create, int options) { - if (!WITHIN_MASK(access, PAL_ACCESS_MASK) || !WITHIN_MASK(share, PAL_SHARE_MASK) || - !WITHIN_MASK(create, PAL_CREATE_MASK) || !WITHIN_MASK(options, PAL_OPTION_MASK)) - return -PAL_ERROR_INVAL; + __UNUSED(access); + __UNUSED(share); + + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); char buf[PAL_SOCKADDR_SIZE]; int len = strlen(uri); diff --git a/Pal/src/host/Linux-SGX/pal_linux.h b/Pal/src/host/Linux-SGX/pal_linux.h index 9e58b6d3..5d660b9d 100644 --- a/Pal/src/host/Linux-SGX/pal_linux.h +++ b/Pal/src/host/Linux-SGX/pal_linux.h @@ -66,18 +66,7 @@ extern struct pal_linux_state { #define PRESET_PAGESIZE (1 << 12) -#define DEFAULT_BACKLOG 2048 - -static inline int HOST_FLAGS (int alloc_type, int prot) -{ - return ((alloc_type & PAL_ALLOC_RESERVE) ? MAP_NORESERVE|MAP_UNINITIALIZED : 0) | - ((prot & PAL_PROT_WRITECOPY) ? MAP_PRIVATE : MAP_SHARED); -} - -static inline int HOST_PROT (int prot) -{ - return prot & (PAL_PROT_READ|PAL_PROT_WRITE|PAL_PROT_EXEC); -} +#define DEFAULT_BACKLOG 2048 #define ACCESS_R 4 #define ACCESS_W 2 diff --git a/Pal/src/host/Linux-SGX/sgx_enclave.c b/Pal/src/host/Linux-SGX/sgx_enclave.c index 82d8853a..1120e32c 100644 --- a/Pal/src/host/Linux-SGX/sgx_enclave.c +++ b/Pal/src/host/Linux-SGX/sgx_enclave.c @@ -114,13 +114,13 @@ static long sgx_ocall_cpuid(void * pms) return 0; } -static long sgx_ocall_open(void * pms) -{ - ms_ocall_open_t * ms = (ms_ocall_open_t *) pms; +static long sgx_ocall_open(void* pms) { + ms_ocall_open_t* ms = (ms_ocall_open_t*)pms; long ret; ODEBUG(OCALL_OPEN, ms); - ret = INLINE_SYSCALL(open, 3, ms->ms_pathname, ms->ms_flags|O_CLOEXEC, - ms->ms_mode); + // FIXME: No idea why someone hardcoded O_CLOEXEC here. We should drop it and carefully + // investigate if this cause any descriptor leaks. + ret = INLINE_SYSCALL(open, 3, ms->ms_pathname, ms->ms_flags | O_CLOEXEC, ms->ms_mode); return ret; } diff --git a/Pal/src/host/Linux/db_devices.c b/Pal/src/host/Linux/db_devices.c index da203772..6a48c7d7 100644 --- a/Pal/src/host/Linux/db_devices.c +++ b/Pal/src/host/Linux/db_devices.c @@ -113,12 +113,17 @@ static int open_standard_term(PAL_HANDLE* handle, const char* param, int access) /* 'open' operation for terminal stream */ static int term_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share, int create, int options) { + __UNUSED(share); + __UNUSED(create); + __UNUSED(options); + if (strcmp_static(type, "tty")) return -PAL_ERROR_INVAL; - if (!WITHIN_MASK(share, PAL_SHARE_MASK) || !WITHIN_MASK(create, PAL_CREATE_MASK) || - !WITHIN_MASK(options, PAL_OPTION_MASK)) - return -PAL_ERROR_INVAL; + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); const char* term = NULL; const char* param = NULL; diff --git a/Pal/src/host/Linux/db_files.c b/Pal/src/host/Linux/db_files.c index 567145f4..e4f0f14a 100644 --- a/Pal/src/host/Linux/db_files.c +++ b/Pal/src/host/Linux/db_files.c @@ -24,6 +24,7 @@ #include "pal_defs.h" #include "pal_linux_defs.h" #include "pal.h" +#include "pal_flags_conv.h" #include "pal_internal.h" #include "pal_linux.h" #include "pal_linux_error.h" @@ -43,8 +44,19 @@ static int file_open(PAL_HANDLE* handle, const char* type, const char* uri, int if (strcmp_static(type, URI_TYPE_FILE)) return -PAL_ERROR_INVAL; + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); + /* try to do the real open */ - int ret = INLINE_SYSCALL(open, 3, uri, HOST_ACCESS(access)|create|options|O_CLOEXEC, share); + // FIXME: No idea why someone hardcoded O_CLOEXEC here. We should drop it and carefully + // investigate if this causes any descriptor leaks. + int ret = INLINE_SYSCALL(open, 3, uri, PAL_ACCESS_TO_LINUX_OPEN(access) | + PAL_CREATE_TO_LINUX_OPEN(create) | + PAL_OPTION_TO_LINUX_OPEN(options) | + O_CLOEXEC, + share); if (IS_ERR(ret)) return unix_to_pal_error(ERRNO(ret)); @@ -124,11 +136,9 @@ static int file_delete (PAL_HANDLE handle, int access) } /* 'map' operation for file stream. */ -static int file_map (PAL_HANDLE handle, void ** addr, int prot, - uint64_t offset, uint64_t size) -{ +static int file_map(PAL_HANDLE handle, void** addr, int prot, uint64_t offset, uint64_t size) { int fd = handle->file.fd; - void * mem = *addr; + void* mem = *addr; /* * work around for fork emulation * the first exec image to be loaded has to be at same address @@ -139,12 +149,11 @@ static int file_map (PAL_HANDLE handle, void ** addr, int prot, /* this address is used. don't over-map it later */ handle->file.map_start = NULL; } - int flags = MAP_FILE|HOST_FLAGS(0, prot)|(mem ? MAP_FIXED : 0); - prot = HOST_PROT(prot); + int flags = MAP_FILE | PAL_MEM_FLAGS_TO_LINUX(0, prot) | (mem ? MAP_FIXED : 0); + prot = PAL_PROT_TO_LINUX(prot); - /* The memory will always allocated with flag MAP_PRIVATE - and MAP_FILE */ - mem = (void *) ARCH_MMAP(mem, size, prot, flags, fd, offset); + /* The memory will always be allocated with flag MAP_PRIVATE and MAP_FILE */ + mem = (void*)ARCH_MMAP(mem, size, prot, flags, fd, offset); if (IS_ERR_P(mem)) return -PAL_ERROR_DENIED; @@ -320,9 +329,8 @@ struct handle_ops file_ops = { /* 'open' operation for directory stream. Directory stream does not have a specific type prefix, its URI looks the same file streams, plus it ended with slashes. dir_open will be called by file_open. */ -static int dir_open (PAL_HANDLE * handle, const char * type, const char * uri, - int access, int share, int create, int options) -{ +static int dir_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share, + int create, int options) { if (strcmp_static(type, URI_TYPE_DIR)) return -PAL_ERROR_INVAL; if (!WITHIN_MASK(access, PAL_ACCESS_MASK)) @@ -330,15 +338,20 @@ static int dir_open (PAL_HANDLE * handle, const char * type, const char * uri, int ret = 0; - if (create & PAL_CREATE_TRY) { + if (create & PAL_CREATE_TRY || create & PAL_CREATE_ALWAYS) { ret = INLINE_SYSCALL(mkdir, 2, uri, share); - if (IS_ERR(ret) && ERRNO(ret) == EEXIST && - create & PAL_CREATE_ALWAYS) - return -PAL_ERROR_STREAMEXIST; + if (IS_ERR(ret)) { + if (ERRNO(ret) == EEXIST && create & PAL_CREATE_ALWAYS) + return -PAL_ERROR_STREAMEXIST; + if (ERRNO(ret) != EEXIST) + return unix_to_pal_error(ERRNO(ret)); + assert(ERRNO(ret) == EEXIST && create & PAL_CREATE_TRY); + } } - ret = INLINE_SYSCALL(open, 3, uri, O_DIRECTORY|options|O_CLOEXEC, 0); + ret = INLINE_SYSCALL(open, 3, uri, O_DIRECTORY | PAL_OPTION_TO_LINUX_OPEN(options) | O_CLOEXEC, + 0); if (IS_ERR(ret)) return unix_to_pal_error(ERRNO(ret)); @@ -348,7 +361,7 @@ static int dir_open (PAL_HANDLE * handle, const char * type, const char * uri, SET_HANDLE_TYPE(hdl, dir); HANDLE_HDR(hdl)->flags |= RFD(0); hdl->dir.fd = ret; - char * path = (void *) hdl + HANDLE_SIZE(dir); + char* path = (void*)hdl + HANDLE_SIZE(dir); memcpy(path, uri, len + 1); hdl->dir.realpath = (PAL_STR) path; hdl->dir.buf = (PAL_PTR) NULL; diff --git a/Pal/src/host/Linux/db_main.c b/Pal/src/host/Linux/db_main.c index 1d11e6cb..bbca1fe9 100644 --- a/Pal/src/host/Linux/db_main.c +++ b/Pal/src/host/Linux/db_main.c @@ -285,8 +285,7 @@ void pal_linux_main(void* initial_rsp, void* fini_callback) { INIT_FAIL(PAL_ERROR_NOMEM, "Out of memory"); snprintf(uri, size, URI_PREFIX_FILE "%s", exec_target); PAL_HANDLE file; - // FIXME: `options` should be `PAL_OPTION_CLOEXEC`, but _DkStreamOpen is totally broken. - int ret = _DkStreamOpen(&file, uri, PAL_ACCESS_RDONLY, 0, 0, 0); + int ret = _DkStreamOpen(&file, uri, PAL_ACCESS_RDONLY, 0, 0, PAL_OPTION_CLOEXEC); free(uri); if (ret < 0) INIT_FAIL(-ret, "Failed to open file to execute"); diff --git a/Pal/src/host/Linux/db_memory.c b/Pal/src/host/Linux/db_memory.c index d8604a4d..186d2dfa 100644 --- a/Pal/src/host/Linux/db_memory.c +++ b/Pal/src/host/Linux/db_memory.c @@ -20,33 +20,35 @@ * This files contains APIs that allocate, free or protect virtual memory. */ -#include "pal_defs.h" -#include "pal_linux_defs.h" +#include "api.h" #include "pal.h" +#include "pal_debug.h" +#include "pal_defs.h" +#include "pal_error.h" +#include "pal_flags_conv.h" #include "pal_internal.h" #include "pal_linux.h" -#include "pal_error.h" -#include "pal_debug.h" -#include "api.h" +#include "pal_linux_defs.h" -#include #include +#include -bool _DkCheckMemoryMappable (const void * addr, size_t size) -{ +bool _DkCheckMemoryMappable(const void* addr, size_t size) { return (addr < DATA_END && addr + size > TEXT_START); } -int _DkVirtualMemoryAlloc (void ** paddr, size_t size, int alloc_type, - int prot) -{ - void * addr = *paddr, * mem = addr; +int _DkVirtualMemoryAlloc(void** paddr, size_t size, int alloc_type, int prot) { + assert(WITHIN_MASK(alloc_type, PAL_ALLOC_MASK)); + assert(WITHIN_MASK(prot, PAL_PROT_MASK)); - int flags = HOST_FLAGS(alloc_type, prot|PAL_PROT_WRITECOPY); - prot = HOST_PROT(prot); + void* addr = *paddr; + void* mem = addr; - flags |= MAP_ANONYMOUS|(addr ? MAP_FIXED : 0); - mem = (void *) ARCH_MMAP(addr, size, prot, flags, -1, 0); + int flags = PAL_MEM_FLAGS_TO_LINUX(alloc_type, prot | PAL_PROT_WRITECOPY); + prot = PAL_PROT_TO_LINUX(prot); + + flags |= MAP_ANONYMOUS | (addr ? MAP_FIXED : 0); + mem = (void*)ARCH_MMAP(addr, size, prot, flags, -1, 0); if (IS_ERR_P(mem)) return unix_to_pal_error(ERRNO_P(mem)); @@ -62,10 +64,8 @@ int _DkVirtualMemoryFree (void * addr, size_t size) return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : 0; } -int _DkVirtualMemoryProtect (void * addr, size_t size, int prot) -{ - int ret = INLINE_SYSCALL(mprotect, 3, addr, size, HOST_PROT(prot)); - +int _DkVirtualMemoryProtect(void* addr, size_t size, int prot) { + int ret = INLINE_SYSCALL(mprotect, 3, addr, size, PAL_PROT_TO_LINUX(prot)); return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : 0; } diff --git a/Pal/src/host/Linux/db_sockets.c b/Pal/src/host/Linux/db_sockets.c index eb63dc66..ebe5a09a 100644 --- a/Pal/src/host/Linux/db_sockets.c +++ b/Pal/src/host/Linux/db_sockets.c @@ -339,7 +339,9 @@ static int tcp_listen(PAL_HANDLE* handle, char* uri, int create, int options) { return -PAL_ERROR_INVAL; #endif - fd = INLINE_SYSCALL(socket, 3, bind_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC | options, 0); + int sock_options = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0; + fd = INLINE_SYSCALL(socket, 3, bind_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC | sock_options, + 0); if (IS_ERR(fd)) return -PAL_ERROR_DENIED; @@ -411,7 +413,7 @@ static int tcp_accept(PAL_HANDLE handle, PAL_HANDLE* client) { socklen_t addrlen = sizeof(struct sockaddr); int ret = 0; - int newfd = INLINE_SYSCALL(accept4, 4, handle->sock.fd, &buffer, &addrlen, O_CLOEXEC); + int newfd = INLINE_SYSCALL(accept4, 4, handle->sock.fd, &buffer, &addrlen, SOCK_CLOEXEC); if (IS_ERR(newfd)) switch (ERRNO(newfd)) { @@ -460,7 +462,9 @@ static int tcp_connect(PAL_HANDLE* handle, char* uri, int options) { if (bind_addr && bind_addr->sa_family != dest_addr->sa_family) return -PAL_ERROR_INVAL; - fd = INLINE_SYSCALL(socket, 3, dest_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC | options, 0); + int sock_options = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0; + fd = INLINE_SYSCALL(socket, 3, dest_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC | sock_options, + 0); if (IS_ERR(fd)) return -PAL_ERROR_DENIED; @@ -521,9 +525,13 @@ failed: /* 'open' operation of tcp stream */ static int tcp_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share, int create, int options) { - if (!WITHIN_MASK(access, PAL_ACCESS_MASK) || !WITHIN_MASK(share, PAL_SHARE_MASK) || - !WITHIN_MASK(create, PAL_CREATE_MASK)) - return -PAL_ERROR_INVAL; + __UNUSED(access); + __UNUSED(share); + + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); size_t uri_len = strlen(uri) + 1; @@ -626,7 +634,9 @@ static int udp_bind(PAL_HANDLE* handle, char* uri, int create, int options) { return -PAL_ERROR_INVAL; #endif - fd = INLINE_SYSCALL(socket, 3, bind_addr->sa_family, SOCK_DGRAM | SOCK_CLOEXEC | options, 0); + int sock_options = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0; + fd = INLINE_SYSCALL(socket, 3, bind_addr->sa_family, SOCK_DGRAM | SOCK_CLOEXEC | sock_options, + 0); if (IS_ERR(fd)) return -PAL_ERROR_DENIED; @@ -687,8 +697,9 @@ static int udp_connect(PAL_HANDLE* handle, char* uri, int create, int options) { return -PAL_ERROR_INVAL; #endif + int sock_options = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0; fd = INLINE_SYSCALL(socket, 3, dest_addr ? dest_addr->sa_family : AF_INET, - SOCK_DGRAM | SOCK_CLOEXEC | options, 0); + SOCK_DGRAM | SOCK_CLOEXEC | sock_options, 0); if (IS_ERR(fd)) return -PAL_ERROR_DENIED; @@ -737,9 +748,13 @@ failed: static int udp_open(PAL_HANDLE* hdl, const char* type, const char* uri, int access, int share, int create, int options) { - if (!WITHIN_MASK(access, PAL_ACCESS_MASK) || !WITHIN_MASK(share, PAL_SHARE_MASK) || - !WITHIN_MASK(create, PAL_CREATE_MASK) || !WITHIN_MASK(options, PAL_OPTION_MASK)) - return -PAL_ERROR_INVAL; + __UNUSED(access); + __UNUSED(share); + + assert(WITHIN_MASK(access, PAL_ACCESS_MASK)); + assert(WITHIN_MASK(share, PAL_SHARE_MASK)); + assert(WITHIN_MASK(create, PAL_CREATE_MASK)); + assert(WITHIN_MASK(options, PAL_OPTION_MASK)); char buf[PAL_SOCKADDR_SIZE]; size_t len = strlen(uri); diff --git a/Pal/src/host/Linux/pal_linux.h b/Pal/src/host/Linux/pal_linux.h index a330634b..4ee8d563 100644 --- a/Pal/src/host/Linux/pal_linux.h +++ b/Pal/src/host/Linux/pal_linux.h @@ -122,24 +122,7 @@ extern struct pal_linux_state { #define PRESET_PAGESIZE (1 << 12) -#define DEFAULT_BACKLOG 2048 - -static inline int HOST_FLAGS (int alloc_type, int prot) -{ - return ((alloc_type & PAL_ALLOC_RESERVE) ? MAP_NORESERVE|MAP_UNINITIALIZED : 0) | - ((prot & PAL_PROT_WRITECOPY) ? MAP_PRIVATE : MAP_SHARED); -} - -static inline int HOST_PROT (int prot) -{ - return prot & (PAL_PROT_READ|PAL_PROT_WRITE|PAL_PROT_EXEC); -} - -static inline int HOST_ACCESS (int access) -{ - return (access & (PAL_ACCESS_RDONLY|PAL_ACCESS_WRONLY|PAL_ACCESS_RDWR)) | - ((access & PAL_ACCESS_APPEND) ? O_APPEND|O_WRONLY : 0); -} +#define DEFAULT_BACKLOG 2048 int clone (int (*__fn) (void * __arg), void * __child_stack, int __flags, const void * __arg, ...); diff --git a/Pal/src/pal_internal.h b/Pal/src/pal_internal.h index ba3ff85f..46c76576 100644 --- a/Pal/src/pal_internal.h +++ b/Pal/src/pal_internal.h @@ -226,8 +226,8 @@ int _DkGetCPUInfo (PAL_CPU_INFO * info); /* Internal DK calls, in case any of the internal routines needs to use them */ /* DkStream calls */ -int _DkStreamOpen (PAL_HANDLE * handle, const char * uri, - int access, int share, int create, int options); +int _DkStreamOpen(PAL_HANDLE* handle, const char* uri, int access, int share, int create, + int options); int _DkStreamDelete (PAL_HANDLE handle, int access); int64_t _DkStreamRead (PAL_HANDLE handle, uint64_t offset, uint64_t count, void * buf, char * addr, int addrlen);