Skip to content
This repository has been archived by the owner on Jan 20, 2022. It is now read-only.

Commit

Permalink
LibOS: race condition on thread exiting
Browse files Browse the repository at this point in the history
Once exiting thread notifies at shim LibOS level, other threads can
release stack memory and tls. But the existing thread can be still
executing resulting in SEGV. Switch stack and tls to private area to
avoid race condition.

Signed-off-by: Isaku Yamahata <isaku.yamahata@gmail.com>
  • Loading branch information
yamahata committed Jul 22, 2019
1 parent 536f6a1 commit f5099d4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 16 deletions.
4 changes: 4 additions & 0 deletions LibOS/shim/include/shim_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ struct shim_thread {
#ifdef PROFILE
unsigned long exit_time;
#endif

__libc_tcb_t exit_tcb;
#define SHIM_THREAD_EXIT_STACK_SIZE (4096)
uint8_t exit_stack[SHIM_THREAD_EXIT_STACK_SIZE];
};

DEFINE_LIST(shim_simple_thread);
Expand Down
61 changes: 45 additions & 16 deletions LibOS/shim/src/sys/shim_exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,49 @@ int try_process_exit (int error_code, int term_signal)
return 0;
}

/*
* Once exiting thread notifies at shim LibOS level, other threads can release
* stack memory and tls. But the existing thread can be still
* executing. Switch stack and tls to private area to avoid race condition.
*/
noreturn static void exit_trampoline (int error_code, void (*func)(int))
{
struct shim_thread * cur_thread = get_cur_thread();

uintptr_t stack_top = (uintptr_t)&cur_thread->exit_stack;
stack_top += sizeof(cur_thread->exit_stack) - 16;
stack_top &= ~15;

populate_tls(&cur_thread->exit_tcb, false);
debug_setbuf(&cur_thread->exit_tcb.shim_tcb, true);

int ret;
__asm__ volatile(
"movq %%rsp, %%rax\n"
"movq %%rbx, %%rsp\n"
"pushq %%rbp\n"
"pushq %%rax\n"
"movq %%rsp, %%rbp\n"
"callq *%%rdx\n"
/* the above callq should never return */
: "=a"(ret) : "b"(stack_top), "D"(error_code), "d"(func));
while (true) {
/* nothing */
}
}

noreturn static void __shim_do_exit_late (int error_code)
{
try_process_exit(error_code, 0);

#ifdef PROFILE
if (ENTER_TIME)
SAVE_PROFILE_INTERVAL_SINCE(syscall_exit, ENTER_TIME);
#endif

DkThreadExit();
}

noreturn int shim_do_exit_group (int error_code)
{
INC_PROFILE_OCCURENCE(syscall_use_ipc);
Expand All @@ -185,14 +228,7 @@ noreturn int shim_do_exit_group (int error_code)
do_kill_proc(cur_thread->tgid, cur_thread->tgid, SIGKILL, false);

debug("now exit the process\n");
try_process_exit(error_code, 0);

#ifdef PROFILE
if (ENTER_TIME)
SAVE_PROFILE_INTERVAL_SINCE(syscall_exit_group, ENTER_TIME);
#endif

DkThreadExit();
exit_trampoline(error_code, &__shim_do_exit_late);
}

noreturn int shim_do_exit (int error_code)
Expand All @@ -212,12 +248,5 @@ noreturn int shim_do_exit (int error_code)
}
#endif

try_process_exit(error_code, 0);

#ifdef PROFILE
if (ENTER_TIME)
SAVE_PROFILE_INTERVAL_SINCE(syscall_exit, ENTER_TIME);
#endif

DkThreadExit();
exit_trampoline(error_code, &__shim_do_exit_late);
}

0 comments on commit f5099d4

Please sign in to comment.