Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

thread: support mprotect-based stack guard #327

Merged
merged 8 commits into from
Apr 20, 2021
20 changes: 18 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,12 @@ AC_ARG_ENABLE([tool],
# --enable-stack-overflow-check
AC_ARG_ENABLE([stack-overflow-check],
[ --enable-stack-overflow-check@<:@=OPT@:>@ enable a stack overflow check
canary|canary-8 - use an 8-byte stack canary.
canary-XX - use an XX-byte stack canary.
canary|canary-8 - use an 8-byte stack canary.
canary-XX - use an XX-byte stack canary.
mprotect - use mprotect. Ignore the failure of mprotect().
Alternatively, users can set ABT_STACK_OVERFLOW_CHECK=mprotect
mprotect-strict - use mprotect. Assert if mprotect() fails.
Alternatively, users can set ABT_STACK_OVERFLOW_CHECK=mprotect_strict
none|no
],,[enable_stack_overflow_check=no])

Expand Down Expand Up @@ -712,6 +716,12 @@ case "$enable_stack_overflow_check" in
AC_MSG_WARN([Unknown value $enable_stack_overflow_check for --enable-stack-overflow-check])
fi
;;
mprotect)
stack_overflow_check_type="ABTI_STACK_CHECK_TYPE_MPROTECT"
;;
mprotect-strict)
stack_overflow_check_type="ABTI_STACK_CHECK_TYPE_MPROTECT_STRICT"
;;
none|no)
stack_overflow_check_type="ABTI_STACK_CHECK_TYPE_NONE"
;;
Expand Down Expand Up @@ -875,6 +885,12 @@ AC_CHECK_LIB(pthread, pthread_join)
# check pthread_barrier
AC_CHECK_FUNCS(pthread_barrier_init)

# check mprotect
AC_CHECK_FUNCS(mprotect)

# check getpagesize
AC_CHECK_FUNCS(getpagesize)

# check dlvsym
ABT_RT_CFLAGS=""
ABT_RT_LDFLAGS=""
Expand Down
37 changes: 33 additions & 4 deletions src/arch/abtd_env.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define ABTD_SCHED_EVENT_FREQ 50
#define ABTD_SCHED_SLEEP_NSEC 100

#define ABTD_SYS_PAGE_SIZE 4096
#define ABTD_HUGE_PAGE_SIZE (2 * 1024 * 1024)
#define ABTD_MEM_PAGE_SIZE (2 * 1024 * 1024)
#define ABTD_MEM_STACK_PAGE_SIZE (8 * 1024 * 1024)
Expand All @@ -28,9 +29,7 @@
#define ABTD_ENV_SIZE_MAX ((size_t)(SIZE_MAX / 2))

static uint32_t roundup_pow2_uint32(uint32_t val);
#ifdef ABT_CONFIG_USE_MEM_POOL
static size_t roundup_pow2_size(size_t val);
#endif
static const char *get_abt_env(const char *env_suffix);
static ABT_bool is_false(const char *str, ABT_bool include0);
static ABT_bool is_true(const char *str, ABT_bool include1);
Expand Down Expand Up @@ -89,6 +88,38 @@ void ABTD_env_init(ABTI_global *p_global)
load_env_uint32("KEY_TABLE_SIZE", ABTD_KEY_TABLE_DEFAULT_SIZE, 1,
ABTD_ENV_UINT32_MAX));

/* ABT_STACK_OVERFLOW_CHECK, ABT_ENV_STACK_OVERFLOW_CHECK */
env = get_abt_env("STACK_OVERFLOW_CHECK");
if (env) {
if (strcasecmp(env, "mprotect_strict") == 0) {
p_global->stack_guard_kind = ABTI_STACK_GUARD_MPROTECT_STRICT;
} else if (strcasecmp(env, "mprotect") == 0) {
p_global->stack_guard_kind = ABTI_STACK_GUARD_MPROTECT;
} else {
/* Otherwise, disable mprotect-based stack guard. */
p_global->stack_guard_kind = ABTI_STACK_GUARD_NONE;
}
} else {
/* Set the default mode. */
#if ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_MPROTECT
p_global->stack_guard_kind = ABTI_STACK_GUARD_MPROTECT;
#elif ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_MPROTECT_STRICT
p_global->stack_guard_kind = ABTI_STACK_GUARD_MPROTECT_STRICT;
#else
/* Stack canary is compile-time setting. */
p_global->stack_guard_kind = ABTI_STACK_GUARD_NONE;
#endif
}

/* ABT_SYS_PAGE_SIZE, ABT_ENV_SYS_PAGE_SIZE
* System page size. It must be 2^N. */
size_t sys_page_size = ABTD_SYS_PAGE_SIZE;
#if HAVE_GETPAGESIZE
sys_page_size = getpagesize();
#endif
p_global->sys_page_size = roundup_pow2_size(
load_env_size("SYS_PAGE_SIZE", sys_page_size, 64, ABTD_ENV_SIZE_MAX));

/* ABT_THREAD_STACKSIZE, ABT_ENV_THREAD_STACKSIZE
* Default stack size for ULT */
p_global->thread_stacksize =
Expand Down Expand Up @@ -267,7 +298,6 @@ static uint32_t roundup_pow2_uint32(uint32_t val)
return ((uint32_t)1) << i;
}

#ifdef ABT_CONFIG_USE_MEM_POOL
static size_t roundup_pow2_size(size_t val)
{
if (val == 0)
Expand All @@ -279,7 +309,6 @@ static size_t roundup_pow2_size(size_t val)
}
return ((size_t)1) << i;
}
#endif

static const char *get_abt_env(const char *env_suffix)
{
Expand Down
11 changes: 11 additions & 0 deletions src/include/abti.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@

#define ABTI_STACK_CHECK_TYPE_NONE 0
#define ABTI_STACK_CHECK_TYPE_CANARY 1
#define ABTI_STACK_CHECK_TYPE_MPROTECT 2
#define ABTI_STACK_CHECK_TYPE_MPROTECT_STRICT 3

enum ABTI_xstream_type {
ABTI_XSTREAM_TYPE_PRIMARY,
Expand All @@ -78,6 +80,12 @@ enum ABTI_sched_used {
ABTI_SCHED_IN_POOL
};

enum ABTI_stack_guard {
ABTI_STACK_GUARD_NONE = 0,
ABTI_STACK_GUARD_MPROTECT,
ABTI_STACK_GUARD_MPROTECT_STRICT,
};

#define ABTI_THREAD_TYPE_EXT ((ABTI_thread_type)0)
#define ABTI_THREAD_TYPE_THREAD ((ABTI_thread_type)(0x1 << 0))
#define ABTI_THREAD_TYPE_ROOT ((ABTI_thread_type)(0x1 << 1))
Expand Down Expand Up @@ -150,6 +158,7 @@ typedef struct ABTI_thread_id_opaque *ABTI_thread_id;
/* Unit-to-thread hash table. */
typedef struct ABTI_atomic_unit_to_thread ABTI_atomic_unit_to_thread;
typedef struct ABTI_unit_to_thread_entry ABTI_unit_to_thread_entry;
typedef enum ABTI_stack_guard ABTI_stack_guard;

/* Architecture-Dependent Definitions */
#include "abtd.h"
Expand Down Expand Up @@ -215,6 +224,7 @@ struct ABTI_global {
uint32_t
mutex_max_handovers; /* Default max. # of local handovers (unused) */
uint32_t mutex_max_wakeups; /* Default max. # of wakeups (unused) */
size_t sys_page_size; /* System page size (typically, 4KB) */
size_t huge_page_size; /* Huge page size */
#ifdef ABT_CONFIG_USE_MEM_POOL
size_t mem_page_size; /* Page size for memory allocation */
Expand All @@ -234,6 +244,7 @@ struct ABTI_global {
ABTI_mem_pool_local_pool mem_pool_desc_ext;
#endif
#endif
ABTI_stack_guard stack_guard_kind; /* Stack guard type. */

ABT_bool print_config; /* Whether to print config on ABT_init */

Expand Down
127 changes: 96 additions & 31 deletions src/include/abti_mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,95 @@ int ABTI_mem_check_lp_alloc(ABTI_global *p_global, int lp_alloc);
#define ABTI_STACK_CANARY_VALUE ((uint64_t)0xbaadc0debaadc0de)

/* Inline functions */
static inline void ABTI_mem_register_stack(void *p_stack, size_t stacksize)
{
#if ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_CANARY
static inline void ABTI_mem_write_stack_canary(void *p_stack)
{
/* Write down stack canary. */
if (p_stack) {
uint64_t i;
for (i = 0;
i < ABTU_roundup_uint64(ABT_CONFIG_STACK_CHECK_CANARY_SIZE, 8);
i += sizeof(uint64_t)) {
((uint64_t *)p_stack)[i] = ABTI_STACK_CANARY_VALUE;
}
uint64_t i;
for (i = 0; i < ABTU_roundup_uint64(ABT_CONFIG_STACK_CHECK_CANARY_SIZE, 8);
i += sizeof(uint64_t)) {
((uint64_t *)p_stack)[i] = ABTI_STACK_CANARY_VALUE;
}
}

static inline void ABTI_mem_check_stack_canary(void *p_stack)
{
uint64_t i;
for (i = 0; i < ABTU_roundup_uint64(ABT_CONFIG_STACK_CHECK_CANARY_SIZE, 8);
i += sizeof(uint64_t)) {
ABTI_ASSERT(((uint64_t *)p_stack)[i] == ABTI_STACK_CANARY_VALUE);
}
}
#endif

static inline void ABTI_mem_register_stack(const ABTI_global *p_global,
void *p_stack, size_t stacksize,
ABT_bool mprotect_if_needed)
{
if (mprotect_if_needed) {
if (p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT ||
p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT_STRICT) {
if (p_stack) {
int abt_errno =
ABTU_mprotect(ABTU_roundup_ptr(p_stack,
p_global->sys_page_size),
p_global->sys_page_size, ABT_TRUE);
if (p_global->stack_guard_kind ==
ABTI_STACK_GUARD_MPROTECT_STRICT) {
ABTI_ASSERT(abt_errno == ABT_SUCCESS);
}
}
} else {
#if ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_CANARY
if (p_stack) {
ABTI_mem_write_stack_canary(p_stack);
}
#endif
}
} else {
#if ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_CANARY
if (!(p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT ||
p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT_STRICT) &&
p_stack) {
ABTI_mem_write_stack_canary(p_stack);
}
#endif
}
ABTI_VALGRIND_REGISTER_STACK(p_stack, stacksize);
}

static inline void ABTI_mem_unregister_stack(void *p_stack)
static inline void ABTI_mem_unregister_stack(const ABTI_global *p_global,
void *p_stack,
ABT_bool mprotect_if_needed)
{
if (mprotect_if_needed) {
if (p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT ||
p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT_STRICT) {
if (p_stack) {
int abt_errno =
ABTU_mprotect(ABTU_roundup_ptr(p_stack,
p_global->sys_page_size),
p_global->sys_page_size, ABT_FALSE);
/* This should not fail since otherwise we cannot free this
* memory. */
ABTI_ASSERT(abt_errno == ABT_SUCCESS);
}
} else {
#if ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_CANARY
if (p_stack) {
uint64_t i;
for (i = 0;
i < ABTU_roundup_uint64(ABT_CONFIG_STACK_CHECK_CANARY_SIZE, 8);
i += sizeof(uint64_t)) {
ABTI_ASSERT(((uint64_t *)p_stack)[i] == ABTI_STACK_CANARY_VALUE);
if (p_stack) {
ABTI_mem_check_stack_canary(p_stack);
}
#endif
}
} else {
#if ABT_CONFIG_STACK_CHECK_TYPE == ABTI_STACK_CHECK_TYPE_CANARY
if (!(p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT ||
p_global->stack_guard_kind == ABTI_STACK_GUARD_MPROTECT_STRICT) &&
p_stack) {
ABTI_mem_check_stack_canary(p_stack);
}
}
#endif
}
ABTI_VALGRIND_UNREGISTER_STACK(p_stack);
}

Expand Down Expand Up @@ -179,24 +240,26 @@ ABTI_mem_alloc_ythread_default(ABTI_global *p_global, ABTI_local *p_local,
&p_stack);
ABTI_CHECK_ERROR(abt_errno);
p_ythread->thread.type = ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK;
ABTI_mem_register_stack(p_global, p_stack, stacksize, ABT_TRUE);
} else {
#ifdef ABT_CONFIG_USE_MEM_POOL
int abt_errno = ABTI_mem_alloc_ythread_mempool_desc_stack_impl(
&p_local_xstream->mem_pool_stack, stacksize, &p_ythread, &p_stack);
ABTI_CHECK_ERROR(abt_errno);
p_ythread->thread.type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK;
ABTI_mem_register_stack(p_global, p_stack, stacksize, ABT_FALSE);
#else
int abt_errno =
ABTI_mem_alloc_ythread_malloc_desc_stack_impl(stacksize, &p_ythread,
&p_stack);
ABTI_CHECK_ERROR(abt_errno);
p_ythread->thread.type = ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK;
ABTI_mem_register_stack(p_global, p_stack, stacksize, ABT_TRUE);
#endif
}
/* Initialize members of ABTI_thread_attr. */
p_ythread->p_stack = p_stack;
p_ythread->stacksize = stacksize;
ABTI_mem_register_stack(p_ythread->p_stack, p_ythread->stacksize);
*pp_ythread = p_ythread;
return ABT_SUCCESS;
}
Expand All @@ -217,24 +280,24 @@ ABTU_ret_err static inline int ABTI_mem_alloc_ythread_mempool_desc_stack(
&p_stack);
ABTI_CHECK_ERROR(abt_errno);
p_ythread->thread.type = ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK;
ABTI_mem_register_stack(p_global, p_stack, stacksize, ABT_TRUE);
} else {
int abt_errno = ABTI_mem_alloc_ythread_mempool_desc_stack_impl(
&p_local_xstream->mem_pool_stack, stacksize, &p_ythread, &p_stack);
ABTI_CHECK_ERROR(abt_errno);
p_ythread->thread.type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK;
ABTI_mem_register_stack(p_global, p_stack, stacksize, ABT_FALSE);
}
/* Copy members of p_attr. */
p_ythread->p_stack = p_stack;
p_ythread->stacksize = stacksize;
ABTI_mem_register_stack(p_ythread->p_stack, p_ythread->stacksize);
*pp_ythread = p_ythread;
return ABT_SUCCESS;
}
#endif

ABTU_ret_err static inline int
ABTI_mem_alloc_ythread_malloc_desc_stack(ABTI_thread_attr *p_attr,
ABTI_ythread **pp_ythread)
ABTU_ret_err static inline int ABTI_mem_alloc_ythread_malloc_desc_stack(
ABTI_global *p_global, ABTI_thread_attr *p_attr, ABTI_ythread **pp_ythread)
{
size_t stacksize = p_attr->stacksize;
ABTI_ythread *p_ythread;
Expand All @@ -248,13 +311,15 @@ ABTI_mem_alloc_ythread_malloc_desc_stack(ABTI_thread_attr *p_attr,
p_ythread->thread.type = ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK;
p_ythread->stacksize = stacksize;
p_ythread->p_stack = p_stack;
ABTI_mem_register_stack(p_ythread->p_stack, p_ythread->stacksize);
ABTI_mem_register_stack(p_global, p_stack, stacksize, ABT_TRUE);
*pp_ythread = p_ythread;
return ABT_SUCCESS;
}

ABTU_ret_err static inline int ABTI_mem_alloc_ythread_mempool_desc(
ABTI_local *p_local, ABTI_thread_attr *p_attr, ABTI_ythread **pp_ythread)
ABTU_ret_err static inline int
ABTI_mem_alloc_ythread_mempool_desc(ABTI_global *p_global, ABTI_local *p_local,
ABTI_thread_attr *p_attr,
ABTI_ythread **pp_ythread)
{
ABTI_ythread *p_ythread;
if (sizeof(ABTI_ythread) <= ABTI_MEM_POOL_DESC_ELEM_SIZE) {
Expand All @@ -272,8 +337,8 @@ ABTU_ret_err static inline int ABTI_mem_alloc_ythread_mempool_desc(
/* Copy members of p_attr. */
p_ythread->stacksize = p_attr->stacksize;
p_ythread->p_stack = p_attr->p_stack;
/* Note that the valgrind registration is ignored if p_stack is NULL. */
ABTI_mem_register_stack(p_ythread->p_stack, p_ythread->stacksize);
ABTI_mem_register_stack(p_global, p_ythread->p_stack, p_ythread->stacksize,
ABT_TRUE);
*pp_ythread = p_ythread;
return ABT_SUCCESS;
}
Expand All @@ -286,7 +351,7 @@ static inline void ABTI_mem_free_thread(ABTI_global *p_global,
#ifdef ABT_CONFIG_USE_MEM_POOL
if (p_thread->type & ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK) {
ABTI_ythread *p_ythread = ABTI_thread_get_ythread(p_thread);
ABTI_mem_unregister_stack(p_ythread->p_stack);
ABTI_mem_unregister_stack(p_global, p_ythread->p_stack, ABT_FALSE);

ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(p_local);
/* Came from a memory pool. */
Expand All @@ -306,18 +371,18 @@ static inline void ABTI_mem_free_thread(ABTI_global *p_global,
/* Non-yieldable thread or yieldable thread without stack. */
ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
if (p_ythread)
ABTI_mem_unregister_stack(p_ythread->p_stack);
ABTI_mem_unregister_stack(p_global, p_ythread->p_stack, ABT_TRUE);
ABTI_mem_free_nythread(p_global, p_local, p_thread);
} else if (p_thread->type & ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK) {
ABTI_ythread *p_ythread = ABTI_thread_get_ythread(p_thread);
ABTI_mem_unregister_stack(p_ythread->p_stack);
ABTI_mem_unregister_stack(p_global, p_ythread->p_stack, ABT_TRUE);
ABTU_free(p_ythread->p_stack);
} else {
ABTI_ASSERT(p_thread->type & ABTI_THREAD_TYPE_MEM_MALLOC_DESC);
ABTI_STATIC_ASSERT(offsetof(ABTI_ythread, thread) == 0);
ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
if (p_ythread)
ABTI_mem_unregister_stack(p_ythread->p_stack);
ABTI_mem_unregister_stack(p_global, p_ythread->p_stack, ABT_TRUE);
ABTU_free(p_thread);
}
}
Expand Down
Loading