diff --git a/LibOS/shim/include/shim_defs.h b/LibOS/shim/include/shim_defs.h index 4d11cff7..664c6254 100644 --- a/LibOS/shim/include/shim_defs.h +++ b/LibOS/shim/include/shim_defs.h @@ -47,8 +47,6 @@ #define CP_INIT_VMA_SIZE (64 * 1024 * 1024) /* 64MB */ -#define EXECVE_RTLD 1 - #define ENABLE_ASLR 1 /* debug message printout */ diff --git a/LibOS/shim/src/sys/shim_exec.c b/LibOS/shim/src/sys/shim_exec.c index 290f28ce..67b5571e 100644 --- a/LibOS/shim/src/sys/shim_exec.c +++ b/LibOS/shim/src/sys/shim_exec.c @@ -38,6 +38,31 @@ #include #include +/* returns 0 if normalized URIs are the same; assumes file URIs */ +static int normalize_and_cmp_uris(const char* uri1, const char* uri2) { + char norm1[STR_SIZE]; + char norm2[STR_SIZE]; + size_t len; + int ret; + + if (!strstartswith_static(uri1, "file:") || !strstartswith_static(uri2, "file:")) + return -1; + + uri1 += static_strlen("file:"); + len = sizeof(norm1); + ret = get_norm_path(uri1, norm1, &len); + if (ret < 0) + return ret; + + uri2 += static_strlen("file:"); + len = sizeof(norm2); + ret = get_norm_path(uri2, norm2, &len); + if (ret < 0) + return ret; + + return memcmp(norm1, norm2, len + 1); +} + static int close_on_exec (struct shim_fd_handle * fd_hdl, struct shim_handle_map * map) { @@ -451,16 +476,23 @@ err: SAVE_PROFILE_INTERVAL(open_file_for_exec); -#if EXECVE_RTLD == 1 - 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); + bool use_same_process = check_last_thread(cur_thread) == 0; + if (use_same_process && !strcmp_static(PAL_CB(host_type), "Linux-SGX")) { + /* for SGX PALs, can use same process only if it is the same executable (because a + * different executable has a different measurement and thus requires a new enclave); + * this special case is to correctly handle e.g. Bash process replacing itself */ + assert(cur_thread->exec); + if (normalize_and_cmp_uris(qstrgetstr(&cur_thread->exec->uri), qstrgetstr(&exec->uri))) { + /* it is not the same executable, definitely cannot use same process */ + use_same_process = false; } - debug("execve() in a new process\n"); } -#endif + + if (use_same_process) { + debug("execve() in the same process\n"); + return shim_do_execve_rtld(exec, argv, envp); + } + debug("execve() in a new process\n"); INC_PROFILE_OCCURENCE(syscall_use_ipc); diff --git a/LibOS/shim/test/regression/exec_same.c b/LibOS/shim/test/regression/exec_same.c new file mode 100644 index 00000000..ee40bfab --- /dev/null +++ b/LibOS/shim/test/regression/exec_same.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +int main(int argc, char** argv, char** envp) { + if (argc > 1) { + puts(argv[1]); + return 0; + } + char* const new_argv[] = {argv[0], "hello from execv process", NULL}; + execv(new_argv[0], new_argv); + + /* must never reach this */ + return 1; +} diff --git a/LibOS/shim/test/regression/test_libos.py b/LibOS/shim/test/regression/test_libos.py index 31b0bb63..b80acdc7 100644 --- a/LibOS/shim/test/regression/test_libos.py +++ b/LibOS/shim/test/regression/test_libos.py @@ -85,14 +85,18 @@ class TC_01_Bootstrap(RegressionTestCase): '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ', stdout) - def test_201_fork_and_exec(self): + def test_201_exec_same(self): + stdout, stderr = self.run_binary(['exec_same']) + self.assertIn('hello from execv process', stdout) + + def test_202_fork_and_exec(self): stdout, stderr = self.run_binary(['fork_and_exec']) # fork and exec 2 page child binary self.assertIn('child exited with status: 0', stdout) self.assertIn('test completed successfully', stdout) - def test_202_vfork_and_exec(self): + def test_203_vfork_and_exec(self): stdout, stderr = self.run_binary(['vfork_and_exec']) # vfork and exec 2 page child binary