Browse Source

Fixing miscellaneous bugs in LibOS

(1) Suppress some compilation warnings
(2) Moving brk within 32MB behind the executable data segment (passing LTP brk tests)
(3) Fix migration of file handles after file deletion
(4) rt_sigaction should take the 4th argument as size of sigset_t
(5) Implement rt_sigpending
(6) sigaltstack should return -ENOMEM if ss_size is smaller than MINSIGSTKSZ
(7) sigsuspend always returns -EINTR
(8) Fix CLOEXEC feature of accept4()
Chia-Che Tsai 6 years ago
parent
commit
a5bc12fd53

+ 2 - 1
LibOS/shim/include/shim_internal.h

@@ -752,7 +752,8 @@ extern const char ** initial_envp;
 void get_brk_region (void ** start, void ** end, void ** current);
 
 int init_randgen (void);
-int init_brk (void);
+int reset_brk (void);
+int init_brk_region (void * brk_region);
 int init_heap (void);
 int init_internal_map (void);
 int init_loader (void);

+ 2 - 4
LibOS/shim/include/shim_signal.h

@@ -13,9 +13,6 @@ struct shim_signal_handle {
     struct __kernel_sigaction * action;
 };
 
-#define NUM_SIGS            64
-#define NUM_KNOWN_SIGS      32
-
 # define BITS_PER_WORD sizeof(unsigned long)
 /* The standard def of this macro is dumb */
 #undef _SIGSET_NWORDS
@@ -146,7 +143,8 @@ void append_signal (struct shim_thread * thread, int sig, siginfo_t * info,
 void deliver_signal (siginfo_t * info, PAL_CONTEXT * context);
 
 __sigset_t * get_sig_mask (struct shim_thread * thread);
-__sigset_t * set_sig_mask (struct shim_thread * thread, __sigset_t * new_set);
+__sigset_t * set_sig_mask (struct shim_thread * thread,
+                           const __sigset_t * new_set);
 
 int do_kill_thread (IDTYPE sender, IDTYPE tgid, IDTYPE tid, int sig,
                     bool use_ipc);

+ 4 - 3
LibOS/shim/include/shim_table.h

@@ -27,7 +27,7 @@ long __shim_mmap (long, long, long, long, long, long);
 long __shim_mprotect (long, long, long);
 long __shim_munmap (long, long);
 long __shim_brk (long);
-long __shim_rt_sigaction (long, long, long);
+long __shim_rt_sigaction (long, long, long, long);
 long __shim_rt_sigprocmask (long, long, long);
 long __shim_rt_sigreturn (long);
 long __shim_ioctl (long, long, long);
@@ -343,7 +343,7 @@ int shim_do_mprotect (void * addr, size_t len, int prot);
 int shim_do_munmap (void * addr, size_t len);
 void * shim_do_brk (void * brk);
 int shim_do_sigaction (int signum, const struct __kernel_sigaction * act,
-                       struct __kernel_sigaction * oldact);
+                       struct __kernel_sigaction * oldact, size_t sigsetsize);
 int shim_do_sigprocmask (int how, const __sigset_t * set, __sigset_t * oldset);
 int shim_do_sigreturn (int __unused);
 int shim_do_ioctl (int fd, int cmd, unsigned long arg);
@@ -442,6 +442,7 @@ pid_t shim_do_getpgrp (void);
 int shim_do_setsid (void);
 int shim_do_getpgid (pid_t pid);
 int shim_do_getsid (pid_t pid);
+int shim_do_sigpending (__sigset_t * set, size_t sigsetsize);
 int shim_do_sigaltstack (const stack_t * ss, stack_t * oss);
 int shim_do_sigsuspend (const __sigset_t * mask);
 void * shim_do_arch_prctl (int code, void * addr);
@@ -525,7 +526,7 @@ int shim_mprotect (void * addr, size_t len, int prot);
 int shim_munmap (void * addr, size_t len);
 void * shim_brk (void * brk);
 int shim_rt_sigaction (int signum, const struct __kernel_sigaction * act,
-                       struct __kernel_sigaction * oldact);
+                       struct __kernel_sigaction * oldact, size_t sigsetsize);
 int shim_rt_sigprocmask (int how, const __sigset_t * set, __sigset_t * oldset);
 int shim_rt_sigreturn (int __unused);
 int shim_ioctl (int fd, int cmd, unsigned long arg);

+ 5 - 3
LibOS/shim/include/shim_types.h

@@ -156,10 +156,12 @@ struct __kernel_sigaction {
 /* linux/aio_abi.h (for io_setup which has no glibc wrapper) */
 typedef unsigned long aio_context_t;
 
-/* bits/sigset.h */
-# define _SIGSET_NWORDS	(1024 / (8 * sizeof (unsigned long int)))
+/* asm/signal.h */
+#define NUM_SIGS            64
+#define NUM_KNOWN_SIGS      32
+
 typedef struct {
-    unsigned long int __val[_SIGSET_NWORDS];
+    unsigned long __val[NUM_SIGS / (8 * sizeof(unsigned long))];
 } __sigset_t;
 
 /* linux/rlimit.h */

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

@@ -392,7 +392,8 @@ __sigset_t * get_sig_mask (struct shim_thread * thread)
     return &(thread->signal_mask);
 }
 
-__sigset_t * set_sig_mask (struct shim_thread * thread, __sigset_t * set)
+__sigset_t * set_sig_mask (struct shim_thread * thread,
+                           const __sigset_t * set)
 {
     if (!thread)
         thread = get_cur_thread();

+ 19 - 0
LibOS/shim/src/elf/shim_rtld.c

@@ -1481,6 +1481,8 @@ int init_internal_map (void)
     return 0;
 }
 
+int init_brk_from_executable (struct shim_handle * exec);
+
 int init_loader (void)
 {
     struct shim_thread * cur_thread = get_cur_thread();
@@ -1507,6 +1509,8 @@ int init_loader (void)
         exec_map = __search_map_by_handle(exec);
     }
 
+    init_brk_from_executable(exec);
+
     if (!interp_map
         && __need_interp(exec_map)
         && (ret = __load_interp_object(exec_map)) < 0)
@@ -1518,6 +1522,21 @@ out:
     return ret;
 }
 
+int init_brk_from_executable (struct shim_handle * exec)
+{
+    struct link_map * exec_map = __search_map_by_handle(exec);
+
+    if (exec_map) {
+        /*
+         * Chia-Che 8/24/2017:
+         * initialize brk region at the end of the executable data segment.
+         */
+        init_brk_region((void *) ALIGN_UP(exec_map->l_map_end));
+    }
+
+    return 0;
+}
+
 int register_library (const char * name, unsigned long load_address)
 {
     debug("glibc register library %s loaded at %p\n",

+ 23 - 4
LibOS/shim/src/fs/chroot/fs.c

@@ -571,7 +571,13 @@ static int chroot_recreate (struct shim_handle * hdl)
         qstrsetstr(&data->host_uri, uri, len);
     }
 
-    return __chroot_open(hdl->dentry, uri, len, hdl->flags, 0, hdl, data);
+    /*
+     * Chia-Che Tsai 8/24/2017:
+     * when recreating a file handle after migration, the file should
+     * not be created again.
+     */
+    return __chroot_open(hdl->dentry, uri, len, hdl->flags & ~(O_CREAT|O_EXCL),
+                         0, hdl, data);
 }
 
 static inline bool check_version (struct shim_handle * hdl)
@@ -914,6 +920,9 @@ static int chroot_truncate (struct shim_handle * hdl, uint64_t len)
     if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0)
         return ret;
 
+    if (!(hdl->acc_mode & MAY_WRITE))
+        return -EINVAL;
+
     struct shim_file_handle * file = &hdl->info.file;
     lock(hdl->lock);
 
@@ -1076,10 +1085,20 @@ static int chroot_checkout (struct shim_handle * hdl)
             hdl->info.file.data = NULL;
     }
 
+    if (hdl->pal_handle) {
+        /*
+         * Chia-Che 8/24/2017:
+         * if the file still exists in the host, no need to send
+         * the handle over RPC; otherwise, send it.
+         */
+        PAL_STREAM_ATTR attr;
+        if (DkStreamAttributesQuery(qstrgetstr(&hdl->uri), &attr))
+            hdl->pal_handle = NULL;
+    }
+
     hdl->info.file.mapsize = 0;
     hdl->info.file.mapoffset = 0;
     hdl->info.file.mapbuf = NULL;
-    hdl->pal_handle = NULL;
     return 0;
 }
 
@@ -1128,13 +1147,13 @@ static int chroot_unlink (struct shim_dentry * dir, struct shim_dentry * dent)
 
     /* Drop the parent's link count */
     struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
-    if (parent_data) { 
+    if (parent_data) {
         lock(parent_data->lock);
         if (parent_data->queried)
             parent_data->nlink--;
         unlock(parent_data->lock);
     }
-    
+
     return 0;
 }
 

+ 1 - 1
LibOS/shim/src/fs/shim_fs.c

@@ -159,7 +159,7 @@ static int __mount_one_other (const char * key, int keylen)
     debug("mounting as %s filesystem: from %s to %s\n", t, uri, p);
 
     if ((ret = mount_fs(t, uri, p)) < 0) {
-        debug("mounting %s on %s (type=%s) failed (%e)\n", t, uri, p,
+        debug("mounting %s on %s (type=%s) failed (%e)\n", uri, p, t,
               -ret);
         return ret;
     }

+ 5 - 4
LibOS/shim/src/shim_syscalls.c

@@ -197,8 +197,9 @@ void * shim_do_brk (void * brk)
 #endif
 
 /* rt_sigaction: sys/shim_sigaction.c */
-DEFINE_SHIM_SYSCALL (rt_sigaction, 3, shim_do_sigaction, int, int, signum,
-                     const struct __kernel_sigaction *, act, struct __kernel_sigaction *, oldact)
+DEFINE_SHIM_SYSCALL (rt_sigaction, 4, shim_do_sigaction, int, int, signum,
+                     const struct __kernel_sigaction *, act,
+                     struct __kernel_sigaction *, oldact, size_t, sigsetsize)
 
 /* rt_sigprocmask: sys/shim_sigaction.c */
 DEFINE_SHIM_SYSCALL (rt_sigprocmask, 3, shim_do_sigprocmask, int, int, how,
@@ -578,8 +579,8 @@ SHIM_SYSCALL_PASSTHROUGH (capget, 2, int, cap_user_header_t, header,
 SHIM_SYSCALL_PASSTHROUGH (capset, 2, int, cap_user_header_t, header,
                           const cap_user_data_t, data)
 
-SHIM_SYSCALL_PASSTHROUGH (rt_sigpending, 2, int, __sigset_t *, set, size_t,
-                          sigsetsize)
+DEFINE_SHIM_SYSCALL (rt_sigpending, 2, shim_do_sigpending, int,
+                     __sigset_t *, set, size_t, sigsetsize)
 
 SHIM_SYSCALL_PASSTHROUGH (rt_sigtimedwait, 4, int, const __sigset_t *, uthese,
                           siginfo_t *, uinfo, const struct timespec *, uts,

+ 34 - 5
LibOS/shim/src/sys/shim_brk.c

@@ -59,7 +59,7 @@ void get_brk_region (void ** start, void ** end, void ** current)
     master_unlock();
 }
 
-int init_brk_region (void)
+int init_brk_region (void * brk_region)
 {
     if (region.brk_start)
         return 0;
@@ -73,8 +73,37 @@ int init_brk_region (void)
             brk_max_size = DEFAULT_BRK_MAX_SIZE;
     }
 
-    void * brk_region = get_unmapped_vma(brk_max_size,
-                                         MAP_PRIVATE|MAP_ANONYMOUS);
+    /*
+     * Chia-Che 8/24/2017
+     * Adding an argument to specify the initial starting
+     * address of brk region.
+     * The general assumption of Linux is that the brk region
+     * should be within [exec-data-end, exec-data-end + 0x2000000)
+     */
+    if (brk_region) {
+        while (true) {
+            uint32_t rand;
+            getrand(&rand, sizeof(rand));
+            rand %= 0x2000000;
+            rand = ALIGN_UP(rand);
+
+            struct shim_vma * vma;
+            if (lookup_overlap_vma(brk_region + rand, brk_max_size, &vma)
+                == -ENOENT) {
+                brk_region += rand;
+                break;
+            }
+
+            brk_region = vma->addr + vma->length;
+            put_vma(vma);
+        }
+    } else {
+        brk_region = get_unmapped_vma(brk_max_size,
+                                      MAP_PRIVATE|MAP_ANONYMOUS);
+        if (!brk_region)
+            return -ENOMEM;
+    }
+
     void * end_brk_region = NULL;
 
     // brk region assigned
@@ -106,7 +135,7 @@ int init_brk_region (void)
     return 0;
 }
 
-int init_brk (void)
+int reset_brk (void)
 {
     master_lock();
 
@@ -132,7 +161,7 @@ int init_brk (void)
 void * shim_do_brk (void * brk)
 {
     master_lock();
-    init_brk_region();
+    init_brk_region(NULL);
 
     if (!brk) {
 unchanged:

+ 4 - 1
LibOS/shim/src/sys/shim_exec.c

@@ -71,6 +71,8 @@ static elf_auxv_t *  new_auxp;
 
 #define REQUIRED_ELF_AUXV       6
 
+int init_brk_from_executable (struct shim_handle * exec);
+
 int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
                          const char ** envp)
 {
@@ -127,13 +129,14 @@ int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
     clean_link_map_list();
     SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec);
 
-    init_brk();
+    reset_brk();
     unmap_all_vmas();
     SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec);
 
     if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0)
         shim_terminate();
 
+    init_brk_from_executable(cur_thread->exec);
     load_elf_interp(cur_thread->exec);
 
     SAVE_PROFILE_INTERVAL(load_new_executable_for_exec);

+ 4 - 14
LibOS/shim/src/sys/shim_fs.c

@@ -275,9 +275,7 @@ int shim_do_chown (const char * path, uid_t uid, gid_t gid)
     if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent)) < 0)
         return ret;
 
-    /* do nothing*/
-
-out:
+    /* XXX: do nothing now */
     put_dentry(dent);
     return ret;
 }
@@ -300,9 +298,7 @@ int shim_do_fchownat (int dfd, const char * filename, uid_t uid, gid_t gid,
     if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent)) < 0)
         goto out;
 
-    /* do nothing */
-
-out_dent:
+    /* XXX: do nothing now */
     put_dentry(dent);
 out:
     put_dentry(dir);
@@ -315,14 +311,8 @@ int shim_do_fchown (int fd, uid_t uid, gid_t gid)
     if (!hdl)
         return -EBADF;
 
-    struct shim_dentry * dent = hdl->dentry;
-    int ret = 0;
-
-    /* do nothing */
-
-out:
-    put_handle(hdl);
-    return ret;
+    /* XXX: do nothing now */
+    return 0;
 }
 
 #define MAP_SIZE    (allocsize * 4)

+ 5 - 0
LibOS/shim/src/sys/shim_getrlimit.c

@@ -55,6 +55,11 @@ int shim_do_getrlimit (int resource, struct __kernel_rlimit * rlim)
             rlim->rlim_max = sys_stack_size;
             return 0;
 
+        case RLIMIT_DATA:
+            rlim->rlim_cur = brk_max_size;
+            rlim->rlim_max = brk_max_size;
+            return 0;
+
         default:
             return -ENOSYS;
     }

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

@@ -563,19 +563,15 @@ int shim_do_ftruncate (int fd, loff_t length)
         return -EBADF;
 
     struct shim_mount * fs = hdl->fs;
-    int ret = -EACCES;
+    int ret = -EINVAL;
 
     if (!fs || !fs->fs_ops)
         goto out;
 
-    if (hdl->type == TYPE_DIR)
+    if (hdl->type == TYPE_DIR ||
+        !fs->fs_ops->truncate)
         goto out;
 
-    if (!fs->fs_ops->truncate) {
-        ret = -EROFS;
-        goto out;
-    }
-
     ret = fs->fs_ops->truncate(hdl, length);
 out:
     put_handle(hdl);

+ 29 - 8
LibOS/shim/src/sys/shim_sigaction.c

@@ -39,11 +39,12 @@
 #include <linux/signal.h>
 
 int shim_do_sigaction (int signum, const struct __kernel_sigaction * act,
-                       struct __kernel_sigaction * oldact)
+                       struct __kernel_sigaction * oldact, size_t sigsetsize)
 {
     /* SIGKILL and SIGSTOP cannot be caught or ignored */
     if (signum == SIGKILL || signum == SIGSTOP ||
-        signum <= 0 || signum > NUM_SIGS)
+        signum <= 0 || signum > NUM_SIGS ||
+        sigsetsize != sizeof(__sigset_t))
         return -EINVAL;
 
     struct shim_thread * cur = get_cur_thread();
@@ -145,14 +146,19 @@ int shim_do_sigaltstack (const stack_t * ss, stack_t * oss)
         return -EINVAL;
 
     struct shim_thread * cur = get_cur_thread();
-    int err = 0;
-
     lock(cur->lock);
 
     if (oss)
         *oss = cur->signal_altstack;
-    if (ss)
+
+    if (ss) {
+        if (ss->ss_size < MINSIGSTKSZ) {
+            unlock(cur->lock);
+            return -ENOMEM;
+        }
+
         cur->signal_altstack = *ss;
+    }
 
     unlock(cur->lock);
     return 0;
@@ -162,7 +168,6 @@ int shim_do_sigsuspend (const __sigset_t * mask)
 {
     __sigset_t * old, tmp;
     struct shim_thread * cur = get_cur_thread();
-    int err = 0;
 
     lock(cur->lock);
 
@@ -174,12 +179,28 @@ int shim_do_sigsuspend (const __sigset_t * mask)
     cur->suspend_on_signal = true;
     thread_setwait(NULL, NULL);
     thread_sleep(NO_TIMEOUT);
-out:
+
     unlock(cur->lock);
     set_sig_mask(cur, old);
+    return -EINTR;
+}
 
-    return err;
+int shim_do_sigpending (__sigset_t * set, size_t sigsetsize)
+{
+    struct shim_thread * cur = get_cur_thread();
 
+    __sigemptyset(set);
+
+    if (!cur->signal_logs)
+        return 0;
+
+    for (int sig = 1 ; sig <= NUM_SIGS ; sig++) {
+        if (atomic_read(&cur->signal_logs[sig - 1].head) !=
+            atomic_read(&cur->signal_logs[sig - 1].tail))
+            __sigaddset(set, sig);
+    }
+
+    return 0;
 }
 
 struct walk_arg {

+ 3 - 3
LibOS/shim/src/sys/shim_socket.c

@@ -951,7 +951,7 @@ int shim_do_accept (int fd, struct sockaddr * addr, socklen_t * addrlen)
     if (!hdl)
         return -EBADF;
 
-    int ret = __do_accept(hdl, flags & FD_CLOEXEC ? O_CLOEXEC : 0,
+    int ret = __do_accept(hdl, flags & O_CLOEXEC,
                           addr, addrlen);
     put_handle(hdl);
     return ret;
@@ -965,7 +965,7 @@ int shim_do_accept4 (int fd, struct sockaddr * addr, socklen_t * addrlen,
         return -EBADF;
 
     int ret = __do_accept(hdl,
-                          (flags & SOCK_CLOEXEC ? FD_CLOEXEC : 0) |
+                          (flags & SOCK_CLOEXEC ? O_CLOEXEC : 0) |
                           (flags & SOCK_NONBLOCK ? O_NONBLOCK : 0),
                           addr, addrlen);
     put_handle(hdl);
@@ -1262,7 +1262,7 @@ int shim_do_recvmmsg (int sockfd, struct mmsghdr * msg, int vlen, int flags,
         struct msghdr * m = &msg[i].msg_hdr;
 
         int bytes = do_recvmsg(sockfd, m->msg_iov, m->msg_iovlen, flags,
-                               m->msg_name, m->msg_namelen);
+                               m->msg_name, &m->msg_namelen);
         if (bytes < 0)
             return total ? : bytes;