From b0bfe6bfa730d12c47c5e6d66d4e1e352ff43233 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Mon, 9 Sep 2013 17:59:32 +0200 Subject: [PATCH] base-linux: fix ELF dataspace execution With this patch, if an ELF dataspace to be executed does not have a path in the host file system, the dataspace content gets copied into a temporary file whose path can be given to 'execve()'. Fixes #879. --- .../src/core/include/core_linux_syscalls.h | 1 + base-linux/src/core/pd_session_component.cc | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/base-linux/src/core/include/core_linux_syscalls.h b/base-linux/src/core/include/core_linux_syscalls.h index 488d03287..e4ee22f50 100644 --- a/base-linux/src/core/include/core_linux_syscalls.h +++ b/base-linux/src/core/include/core_linux_syscalls.h @@ -17,6 +17,7 @@ /* basic Linux syscall bindings */ #include #include +#include /******************************************************* diff --git a/base-linux/src/core/pd_session_component.cc b/base-linux/src/core/pd_session_component.cc index bacb1f969..ff451fd27 100644 --- a/base-linux/src/core/pd_session_component.cc +++ b/base-linux/src/core/pd_session_component.cc @@ -364,6 +364,8 @@ int Pd_session_component::assign_parent(Parent_capability parent) void Pd_session_component::start(Capability binary) { + const char *tmp_filename = "temporary_executable_elf_dataspace_file_for_execve"; + /* lookup binary dataspace */ Object_pool::Guard ds(_ds_ep->lookup_and_lock(binary)); @@ -372,7 +374,32 @@ void Pd_session_component::start(Capability binary) return; /* XXX reflect error to client */ } - Linux_dataspace::Filename filename = ds->fname(); + const char *filename = ds->fname().buf; + + /* + * In order to be executable via 'execve', a program must be represented as + * a file on the Linux file system. However, this is not the case for a + * plain RAM dataspace that contains an ELF image. In this case, we copy + * the dataspace content into a temporary file whose path is passed to + * 'execve()'. + */ + if (strcmp(filename, "") == 0) { + + filename = tmp_filename; + + int tmp_binary_fd = lx_open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRWXU); + if (tmp_binary_fd < 0) { + PERR("Could not create file '%s'", filename); + return; /* XXX reflect error to client */ + } + + char buf[4096]; + int num_bytes = 0; + while ((num_bytes = lx_read(ds->fd().dst().socket, buf, sizeof(buf))) != 0) + lx_write(tmp_binary_fd, buf, num_bytes); + + lx_close(tmp_binary_fd); + } /* pass parent capability as environment variable to the child */ enum { ENV_STR_LEN = 256 }; @@ -412,13 +439,17 @@ void Pd_session_component::start(Capability binary) enum { STACK_SIZE = 4096 }; static char stack[STACK_SIZE]; /* initial stack used by the child until calling 'execve' */ + /* * Argument frame as passed to 'clone'. Because, we can only pass a single * pointer, all arguments are embedded within the 'execve_args' struct. */ - Execve_args arg(filename.buf, _root, argv_buf, env, _uid, _gid, + Execve_args arg(filename, _root, argv_buf, env, _uid, _gid, _parent.dst().socket); _pid = lx_create_process((int (*)(void *))_exec_child, stack + STACK_SIZE - sizeof(umword_t), &arg); + + if (strcmp(filename, tmp_filename) == 0) + lx_unlink(filename); };