Browse Source

Detecting invalid user memory given as system call inputs (#210)

* Detecting invalid user memory given as system call inputs

* Fixing the test for invalid socket address sizes

* Fixing accept return code - return -EINVAL for any invalid addr buffer

* add more test_user_memory() and test_user_string()

* sigaction and sigprocmask allow NULL arguments

* fix an assertion in sigaction

* fix connection failure for lighttpd

* fix for accept4 error code

* fix a bug for sendmsg

* fixing connect() error code

* add more ltp tests to the PASSED list

* fix a memory bug in test_user_memory()

* Handle the corner case that an IPC port may remain opened after the record is deleted and cause hanging of IPC senders

* Fixing more error code related bugs; resurrecting LTP tests from the BLOCKED list

* Add comments for test_user_memory() and test_user_string(); disable preemption inside the two helper functions

* Fixing some race coniditions; map->lock is not properly unlocked in poll() system call

* remove preadv and pwritev from PASSED list

* fixing a bug causing object allocation to fail in the library OS

* adding comments for the memory barrier in shim_ipc.c and shim_ipc_helper.c

* adding a comment for the new field in shim_tcb

* update the reference of lmbench-2.5

* Fixing some error code in read(), write(), pread(), pwrite(), readv(), and writev()

* adding some passed LTP tests
Chia-Che Tsai 5 years ago
parent
commit
e01769337c

+ 1 - 0
LibOS/shim/include/shim_fs.h

@@ -228,6 +228,7 @@ struct shim_d_ops {
 };
 
 #define MAX_PATH        4096
+#define MAX_FILENAME    255
 
 DEFINE_LIST(shim_mount);
 struct shim_mount {

+ 3 - 0
LibOS/shim/include/shim_internal.h

@@ -760,4 +760,7 @@ int init_internal_map (void);
 int init_loader (void);
 int init_manifest (PAL_HANDLE manifest_handle);
 
+bool test_user_memory (void * addr, size_t size, bool write);
+bool test_user_string (const char * addr);
+
 #endif /* _PAL_INTERNAL_H_ */

+ 1 - 1
LibOS/shim/include/shim_ipc.h

@@ -101,7 +101,7 @@ struct shim_ipc_port {
 
     port_fini           fini[MAX_IPC_PORT_FINI_CB];
 
-    bool                update, recent;
+    bool                update, recent, deleted;
     struct {
         unsigned int    type;
         IDTYPE          vmid;

+ 8 - 0
LibOS/shim/include/shim_tls.h

@@ -73,6 +73,14 @@ typedef struct {
     void *                  debug_buf;
     int                     last_lock;
     struct lock_record      held_locks[NUM_LOCK_RECORD];
+
+    /* This record is for testing the memory of user inputs.
+     * If a segfault occurs with the range [start, end],
+     * the code addr is set to cont_addr to alert the caller. */
+    struct {
+        void * start, * end;
+        void * cont_addr;
+    } test_range;
 } shim_tcb_t;
 
 #ifdef IN_SHIM

+ 111 - 1
LibOS/shim/src/bookkeep/shim_signal.c

@@ -54,7 +54,8 @@ allocate_signal_log (struct shim_thread * thread, int sig)
         tail = (tail == MAX_SIGNAL_LOG - 1) ? 0 : tail + 1;
     } while (atomic_cmpxchg(&log->tail, old_tail, tail) == tail);
 
-    debug("signal_logs[%d]: head=%d, tail=%d\n", sig -1, head, tail);
+    debug("signal_logs[%d]: head=%d, tail=%d (counter = %d)\n", sig - 1,
+          head, tail, thread->has_signal.counter + 1);
 
     atomic_inc(&thread->has_signal);
 
@@ -246,6 +247,15 @@ ret_exception:
 
 static void memfault_upcall (PAL_PTR event, PAL_NUM arg, PAL_CONTEXT * context)
 {
+    shim_tcb_t * tcb = SHIM_GET_TLS();
+    if (tcb->test_range.cont_addr && arg
+        && (void *) arg >= tcb->test_range.start
+        && (void *) arg <= tcb->test_range.end) {
+        assert(context);
+        context->rip = (PAL_NUM) tcb->test_range.cont_addr;
+        goto ret_exception;
+    }
+
     if (IS_INTERNAL_TID(get_cur_tid()) || is_internal(context)) {
 internal:
         internal_fault("Internal memory fault", arg, context);
@@ -295,6 +305,102 @@ ret_exception:
     DkExceptionReturn(event);
 }
 
+/*
+ * 'test_user_memory' and 'test_user_string' are helper functions for testing
+ * if a user-given buffer or data structure is readable / writable (according
+ * to the system call semantics). If the memory test fails, the system call
+ * should return -EFAULT or -EINVAL accordingly. These helper functions cannot
+ * guarantee further corruption of the buffer, or if the buffer is unmapped
+ * with a concurrent system call. The purpose of these functions is simply for
+ * the compatibility with programs that rely on the error numbers, such as the
+ * LTP test suite.
+ */
+bool test_user_memory (void * addr, size_t size, bool write)
+{
+    if (!size)
+        return false;
+
+    shim_tcb_t * tcb = SHIM_GET_TLS();
+    assert(tcb && tcb->tp);
+    __disable_preempt(tcb);
+
+    if (addr + size - 1 < addr)
+        size = (void *) 0x0 - addr;
+
+    bool has_fault = true;
+
+    /* Add the memory region to the watch list. This is not racy because
+     * each thread has its own record. */
+    assert(!tcb->test_range.cont_addr);
+    tcb->test_range.cont_addr = &&ret_fault;
+    tcb->test_range.start = addr;
+    tcb->test_range.end = addr + size - 1;
+
+    /* Try to read or write into one byte inside each page */
+    void * tmp = addr;
+    while (tmp <= addr + size - 1) {
+        if (write) {
+            *(volatile char *) tmp = *(volatile char *) tmp;
+        } else {
+            *(volatile char *) tmp;
+        }
+        tmp = ALIGN_UP(tmp + 1);
+    }
+
+    has_fault = false; /* All accesses have passed. Nothing wrong. */
+
+ret_fault:
+    /* If any read or write into the target region causes an exception,
+     * the control flow will immediately jump to here. */
+    tcb->test_range.cont_addr = NULL;
+    tcb->test_range.start = tcb->test_range.end = NULL;
+    __enable_preempt(tcb);
+    return has_fault;
+}
+
+/*
+ * This function tests a user string with unknown length. It only tests
+ * whether the memory is readable.
+ */
+bool test_user_string (const char * addr)
+{
+    shim_tcb_t * tcb = SHIM_GET_TLS();
+    assert(tcb && tcb->tp);
+    __disable_preempt(tcb);
+
+    bool has_fault = true;
+
+    assert(!tcb->test_range.cont_addr);
+    tcb->test_range.cont_addr = &&ret_fault;
+
+    /* Test one page at a time. */
+    const char * next = ALIGN_UP(addr + 1);
+    do {
+        /* Add the memory region to the watch list. This is not racy because
+         * each thread has its own record. */
+        tcb->test_range.start = (void *) addr;
+        tcb->test_range.end = (void *) (next - 1);
+        *(volatile char *) addr; /* try to read one byte from the page */
+
+        /* If the string ends in this page, exit the loop. */
+        if (strnlen(addr, next - addr) < next - addr)
+            break;
+
+        addr = next;
+        next = ALIGN_UP(addr + 1);
+    } while (addr < next);
+
+    has_fault = false; /* All accesses have passed. Nothing wrong. */
+
+ret_fault:
+    /* If any read or write into the target region causes an exception,
+     * the control flow will immediately jump to here. */
+    tcb->test_range.cont_addr = NULL;
+    tcb->test_range.start = tcb->test_range.end = NULL;
+    __enable_preempt(tcb);
+    return has_fault;
+}
+
 static void illegal_upcall (PAL_PTR event, PAL_NUM arg, PAL_CONTEXT * context)
 {
     if (IS_INTERNAL_TID(get_cur_tid()) || is_internal(context)) {
@@ -514,6 +620,8 @@ void handle_signal (bool delayed_only)
 
     struct shim_thread * thread = (struct shim_thread *) tcb->tp;
 
+    debug("handle signal (counter = %d)\n", thread->has_signal.counter);
+
     /* Fast path */
     if (!thread->has_signal.counter)
         return;
@@ -521,6 +629,7 @@ void handle_signal (bool delayed_only)
     __disable_preempt(tcb);
 
     if ((tcb->context.preempt & ~SIGNAL_DELAYED) > 1) {
+        debug("signal delayed (%d)\n", tcb->context.preempt & ~SIGNAL_DELAYED);
         tcb->context.preempt |= SIGNAL_DELAYED;
         goto out;
     }
@@ -531,6 +640,7 @@ void handle_signal (bool delayed_only)
     __handle_signal(tcb, 0, NULL);
 out:
     __enable_preempt(tcb);
+    debug("__enable_preempt: %s:%d\n", __FILE__, __LINE__);
 }
 
 void append_signal (struct shim_thread * thread, int sig, siginfo_t * info,

+ 1 - 0
LibOS/shim/src/bookkeep/shim_thread.c

@@ -500,6 +500,7 @@ relock:
     listp_for_each_entry_safe(tmp, n, &thread_list, list) {
         if (tmp->tid <= min_tid)
             continue;
+
         bool unlocked = false;
         ret = (*callback) (tmp, arg, &unlocked);
         if (ret < 0 && ret != -ESRCH) {

+ 10 - 0
LibOS/shim/src/fs/chroot/fs.c

@@ -786,6 +786,11 @@ static int chroot_read (struct shim_handle * hdl, void * buf,
         goto out;
     }
 
+    if (!(hdl->acc_mode & MAY_READ)) {
+        ret = -EBADF;
+        goto out;
+    }
+
     struct shim_file_handle * file = &hdl->info.file;
 
     if (file->buf_type == FILEBUF_MAP) {
@@ -822,6 +827,11 @@ static int chroot_write (struct shim_handle * hdl, const void * buf,
         goto out;
     }
 
+    if (!(hdl->acc_mode & MAY_WRITE)) {
+        ret = -EBADF;
+        goto out;
+    }
+
     struct shim_file_handle * file = &hdl->info.file;
 
     if (hdl->info.file.buf_type == FILEBUF_MAP) {

+ 5 - 0
LibOS/shim/src/fs/shim_namei.c

@@ -311,6 +311,11 @@ int __path_lookupat (struct shim_dentry * start, const char * path, int flags,
             my_pathlen++;
         }
 
+        if (my_pathlen > MAX_FILENAME) {
+            err = -ENAMETOOLONG;
+            goto out;
+        }
+
         /* Handle . */
         if (my_pathlen == 1 && *path == '.') {
             /* For the recursion to work, we need to do the following:

+ 1 - 2
LibOS/shim/src/fs/socket/fs.c

@@ -218,7 +218,6 @@ static int socket_poll (struct shim_handle * hdl, int poll_type)
 
     PAL_STREAM_ATTR attr;
     if (!DkStreamAttributesQuerybyHandle(hdl->pal_handle, &attr)) {
-        debug("socket_poll: Setting -PAL_ERRNO %d\n", PAL_ERRNO);
         ret = -PAL_ERRNO;
         goto out;
     }
@@ -238,7 +237,7 @@ static int socket_poll (struct shim_handle * hdl, int poll_type)
 
 out:
     if (ret < 0) {
-        debug("Setting sock error %d\n", ret);
+        debug("socket_poll failed (%d)\n", ret);
         sock->error = -ret;
     }
 

+ 14 - 2
LibOS/shim/src/ipc/shim_ipc.c

@@ -368,11 +368,23 @@ int send_ipc_message (struct shim_ipc_msg * msg, struct shim_ipc_port * port)
     assert(msg->size >= IPC_MSG_MINIMAL_SIZE);
     msg->src = cur_process.vmid;
 
-    int ret = DkStreamWrite(port->pal_handle, 0, msg->size, msg, NULL);
+    debug("send ipc message to port %p (handle %p)\n", port,
+          port->pal_handle);
+
+    PAL_HANDLE pal_handle = port->pal_handle;
+
+    /* Read memory barrier needed here to ensure pal_handle is alive
+     * if port->deleted is not true. */
+    rmb();
+
+    if (port->deleted)
+        return -ECONNRESET;
+
+    int ret = DkStreamWrite(pal_handle, 0, msg->size, msg, NULL);
 
     if (ret == 0 && PAL_NATIVE_ERRNO) {
         debug("port %p (handle %p) is removed at sending\n", port,
-              port->pal_handle);
+              pal_handle);
 
         del_ipc_port_fini(port, -ECHILD);
         return -PAL_ERRNO;

+ 10 - 4
LibOS/shim/src/ipc/shim_ipc_helper.c

@@ -309,8 +309,10 @@ static struct shim_ipc_port * __get_new_ipc_port (PAL_HANDLE hdl)
                 get_mem_obj_from_mgr_enlarge(port_mgr,
                                              size_align_up(PORT_MGR_ALLOC));
 
-    if (!port)
+    if (!port) {
+        debug("failed to allocate shim_ipc_port\n");
         return NULL;
+    }
 
     memset(port, 0, sizeof(struct shim_ipc_port));
     port->pal_handle = hdl;
@@ -378,6 +380,9 @@ static bool __del_ipc_port (struct shim_ipc_port * port, int type)
     bool need_restart = false;
     type = type ? (type & port->info.type) : port->info.type;
 
+    port->deleted = true; /* prevent further usage of the port */
+    wmb(); /* commit the state to the memory */
+
     if ((type & IPC_PORT_KEEPALIVE) ^
         (port->info.type & IPC_PORT_KEEPALIVE))
         need_restart = true;
@@ -476,8 +481,10 @@ void del_ipc_port_fini (struct shim_ipc_port * port, unsigned int exitcode)
         listp_for_each_entry_safe(msg, n, &port->msgs, list) {
             listp_del_init(msg, &port->msgs, list);
             msg->retval = -ECONNRESET;
-            if (msg->thread)
+            if (msg->thread) {
+                debug("wake up thread %d\n", msg->thread->tid);
                 thread_wakeup(msg->thread);
+            }
         }
     }
 
@@ -829,9 +836,8 @@ static void shim_ipc_helper (void * arg)
            nalive) {
         /* do a global poll on all the ports */
         polled = DkObjectsWaitAny(port_num + 1, local_ports, NO_TIMEOUT);
-
         barrier();
-        
+
         if (!polled)
             continue;
 

+ 7 - 7
LibOS/shim/src/ipc/shim_ipc_pid.c

@@ -135,7 +135,7 @@ int ipc_pid_kill_callback (IPC_CALLBACK_ARGS)
     struct shim_ipc_pid_kill * msgin =
             (struct shim_ipc_pid_kill *) msg->msg;
 
-    debug("ipc callback form %u: IPC_PID_KILL(%u, %u, %d)\n",
+    debug("ipc callback from %u: IPC_PID_KILL(%u, %u, %d)\n",
           msg->src, msgin->sender, msgin->id, msgin->signum);
 
     int ret = 0;
@@ -201,7 +201,7 @@ int ipc_pid_getstatus_callback (IPC_CALLBACK_ARGS)
                             (struct shim_ipc_pid_getstatus *) msg->msg;
     int ret = 0;
 
-    debug("ipc callback form %u: IPC_PID_GETSTATUS(%d, [%u, ...])\n",
+    debug("ipc callback from %u: IPC_PID_GETSTATUS(%d, [%u, ...])\n",
           msg->src, msgin->npids, msgin->pids[0]);
 
     struct thread_status {
@@ -287,10 +287,10 @@ int ipc_pid_retstatus_callback (IPC_CALLBACK_ARGS)
                             (struct shim_ipc_pid_retstatus *) msg->msg;
 
     if (msgin->nstatus)
-        debug("ipc callback form %u: IPC_PID_RETSTATUS(%d, [%u, ...])\n",
+        debug("ipc callback from %u: IPC_PID_RETSTATUS(%d, [%u, ...])\n",
               msg->src, msgin->nstatus, msgin->status[0].pid);
     else
-        debug("ipc callback form %u: IPC_PID_RETSTATUS(0, [])\n", msg->src);
+        debug("ipc callback from %u: IPC_PID_RETSTATUS(0, [])\n", msg->src);
 
 
     struct shim_ipc_msg_obj * obj = find_ipc_msg_duplex(port, msg->seq);
@@ -511,7 +511,7 @@ int ipc_pid_getmeta_callback (IPC_CALLBACK_ARGS)
                             (struct shim_ipc_pid_getmeta *) msg->msg;
     int ret = 0;
 
-    debug("ipc callback form %u: IPC_PID_GETMETA(%u, %s)\n", msg->src,
+    debug("ipc callback from %u: IPC_PID_GETMETA(%u, %s)\n", msg->src,
           msgin->pid, pid_meta_code_str[msgin->code]);
 
     struct shim_thread * thread = lookup_thread(msgin->pid);
@@ -610,7 +610,7 @@ int ipc_pid_retmeta_callback (IPC_CALLBACK_ARGS)
     struct shim_ipc_pid_retmeta * msgin =
                             (struct shim_ipc_pid_retmeta *) msg->msg;
 
-    debug("ipc callback form %u: IPC_PID_RETMETA(%u, %s, %d)\n", msg->src,
+    debug("ipc callback from %u: IPC_PID_RETMETA(%u, %s, %d)\n", msg->src,
           msgin->pid, pid_meta_code_str[msgin->code], msgin->datasize);
 
     struct shim_ipc_msg_obj * obj = find_ipc_msg_duplex(port, msg->seq);
@@ -675,7 +675,7 @@ int ipc_pid_nop_callback (IPC_CALLBACK_ARGS)
     struct shim_ipc_pid_nop * msgin =
                         (struct shim_ipc_pid_nop *) &msg->msg;
 
-    debug("ipc callback form %u: IPC_PID_NOP(%d)\n", msg->src,
+    debug("ipc callback from %u: IPC_PID_NOP(%d)\n", msg->src,
           msgin->count);
 
     if (!(--msgin->count)) {

+ 18 - 9
LibOS/shim/src/shim_malloc.c

@@ -61,7 +61,7 @@ DEFINE_PROFILE_CATAGORY(memory, );
 void * __system_malloc (size_t size)
 {
     size_t alloc_size = ALIGN_UP(size);
-    void * addr;
+    void * addr, * ret_addr;
     int flags = MAP_PRIVATE|MAP_ANONYMOUS|VMA_INTERNAL;
 
     /*
@@ -77,14 +77,23 @@ void * __system_malloc (size_t size)
     if (!addr)
         return NULL;
 
-    void * ret_addr = DkVirtualMemoryAlloc(addr, alloc_size, 0,
-                                           PAL_PROT_WRITE|PAL_PROT_READ);
-
-    if (!ret_addr) {
-        bkeep_munmap(addr, alloc_size, flags);
-        return NULL;
-    }
-
+    do {
+        ret_addr = DkVirtualMemoryAlloc(addr, alloc_size, 0,
+                                        PAL_PROT_WRITE|PAL_PROT_READ);
+
+        if (!ret_addr) {
+            /* If the allocation is interrupted by signal, try to handle the
+             * signal and then retry the allocation. */
+            if (PAL_NATIVE_ERRNO == PAL_ERROR_INTERRUPTED) {
+                handle_signal(true);
+                continue;
+            }
+
+            debug("failed to allocate memory (%d)\n", -PAL_ERRNO);
+            bkeep_munmap(addr, alloc_size, flags);
+            return NULL;
+        }
+    } while (!ret_addr);
     assert(addr == ret_addr);
     return addr;
 }

+ 1 - 1
LibOS/shim/src/shim_parser.c

@@ -118,7 +118,7 @@ struct parser_table {
     { .slow = 0, .parser = { NULL } }, /* shmctl */
     { .slow = 0, .parser = { NULL } }, /* dup */
     { .slow = 0, .parser = { NULL } }, /* dup2 */
-    { .slow = 0, .parser = { NULL } }, /* pause */
+    { .slow = 1, .parser = { NULL } }, /* pause */
     { .slow = 1,
       .parser = { &parse_timespec } }, /* nanosleep */
     { .slow = 0, .parser = { NULL } }, /* getitimer */

+ 6 - 0
LibOS/shim/src/sys/shim_access.c

@@ -40,6 +40,9 @@ int shim_do_access (const char * file, mode_t mode)
     if (!file)
         return -EINVAL;
 
+    if (test_user_string(file))
+        return -EFAULT;
+
     struct shim_dentry * dent = NULL;
     int ret = 0;
 
@@ -55,6 +58,9 @@ int shim_do_faccessat (int dfd, const char * filename, mode_t mode)
     if (!filename)
         return -EINVAL;
 
+    if (test_user_string(filename))
+        return -EFAULT;
+
     if (*filename == '/')
         return shim_do_access(filename, mode);
 

+ 6 - 0
LibOS/shim/src/sys/shim_alarm.c

@@ -81,6 +81,10 @@ int shim_do_setitimer (int which, struct __kernel_itimerval * value,
 
     if (!value)
         return -EFAULT;
+    if (test_user_memory(value, sizeof(*value), false))
+        return -EFAULT;
+    if (ovalue && test_user_memory(ovalue, sizeof(*ovalue), true))
+        return -EFAULT;
 
     unsigned long setup_time = DkSystemTimeQuery();
 
@@ -125,6 +129,8 @@ int shim_do_getitimer (int which, struct __kernel_itimerval * value)
 
     if (!value)
         return -EFAULT;
+    if (test_user_memory(value, sizeof(*value), true))
+        return -EFAULT;
 
     unsigned long setup_time = DkSystemTimeQuery();
 

+ 33 - 0
LibOS/shim/src/sys/shim_fs.c

@@ -49,6 +49,9 @@ int shim_do_unlink (const char * file)
     if (!file)
         return -EINVAL;
 
+    if (test_user_string(file))
+        return -EFAULT;
+
     struct shim_dentry * dent = NULL;
     int ret = 0;
 
@@ -78,6 +81,12 @@ int shim_do_unlinkat (int dfd, const char * pathname, int flag)
     if (!pathname)
         return -EINVAL;
 
+    if (test_user_string(pathname))
+        return -EFAULT;
+
+    if (flag & ~AT_REMOVEDIR)
+        return -EINVAL;
+
     if (*pathname == '/')
         return (flag & AT_REMOVEDIR) ? shim_do_rmdir(pathname) :
                shim_do_unlink(pathname);
@@ -133,6 +142,9 @@ int shim_do_mkdirat (int dfd, const char * pathname, int mode)
     if (!pathname)
         return -EINVAL;
 
+    if (test_user_string(pathname))
+        return -EFAULT;
+
     if (*pathname == '/')
         return shim_do_mkdir(pathname, mode);
 
@@ -154,6 +166,12 @@ int shim_do_rmdir (const char * pathname)
     int ret = 0;
     struct shim_dentry * dent = NULL;
 
+    if (!pathname)
+        return -EINVAL;
+
+    if (test_user_string(pathname))
+        return -EFAULT;
+
     if ((ret = path_lookupat(NULL, pathname, LOOKUP_OPEN|LOOKUP_DIRECTORY,
                              &dent, NULL)) < 0)
         return ret;
@@ -197,6 +215,9 @@ int shim_do_chmod (const char * path, mode_t mode)
     struct shim_dentry * dent = NULL;
     int ret = 0;
 
+    if (test_user_string(path))
+        return -EFAULT;
+
     if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
 
@@ -218,6 +239,9 @@ int shim_do_fchmodat (int dfd, const char * filename, mode_t mode)
     if (!filename)
         return -EINVAL;
 
+    if (test_user_string(filename))
+        return -EFAULT;
+
     if (*filename == '/')
         return shim_do_chmod(filename, mode);
 
@@ -272,6 +296,12 @@ int shim_do_chown (const char * path, uid_t uid, gid_t gid)
     struct shim_dentry * dent = NULL;
     int ret = 0;
 
+    if (!path)
+        return -EINVAL;
+
+    if (test_user_string(path))
+        return -EFAULT;
+
     if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
 
@@ -286,6 +316,9 @@ int shim_do_fchownat (int dfd, const char * filename, uid_t uid, gid_t gid,
     if (!filename)
         return -EINVAL;
 
+    if (test_user_string(filename))
+        return -EFAULT;
+
     if (*filename == '/')
         return shim_do_chown(filename, uid, gid);
 

+ 24 - 11
LibOS/shim/src/sys/shim_getcwd.c

@@ -35,14 +35,17 @@
 
 #include <errno.h>
 
+#ifndef ERANGE
+# define ERANGE 34
+#endif
+
 int shim_do_getcwd (char * buf, size_t len)
 {
-    int ret = 0;
+    if (!buf || !len)
+        return -EINVAL;
 
-    if (buf == NULL || len == 0) {
-        ret = -EINVAL;
-        goto out;
-    }
+    if (test_user_memory(buf, len, true))
+        return -EFAULT;
 
     struct shim_thread * thread = get_cur_thread();
     assert(thread);
@@ -52,14 +55,15 @@ int shim_do_getcwd (char * buf, size_t len)
     int plen;
     const char * path = dentry_get_path(cwd, true, &plen);
 
-    if (plen > len) {
+    int ret;
+    if (plen >= MAX_PATH) {
         ret = -ENAMETOOLONG;
-        goto out;
-    } else
+    } else if (plen + 1 > len) {
+        ret = -ERANGE;
+    } else {
         ret = plen;
-
-    memcpy(buf, path, plen + 1);
-out:
+        memcpy(buf, path, plen + 1);
+    }
     return ret;
 }
 
@@ -70,6 +74,15 @@ int shim_do_chdir (const char * filename)
     struct shim_dentry * dent = NULL;
     int ret;
 
+    if (!filename)
+        return -EINVAL;
+
+    if (test_user_string(filename))
+        return -EFAULT;
+
+    if (strnlen(filename, MAX_PATH + 1) == MAX_PATH + 1)
+        return -ENAMETOOLONG;
+
     if ((ret = path_lookupat(NULL, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
         return ret;
 

+ 34 - 3
LibOS/shim/src/sys/shim_open.c

@@ -61,9 +61,13 @@ 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 (!buf || test_user_memory(buf, count, true))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
+
     int ret = do_handle_read(hdl, buf, count);
     put_handle(hdl);
     return ret;
@@ -88,6 +92,9 @@ 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 (!buf || test_user_memory((void *) buf, count, false))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -99,7 +106,10 @@ 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 (!file || !(*file))
+    if (!file || test_user_string(file))
+        return -EFAULT;
+
+    if (file[0] == '\0')
         return -EINVAL;
 
     struct shim_handle * hdl = get_new_handle();
@@ -124,8 +134,8 @@ int shim_do_creat (const char * path, mode_t mode)
 
 int shim_do_openat (int dfd, const char * filename, int flags, int mode)
 {
-    if (!filename)
-        return -EINVAL;
+    if (!filename || test_user_string(filename))
+        return -EFAULT;
 
     if (*filename == '/')
         return shim_do_open(filename, flags, mode);
@@ -198,6 +208,12 @@ out:
 
 size_t shim_do_pread64 (int fd, char * buf, size_t count, loff_t pos)
 {
+    if (!buf || test_user_memory(buf, count, true))
+        return -EFAULT;
+
+    if (pos < 0)
+        return -EINVAL;
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -243,6 +259,12 @@ out:
 
 size_t shim_do_pwrite64 (int fd, char * buf, size_t count, loff_t pos)
 {
+    if (!buf || test_user_memory(buf, count, false))
+        return -EFAULT;
+
+    if (pos < 0)
+        return -EINVAL;
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -310,6 +332,9 @@ static inline int get_dirent_type (mode_t type)
 
 size_t shim_do_getdents (int fd, struct linux_dirent * buf, size_t count)
 {
+    if (!buf || test_user_memory(buf, count, true))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -415,6 +440,9 @@ out_no_unlock:
 
 size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count)
 {
+    if (!buf || test_user_memory(buf, count, true))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -546,6 +574,9 @@ int shim_do_truncate (const char * path, loff_t length)
     struct shim_dentry * dent = NULL;
     int ret = 0;
 
+    if (!path || test_user_string(path))
+        return -EFAULT;
+
     if ((ret = path_lookupat(NULL, path, 0, &dent, NULL)) < 0)
         return ret;
 

+ 4 - 4
LibOS/shim/src/sys/shim_pipe.c

@@ -79,8 +79,8 @@ err:
 
 int shim_do_pipe2 (int * filedes, int flags)
 {
-    if (!filedes)
-        return -EINVAL;
+    if (!filedes || test_user_memory(filedes, 2 * sizeof(int), true))
+        return -EFAULT;
 
     int ret = 0;
 
@@ -150,8 +150,8 @@ int shim_do_socketpair (int domain, int type, int protocol, int * sv)
     if (type != SOCK_STREAM)
         return -EPROTONOSUPPORT;
 
-    if (!sv)
-        return -EINVAL;
+    if (!sv || test_user_memory(sv, 2 * sizeof(int), true))
+        return -EFAULT;
 
     int ret = 0;
     struct shim_handle * hdl1 = get_new_handle();

+ 2 - 1
LibOS/shim/src/sys/shim_poll.c

@@ -218,6 +218,7 @@ no_op:
 
                 if (polled < 0) {
                     if (polled != -EAGAIN) {
+                        unlock(map->lock);
                         ret = polled;
                         goto done_polling;
                     }
@@ -278,7 +279,7 @@ done_finding:
         SAVE_PROFILE_INTERVAL(do_poll_update_bookkeeping);
     }
 
-    unlock(cur->handle_map->lock);
+    unlock(map->lock);
 
     SAVE_PROFILE_INTERVAL_SINCE(do_poll_first_loop, begin_time);
 

+ 18 - 0
LibOS/shim/src/sys/shim_sigaction.c

@@ -47,6 +47,12 @@ int shim_do_sigaction (int signum, const struct __kernel_sigaction * act,
         sigsetsize != sizeof(__sigset_t))
         return -EINVAL;
 
+    if (act && test_user_memory((void *) act, sizeof(*act), false))
+        return -EFAULT;
+
+    if (oldact && test_user_memory(oldact, sizeof(*oldact), false))
+        return -EFAULT;
+
     struct shim_thread * cur = get_cur_thread();
     int err = 0;
 
@@ -97,6 +103,12 @@ int shim_do_sigprocmask (int how, const __sigset_t * set, __sigset_t * oldset)
         how != SIG_SETMASK)
         return -EINVAL;
 
+    if (set && test_user_memory((void *) set, sizeof(*set), false))
+        return -EFAULT;
+
+    if (oldset && test_user_memory(oldset, sizeof(*oldset), false))
+        return -EFAULT;
+
     struct shim_thread * cur = get_cur_thread();
     int err = 0;
 
@@ -166,6 +178,9 @@ int shim_do_sigaltstack (const stack_t * ss, stack_t * oss)
 
 int shim_do_sigsuspend (const __sigset_t * mask)
 {
+    if (!mask || test_user_memory((void *) mask, sizeof(*mask), false))
+        return -EFAULT;
+
     __sigset_t * old, tmp;
     struct shim_thread * cur = get_cur_thread();
 
@@ -187,6 +202,9 @@ int shim_do_sigsuspend (const __sigset_t * mask)
 
 int shim_do_sigpending (__sigset_t * set, size_t sigsetsize)
 {
+    if (!set || test_user_memory(set, sizeof(*set), false))
+        return -EFAULT;
+
     struct shim_thread * cur = get_cur_thread();
 
     __sigemptyset(set);

+ 93 - 27
LibOS/shim/src/sys/shim_socket.c

@@ -67,6 +67,18 @@
 
 static int rebase_on_lo __attribute_migratable = -1;
 
+static int minimal_addrlen (int domain)
+{
+    switch(domain) {
+        case AF_INET:
+            return sizeof(struct sockaddr_in);
+        case AF_INET6:
+            return sizeof(struct sockaddr_in6);
+        default:
+            return sizeof(struct sockaddr);
+    }
+}
+
 static int init_port_rebase (void)
 {
     if (rebase_on_lo != -1)
@@ -326,26 +338,25 @@ static inline void unix_copy_addr (struct sockaddr * saddr,
     memcpy(un->sun_path, path, size + 1);
 }
 
-static bool inet_check_addr (int domain, struct sockaddr * addr, int addrlen)
+static int inet_check_addr (int domain, struct sockaddr * addr, int addrlen)
 {
     if (domain == AF_INET) {
-        if (addr->sa_family != AF_INET ||
-            addrlen != sizeof(struct sockaddr_in))
-            return false;
-        return true;
+        if (addr->sa_family != AF_INET)
+            return -EAFNOSUPPORT;
+        if (addrlen != sizeof(struct sockaddr_in))
+            return -EINVAL;
+        return 0;
     }
 
     if (domain == AF_INET6) {
         if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
-            return false;
-        if (addrlen != ((addr->sa_family == AF_INET) ?
-                        sizeof(struct sockaddr_in) :
-                        sizeof(struct sockaddr_in6)))
-            return false;
-        return true;
+            return -EAFNOSUPPORT;
+        if (addrlen != minimal_addrlen(addr->sa_family))
+            return -EINVAL;
+        return 0;
     }
 
-    return false;
+    return -EINVAL;
 }
 
 static int inet_copy_addr (int domain, struct sockaddr * saddr,
@@ -447,6 +458,9 @@ static int create_socket_uri (struct shim_handle * hdl)
 
 int shim_do_bind (int sockfd, struct sockaddr * addr, socklen_t addrlen)
 {
+    if (!addr || test_user_memory(addr, addrlen, false))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
     int ret = -EINVAL;
     if (!hdl)
@@ -496,7 +510,7 @@ int shim_do_bind (int sockfd, struct sockaddr * addr, socklen_t addrlen)
         sock->addr.un.dentry = dent;
 
     } else if (sock->domain == AF_INET || sock->domain == AF_INET6) {
-        if (!inet_check_addr(sock->domain, addr, addrlen))
+        if ((ret = inet_check_addr(sock->domain, addr, addrlen)) < 0)
             goto out;
         inet_save_addr(sock->domain, &sock->addr.in.bind, addr);
         inet_rebase_port(false, sock->domain, &sock->addr.in.bind, true);
@@ -698,6 +712,9 @@ out:
  */
 int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
 {
+    if (!addr || test_user_memory(addr, addrlen, false))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
 
     if (!hdl)
@@ -727,6 +744,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
         }
 
         debug("shim_connect: reconnect on a stream socket\n");
+        ret = -EISCONN;
         goto out;
     }
 
@@ -772,7 +790,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
     }
 
     if (sock->domain != AF_UNIX) {
-        if (!inet_check_addr(sock->domain, addr, addrlen))
+        if ((ret = inet_check_addr(sock->domain, addr, addrlen)) < 0)
             goto out;
         inet_save_addr(sock->domain, &sock->addr.in.conn, addr);
         inet_rebase_port(false, sock->domain, &sock->addr.in.conn, false);
@@ -789,7 +807,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
                                       hdl->flags & O_NONBLOCK);
 
     if (!pal_hdl) {
-        ret = -PAL_ERRNO;
+        ret = (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED) ? -ECONNREFUSED : -PAL_ERRNO;
         goto out;
     }
 
@@ -862,6 +880,17 @@ int __do_accept (struct shim_handle * hdl, int flags, struct sockaddr * addr,
         return -EOPNOTSUPP;
     }
 
+    if (addr) {
+        if (!addrlen || test_user_memory(addrlen, sizeof(*addrlen), false))
+            return -EINVAL;
+
+        if (*addrlen < minimal_addrlen(sock->domain))
+            return -EINVAL;
+
+        if (test_user_memory(addr, *addrlen, true))
+            return -EINVAL;
+    }
+
     lock(hdl->lock);
 
     if (sock->sock_state != SOCK_LISTENED) {
@@ -950,10 +979,10 @@ int __do_accept (struct shim_handle * hdl, int flags, struct sockaddr * addr,
         if (addr) {
             inet_copy_addr(sock->domain, addr, &sock->addr.in.conn);
 
-            if (addrlen)
-                *addrlen = (sock->domain == AF_INET) ?
-                    sizeof(struct sockaddr_in) :
-                    sizeof(struct sockaddr_in6);
+            if (addrlen) {
+                assert(sock->domain == AF_INET || sock->domain == AF_INET6);
+                *addrlen = minimal_addrlen(sock->domain);
+            }
         }
     }
 
@@ -1004,14 +1033,25 @@ static ssize_t do_sendmsg (int fd, struct iovec * bufs, int nbufs, int flags,
     if (!hdl)
         return -EBADF;
 
-    int ret = -EINVAL;
+    int ret = -ENOTSOCK;
+    if (hdl->type != TYPE_SOCK)
+        goto out;
 
-    if (hdl->type != TYPE_SOCK) {
-        ret = -ENOTSOCK;
+    struct shim_sock_handle * sock = &hdl->info.sock;
+
+    ret = -EFAULT;
+    if (addr && test_user_memory((void *) addr, addrlen, false))
+        goto out;
+
+    if (!bufs || test_user_memory(bufs, sizeof(*bufs) * nbufs, false))
         goto out;
+
+    for (int i = 0 ; i < nbufs ; i++) {
+        if (!bufs[i].iov_base ||
+            test_user_memory(bufs[i].iov_base, bufs[i].iov_len, false))
+            goto out;
     }
 
-    struct shim_sock_handle * sock = &hdl->info.sock;
     lock(hdl->lock);
 
     PAL_HANDLE pal_hdl = hdl->pal_handle;
@@ -1156,14 +1196,34 @@ static ssize_t do_recvmsg (int fd, struct iovec * bufs, int nbufs, int flags,
     if (!hdl)
         return -EBADF;
 
-    int ret = 0;
+    int ret = -ENOTSOCK;
+    if (hdl->type != TYPE_SOCK)
+        goto out;
 
-    if (hdl->type != TYPE_SOCK) {
-        ret = -ENOTSOCK;
+    struct shim_sock_handle * sock = &hdl->info.sock;
+
+    if (addr) {
+        ret = -EINVAL;
+        if (!addrlen || test_user_memory(addrlen, sizeof(*addrlen), false))
+            goto out;
+
+        if (*addrlen < minimal_addrlen(sock->domain))
+            goto out;
+
+        if (test_user_memory(addr, *addrlen, true))
+            goto out;
+    }
+
+    ret = -EFAULT;
+    if (!bufs || test_user_memory(bufs, sizeof(*bufs) * nbufs, false))
         goto out;
+
+    for (int i = 0 ; i < nbufs ; i++) {
+        if (!bufs[i].iov_base ||
+            test_user_memory(bufs[i].iov_base, bufs[i].iov_len, true))
+            goto out;
     }
 
-    struct shim_sock_handle * sock = &hdl->info.sock;
     lock(hdl->lock);
 
     PAL_HANDLE pal_hdl = hdl->pal_handle;
@@ -1361,6 +1421,9 @@ int shim_do_getsockname (int sockfd, struct sockaddr * addr, int * addrlen)
     if (*addrlen <= 0)
         return -EINVAL;
 
+    if (test_user_memory(addr, *addrlen, true))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -1398,6 +1461,9 @@ int shim_do_getpeername (int sockfd, struct sockaddr * addr, int * addrlen)
     if (*addrlen <= 0)
         return -EINVAL;
 
+    if (test_user_memory(addr, *addrlen, true))
+        return -EFAULT;
+
     struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
     if (!hdl)
         return -EBADF;

+ 14 - 5
LibOS/shim/src/sys/shim_stat.c

@@ -36,7 +36,10 @@
 
 int shim_do_stat (const char * file, struct stat * stat)
 {
-    if (!file)
+    if (!file || test_user_string(file))
+        return -EFAULT;
+
+    if (!stat && test_user_memory(stat, sizeof(*stat), true))
         return -EFAULT;
 
     int ret;
@@ -61,7 +64,10 @@ out:
 
 int shim_do_lstat (const char * file, struct stat * stat)
 {
-    if (!file)
+    if (!file || test_user_string(file))
+        return -EFAULT;
+
+    if (!stat && test_user_memory(stat, sizeof(*stat), true))
         return -EFAULT;
 
     int ret;
@@ -107,7 +113,10 @@ out:
 
 int shim_do_readlink (const char * file, char * buf, int bufsize)
 {
-    if (!file)
+    if (!file || test_user_string(file))
+        return -EFAULT;
+
+    if (!buf || !bufsize || test_user_memory(buf, bufsize, true))
         return -EFAULT;
 
     if (bufsize <= 0)
@@ -146,7 +155,7 @@ out:
 
 static int __do_statfs (struct shim_mount * fs, struct statfs * buf)
 {
-    if (!buf)
+    if (!buf || test_user_memory(buf, sizeof(*buf), true))
         return -EFAULT;
 
     memset(buf, 0, sizeof(*buf));
@@ -164,7 +173,7 @@ static int __do_statfs (struct shim_mount * fs, struct statfs * buf)
 
 int shim_do_statfs (const char * path, struct statfs * buf)
 {
-    if (!path)
+    if (!path || test_user_string(path))
         return -EFAULT;
 
     int ret;

+ 15 - 0
LibOS/shim/src/sys/shim_time.c

@@ -39,6 +39,12 @@ int shim_do_gettimeofday (struct __kernel_timeval * tv,
     if (!tv)
         return -EINVAL;
 
+    if (test_user_memory(tv, sizeof(*tv), true))
+        return -EFAULT;
+
+    if (tz && test_user_memory(tz, sizeof(*tz), true))
+        return -EFAULT;
+
     long time = DkSystemTimeQuery();
 
     if (time == -1)
@@ -56,6 +62,9 @@ time_t shim_do_time (time_t * tloc)
     if (time == -1)
         return -PAL_ERRNO;
 
+    if (tloc && test_user_memory(tloc, sizeof(*tloc), true))
+        return -EFAULT;
+
     time_t t = time / 1000000;
 
     if (tloc)
@@ -72,6 +81,9 @@ int shim_do_clock_gettime (clockid_t which_clock,
     if (!tp)
         return -EINVAL;
 
+    if (test_user_memory(tp, sizeof(*tp), true))
+        return -EFAULT;
+
     long time = DkSystemTimeQuery();
 
     if (time == -1)
@@ -90,6 +102,9 @@ int shim_do_clock_getres (clockid_t which_clock,
     if (!tp)
         return -EINVAL;
 
+    if (test_user_memory(tp, sizeof(*tp), true))
+        return -EFAULT;
+
     tp->tv_sec  = 0;
     tp->tv_nsec = 1000;
     return 0;

+ 3 - 0
LibOS/shim/src/sys/shim_uname.c

@@ -43,6 +43,9 @@ static struct old_utsname graphene_uname = {
 
 int shim_do_uname (struct old_utsname * buf)
 {
+    if (!buf || test_user_memory(buf, sizeof(*buf), true))
+        return -EFAULT;
+
     memcpy(buf, &graphene_uname, sizeof(graphene_uname));
     return 0;
 }

+ 26 - 2
LibOS/shim/src/sys/shim_wrappers.c

@@ -37,9 +37,18 @@
 
 ssize_t shim_do_readv (int fd, const struct iovec * vec, int vlen)
 {
-    if (!vec)
+    if (!vec || test_user_memory((void *) vec, sizeof(*vec) * vlen, false))
         return -EINVAL;
 
+    for (int i = 0 ; i < vlen ; i++) {
+        if (vec[i].iov_base) {
+            if (vec[i].iov_base + vec[i].iov_len <= vec[i].iov_base)
+                return -EINVAL;
+            if (test_user_memory(vec[i].iov_base, vec[i].iov_len, true))
+                return -EFAULT;
+        }
+    }
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -57,6 +66,9 @@ ssize_t shim_do_readv (int fd, const struct iovec * vec, int vlen)
     for (int i = 0 ; i < vlen ; i++) {
         int b_vec;
 
+        if (!vec[i].iov_base)
+            continue;
+
         b_vec = hdl->fs->fs_ops->read(hdl, vec[i].iov_base, vec[i].iov_len);
         if (b_vec < 0) {
             ret = bytes ? : b_vec;
@@ -89,9 +101,18 @@ out:
  */
 ssize_t shim_do_writev (int fd, const struct iovec * vec, int vlen)
 {
-    if(!vec)
+    if (!vec || test_user_memory((void *) vec, sizeof(*vec) * vlen, false))
         return -EINVAL;
 
+    for (int i = 0 ; i < vlen ; i++) {
+        if (vec[i].iov_base) {
+            if (vec[i].iov_base + vec[i].iov_len < vec[i].iov_base)
+                return -EINVAL;
+            if (test_user_memory(vec[i].iov_base, vec[i].iov_len, false))
+                return -EFAULT;
+        }
+    }
+
     struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
     if (!hdl)
         return -EBADF;
@@ -110,6 +131,9 @@ ssize_t shim_do_writev (int fd, const struct iovec * vec, int vlen)
     {
         int b_vec;
 
+        if (!vec[i].iov_base)
+            continue;
+
         b_vec = hdl->fs->fs_ops->write(hdl, vec[i].iov_base, vec[i].iov_len);
         if (b_vec < 0) {
             ret = bytes ? : b_vec;

+ 1 - 1
LibOS/shim/test/apps/lmbench/lmbench-2.5

@@ -1 +1 @@
-Subproject commit 1511feaba06c3a145f48790f35d9463e42a5ac74
+Subproject commit 806efeeee2a5a896a251ba44be37410ec7776c90

+ 8 - 10
LibOS/shim/test/apps/ltp/BLOCKED

@@ -1,4 +1,3 @@
-chdir04
 epoll_wait01
 fcntl15
 fcntl15_64
@@ -21,15 +20,17 @@ msgrcv04
 msgrcv06
 open12
 open14
-openat01
 openat03
 pselect02
 pselect02_64
-pwrite02
-pwrite02_64
-readdir02
-readv02
-readv03
+preadv01
+preadv01_64
+preadv02
+preadv02_64
+pwritev01
+pwritev01_64
+pwritev02
+pwritev02_64
 rename04
 rename14
 rmdir05
@@ -76,8 +77,6 @@ kill10
 kill12
 nosleep04
 nanosleep04
-pipe04
-pipe05
 pipe07
 process_vm_readv02
 process_vm_readv03
@@ -87,5 +86,4 @@ setitimer02
 set_robust_list01
 signal01
 trace05
-uname02
 waitpid04

+ 108 - 16
LibOS/shim/test/apps/ltp/PASSED

@@ -10,6 +10,14 @@ accept4_01,1
 accept4_01,2
 accept4_01,3
 accept4_01,4
+access03,2
+access03,3
+access03,4
+access03,5
+access03,6
+access03,7
+access03,8
+access03,9
 alarm01,1
 alarm02,1
 alarm02,2
@@ -23,9 +31,17 @@ asyncio02,3
 asyncio02,4
 asyncio02,5
 asyncio02,6
+bind01,1
+bind01,2
+bind01,3
+bind01,4
+bind01,5
 brk01,1
 chdir01,1
 chdir02,1
+chdir04,1
+chdir04,2
+chdir04,3
 chmod01,1
 chmod01,2
 chmod01,3
@@ -56,6 +72,7 @@ clock_getres01,9
 clock_getres01,10
 clock_getres01,11
 clock_getres01,12
+clock_nanosleep01,11
 clone01,1
 clone03,1
 clone04,1
@@ -85,6 +102,12 @@ confstr01,17
 confstr01,18
 confstr01,19
 connect01,1
+connect01,2
+connect01,3
+connect01,4
+connect01,5
+connect01,6
+connect01,7
 creat01,2
 creat01,3
 creat01,4
@@ -120,6 +143,8 @@ epoll_wait03,2
 execl01,1
 execlp01,1
 execv01,1
+execve03,1
+execve03,2
 execvp01,1
 exit01,1
 exit02,1
@@ -163,6 +188,8 @@ fcntl27,1
 fcntl27_64,1
 fcntl28,1
 fcntl28_64,1
+fcntl29,1
+fcntl29_64,1
 fdatasync01,1
 fdatasync02,1
 flock06,2
@@ -212,6 +239,7 @@ futex_wait01,1
 futex_wait01,2
 futex_wait01,3
 futex_wait01,4
+futex_wait03,1
 futex_wait04,1
 futex_wait05,1
 futex_wait_bitset01,1
@@ -223,6 +251,14 @@ futex_wake01,4
 futex_wake01,5
 futex_wake01,6
 getcontext01,1
+getcwd01,1
+getcwd01,2
+getcwd01,3
+getcwd01,4
+getcwd02,3
+getcwd02,4
+getcwd02,5
+getcwd02,8
 getdents02,1
 getdents02,2
 getdents02,3
@@ -245,6 +281,8 @@ getpeername01,1
 getpeername01,2
 getpeername01,3
 getpeername01,4
+getpeername01,5
+getpeername01,6
 getpgid01,1
 getpgid01,2
 getpgrp01,1
@@ -269,6 +307,7 @@ gettid01,1
 getuid01,1
 getuid03,1
 kill01,1
+kill03,1
 kill09,1
 listen01,1
 listen01,2
@@ -320,6 +359,7 @@ mmap09,1
 mmap09,2
 mmap09,3
 mmap13,1
+mprotect01,2
 mprotect01,3
 mprotect02,1
 mprotect02,2
@@ -333,14 +373,22 @@ msgsnd03,4
 msgsnd04,1
 munmap01,1
 munmap02,1
+munmap03,3
 nanosleep01,1
 nanosleep03,1
 newuname01,1
 open01,2
 open03,1
 open08,1
+open08,4
+open08,6
 open09,1
 open09,2
+openat01,1
+openat01,2
+openat01,3
+openat01,4
+openat01,5
 pathconf01,1
 pathconf01,2
 pathconf01,3
@@ -350,23 +398,21 @@ pathconf01,6
 pathconf01,7
 personality02,1
 pipe01,2
+pipe04,1
+pipe04,2
+pipe05,1
 pipe09,1
 pipe10,1
 pipe2_01,1
 poll01,1
 poll01,2
+poll02,1
 pread01,1
 pread01_64,1
 pread02,1
+pread02,2
 pread02_64,1
-preadv01,2
-preadv01,3
-preadv01,4
-preadv01_64,2
-preadv01_64,3
-preadv01_64,4
-preadv02,2
-preadv02_64,2
+pread02_64,2
 process_vm01,2
 process_vm01,4
 process_vm01,6
@@ -397,21 +443,32 @@ pselect01_64,8
 pselect01_64,9
 pwrite01,1
 pwrite01_64,1
+pwrite02,1
+pwrite02,2
+pwrite02,3
+pwrite02,4
+pwrite02_64,1
+pwrite02_64,2
+pwrite02_64,3
+pwrite02_64,4
 pwrite04,2
 pwrite04_64,2
-pwritev01,2
-pwritev01,3
-pwritev01,4
-pwritev01_64,2
-pwritev01_64,3
-pwritev01_64,4
-pwritev02,2
-pwritev02_64,2
 read01,1
 read04,1
 readdir01,1
+readdir02,1
 readv01,1
 readv01,2
+readv02,1
+readv02,2
+readv02,3
+readv02,4
+recv01,1
+recv01,2
+recvfrom01,1
+recvfrom01,2
+recvmsg01,1
+recvmsg01,2
 rmdir01,1
 rmdir04,1
 rt_sigaction01,1
@@ -747,13 +804,23 @@ semget03,1
 semop01,1
 semop04,1
 semop04,2
+send01,1
+send01,2
+send01,3
 sendfile03,1
 sendfile03,2
 sendfile03,3
+sendfile05,1
 sendfile03_64,1
 sendfile03_64,2
 sendfile03_64,3
 sendfile05_64,1
+sendto01,1
+sendto01,2
+sendto01,3
+sendto01,4
+sendto01,7
+sendto02,2
 setgid01,1
 setitimer01,1
 setpgid01,1
@@ -877,6 +944,7 @@ signal06,2
 signal06,3
 signal06,4
 signal06,5
+sigpending02,1
 sigprocmask01,1
 sigsuspend01,1
 socket01,4
@@ -889,10 +957,17 @@ socket02,5
 socketcall02,1
 socketcall03,1
 socketcall04,1
+socketpair01,2
+socketpair01,6
+socketpair01,7
 socketpair02,2
 sockioctl01,1
 stat02,1
 stat02_64,1
+stat03,3
+stat03,4
+stat03_64,3
+stat03_64,4
 stat05,1
 stat05_64,1
 string01,1
@@ -955,12 +1030,14 @@ tkill01,2
 truncate01,1
 truncate01_64,1
 uname01,1
+uname02,1
 uname03,1
 unlink05,1
 unlinkat01,1
 unlinkat01,2
 unlinkat01,3
 unlinkat01,4
+unlinkat01,5
 unlinkat01,6
 unlinkat01,7
 ustat02,1
@@ -974,6 +1051,8 @@ waitpid01,2
 waitpid02,1
 waitpid02,2
 waitpid02,3
+waitpid03,1
+waitpid03,2
 waitpid05,1
 waitpid05,2
 waitpid05,3
@@ -1003,3 +1082,16 @@ write02,1
 write03,1
 write05,1
 write05,2
+writev01,2
+writev01,3
+writev01,4
+writev01,5
+writev01,6
+writev07,4
+writev07,5
+writev07,8
+writev07,9
+writev07,12
+writev07,13
+writev07,16
+writev07,17

+ 3 - 0
Pal/src/host/Linux-SGX/pal_linux_error.h

@@ -33,6 +33,9 @@ int unix_to_pal_error (int unix_errno)
             return -PAL_ERROR_TOOLONG;
         case EISDIR:
             return -PAL_ERROR_STREAMISDIR;
+        case ECONNRESET:
+        case EPIPE:
+            return -PAL_ERROR_CONNFAILED;
         default:
             return -PAL_ERROR_DENIED;
     }

+ 2 - 17
Pal/src/host/Linux/db_pipes.c

@@ -361,14 +361,7 @@ static int64_t pipe_read (PAL_HANDLE handle, uint64_t offset, uint64_t len,
 #endif
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case EWOULDBLOCK:
-                return-PAL_ERROR_TRYAGAIN;
-            case EINTR:
-                return -PAL_ERROR_INTERRUPTED;
-            default:
-                return -PAL_ERROR_DENIED;
-        }
+        bytes = unix_to_pal_error(ERRNO(bytes));
 
     if (!bytes)
         return -PAL_ERROR_ENDOFSTREAM;
@@ -420,15 +413,7 @@ static int64_t pipe_write (PAL_HANDLE handle, uint64_t offset, uint64_t len,
                         WRITEABLE(0);
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case EWOULDBLOCK:
-                HANDLE_HDR(handle)->flags &= ~writeable;
-                return-PAL_ERROR_TRYAGAIN;
-            case EINTR:
-                return -PAL_ERROR_INTERRUPTED;
-            default:
-                return -PAL_ERROR_DENIED;
-        }
+        bytes = unix_to_pal_error(ERRNO(bytes));
 
     if (bytes == len)
         HANDLE_HDR(handle)->flags |= writeable;

+ 6 - 53
Pal/src/host/Linux/db_sockets.c

@@ -599,12 +599,7 @@ static int64_t tcp_read (PAL_HANDLE handle, uint64_t offset, uint64_t len,
     int64_t bytes = INLINE_SYSCALL(recvmsg, 3, handle->sock.fd, &hdr, 0);
 
     if (IS_ERR(bytes))
-        switch (ERRNO(bytes)) {
-            case EWOULDBLOCK:
-                return -PAL_ERROR_TRYAGAIN;
-            default:
-                return unix_to_pal_error(ERRNO(bytes));
-        }
+        return unix_to_pal_error(ERRNO(bytes));
 
     if (!bytes)
         return -PAL_ERROR_ENDOFSTREAM;
@@ -637,16 +632,7 @@ static int64_t tcp_write (PAL_HANDLE handle, uint64_t offset, uint64_t len,
     int64_t bytes = INLINE_SYSCALL(sendmsg, 3, handle->sock.fd, &hdr, MSG_NOSIGNAL);
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case ECONNRESET:
-            case EPIPE:
-                return -PAL_ERROR_CONNFAILED;
-            case EWOULDBLOCK:
-                HANDLE_HDR(handle)->flags &= ~WRITEABLE(0);
-                return -PAL_ERROR_TRYAGAIN;
-            default:
-                return unix_to_pal_error(ERRNO(bytes));
-        }
+        bytes = unix_to_pal_error(ERRNO(bytes));
 
     if (bytes == len)
         HANDLE_HDR(handle)->flags |= WRITEABLE(0);
@@ -831,14 +817,7 @@ static int64_t udp_receive (PAL_HANDLE handle, uint64_t offset, uint64_t len,
     int64_t bytes = INLINE_SYSCALL(recvmsg, 3, handle->sock.fd, &hdr, 0);
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case EWOULDBLOCK:
-                return -PAL_ERROR_TRYAGAIN;
-            case EINTR:
-                return -PAL_ERROR_INTERRUPTED;
-            default:
-                return unix_to_pal_error(ERRNO(bytes));
-        }
+        return unix_to_pal_error(ERRNO(bytes));
 
     return bytes;
 }
@@ -870,16 +849,7 @@ static int64_t udp_receivebyaddr (PAL_HANDLE handle, uint64_t offset, uint64_t l
     int64_t bytes = INLINE_SYSCALL(recvmsg, 3, handle->sock.fd, &hdr, 0);
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case EWOULDBLOCK:
-                return -PAL_ERROR_TRYAGAIN;
-            case EINTR:
-                return -PAL_ERROR_INTERRUPTED;
-            case ECONNREFUSED:
-                return -PAL_ERROR_STREAMNOTEXIST;
-            default:
-                return unix_to_pal_error(ERRNO(bytes));
-        }
+        return unix_to_pal_error(ERRNO(bytes));
 
     char * addr_uri = strcpy_static(addr, "udp:", addrlen);
     if (!addr_uri)
@@ -917,16 +887,7 @@ static int64_t udp_send (PAL_HANDLE handle, uint64_t offset, uint64_t len,
     int64_t bytes = INLINE_SYSCALL(sendmsg, 3, handle->sock.fd, &hdr, MSG_NOSIGNAL);
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case EAGAIN:
-                HANDLE_HDR(handle)->flags &= ~WRITEABLE(0);
-                return -PAL_ERROR_TRYAGAIN;
-            case ECONNRESET:
-            case EPIPE:
-                return -PAL_ERROR_CONNFAILED;
-            default:
-                return unix_to_pal_error(ERRNO(bytes));
-        }
+        bytes = unix_to_pal_error(ERRNO(bytes));
 
     if (bytes == len)
         HANDLE_HDR(handle)->flags |= WRITEABLE(0);
@@ -976,15 +937,7 @@ static int64_t udp_sendbyaddr (PAL_HANDLE handle, uint64_t offset, uint64_t len,
     int64_t bytes = INLINE_SYSCALL(sendmsg, 3, handle->sock.fd, &hdr, MSG_NOSIGNAL);
 
     if (IS_ERR(bytes))
-        switch(ERRNO(bytes)) {
-            case ECONNRESET:
-            case EPIPE:
-                return -PAL_ERROR_CONNFAILED;
-            case EAGAIN:
-                HANDLE_HDR(handle)->flags &= ~WRITEABLE(0);
-            default:
-                return unix_to_pal_error(ERRNO(bytes));
-        }
+        bytes = unix_to_pal_error(ERRNO(bytes));
 
     if (bytes == len)
         HANDLE_HDR(handle)->flags |= WRITEABLE(0);

+ 3 - 0
Pal/src/host/Linux/pal_linux_error.h

@@ -33,6 +33,9 @@ int unix_to_pal_error (int unix_errno)
             return -PAL_ERROR_TOOLONG;
         case EISDIR:
             return -PAL_ERROR_STREAMISDIR;
+        case ECONNRESET:
+        case EPIPE:
+            return -PAL_ERROR_CONNFAILED;
         default:
             return -PAL_ERROR_DENIED;
     }