Skip to content

Commit

Permalink
Merge pull request #327 from shintaro-iwasaki/pr/mprotect_stack
Browse files Browse the repository at this point in the history
thread: support mprotect-based stack guard
  • Loading branch information
shintaro-iwasaki authored Apr 20, 2021
2 parents be4fa26 + be72bd6 commit 79f45a6
Show file tree
Hide file tree
Showing 15 changed files with 589 additions and 59 deletions.
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

0 comments on commit 79f45a6

Please sign in to comment.