Browse Source

Fix a bug introduced by commit 3a40af399d1d85 (#94)

* Fix a PAL unit test

* Make the PAL unit tests fail properly if one that should work doesn't.

* Get consistent indexes with and without graphene ipc module

* A little debugging output for ltp flakiness.  Seems to make things a little more stable.

* A bugfix for issue #80. The migration is not complete when a file-backed VMA is larger than
the file size, but the file size is not page-aligned. In Linux, if the file size is smaller
than the mapped memory, accessing the remaining memory that is not backed by the file will
trigger a SIGBUS. However, it is fine to access the remaining memory within the last page that
still overlaps with file, and won't trigger a SIGBUS. This area is commonly used in ELF binary
to store uninitialized, static variables. To improve fork latency, Graphene chooses to
truncate the migration size as the file size, but missed the memory which belongs to the last
file-backed page. The migration size should be aligned up to the page size.

* Fix assertion lines in PAL and LibOS

* Make sure the return code is correct for the LTP script, bump up some timeouts

* Only run gipc tests when the module is loaded, for the purposes of getting CI to work.

* Build fix
Don Porter 6 years ago
parent
commit
f67fe09124
44 changed files with 298 additions and 124 deletions
  1. 1 0
      LICENSE.addendum.txt
  2. 9 0
      LibOS/shim/include/shim_internal.h
  3. 4 0
      LibOS/shim/src/bookkeep/shim_signal.c
  4. 50 21
      LibOS/shim/src/bookkeep/shim_vma.c
  5. 0 3
      LibOS/shim/src/fs/chroot/fs.c
  6. 3 1
      LibOS/shim/src/shim_init.c
  7. 8 3
      LibOS/shim/src/sys/shim_exec.c
  8. 5 0
      LibOS/shim/src/utils/printf.c
  9. 29 10
      LibOS/shim/test/apps/lmbench/lmbench-2.5/src/lat_sig.c
  10. 1 0
      LibOS/shim/test/apps/lmbench/manifest.template
  11. 4 1
      LibOS/shim/test/apps/lmbench/sh.manifest.template
  12. 25 25
      LibOS/shim/test/apps/ltp/PASSED
  13. 5 1
      LibOS/shim/test/apps/ltp/TIMEOUTS
  14. 17 2
      LibOS/shim/test/apps/ltp/fetch.py
  15. 27 14
      Pal/regression/00_Bootstrap.py
  16. 2 1
      Pal/regression/00_Symbols.py
  17. 2 1
      Pal/regression/01_Exception.py
  18. 2 1
      Pal/regression/02_Directory.py
  19. 2 1
      Pal/regression/02_File.py
  20. 8 3
      Pal/regression/02_Memory.py
  21. 2 1
      Pal/regression/02_Misc.py
  22. 2 1
      Pal/regression/02_Pipe.py
  23. 2 1
      Pal/regression/02_Semaphore.py
  24. 2 1
      Pal/regression/02_Socket.py
  25. 2 1
      Pal/regression/02_Thread.py
  26. 6 3
      Pal/regression/03_Process.py
  27. 15 1
      Pal/regression/04_Ipc.py
  28. 2 1
      Pal/regression/04_SendHandle.py
  29. 5 2
      Pal/regression/05_Process.py
  30. 5 2
      Pal/regression/05_Reference_Monitor.py
  31. 6 6
      Pal/regression/Makefile
  32. 1 1
      Pal/src/Makefile
  33. 1 1
      Pal/src/db_exception.c
  34. 1 0
      Pal/src/db_main.c
  35. 2 1
      Pal/src/host/Linux-SGX/db_files.c
  36. 1 0
      Pal/src/host/Linux-SGX/pal_linux_defs.h
  37. 12 2
      Pal/src/host/Linux-SGX/sgx_exception.c
  38. 3 4
      Pal/src/host/Linux-SGX/sgx_framework.c
  39. 4 1
      Pal/src/host/Linux-SGX/sgx_main.c
  40. 2 0
      Pal/src/host/Linux-SGX/signer/pal-sgx-sign
  41. 1 0
      Pal/src/pal.h
  42. 2 0
      Pal/src/pal_internal.h
  43. 1 1
      Pal/src/printf.c
  44. 14 5
      Scripts/regression.py

+ 1 - 0
LICENSE.addendum.txt

@@ -20,3 +20,4 @@ A number of files taken from other C libraries:
 
 [incomplete: more to come]
 
+

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

@@ -83,6 +83,7 @@ void debug_vprintf (const char * fmt, va_list * ap);
 #define SYSPRINT_BUFFER_SIZE    256
 
 void handle_printf (PAL_HANDLE hdl, const char * fmt, ...);
+void handle_vprintf (PAL_HANDLE hdl, const char * fmt, va_list * ap);
 
 #define __sys_printf(fmt, ...)                                              \
     do {                                                                    \
@@ -91,6 +92,14 @@ void handle_printf (PAL_HANDLE hdl, const char * fmt, ...);
            handle_printf(_hdl, (fmt), ##__VA_ARGS__);                       \
     } while (0)
 
+#define __sys_vprintf(fmt, va)                                              \
+    do {                                                                    \
+        PAL_HANDLE _hdl = __open_shim_stdio();                              \
+        if (_hdl)                                                           \
+            handle_vprintf(_hdl, (fmt), (va));                              \
+    } while (0)
+
+
 #define __sys_fprintf(hdl, fmt, ...)                                        \
     do {                                                                    \
         handle_printf((hdl), (fmt), ##__VA_ARGS__);                         \

+ 4 - 0
LibOS/shim/src/bookkeep/shim_signal.c

@@ -54,6 +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);
+
     atomic_inc(&thread->has_signal);
 
     return &log->logs[old_tail];
@@ -85,6 +87,8 @@ fetch_signal_log (shim_tcb_t * tcb, struct shim_thread * thread, int sig)
         log->logs[old_head] = signal;
     }
 
+    debug("signal_logs[%d]: head=%d, tail=%d\n", sig -1, head, tail);
+
     atomic_dec(&thread->has_signal);
 
     return signal;

+ 50 - 21
LibOS/shim/src/bookkeep/shim_vma.c

@@ -123,11 +123,19 @@ int init_vma (void)
         return -ENOMEM;
     }
 
+    debug("User space range given from PAL: %p-%p\n",
+          (void *) PAL_CB(user_address.start),
+          (void *) PAL_CB(user_address.end));
+
     heap_bottom = (void *) PAL_CB(user_address.start);
-    if (heap_bottom + DEFAULT_HEAP_MIN_SIZE > PAL_CB(executable_range.start) &&
-        heap_bottom < PAL_CB(executable_range.end))
+    if (heap_bottom + DEFAULT_HEAP_MIN_SIZE > PAL_CB(executable_range.start)
+        && heap_bottom < PAL_CB(executable_range.end)
+        && heap_top > PAL_CB(executable_range.start))
         heap_bottom = (void *) ALIGN_UP(PAL_CB(executable_range.end));
 
+    debug("setting initial heap to %p-%p\n", heap_bottom,
+          (void *) PAL_CB(user_address.end));
+
     __set_heap_top(heap_bottom, (void *) PAL_CB(user_address.end));
 
     bkeep_shim_heap();
@@ -252,7 +260,6 @@ static bool check_vma_flags (const struct shim_vma * vma, const int * flags)
     }
 
     return true;
-
 }
 
 static inline void __set_comment (struct shim_vma * vma, const char * comment)
@@ -405,9 +412,9 @@ static int __bkeep_munmap (void * addr, uint64_t length, const int * flags)
                 return -EACCES;
             __remove_vma(tmp);
         } else if (test_vma_overlap (tmp, addr, length)) {
-            unsigned long before_length;
-            unsigned long after_length;
-            unsigned long after_offset;
+            uint64_t before_length;
+            uint64_t after_length;
+            uint64_t after_offset;
 
             if (addr > tmp->addr)
                 before_length = addr - tmp->addr;
@@ -669,10 +676,10 @@ static void __set_heap_top (void * bottom, void * top)
         return;
     }
 
-    unsigned long rand;
-    while (getrand(&rand, sizeof(unsigned long)) < sizeof(unsigned long));
+    uint64_t rand;
+    while (getrand(&rand, sizeof(uint64_t)) < sizeof(uint64_t));
 
-    rand %= (unsigned long) (top - bottom) / allocsize;
+    rand %= (uint64_t) (top - bottom) / allocsize;
     heap_top = bottom + rand * allocsize;
     debug("heap top adjusted to %p\n", heap_top);
 }
@@ -688,11 +695,15 @@ void * get_unmapped_vma (uint64_t length, int flags)
     __check_delayed_bkeep();
 
     if (heap_top - heap_bottom < length) {
+        debug("current heap %p-%p is not enough for allocating %lld bytes\n",
+              heap_bottom, heap_top, length);
         unlock(vma_list_lock);
         put_vma(new);
         return NULL;
     }
 
+    debug("find unmapped vma between %p-%p\n", heap_bottom, heap_top);
+
     do {
         int found = 0;
         new->addr   = heap_top - length;
@@ -759,12 +770,17 @@ void * get_unmapped_vma_for_cp (uint64_t length)
     if (!new)
         return NULL;
 
+    if (length > PAL_CB(user_address.end) - PAL_CB(user_address.start)) {
+        debug("user space is not enough for allocating %lld bytes\n", length);
+        return NULL;
+    }
+
     lock(vma_list_lock);
 
     __check_delayed_bkeep();
 
-    unsigned long top = (unsigned long) PAL_CB(user_address.end) - length;
-    unsigned long bottom = (unsigned long) heap_top;
+    uint64_t top = (uint64_t) PAL_CB(user_address.end) - length;
+    uint64_t bottom = (uint64_t) heap_top;
     int flags = MAP_ANONYMOUS|VMA_UNMAPPED|VMA_INTERNAL;
     void * addr;
 
@@ -776,9 +792,9 @@ void * get_unmapped_vma_for_cp (uint64_t length)
     debug("find unmapped vma between %p-%p\n", bottom, top);
 
     for (int i = 0 ; i < NTRIES ; i++) {
-        unsigned long rand;
-        while (getrand(&rand, sizeof(unsigned long)) < sizeof(unsigned long));
-        rand %= (unsigned long) (top - bottom) / allocsize;
+        uint64_t rand;
+        while (getrand(&rand, sizeof(uint64_t)) < sizeof(uint64_t));
+        rand %= (uint64_t) (top - bottom) / allocsize;
         addr = (void *) bottom + rand * allocsize;
         if (!__lookup_overlap_vma(addr, length, &prev))
             break;
@@ -875,8 +891,9 @@ static struct shim_vma * __lookup_supervma (const void * addr, uint64_t length,
                                             struct shim_vma ** pprev)
 {
     struct shim_vma * tmp, * prev = NULL;
-
+    
     listp_for_each_entry(tmp, &vma_list, list) {
+
         if (test_vma_contain(tmp, addr, length)) {
             if (pprev)
                 *pprev = prev;
@@ -884,6 +901,16 @@ static struct shim_vma * __lookup_supervma (const void * addr, uint64_t length,
         }
 
         /* Assert we are really sorted */
+        if (!(!prev || prev->addr + prev->length <= tmp->addr)) {
+            struct shim_vma * tmp2;
+            warn("Failure\n");
+            listp_for_each_entry(tmp2, &vma_list, list) {
+                warn ("Entry: %llx..%llx (%llx)\n", tmp2->addr, tmp2->addr + tmp2->length, tmp2->length);
+            }
+            warn("Prev is %p, tmp->addr = %llx, len is %llx\n", prev, tmp->addr, tmp->length);
+            if (prev)
+                warn("prev addr is %llx, len is %llx\n", prev->addr, prev->length);
+        }
         assert(!prev || prev->addr + prev->length <= tmp->addr);
         /* Insert in order; break once we are past the appropriate point  */
         if (tmp->addr > addr)
@@ -1141,9 +1168,11 @@ BEGIN_CP_FUNC(vma)
         if (vma->file) {
             uint64_t file_len = get_file_size(vma->file);
             if (file_len >= 0 &&
-                vma->offset + vma->length > file_len)
+                vma->offset + vma->length > file_len) {
                 send_size = file_len > vma->offset ?
-                    file_len - vma->offset : 0;
+                            file_len - vma->offset : 0;
+                send_size = ALIGN_UP(send_size);
+            }
         }
 
         if (!send_size)
@@ -1379,14 +1408,14 @@ void print_vma_hash (struct shim_vma * vma, void * addr, uint64_t len,
         DkVirtualMemoryProtect(vma->addr, vma->length, PAL_PROT_READ);
     }
 
-    for (unsigned long p = (unsigned long) addr ;
-         p < (unsigned long) addr + len ; p += allocsize) {
-            unsigned long hash = 0;
+    for (uint64_t p = (uint64_t) addr ;
+         p < (uint64_t) addr + len ; p += allocsize) {
+            uint64_t hash = 0;
             struct shim_md5_ctx ctx;
             md5_init(&ctx);
             md5_update(&ctx, (void *) p, allocsize);
             md5_final(&ctx);
-            memcpy(&hash, ctx.digest, sizeof(unsigned long));
+            memcpy(&hash, ctx.digest, sizeof(uint64_t));
         }
 
     if (!(vma->prot & PROT_READ))

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

@@ -390,9 +390,6 @@ static int chroot_lookup (struct shim_dentry * dent, bool force)
     if (!force)
         return -ESKIPPED;
 
-    if (dent->fs && dent == dent->fs->root)
-        return 0;
-
     return query_dentry(dent, NULL, NULL, NULL);
 }
 

+ 3 - 1
LibOS/shim/src/shim_init.c

@@ -65,7 +65,7 @@ void warn (const char *format, ...)
 { 
     va_list args;
     va_start (args, format);
-    __sys_printf(format, args);
+    __sys_vprintf(format, &args);
     va_end (args);
 }
 
@@ -662,6 +662,8 @@ int shim_init (int argc, void * args, void ** return_stack)
     unsigned long begin_time = GET_PROFILE_INTERVAL();
 #endif
 
+    debug("host: %s\n", PAL_CB(host_type));
+
     DkSetExceptionHandler(&handle_failure, PAL_EVENT_FAILURE, 0);
 
     allocsize = PAL_CB(alloc_align);

+ 8 - 3
LibOS/shim/src/sys/shim_exec.c

@@ -354,9 +354,14 @@ err:
     SAVE_PROFILE_INTERVAL(open_file_for_exec);
 
 #if EXECVE_RTLD == 1
-    int is_last = check_last_thread(cur_thread) == 0;
-    if (is_last)
-        return shim_do_execve_rtld(exec, argv, envp);
+    if (!strcmp_static(PAL_CB(host_type), "Linux-SGX")) {
+        int is_last = check_last_thread(cur_thread) == 0;
+        if (is_last) {
+            debug("execve() in the same process\n");
+            return shim_do_execve_rtld(exec, argv, envp);
+        }
+        debug("execve() in a new process\n");
+    }
 #endif
 
     INC_PROFILE_OCCURENCE(syscall_use_ipc);

+ 5 - 0
LibOS/shim/src/utils/printf.c

@@ -186,3 +186,8 @@ void handle_printf (PAL_HANDLE hdl, const char * fmt, ...)
     sys_vfprintf(hdl, fmt, &ap);
     va_end(ap);
 }
+
+void handle_vprintf (PAL_HANDLE hdl, const char * fmt, va_list * ap)
+{
+    sys_vfprintf(hdl, fmt, ap);
+}

+ 29 - 10
LibOS/shim/test/apps/lmbench/lmbench-2.5/src/lat_sig.c

@@ -28,12 +28,14 @@ void	handler() { }
 #define ITER_UNITS 50
 
 void	prot() {
-
 	if (++caught == to_catch) {
 		double	u;
 		double mean;
 		double var;
-
+		char *buffer;
+		double ci;
+		int n;
+		double level;
 
 		u = stop(0,0);
 		u /= (double) to_catch;
@@ -41,17 +43,34 @@ void	prot() {
 		times[pos++] = u;
 		
 		mean = calc_mean(times, pos);
-		fprintf(stderr, "mean=%.4f adj_mean=%.4f\n", mean, adj_mean);
-		
 		var = calc_variance(mean, times, pos);
-		fprintf(stderr, "var=%.4f adj_var=%.4f\n", var, adj_var);
-
 		mean -= adj_mean;
 		var += adj_var;
-
-		fprintf(stderr, "Protection fault: "
-			"[mean=%.4lf +/-%.4lf] microseconds\n",
-			mean, ci_width(sqrt(var), pos));
+		ci = ci_width(sqrt(var), pos);
+
+		buffer = malloc(80);
+		n = 0;
+		strcpy(buffer + n, "mean=");
+		n += 5;
+		for (level = 1; level < mean; level *= 10);
+		while (level > 0.0001) {
+			if (level == 1) buffer[n++] = '.';
+			level /= 10;
+			buffer[n++] = '0' + (int) (mean / level);
+			mean -= ((int) (mean / level)) * level;
+		}
+		strcpy(buffer + n, " +/-");
+		n += 4;
+		for (level = 1; level < ci; level *= 10);
+		while (level > 0.0001) {
+			if (level == 1) buffer[n++] = '.';
+			level /= 10;
+			buffer[n++] = '0' + (int) (ci / level);
+			mean -= ((int) (ci / level)) * level;
+		}
+		n += 4;
+		buffer[n++] = '\n';
+		write(2, buffer, n);
 
 		exit(0);
 	}

+ 1 - 0
LibOS/shim/test/apps/lmbench/manifest.template

@@ -26,6 +26,7 @@ net.allow_bind.1 = 0.0.0.0:31233-31237
 net.allow_bind.2 = 0.0.0.0:34297-34298
 net.allow_peer.1 = 127.0.0.1:0-65535
 
+glibc.heap_size = 16M
 sys.brk.size = 32M
 sys.stack.size = 4M
 

+ 4 - 1
LibOS/shim/test/apps/lmbench/sh.manifest.template

@@ -1,7 +1,7 @@
 loader.preload = file:$(SHIMPATH)
 loader.exec = file:/bin/sh
 loader.env.LD_LIBRARY_PATH = /lib:/lib64
-loader.debug_type = inline
+loader.debug_type = none
 
 fs.mount.tmp1.type = chroot
 fs.mount.tmp1.path = /tmp
@@ -15,6 +15,7 @@ fs.mount.lib.type = chroot
 fs.mount.lib.path = /lib
 fs.mount.lib.uri = file:$(LIBCDIR)
 
+sgx.enclave_size = 128M
 sys.brk.size = 32M
 sys.stack.size = 4M
 
@@ -24,4 +25,6 @@ sgx.trusted_files.libdl = file:$(LIBCDIR)/libdl.so.2
 sgx.trusted_files.libm = file:$(LIBCDIR)/libm.so.6
 sgx.trusted_files.libpthread = file:$(LIBCDIR)/libpthread.so.0
 
+sgx.trusted_files.hello = file:hello
+
 sgx.trusted_children.hello = file:hello.sig

+ 25 - 25
LibOS/shim/test/apps/ltp/PASSED

@@ -35,17 +35,17 @@ chmod02,8
 chmod03,1
 chown01,1
 chroot02,1
+clock_getres01,2
 clock_getres01,3
 clock_getres01,4
 clock_getres01,5
-clock_getres01,6
+clock_getres01,7
 clock_getres01,8
 clock_getres01,9
 clock_getres01,10
 clock_getres01,11
 clock_getres01,12
-clock_getres01,13
-clock_nanosleep01,12
+clock_nanosleep01,11
 clone01,1
 clone03,1
 clone04,1
@@ -74,13 +74,13 @@ confstr01,16
 confstr01,17
 confstr01,18
 confstr01,19
+creat01,2
 creat01,3
 creat01,4
 creat01,5
 creat01,6
 creat01,7
-creat01,8
-creat03,4
+creat03,3
 dup01,1
 dup02,1
 dup02,2
@@ -92,14 +92,14 @@ dup203,1
 dup203,2
 dup204,1
 dup204,2
-epoll_create1_01,3
-epoll_ctl01,3
-epoll_ctl01,5
+epoll_create1_01,2
+epoll_ctl01,2
+epoll_ctl01,4
+epoll_ctl02,2
 epoll_ctl02,3
-epoll_ctl02,4
+epoll_ctl02,6
 epoll_ctl02,7
 epoll_ctl02,8
-epoll_ctl02,9
 epoll_wait03,1
 epoll_wait03,2
 execl01,1
@@ -317,7 +317,7 @@ pathconf01,5
 pathconf01,6
 pathconf01,7
 personality02,1
-pipe01,3
+pipe01,2
 pipe09,1
 pipe10,1
 pipe2_01,1
@@ -328,14 +328,14 @@ pread01,1
 pread01_64,1
 pread02,1
 pread02_64,1
+preadv01,2
 preadv01,3
 preadv01,4
-preadv01,5
+preadv01_64,2
 preadv01_64,3
 preadv01_64,4
-preadv01_64,5
-preadv02,3
-preadv02_64,3
+preadv02,2
+preadv02_64,2
 process_vm01,2
 process_vm01,4
 process_vm01,6
@@ -368,14 +368,14 @@ pwrite01,1
 pwrite01_64,1
 pwrite04,2
 pwrite04_64,2
+pwritev01,2
 pwritev01,3
 pwritev01,4
-pwritev01,5
+pwritev01_64,2
 pwritev01_64,3
 pwritev01_64,4
-pwritev01_64,5
-pwritev02,3
-pwritev02_64,3
+pwritev02,2
+pwritev02_64,2
 read01,1
 read04,1
 readdir01,1
@@ -838,17 +838,17 @@ signal06,4
 signal06,5
 sigprocmask01,1
 sigsuspend01,1
-socket01,10
-socket01,5
-socket01,7
+socket01,4
+socket01,6
+socket01,9
+socket02,2
 socket02,3
 socket02,4
 socket02,5
-socket02,6
 socketcall02,1
 socketcall03,1
 socketcall04,1
-socketpair02,3
+socketpair02,2
 sockioctl01,1
 stat02,1
 stat02_64,1
@@ -857,9 +857,9 @@ stat05_64,1
 string01,1
 sync01,1
 sync02,1
+syscall01,2
 syscall01,3
 syscall01,4
-syscall01,5
 sysconf01,1
 sysconf01,2
 sysconf01,4

+ 5 - 1
LibOS/shim/test/apps/ltp/TIMEOUTS

@@ -1,5 +1,9 @@
 testcase,timeout
-clone05,30
 alarm01,5
 alarm06,16
+clone05,30
+faccessat01,40
+kill09,40
+read01,40
+wait401,40
 waitpid05,160

+ 17 - 2
LibOS/shim/test/apps/ltp/fetch.py

@@ -5,6 +5,7 @@ import time
 import signal
 import tempfile
 import multiprocessing
+import sys
 
 def run(cmd, timeout, test):
     try:
@@ -33,6 +34,7 @@ def run(cmd, timeout, test):
         return None
     finally:
         if p is not None and p.poll() is None:
+            print 'killing %s' % test
             os.killpg(os.getpgid(p.pid), signal.SIGKILL)
 
 def finish(result):
@@ -46,8 +48,14 @@ def finish(result):
             count = 1
             for output in result['output']:
                 tokens = output.split()
+
                 if len(tokens) < 2:
                     continue
+
+                # Drop this line so that we get consistent offsets
+                if output == "WARNING: no physical memory support, process creation will be slow.\n":
+                    continue
+
                 if tokens[1].isdigit():
                     test_subtest = test + "," + tokens[1]
                     count = int(tokens[1]) + 1
@@ -76,13 +84,15 @@ def finish(result):
                 elif "TCONF" in output or "TBROK" in output or "BROK" in output or "error" in output:
                     print >>broken_tests_fh, test_subtest
                     # Syscall not implemented or test preparation failed
-                    print "[Broken ] " + test_subtest
+                    print "[Broken(a) ] " + test_subtest + CEND
                     current_broken[test_subtest] = 1
                     reported = True
 
             if (not reported):
                 print >>broken_tests_fh, test
-                print CRED + "[Broken ] " + test + CEND
+                print CRED + "[Broken(b) ] " + test + CEND
+                for output in result['output']:
+                    print output
                 current_broken[test] = 1
 
     except Exception as e:
@@ -156,11 +166,16 @@ with open(stablePass, 'rb') as csvfile:
 
 print "\n\nRESULT [Difference] :\n---------------------\n"
 
+rv = 0
+
 for test in sorted(stable_passed):
     if not test in current_passed:
         print CRED + "Test '" + test + "' did not pass in the current run!!" + CEND
+        rv = -1
 
 for test in sorted(current_passed):
     if not test in stable_passed:
         print CGREEN + "Test '" + test + "' passed in the current run!!" + CEND
 print "\n"
+
+sys.exit(rv)

+ 27 - 14
Pal/regression/00_Bootstrap.py

@@ -4,6 +4,10 @@ import os, sys, mmap
 from regression import Regression
 
 loader = os.environ['PAL_LOADER']
+try:
+    sgx = os.environ['SGX_RUN']
+except KeyError:
+    sgx = False
 
 def manifest_file(file):
     if 'SGX_RUN' in os.environ and os.environ['SGX_RUN'] == '1':
@@ -42,14 +46,17 @@ regression.add_check(name="Control Block: Allocation Alignment",
 regression.add_check(name="Control Block: Executable Range",
     check=lambda res: "Executable Range OK" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 # Running ..Bootstrap
 regression = Regression(loader, "..Bootstrap")
 
 regression.add_check(name="Dotdot handled properly",
     check=lambda res: "User Program Started" in res[0].log)
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
+    
 
 # Running Bootstrap2
 regression = Regression(loader, "Bootstrap2")
@@ -57,7 +64,8 @@ regression = Regression(loader, "Bootstrap2")
 regression.add_check(name="Control Block: Manifest as Executable Name",
     check=lambda res: "Loaded Manifest: file:" + manifest_file("Bootstrap2") in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 # Running Bootstrap3
 regression = Regression(loader, "Bootstrap3")
@@ -70,7 +78,8 @@ regression.add_check(name="Preload Libraries Linking",
     check=lambda res: "Preloaded Function 1 Called" in res[0].log and
                       "Preloaded Function 2 Called" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 # Running Bootstrap4
 regression = Regression(loader, manifest_file("Bootstrap4"))
@@ -81,7 +90,8 @@ regression.add_check(name="Control Block: Manifest as Argument",
 regression.add_check(name="Control Block: Executable as in Manifest",
     check=lambda res: "Loaded Executable: file:Bootstrap" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 # Running Bootstrap4.manifest
 regression = Regression(executable = "./" + manifest_file("Bootstrap4"))
@@ -95,7 +105,8 @@ regression.add_check(name="Control Block: Executable as in Manifest (Load by She
 regression.add_check(name="Arguments: loader.execname in Manifest",
     check=lambda res: "argv[0] = Bootstrap" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 # Running Bootstrap5.manifest
 regression = Regression(loader, manifest_file("Bootstrap5"))
@@ -104,13 +115,15 @@ regression.add_check(name="Bootstrap without Executable but Preload Libraries",
     check=lambda res: "Binary 1 Preloaded" in res[0].log and
                       "Binary 2 Preloaded" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
-# Running Bootstrap6.manifest
-regression = Regression(loader, manifest_file("Bootstrap6"), timeout = 100000)
+# Running Bootstrap6.manifest - SGX-specific test
+if sgx:
+    regression = Regression(loader, manifest_file("Bootstrap6"), timeout = 100000)
+    regression.add_check(name="8GB Enclave Creation (SGX Only)",
+                         check=lambda res: "Loaded Manifest: file:Bootstrap6.manifest.sgx" in res[0].log and
+                         "Executable Range OK" in res[0].log)
 
-regression.add_check(name="8GB Enclave Creation (SGX Only)",
-    check=lambda res: "Loaded Manifest: file:Bootstrap6.manifest.sgx" in res[0].log and
-                      "Executable Range OK" in res[0].log)
-
-regression.run_checks()
+    rv = regression.run_checks()
+    if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/00_Symbols.py

@@ -69,4 +69,5 @@ def check_symbols(res):
     return True
 
 regression.add_check(name="Symbol Resolution", check=check_symbols);
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/01_Exception.py

@@ -20,4 +20,5 @@ regression.add_check(name="Exception Handler Swap",
 regression.add_check(name="Exception Handling (Set Context)",
     check=lambda res: any([line.startswith("Div-by-Zero Exception Handler 1") for line in res[0].log]))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_Directory.py

@@ -55,4 +55,5 @@ regression.add_check(name="Directory Attribute Query by Handle",
 regression.add_check(name="Directory Deletion",
     check=lambda res: not os.path.exists("dir_delete.tmp"))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_File.py

@@ -61,4 +61,5 @@ regression.add_check(name="Set File Length",
 regression.add_check(name="File Deletion",
     check=lambda res: not os.path.exists("file_delete.tmp"))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 8 - 3
Pal/regression/02_Memory.py

@@ -4,6 +4,10 @@ import os, sys, mmap
 from regression import Regression
 
 loader = os.environ['PAL_LOADER']
+try:
+    sgx = os.environ['SGX_RUN']
+except KeyError:
+    sgx = 0
 
 regression = Regression(loader, "Memory")
 
@@ -13,11 +17,11 @@ regression.add_check(name="Memory Allocation",
 regression.add_check(name="Memory Allocation with Address",
     check=lambda res: "Memory Allocation with Address OK" in res[0].log)
 
-regression.add_check(name="Memory Protection",
+regression.add_check(name="Memory Protection", flaky = sgx,
     check=lambda res: "Memory Allocation Protection (RW) OK" in res[0].log and
                       "Memory Protection (R) OK" in res[0].log)
 
-regression.add_check(name="Memory Deallocation",
+regression.add_check(name="Memory Deallocation", flaky = sgx,
     check=lambda res: "Memory Deallocation OK" in res[0].log)
 
 def check_quota(res):
@@ -31,4 +35,5 @@ regression.add_check(name="Get Memory Total Quota", check=check_quota)
 regression.add_check(name="Get Memory Available Quota",
     check=lambda res: "Get Memory Available Quota OK" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_Misc.py

@@ -19,4 +19,5 @@ regression.add_check(name="Delay Execution for 3 Seconds",
 regression.add_check(name="Generate Random Bits",
     check=lambda res: "Generate Random Bits OK" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_Pipe.py

@@ -22,4 +22,5 @@ regression.add_check(name="Pipe Transmission",
                       "Pipe Write 2 OK" in res[0].log and
                       "Pipe Read 2: Hello World 2" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_Semaphore.py

@@ -22,4 +22,5 @@ regression.add_check(name="Semaphore: Acquire Unlocked Semaphores",
                       "Locked binary semaphore successfully (0)." in res[0].log and
                       "Locked non-binary semaphore successfully (0)." in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_Socket.py

@@ -37,4 +37,5 @@ regression.add_check(name="Bound UDP Socket Transmission",
                       "UDP Write 4 OK" in res[0].log and
                       "UDP Read 4: Hello World 2" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/02_Thread.py

@@ -21,4 +21,5 @@ regression.add_check(name="Set Thread Private Segment Register",
 regression.add_check(name="Thread Exit",
     check=lambda res: "Child Thread Exited" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 6 - 3
Pal/regression/03_Process.py

@@ -31,14 +31,16 @@ regression.add_check(name="Multi-Process Broadcast Channel Transmission",
     check=lambda res: check_times("Broadcast Write OK",            res[0].log, 1) and
                       check_times("Broadcast Read: Hello World 1", res[0].log, 3))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 regression = Regression(loader, "Process2")
 
 regression.add_check(name="Process Creation with a Different Binary",
     check=lambda res: check_times("User Program Started", res[0].log, 1))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)
 
 regression = Regression(loader, "Process3")
 
@@ -46,4 +48,5 @@ regression.add_check(name="Process Creation without Executable",
     check=lambda res: check_times("Binary 1 Preloaded", res[0].log, 2) and
                       check_times("Binary 2 Preloaded", res[0].log, 2))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 15 - 1
Pal/regression/04_Ipc.py

@@ -4,7 +4,20 @@ import os, sys, mmap
 from regression import Regression
 
 loader = os.environ['PAL_LOADER']
+try:
+    sgx = os.environ['SGX_RUN']
+except KeyError:
+    sgx = 0
+    
+if sgx:
+    print "Bulk IPC not supported on SGX"
+    exit(0)
 
+## XXX Should really be running these tests as part of CI 
+if not os.path.exists('/dev/gipc'):
+    print "GIPC not loaded; skipping these tests\n"
+    exit(0)
+    
 def prepare_files(args):
     with open("ipc_mapping.tmp", "w") as f:
         f.write("Hello World")
@@ -56,4 +69,5 @@ regression.add_check(name="Map and Commit Huge Physical Memory",
     check=lambda res: "[Test 5] Physical Memory Commit OK" in res[0].log and
                       "[Test 5] Physical Memory Map   : Hello World" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 2 - 1
Pal/regression/04_SendHandle.py

@@ -27,4 +27,5 @@ regression.add_check(name="Send Socket Handle",
 regression.add_check(name="Send File Handle",
         check=lambda res: check_times("Receive File Handle: Hello World", res[0].log, 1))
 
-regression.run_checks()
+rv = regression.run_checks()
+if rv: sys.exit(rv)

+ 5 - 2
Pal/regression/05_Process.py

@@ -35,7 +35,9 @@ regression.add_check(name="Multi-Process Broadcast Channel Transmission",
     check=lambda res: check_times("Broadcast Write OK",            res[0].log, 1) and
                       check_times("Broadcast Read: Hello World 1", res[0].log, 3))
 
-regression.run_checks()
+rv = regression.run_checks()
+## dp : For now, let these tests fail.  We should fix this.
+#if rv: sys.exit(rv)
 
 regression = Regression(loader, "Process2")
 
@@ -43,4 +45,5 @@ regression.add_check(name="Process Creation without Executable",
     check=lambda res: check_times("Binary 1 Preloaded", res[0].log, 2) and
                       check_times("Binary 2 Preloaded", res[0].log, 2))
 
-regression.run_checks()
+rv = regression.run_checks()
+#if rv: sys.exit(rv)

+ 5 - 2
Pal/regression/05_Reference_Monitor.py

@@ -44,7 +44,9 @@ regression.add_check(name="Control Block: Allocation Alignment",
 regression.add_check(name="Control Block: Executable Range",
     check=lambda res: "Executable Range OK" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+## dp: For now, let the ref monitor checks fail; we should fix this
+#if rv: sys.exit(rv)
 
 # Running Bootstrap3
 regression = Regression(loader, "Bootstrap3")
@@ -57,4 +59,5 @@ regression.add_check(name="Preload Libraries Linking",
     check=lambda res: "Preloaded Function 1 Called" in res[0].log and
                       "Preloaded Function 2 Called" in res[0].log)
 
-regression.run_checks()
+rv = regression.run_checks()
+#if rv: sys.exit(rv)

+ 6 - 6
Pal/regression/Makefile

@@ -74,17 +74,17 @@ endif
 
 regression: $(call expand_target,$(target))
 	@printf "\n\nBasic Bootstrapping:\n"
-	@for f in $(wildcard 00_*.py); do env $(PYTHONENV) python $$f; done
+	@for f in $(wildcard 00_*.py); do env $(PYTHONENV) python $$f || exit $?; done
 	@printf "\n\nException Handling:\n"
-	@for f in $(wildcard 01_*.py); do env $(PYTHONENV) python $$f; done
+	@for f in $(wildcard 01_*.py); do env $(PYTHONENV) python $$f || exit $?; done
 	@printf "\n\nSingle-Process Functionalities:\n"
-	@for f in $(wildcard 02_*.py); do env $(PYTHONENV) python $$f; done
+	@for f in $(wildcard 02_*.py); do env $(PYTHONENV) python $$f || exit $?; done
 	@printf "\n\nProcess Creation:\n"
-	@for f in $(wildcard 03_*.py); do env $(PYTHONENV) python $$f; done
+	@for f in $(wildcard 03_*.py); do env $(PYTHONENV) python $$f || exit $?; done
 	@printf "\n\nMulti-Process Functionalities:\n"
-	@for f in $(wildcard 04_*.py); do env $(PYTHONENV) python $$f; done
+	@for f in $(wildcard 04_*.py); do env $(PYTHONENV) python $$f || exit $?; done
 	@printf "\n\nReference Monitor (Optional):\n"
-	@for f in $(wildcard 05_*.py); do env $(PYTHONENV) python $$f; done
+	@for f in $(wildcard 05_*.py); do env $(PYTHONENV) python $$f || exit $?; done
 	@printf "\n\n"
 
 clean:

+ 1 - 1
Pal/src/Makefile

@@ -31,7 +31,7 @@ endif
 files_to_build = $(pal_lib) $(pal_lib_post) $(pal_static) \
 		 $(pal_loader) $(pal_sec)
 
-defs	= -DIN_PAL -D$(PAL_HOST_MACRO) -DPAL_DIR=$(PAL_DIR) \
+defs	= -DIN_PAL -DHOST_TYPE="$(PAL_HOST)" -D$(PAL_HOST_MACRO) -DPAL_DIR=$(PAL_DIR) \
 	  -DRUNTIME_DIR=$(RUNTIME_DIR)
 objs	= $(addprefix db_,streams memory threading semaphore events process \
 	    object main misc ipc exception rtld) slab printf

+ 1 - 1
Pal/src/db_exception.c

@@ -94,7 +94,7 @@ void warn (const char *format, ...)
 { 
     va_list args;
     va_start (args, format);
-    printf(format, args);
+    vprintf(format, &args);
     va_end (args);
 }
 

+ 1 - 0
Pal/src/db_main.c

@@ -434,6 +434,7 @@ has_manifest:
 
     set_debug_type();
 
+    __pal_control.host_type          = XSTRINGIFY(HOST_TYPE);
     __pal_control.process_id         = _DkGetProcessId();
     __pal_control.host_id            = _DkGetHostId();
     __pal_control.manifest_handle    = manifest_handle;

+ 2 - 1
Pal/src/host/Linux-SGX/db_files.c

@@ -185,7 +185,8 @@ static int file_map (PAL_HANDLE handle, void ** addr, int prot,
     void * umem;
     int ret;
 
-    if (!stubs && !mem) {
+    if (!stubs && !(prot & PAL_PROT_WRITECOPY)) {
+map_untrusted:
         ret = ocall_map_untrusted(handle->file.fd, offset, size,
                                   HOST_PROT(prot), &mem);
         if (!ret)

+ 1 - 0
Pal/src/host/Linux-SGX/pal_linux_defs.h

@@ -4,6 +4,7 @@
 #ifndef PAL_LINUX_DEFS_H
 #define PAL_LINUX_DEFS_H
 
+#define ENCLAVE_HIGH_ADDRESS    (0x800000000)
 #define SSAFRAMENUM         (2)
 #define MEMORY_GAP          (PRESET_PAGESIZE)
 #define ENCLAVE_STACK_SIZE  (PRESET_PAGESIZE * 16)

+ 12 - 2
Pal/src/host/Linux-SGX/sgx_exception.c

@@ -253,10 +253,20 @@ static void _DkResumeSighandler (int signum, siginfo_t * info,
         INLINE_SYSCALL(exit, 1, 1);
     }
 
+    int event = 0;
+    switch(signum) {
+        case SIGBUS:
+        case SIGSEGV:
+            event = PAL_EVENT_MEMFAULT;
+            break;
+        case SIGILL:
+            event = PAL_EVENT_ILLEGAL;
+            break;
+    }
 #if SGX_HAS_FSGSBASE != 0
-    sgx_raise((signum == SIGBUS) ? PAL_EVENT_MEMFAULT : 0);
+    sgx_raise(event);
 #else
-    uc->uc_mcontext.gregs[REG_R9] = (signum == SIGBUS) ? PAL_EVENT_MEMFAULT : 0;
+    uc->uc_mcontext.gregs[REG_R9] = event;
 #endif
 }
 

+ 3 - 4
Pal/src/host/Linux-SGX/sgx_framework.c

@@ -142,14 +142,13 @@ int create_enclave(sgx_arch_secs_t * secs,
 
     if (baseaddr) {
         secs->baseaddr = (uint64_t) baseaddr & ~(secs->size - 1);
-        flags |= MAP_FIXED;
     } else {
-        secs->baseaddr = 0ULL;
+        secs->baseaddr = ENCLAVE_HIGH_ADDRESS;
     }
 
     uint64_t addr = INLINE_SYSCALL(mmap, 6, secs->baseaddr, secs->size,
-                                   PROT_READ|PROT_WRITE|PROT_EXEC, flags,
-                                   isgx_device, 0);
+                                   PROT_READ|PROT_WRITE|PROT_EXEC,
+                                   flags|MAP_FIXED, isgx_device, 0);
 
     if (IS_ERR_P(addr)) {
         if (ERRNO_P(addr) == 1 && (flags | MAP_FIXED))

+ 4 - 1
Pal/src/host/Linux-SGX/sgx_main.c

@@ -375,7 +375,10 @@ int initialize_enclave (struct pal_enclave * enclave)
         if (areas[i].addr)
             continue;
         areas[i].addr = populating - areas[i].size;
-        populating = areas[i].addr - MEMORY_GAP;
+        if (&areas[i] == exec_area)
+            populating = areas[i].addr;
+        else
+            populating = areas[i].addr - MEMORY_GAP;
     }
 
     enclave_entry_addr += pal_area->addr;

+ 2 - 0
Pal/src/host/Linux-SGX/signer/pal-sgx-sign

@@ -733,6 +733,8 @@ if __name__ == "__main__":
 
     if len([a for a in memory_areas if a.addr is not None]) > 0:
         manifest['sgx.static_address'] = '1'
+    else:
+        ENCLAVE_HEAP_MIN = 0
 
     # Add manifest at the top
     shutil.copy2(args['manifest'], args['output'])

+ 1 - 0
Pal/src/pal.h

@@ -145,6 +145,7 @@ typedef struct {
 
 /********** PAL APIs **********/
 typedef struct {
+    PAL_STR host_type;
     /* An identifier of current picoprocess */
     PAL_NUM process_id;
     PAL_NUM host_id;

+ 2 - 0
Pal/src/pal_internal.h

@@ -420,6 +420,8 @@ void free (void * mem);
 
 void _DkPrintConsole (const void * buf, int size);
 int printf  (const char  *fmt, ...);
+#include <stdarg.h>
+int vprintf(const char * fmt, va_list *ap);
 void write_log (int nstrs, ...);
 
 static inline void log_stream (const char * uri)

+ 1 - 1
Pal/src/printf.c

@@ -48,7 +48,7 @@ fputch(void * f, int ch, struct printbuf * b)
     return 0;
 }
 
-static int
+int
 vprintf(const char * fmt, va_list *ap)
 {
     struct printbuf b;

+ 14 - 5
Scripts/regression.py

@@ -21,16 +21,17 @@ class Regression:
             self.timeout = timeout
         self.keep_log = (os.getenv('KEEP_LOG', '0') == '1')
 
-    def add_check(self, name, check, times = 1, args = []):
+    def add_check(self, name, check, times = 1, flaky=0, args = []):
         combined_args = ' '.join(args)
         if not combined_args in self.runs:
             self.runs[combined_args] = []
-        self.runs[combined_args].append((name, check, times))
+        self.runs[combined_args].append((name, check, flaky, times))
 
     def run_checks(self):
+        something_failed = 0
         for combined_args in self.runs:
             needed_times = 1
-            for (name, check, times) in self.runs[combined_args]:
+            for (name, check, flaky, times) in self.runs[combined_args]:
                 if needed_times < times:
                     needed_times = times
 
@@ -77,7 +78,7 @@ class Regression:
 
                 run_times = run_times + 1
                 keep_log = False
-                for (name, check, times) in self.runs[combined_args]:
+                for (name, check, flaky, times) in self.runs[combined_args]:
                     if run_times == times:
                         result = check(outputs)
                         if result:
@@ -86,10 +87,18 @@ class Regression:
                             print '\033[93m[Fail   ]\033[0m', name
                             if timed_out : print 'Test timed out!'
                             keep_log = True
-
+                            if flaky:
+                                print '   This test is kown  not to work, but should be fixed'
+                            else:
+                                something_failed = 1
+                            
                 if self.keep_log and keep_log:
                     sargs = [re.sub(r"\W", '_', a).strip('_') for a in args]
                     filename = 'log-' + '_'.join(sargs) + '_' + time.strftime("%Y%m%d_%H%M%S")
                     with open(filename, 'w') as f:
                         f.write(log + out)
                     print 'keep log to %s' % (filename)
+        if something_failed:
+            return -1
+        else:
+            return 0