Skip to content

Commit

Permalink
Merge pull request #10549 from xavierleroy/arm64-signals
Browse files Browse the repository at this point in the history
Stack overflow detection and naked pointers checking for ARM64 (Linux and macOS)
  • Loading branch information
xavierleroy committed Aug 24, 2021
2 parents 1bd0e66 + 50495f6 commit 672965b
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 60 deletions.
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

0 comments on commit 672965b

Please sign in to comment.