diff --git a/LibOS/shim/src/bookkeep/shim_handle.c b/LibOS/shim/src/bookkeep/shim_handle.c index ef6eb2d9e4..113e66bc54 100644 --- a/LibOS/shim/src/bookkeep/shim_handle.c +++ b/LibOS/shim/src/bookkeep/shim_handle.c @@ -165,6 +165,49 @@ int init_handle(void) { return 0; } +static int init_default_handle(struct shim_handle_map* handle_map, int fd, const char* manifest_key, + bool write) { + assert(locked(&handle_map->lock)); + + struct shim_handle* hdl = get_new_handle(); + if (!hdl) { + return -ENOMEM; + } + + char* path = NULL; + int ret = toml_string_in(g_manifest_root, manifest_key, &path); + if (ret < 0) { + log_error("Cannot parse '%s'", manifest_key); + put_handle(hdl); + return -EINVAL; + } + if (path) { + if (strstartswith(path, URI_PREFIX_FILE)) { + log_error("'%s' must be an in-Graphene fs path", manifest_key); + put_handle(hdl); + free(path); + return -EINVAL; + } + int flags = write ? O_WRONLY | O_CREAT : O_RDONLY; + ret = open_namei(hdl, /*start=*/NULL, path, flags, /*mode=*/0600, /*found=*/NULL); + free(path); + if (ret < 0) { + log_error("%s: cannot open '%s': %d", __func__, path, ret); + put_handle(hdl); + return ret; + } + } else { + if ((ret = init_tty_handle(hdl, write)) < 0) { + put_handle(hdl); + return ret; + } + } + + __init_handle(&handle_map->map[fd], /*fd=*/fd, hdl, /*flags=*/0); + put_handle(hdl); + return 0; +} + int init_important_handles(void) { int ret; struct shim_thread* thread = get_cur_thread(); @@ -195,51 +238,31 @@ int init_important_handles(void) { } } - /* initialize stdin */ - if (!HANDLE_ALLOCATED(handle_map->map[0])) { - struct shim_handle* stdin_hdl = get_new_handle(); - if (!stdin_hdl) { - unlock(&handle_map->lock); - return -ENOMEM; - } + assert(g_manifest_root); - if ((ret = init_tty_handle(stdin_hdl, /*write=*/false)) < 0) { + if (!g_pal_control->parent_process) { + ret = init_default_handle(handle_map, /*fd=*/0, "libos.redirect_fd.stdin", /*write=*/false); + if (ret < 0) { unlock(&handle_map->lock); - put_handle(stdin_hdl); return ret; } - __init_handle(&handle_map->map[0], /*fd=*/0, stdin_hdl, /*flags=*/0); - put_handle(stdin_hdl); - } - - /* initialize stdout */ - if (!HANDLE_ALLOCATED(handle_map->map[1])) { - struct shim_handle* stdout_hdl = get_new_handle(); - if (!stdout_hdl) { + ret = init_default_handle(handle_map, /*fd=*/1, "libos.redirect_fd.stdout", /*write=*/true); + if (ret < 0) { unlock(&handle_map->lock); - return -ENOMEM; + return ret; } - if ((ret = init_tty_handle(stdout_hdl, /*write=*/true)) < 0) { + ret = init_default_handle(handle_map, /*fd=*/2, "libos.redirect_fd.stderr", /*write=*/true); + if (ret < 0) { unlock(&handle_map->lock); - put_handle(stdout_hdl); return ret; } - __init_handle(&handle_map->map[1], /*fd=*/1, stdout_hdl, /*flags=*/0); - put_handle(stdout_hdl); - } - - /* initialize stderr as duplicate of stdout */ - if (!HANDLE_ALLOCATED(handle_map->map[2])) { - struct shim_handle* stdout_hdl = handle_map->map[1]->handle; - __init_handle(&handle_map->map[2], /*fd=*/2, stdout_hdl, /*flags=*/0); + if (handle_map->fd_top == FD_NULL || handle_map->fd_top < 2) + handle_map->fd_top = 2; } - if (handle_map->fd_top == FD_NULL || handle_map->fd_top < 2) - handle_map->fd_top = 2; - unlock(&handle_map->lock); done: diff --git a/LibOS/shim/test/regression/exec_victim.c b/LibOS/shim/test/regression/exec_victim.c index 773556e605..6894eaa345 100644 --- a/LibOS/shim/test/regression/exec_victim.c +++ b/LibOS/shim/test/regression/exec_victim.c @@ -17,24 +17,5 @@ int main(int argc, char** argv, const char** envp) { fprintf(out, "Hello World (%s)!\n", argv[0]); fprintf(out, "envp[\'IN_EXECVE\'] = %s\n", getenv("IN_EXECVE")); - fprintf( - out, - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ -\n"); return 0; } diff --git a/LibOS/shim/test/regression/fork_and_exec.c b/LibOS/shim/test/regression/fork_and_exec.c index 7b10237175..36742b8191 100644 --- a/LibOS/shim/test/regression/fork_and_exec.c +++ b/LibOS/shim/test/regression/fork_and_exec.c @@ -1,4 +1,6 @@ -#define _XOPEN_SOURCE 700 +#define _GNU_SOURCE +#include +#include #include #include #include @@ -9,6 +11,23 @@ int main(int argc, const char** argv, const char** envp) { pid_t child_pid; + char c = 0; + ssize_t x = read(0, &c, 1); + if (x < 0) { + err(1, "stdin read failed"); + } else if (x != 1) { + assert(x == 0); + errx(1, "unexpected eof on stdin"); + } + assert(c == 'a'); + x = read(0, &c, 1); + if (x < 0) { + err(1, "stdin 2nd read failed"); + } + if (x != 0) { + errx(1, "stdin read succeeded unexpectedly"); + } + /* duplicate STDOUT into newfd and pass it as exec_victim argument * (it will be inherited by exec_victim) */ int newfd = dup(1); diff --git a/LibOS/shim/test/regression/fork_and_exec.manifest.template b/LibOS/shim/test/regression/fork_and_exec.manifest.template new file mode 100644 index 0000000000..ff82eac7ee --- /dev/null +++ b/LibOS/shim/test/regression/fork_and_exec.manifest.template @@ -0,0 +1,38 @@ +loader.preload = "file:{{ graphene.libos }}" +libos.entrypoint = "fork_and_exec" +loader.argv0_override = "fork_and_exec" +loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}" + +fs.mount.graphene_lib.type = "chroot" +fs.mount.graphene_lib.path = "/lib" +fs.mount.graphene_lib.uri = "file:{{ graphene.runtimedir() }}" + +fs.mount.host_lib.type = "chroot" +fs.mount.host_lib.path = "{{ arch_libdir }}" +fs.mount.host_lib.uri = "file:{{ arch_libdir }}" + +fs.mount.host_usr_lib.type = "chroot" +fs.mount.host_usr_lib.path = "/usr/{{ arch_libdir }}" +fs.mount.host_usr_lib.uri = "file:/usr/{{ arch_libdir }}" + +fs.mount.bin.type = "chroot" +fs.mount.bin.path = "/bin" +fs.mount.bin.uri = "file:/bin" + +libos.redirect_fd.stdin = "fork_and_exec.stdin" +libos.redirect_fd.stdout = "fork_and_exec.stdout" +libos.redirect_fd.stderr = "fork_and_exec.stderr" + +sgx.trusted_files.runtime = "file:{{ graphene.runtimedir() }}/" +sgx.trusted_files.libgcc_s = "file:{{ arch_libdir }}/libgcc_s.so.1" +sgx.trusted_files.libstdcxx = "file:/usr{{ arch_libdir }}/libstdc++.so.6" + +sgx.trusted_files.entrypoint = "file:{{ entrypoint }}" +sgx.trusted_files.exec_victim = "file:exec_victim" + +sgx.allowed_files.stdin = "file:fork_and_exec.stdin" +sgx.allowed_files.stdout = "file:fork_and_exec.stdout" +sgx.allowed_files.stderr = "file:fork_and_exec.stderr" + +sgx.thread_num = 8 +sgx.nonpie_binary = true diff --git a/LibOS/shim/test/regression/test_libos.py b/LibOS/shim/test/regression/test_libos.py index 3fdf07b856..1c34d3085d 100644 --- a/LibOS/shim/test/regression/test_libos.py +++ b/LibOS/shim/test/regression/test_libos.py @@ -111,11 +111,7 @@ def test_110_basic_bootstrapping_cpp(self): def test_200_exec(self): stdout, _ = self.run_binary(['exec']) - # 2 page child binary - self.assertIn( - '0' * 89 + ' ' + - ('0' * 93 + ' ') * 15, - stdout) + self.assertIn('Hello World (./exec_victim)!', stdout) def test_201_exec_same(self): args = ['arg_#%d' % i for i in range(50)] @@ -124,11 +120,29 @@ def test_201_exec_same(self): self.assertIn(arg + '\n', stdout) def test_202_fork_and_exec(self): + paths = ['fork_and_exec.stdin', 'fork_and_exec.stdout', 'fork_and_exec.stderr'] + for path in paths: + if os.path.exists(path): + os.remove(path) + with open(paths[0], 'wb') as f: + f.write(b'a') + stdout, _ = self.run_binary(['fork_and_exec'], timeout=60) - # fork and exec 2 page child binary - self.assertIn('child exited with status: 0', stdout) - self.assertIn('test completed successfully', stdout) + with open(paths[1], 'rb') as f: + file_stdout = f.read() + with open(paths[2], 'rb') as f: + file_stderr = f.read() + + for path in paths: + if os.path.exists(path): + os.remove(path) + + self.assertIn(b'Hello World (./exec_victim)!', file_stdout) + self.assertIn(b'child exited with status: 0', file_stdout) + self.assertIn(b'test completed successfully', file_stdout) + self.assertEqual(b'', file_stderr) + self.assertEqual(b'', stdout) def test_203_vfork_and_exec(self): stdout, _ = self.run_binary(['vfork_and_exec'], timeout=60)