|
@@ -61,59 +61,31 @@ DEFINE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec, exec_rtld);
|
|
|
DEFINE_PROFILE_INTERVAL(unmap_all_vmas_for_exec, exec_rtld);
|
|
|
DEFINE_PROFILE_INTERVAL(load_new_executable_for_exec, exec_rtld);
|
|
|
|
|
|
-static void * old_stack_top, * old_stack, * old_stack_red;
|
|
|
-static const char ** new_argp;
|
|
|
-static int new_argc;
|
|
|
-static int * new_argcp;
|
|
|
-static elf_auxv_t * new_auxp;
|
|
|
-
|
|
|
int init_brk_from_executable (struct shim_handle * exec);
|
|
|
|
|
|
-int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
|
|
|
- const char ** envp)
|
|
|
+struct execve_rtld_arg
|
|
|
{
|
|
|
- BEGIN_PROFILE_INTERVAL();
|
|
|
+ void * old_stack_top;
|
|
|
+ void * old_stack;
|
|
|
+ void * old_stack_red;
|
|
|
+ const char ** new_argp;
|
|
|
+ int * new_argcp;
|
|
|
+ elf_auxv_t * new_auxp;
|
|
|
+};
|
|
|
+
|
|
|
+static void __shim_do_execve_rtld (struct execve_rtld_arg * __arg)
|
|
|
+{
|
|
|
+ struct execve_rtld_arg arg;
|
|
|
+ memcpy(&arg, __arg, sizeof(arg));
|
|
|
+ void * old_stack_top = arg.old_stack_top;
|
|
|
+ void * old_stack = arg.old_stack;
|
|
|
+ void * old_stack_red = arg.old_stack_red;
|
|
|
+ const char ** new_argp = arg.new_argp;
|
|
|
+ int * new_argcp = arg.new_argcp;
|
|
|
+ elf_auxv_t * new_auxp = arg.new_auxp;
|
|
|
|
|
|
struct shim_thread * cur_thread = get_cur_thread();
|
|
|
- int ret;
|
|
|
-
|
|
|
- if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0)
|
|
|
- return ret;
|
|
|
-
|
|
|
- SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec);
|
|
|
-
|
|
|
- void * tcb = malloc(sizeof(__libc_tcb_t));
|
|
|
- if (!tcb)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- populate_tls(tcb, false);
|
|
|
- __disable_preempt(&((__libc_tcb_t *) tcb)->shim_tcb); // Temporarily disable preemption
|
|
|
- // during execve().
|
|
|
- debug("set tcb to %p\n", tcb);
|
|
|
-
|
|
|
- put_handle(cur_thread->exec);
|
|
|
- get_handle(hdl);
|
|
|
- cur_thread->exec = hdl;
|
|
|
-
|
|
|
- old_stack_top = cur_thread->stack_top;
|
|
|
- old_stack = cur_thread->stack;
|
|
|
- old_stack_red = cur_thread->stack_red;
|
|
|
- cur_thread->stack_top = NULL;
|
|
|
- cur_thread->stack = NULL;
|
|
|
- cur_thread->stack_red = NULL;
|
|
|
-
|
|
|
- initial_envp = NULL;
|
|
|
- new_argc = 0;
|
|
|
- for (const char ** a = argv ; *a ; a++, new_argc++);
|
|
|
-
|
|
|
- new_argcp = &new_argc;
|
|
|
- if ((ret = init_stack(argv, envp, &new_argcp, &new_argp, &new_auxp)) < 0)
|
|
|
- return ret;
|
|
|
-
|
|
|
- SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec);
|
|
|
-
|
|
|
- SWITCH_STACK(new_argp);
|
|
|
- cur_thread = get_cur_thread();
|
|
|
+ int ret = 0;
|
|
|
|
|
|
UPDATE_PROFILE_INTERVAL();
|
|
|
|
|
@@ -133,8 +105,10 @@ int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
|
|
|
size_t count = DEFAULT_VMA_COUNT;
|
|
|
struct shim_vma_val * vmas = malloc(sizeof(struct shim_vma_val) * count);
|
|
|
|
|
|
- if (!vmas)
|
|
|
- return -ENOMEM;
|
|
|
+ if (!vmas) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
|
|
|
retry_dump_vmas:
|
|
|
ret = dump_all_vmas(vmas, count);
|
|
@@ -144,7 +118,8 @@ retry_dump_vmas:
|
|
|
= malloc(sizeof(struct shim_vma_val) * count * 2);
|
|
|
if (!new_vmas) {
|
|
|
free(vmas);
|
|
|
- return -ENOMEM;
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto error;
|
|
|
}
|
|
|
free(vmas);
|
|
|
vmas = new_vmas;
|
|
@@ -154,7 +129,7 @@ retry_dump_vmas:
|
|
|
|
|
|
if (ret < 0) {
|
|
|
free(vmas);
|
|
|
- return ret;
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
count = ret;
|
|
@@ -176,11 +151,10 @@ retry_dump_vmas:
|
|
|
SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec);
|
|
|
|
|
|
if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0)
|
|
|
- shim_terminate(ret);
|
|
|
+ goto error;
|
|
|
|
|
|
- ret = init_brk_from_executable(cur_thread->exec);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
+ if ((ret = init_brk_from_executable(cur_thread->exec)) < 0)
|
|
|
+ goto error;
|
|
|
|
|
|
load_elf_interp(cur_thread->exec);
|
|
|
|
|
@@ -195,6 +169,68 @@ retry_dump_vmas:
|
|
|
|
|
|
debug("execve: start execution\n");
|
|
|
execute_elf_object(cur_thread->exec, new_argcp, new_argp, new_auxp);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+error:
|
|
|
+ debug("execve: failed %d\n", ret);
|
|
|
+ shim_terminate(ret);
|
|
|
+}
|
|
|
+
|
|
|
+static int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
|
|
|
+ const char ** envp)
|
|
|
+{
|
|
|
+ BEGIN_PROFILE_INTERVAL();
|
|
|
+
|
|
|
+ struct shim_thread * cur_thread = get_cur_thread();
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec);
|
|
|
+
|
|
|
+ void * tcb = malloc(sizeof(__libc_tcb_t));
|
|
|
+ if (!tcb)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ populate_tls(tcb, false);
|
|
|
+ __disable_preempt(&((__libc_tcb_t *) tcb)->shim_tcb); // Temporarily disable preemption
|
|
|
+ // during execve().
|
|
|
+ debug("set tcb to %p\n", tcb);
|
|
|
+
|
|
|
+ put_handle(cur_thread->exec);
|
|
|
+ get_handle(hdl);
|
|
|
+ cur_thread->exec = hdl;
|
|
|
+
|
|
|
+ void * old_stack_top = cur_thread->stack_top;
|
|
|
+ void * old_stack = cur_thread->stack;
|
|
|
+ void * old_stack_red = cur_thread->stack_red;
|
|
|
+ cur_thread->stack_top = NULL;
|
|
|
+ cur_thread->stack = NULL;
|
|
|
+ cur_thread->stack_red = NULL;
|
|
|
+
|
|
|
+ initial_envp = NULL;
|
|
|
+ int new_argc = 0;
|
|
|
+ for (const char ** a = argv ; *a ; a++, new_argc++);
|
|
|
+
|
|
|
+ int * new_argcp = &new_argc;
|
|
|
+ const char ** new_argp;
|
|
|
+ elf_auxv_t * new_auxp;
|
|
|
+ if ((ret = init_stack(argv, envp, &new_argcp, &new_argp, &new_auxp)) < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec);
|
|
|
+
|
|
|
+ struct execve_rtld_arg arg = {
|
|
|
+ .old_stack_top = old_stack_top,
|
|
|
+ .old_stack = old_stack,
|
|
|
+ .old_stack_red = old_stack_red,
|
|
|
+ .new_argp = new_argp,
|
|
|
+ .new_argcp = new_argcp,
|
|
|
+ .new_auxp = new_auxp
|
|
|
+ };
|
|
|
+ __SWITCH_STACK(new_argcp, &__shim_do_execve_rtld, &arg);
|
|
|
return 0;
|
|
|
}
|
|
|
|