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

Stack overflow detection and naked pointers checking for ARM64 #10549

Merged
merged 5 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Working version
*blit_* function during Mark phase
(François Bobot, reported by Stephen Dolan, reviewed by Damien Doligez)

- #10549: Stack overflow detection and naked pointers checking for ARM64
(Xavier Leroy, review by Stephen Dolan)


### Code generation and optimizations:

### Standard library:
Expand Down
5 changes: 3 additions & 2 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1771,7 +1771,7 @@ AC_MSG_CHECKING([whether stack overflows can be detected])

AS_CASE([$arch,$system],
[i386,linux_elf|amd64,linux|amd64,macosx \
|amd64,openbsd|i386,bsd_elf],
|amd64,openbsd|i386,bsd_elf|arm64,linux|arm64,macosx],
[AC_DEFINE([HAS_STACK_OVERFLOW_DETECTION])
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
Expand Down Expand Up @@ -1841,7 +1841,8 @@ AS_IF([test x"$enable_naked_pointers_checker" = "xyes" ],
AS_CASE(["$arch","$system"],
[amd64,linux|amd64,macosx \
|amd64,openbsd|amd64,win64 \
|amd64,freebsd|amd64,solaris],
|amd64,freebsd|amd64,solaris \
|arm64,linux|arm64,macosx],
[naked_pointers_checker=true
AC_DEFINE([NAKED_POINTERS_CHECKER])],
[*],
Expand Down
20 changes: 20 additions & 0 deletions runtime/arm64.S
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,26 @@ FUNCTION(caml_raise_exception)
CFI_ENDPROC
END_FUNCTION(caml_raise_exception)

/* Raise a Stack_overflow exception on return from segv_handler()
(in runtime/signals_nat.c). On entry, the stack is full, so we
cannot record a backtrace.
No CFI information here since this function disrupts the stack
backtrace anyway.
Since we have returned from the signal handler, the DOMAIN_STATE_PTR,
TRAP_PTR and ALLOC_PTR registers should have the same values
they had in the faulting OCaml code, so don't try to reload them. */

FUNCTION(caml_stack_overflow)
/* Load the exception bucket */
ADDRGLOBAL(x0, caml_exn_Stack_overflow)
/* Cut stack at current trap handler */
mov sp, TRAP_PTR
/* Pop previous handler and jump to it */
ldr TMP, [sp, 8]
ldr TRAP_PTR, [sp], 16
br TMP
END_FUNCTION(caml_stack_overflow)

/* Callback from C to OCaml */

FUNCTION(caml_callback_asm)
Expand Down
30 changes: 28 additions & 2 deletions runtime/major_gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ void caml_finalise_heap (void)

#if defined(NAKED_POINTERS_CHECKER) && defined(NATIVE_CODE)

#ifdef _WIN32
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

Expand All @@ -1312,7 +1312,7 @@ Caml_inline int safe_load(volatile header_t * p, header_t * result)
return 1;
}

#else
#elif defined(TARGET_amd64)

Caml_inline int safe_load (header_t * addr, /*out*/ header_t * contents)
{
Expand All @@ -1336,6 +1336,32 @@ Caml_inline int safe_load (header_t * addr, /*out*/ header_t * contents)
return ok;
}

#elif defined(TARGET_arm64)

Caml_inline int safe_load (header_t * addr, /*out*/ header_t * contents)
{
int ok;
header_t h;
intnat tmp;

asm volatile(
"adr %[tmp], 1f \n\t"
"str %[tmp], [%[handler]] \n\t"
"mov %w[ok], #0 \n\t"
"ldr %[h], [%[addr]] \n\t"
"mov %w[ok], #1 \n\t"
"1: \n\t"
"mov %[tmp], #0 \n\t"
"str %[tmp], [%[handler]]"
: [tmp] "=&r" (tmp), [ok] "=&r" (ok), [h] "=&r" (h)
: [addr] "r" (addr),
[handler] "r" (&(Caml_state->checking_pointer_pc)));
*contents = h;
return ok;
}

#else
#error "NAKED_POINTERS_CHECKER not supported on this platform"
#endif

static void is_naked_pointer_safe (value v, value *p)
Expand Down
133 changes: 79 additions & 54 deletions runtime/signals_osdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,61 @@

#define RETURN_AFTER_STACK_OVERFLOW

/****************** AMD64, Solaris x86 */

#elif defined(TARGET_amd64) && defined (SYS_solaris)

#include <ucontext.h>

#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, ucontext_t * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO

typedef greg_t context_reg;
#define CONTEXT_PC (context->uc_mcontext.gregs[REG_RIP])
#define CONTEXT_C_ARG_1 (context->uc_mcontext.gregs[REG_RDI])
#define CONTEXT_SP (context->uc_mcontext.gregs[REG_RSP])
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.gregs[REG_R15])
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

/****************** AMD64, OpenBSD */

#elif defined(TARGET_amd64) && defined (SYS_openbsd)

#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, struct sigcontext * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO

#define CONTEXT_PC (context->sc_rip)
#define CONTEXT_C_ARG_1 (context->sc_rdi)
#define CONTEXT_SP (context->sc_rsp)
#define CONTEXT_YOUNG_PTR (context->sc_r15)
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

/****************** AMD64, NetBSD */

#elif defined(TARGET_amd64) && defined (SYS_netbsd)

#include <ucontext.h>
#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, ucontext_t * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO

#define CONTEXT_PC (_UC_MACHINE_PC(context))
#define CONTEXT_C_ARG_1 (context->uc_mcontext.gregs[REG_RDI])
#define CONTEXT_SP (_UC_MACHINE_SP(context))
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.gregs[REG_R15])
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

/****************** ARM, Linux */

#elif defined(TARGET_arm) && (defined(SYS_linux_eabi) \
Expand Down Expand Up @@ -102,85 +157,55 @@
typedef unsigned long context_reg;
#define CONTEXT_PC (context->uc_mcontext.pc)
#define CONTEXT_SP (context->uc_mcontext.sp)
#define CONTEXT_EXCEPTION_POINTER (context->uc_mcontext.regs[26])
#define CONTEXT_C_ARG_1 (context->uc_mcontext.regs[0])
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.regs[27])
#define CONTEXT_FAULTING_ADDRESS ((char *) context->uc_mcontext.fault_address)

/****************** ARM64, FreeBSD */
#define RETURN_AFTER_STACK_OVERFLOW

#elif defined(TARGET_arm64) && defined(SYS_freebsd)
/****************** ARM64, MacOSX */

#elif defined(TARGET_arm64) && defined (SYS_macosx)

#include <sys/ucontext.h>

#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, ucontext_t * context)
static void name(int sig, siginfo_t * info, void * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_sigaction = (name); \
sigact.sa_flags = SA_SIGINFO

typedef unsigned long context_reg;
#define CONTEXT_PC (context->uc_mcontext.mc_gpregs.gp_elr)
#define CONTEXT_SP (context->uc_mcontext.mc_gpregs.gp_sp)
#define CONTEXT_EXCEPTION_POINTER (context->uc_mcontext.mc_gpregs.gp_x[26])
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.mc_gpregs.gp_x[27])
typedef unsigned long long context_reg;
#define CONTEXT_STATE (((ucontext_t *)context)->uc_mcontext->__ss)
#define CONTEXT_PC (CONTEXT_STATE.__pc)
#define CONTEXT_SP (CONTEXT_STATE.__sp)
#define CONTEXT_C_ARG_1 (CONTEXT_STATE.__x[0])
#define CONTEXT_YOUNG_PTR (CONTEXT_STATE.__x[27])
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

#define RETURN_AFTER_STACK_OVERFLOW

/****************** AMD64, Solaris x86 */
/****************** ARM64, FreeBSD */

#elif defined(TARGET_amd64) && defined (SYS_solaris)
#elif defined(TARGET_arm64) && defined(SYS_freebsd)

#include <ucontext.h>
#include <sys/ucontext.h>

#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, ucontext_t * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO

typedef greg_t context_reg;
#define CONTEXT_PC (context->uc_mcontext.gregs[REG_RIP])
#define CONTEXT_C_ARG_1 (context->uc_mcontext.gregs[REG_RDI])
#define CONTEXT_SP (context->uc_mcontext.gregs[REG_RSP])
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.gregs[REG_R15])
typedef unsigned long context_reg;
#define CONTEXT_PC (context->uc_mcontext.mc_gpregs.gp_elr)
#define CONTEXT_SP (context->uc_mcontext.mc_gpregs.gp_sp)
#define CONTEXT_EXCEPTION_POINTER (context->uc_mcontext.mc_gpregs.gp_x[26])
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.mc_gpregs.gp_x[27])
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

/****************** AMD64, OpenBSD */

#elif defined(TARGET_amd64) && defined (SYS_openbsd)

#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, struct sigcontext * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO

#define CONTEXT_PC (context->sc_rip)
#define CONTEXT_C_ARG_1 (context->sc_rdi)
#define CONTEXT_SP (context->sc_rsp)
#define CONTEXT_YOUNG_PTR (context->sc_r15)
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

/****************** AMD64, NetBSD */

#elif defined(TARGET_amd64) && defined (SYS_netbsd)

#include <ucontext.h>
#define DECLARE_SIGNAL_HANDLER(name) \
static void name(int sig, siginfo_t * info, ucontext_t * context)

#define SET_SIGACT(sigact,name) \
sigact.sa_sigaction = (void (*)(int,siginfo_t *,void *)) (name); \
sigact.sa_flags = SA_SIGINFO

#define CONTEXT_PC (_UC_MACHINE_PC(context))
#define CONTEXT_C_ARG_1 (context->uc_mcontext.gregs[REG_RDI])
#define CONTEXT_SP (_UC_MACHINE_SP(context))
#define CONTEXT_YOUNG_PTR (context->uc_mcontext.gregs[REG_R15])
#define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr)

/****************** I386, Linux */

Expand Down